Skip to content

Commit

Permalink
feat: contact backup
Browse files Browse the repository at this point in the history
  • Loading branch information
cssxsh committed Oct 27, 2022
1 parent 9d8a9ef commit a67d73c
Show file tree
Hide file tree
Showing 4 changed files with 197 additions and 0 deletions.
121 changes: 121 additions & 0 deletions src/main/kotlin/xyz/cssxsh/mirai/admin/MiraiBackupService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package xyz.cssxsh.mirai.admin

import io.ktor.utils.io.core.*
import io.ktor.utils.io.streams.*
import net.mamoe.mirai.*
import net.mamoe.mirai.contact.*
import xyz.cssxsh.mirai.spi.*
import java.io.File
import java.util.zip.*
import kotlin.io.use

public object MiraiBackupService : BackupService {
override val level: Int = 0
override val id: String = "default-backup"

private fun ZipOutputStream.writeEntry(name: String, block: BytePacketBuilder.() -> Unit) {
putNextEntry(ZipEntry(name))
writePacket(block)
closeEntry()
}

override fun group() {
val backup = File("backup/group.${System.currentTimeMillis()}.zip")
backup.parentFile.mkdirs()
backup.outputStream().buffered().use { buffered ->
val output = ZipOutputStream(buffered)

output.writeEntry("readme.txt") {
append("csv 文件可以用 excel 或 wps 打开,或者你可以直接当成普通的文本文件编辑")
}

for (bot in Bot.instances) {
for (group in bot.groups) {
output.writeEntry("${bot.id}.${group.id}.group.csv") {
append("group, uid, name").append('\n')

for (member in group.members) {
append(group.id.toString())
.append(", ")
.append(member.id.toString())
.append(", ")
.append(member.nameCardOrNick)
.append('\n')
}
}
}
}
output.close()
}
}

override fun friend() {
val backup = File("backup/friend.${System.currentTimeMillis()}.zip")
backup.parentFile.mkdirs()
backup.outputStream().buffered().use { buffered ->
val output = ZipOutputStream(buffered)

output.writeEntry("readme.txt") {
append("csv 文件可以用 excel 或 wps 打开,或者你可以直接当成普通的文本文件编辑")
}

for (bot in Bot.instances) {

output.writeEntry("${bot.id}.friend.csv") {
append("bot, uid, name, group").append('\n')

for (friend in bot.friends) {
append(bot.id.toString())
.append(", ")
.append(friend.id.toString())
.append(", ")
.append(friend.remarkOrNick)
.append(", ")
.append(friend.friendGroup.name)
.append('\n')
}
}
}
output.close()
}
}

override fun bot() {
val backup = File("backup/bot.${System.currentTimeMillis()}.zip")
backup.outputStream().buffered(1 shl 23).use { buffered ->
val output = ZipOutputStream(buffered)
val bots = File("bots")
for (bot in bots.listFiles().orEmpty()) {
val device = bot.resolve("device.json")
if (device.exists()) {
val entry = ZipEntry("bots/${bot.name}/device.json")
entry.time = device.lastModified()
output.putNextEntry(entry)
device.inputStream().use { input -> input.transferTo(output) }
output.closeEntry()
}

val cache = bot.resolve("cache")
for (file in cache.listFiles() ?: continue) {
if (file.isDirectory) continue
val entry = ZipEntry("bots/${bot.name}/cache/${file.name}")
entry.time = file.lastModified()
output.putNextEntry(entry)
file.inputStream().use { input -> input.transferTo(output) }
output.closeEntry()
}
output.flush()
}

val yml = File("config/Console/AutoLogin.yml")
if (yml.exists()) {
val entry = ZipEntry("config/Console/AutoLogin.yml")
entry.time = yml.lastModified()
output.putNextEntry(entry)
yml.inputStream().use { input -> input.transferTo(output) }
output.closeEntry()
}
output.close()
}
}
}
43 changes: 43 additions & 0 deletions src/main/kotlin/xyz/cssxsh/mirai/admin/MiraiService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ internal fun ComparableService.Loader.reload() {
instances.add(MiraiContentCensor)
instances.add(MiraiBlackList)
instances.add(MiraiMessageTimer)
instances.add(MiraiBackupService)
}

internal fun ComparableService.Loader.render(): String = buildString {
Expand Down Expand Up @@ -178,4 +179,46 @@ internal fun quote(event: MessageEvent): MessageSource? {
}
}
return null
}

internal fun backup() {
if (ComparableService<BackupService>().isEmpty()) throw UnsupportedOperationException("没有任何实例")
for (backup in ComparableService<BackupService>()) {
try {
backup.bot()
} catch (cause: UnsupportedOperationException) {
continue
} catch (cause: Exception) {
logger.warning({ "backup bot failure." }, cause)
continue
}
logger.info { "backup bot ok by ${backup.id}" }
break
}

for (backup in ComparableService<BackupService>()) {
try {
backup.friend()
} catch (cause: UnsupportedOperationException) {
continue
} catch (cause: Exception) {
logger.warning({ "backup friend failure." }, cause)
continue
}
logger.info { "backup friend ok by ${backup.id}" }
break
}

for (backup in ComparableService<BackupService>()) {
try {
backup.group()
} catch (cause: UnsupportedOperationException) {
continue
} catch (cause: Exception) {
logger.warning({ "backup group failure." }, cause)
continue
}
logger.info { "backup group ok by ${backup.id}" }
break
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,18 @@ public object AdminContactCommand : CompositeCommand(

sendMessage(message)
}

@SubCommand
@Description("备份联系人数据")
public suspend fun CommandSender.backup() {
val message = try {
xyz.cssxsh.mirai.admin.backup()
"备份已开始"
} catch (cause: Exception) {
logger.warning({ "出现错误" }, cause)
"出现错误"
}

sendMessage(message)
}
}
19 changes: 19 additions & 0 deletions src/main/kotlin/xyz/cssxsh/mirai/spi/BackupService.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

package xyz.cssxsh.mirai.spi

import kotlin.jvm.*

/**
* 备份服务, 当操作不支持时 throw [UnsupportedOperationException]
*/
public interface BackupService : ComparableService {

@Throws(UnsupportedOperationException::class)
public fun group()

@Throws(UnsupportedOperationException::class)
public fun friend()

@Throws(UnsupportedOperationException::class)
public fun bot()
}

0 comments on commit a67d73c

Please sign in to comment.