00ll00 5 лет назад
Родитель
Сommit
9d4aaef0a8

+ 0 - 18
src/main/kotlin/bot_luo_core/cli/Cmd.kt

@@ -13,108 +13,90 @@ abstract class Cmd(val context: CmdContext) {
     /**
      * 执行成功,增加次数统计,设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun SUCCESS(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = true,
         addCount = true,
         setTime = true,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 
     /**
      * 执行成功,不增加次数统计,设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun SUCCESS_NOT_ADD_COUNT(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = true,
         addCount = false,
         setTime = true,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 
     /**
      * 执行成功,增加次数统计,不设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun SUCCESS_NOT_SET_TIME(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = true,
         addCount = true,
         setTime = false,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 
     /**
      * 执行失败,不增加次数统计,不设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun FATAL(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = false,
         addCount = false,
         setTime = false,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 
     /**
      * 执行失败,增加次数统计,不设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun FATAL_BUT_ADD_COUNT(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = false,
         addCount = true,
         setTime = false,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 
     /**
      * 执行失败,不增加次数统计,设置时间
      *
-     * @param addSpecialCount 增加特殊计次
      * @param uploadFile 0:不允许上传 1:超过限制时上传 2:始终上传
      */
     fun FATAL_BUT_SET_TIME(
-        addSpecialCount: Boolean = false,
         uploadFile: Int = 0
     ) = CmdReceipt(
         time = context.time,
         success = false,
         addCount = false,
         setTime = true,
-        addSpecialCount = addSpecialCount,
         uploadOutputFile = uploadFile
     )
 }

+ 0 - 2
src/main/kotlin/bot_luo_core/cli/CmdReceipt.kt

@@ -1,6 +1,5 @@
 package bot_luo_core.cli
 
-import java.util.*
 import kotlin.collections.ArrayList
 
 data class CmdReceipt(
@@ -8,7 +7,6 @@ data class CmdReceipt(
     val success: Boolean,
     val addCount: Boolean,
     val setTime: Boolean,
-    val addSpecialCount: Boolean,
     val messages: ArrayList<String> = ArrayList(),
     val f: String? = null,
     val b: String? = null,

+ 32 - 41
src/main/kotlin/bot_luo_core/cli/commands/DataCmd.kt

@@ -7,9 +7,11 @@ import bot_luo_core.cli.annotation.Method
 import bot_luo_core.cli.checkers.GroupCmdWorkingChecker
 import bot_luo_core.cli.exceptions.SyntaxError
 import bot_luo_core.cli.handlers.GroupArgHandler
+import bot_luo_core.cli.handlers.JsonArgHandler
 import bot_luo_core.cli.handlers.JsonPathArgHandler
 import bot_luo_core.cli.handlers.UserArgHandler
 import bot_luo_core.data.*
+import bot_luo_core.util.GSON
 import bot_luo_core.util.TableBuilder
 import bot_luo_core.util.indices
 import bot_luo_core.util.set
@@ -83,14 +85,14 @@ class DataCmd(context: CmdContext) : Cmd(context) {
 
     /*  ========================  set  ========================  */
 
-    suspend fun set(dataObject: DataObject, objName: String, objId: String = "", path: ArrayList<String>, value: String): CmdReceipt {
+    suspend fun set(dataObject: DataObject, objName: String, objId: String = "", path: ArrayList<String>, value: JsonElement): CmdReceipt {
         val table = TableBuilder(4)
         table.th("写入${objName}数据 —— $objId")
         table.p("/"+path.joinToString("/")).br().br()
         try { withLockedAccessing(dataObject) {
             dataObject.markDirty()
-            val (old, new) = writeByPathTyped(dataObject.element, path, defaultCast(value))
-            table.tr(formatValue(old)).td("->").td(formatValue(new))
+            val old = writeByPathTyped(dataObject.element, path, value)
+            table.tr(formatValue(old)).td("->").td(formatValue(value))
             context.print(table.toString())
             return SUCCESS
         } } catch (e: NullPointerException) {
@@ -102,14 +104,14 @@ class DataCmd(context: CmdContext) : Cmd(context) {
         return FATAL
     }
 
-    suspend fun set(dataArray: DataArray, arrayName: String, arrayId: String = "", path: ArrayList<String>, value: String): CmdReceipt {
+    suspend fun set(dataArray: DataArray, arrayName: String, arrayId: String = "", path: ArrayList<String>, value: JsonElement): CmdReceipt {
         val table = TableBuilder(4)
         table.th("写入${arrayName}数据 —— $arrayId")
         table.p("/"+path.joinToString("/")).br().br()
         try { withLockedAccessing(dataArray) {
             dataArray.markDirty()
-            val (old, new) = writeByPathTyped(dataArray.element, path, defaultCast(value))
-            table.tr(formatValue(old)).td("->").td(formatValue(new))
+            val old = writeByPathTyped(dataArray.element, path, value)
+            table.tr(formatValue(old)).td("->").td(formatValue(value))
             context.print(table.toString())
             return SUCCESS
         } } catch (e: NullPointerException) {
@@ -127,7 +129,8 @@ class DataCmd(context: CmdContext) : Cmd(context) {
         table.p("/"+path.joinToString("/")).br().br()
         try { withLockedAccessing(dataObject) {
             dataObject.markDirty()
-            val (old, new) = writeByPathTyped(dataObject.element, path, value castTo type)
+            val new = value castTo type
+            val old = writeByPathTyped(dataObject.element, path, new)
             table.tr(formatValue(old)).td("->").td(formatValue(new))
             context.print(table.toString())
             return SUCCESS
@@ -146,7 +149,8 @@ class DataCmd(context: CmdContext) : Cmd(context) {
         table.p("/"+path.joinToString("/")).br().br()
         try { withLockedAccessing(dataArray) {
             dataArray.markDirty()
-            val (old, new) = writeByPathTyped(dataArray.element, path, value castTo type)
+            val new = value castTo type
+            val old = writeByPathTyped(dataArray.element, path, new)
             table.tr(formatValue(old)).td("->").td(formatValue(new))
             context.print(table.toString())
             return SUCCESS
@@ -165,8 +169,8 @@ class DataCmd(context: CmdContext) : Cmd(context) {
         group: Group,
         @Argument(name = "路径", handler = JsonPathArgHandler::class)
         path: ArrayList<String>,
-        @Argument(name = "值")
-        value: String
+        @Argument(name = "值", handler = JsonArgHandler::class)
+        value: JsonElement
     ): CmdReceipt = set(group, "群组", "${group.name}(${group.id})", path, value)
 
     @Method(name = "set-user", alias = ["su"], pmsLevel = CmdPermissionLevel.DEBUG, ignoreCheckers = [GroupCmdWorkingChecker::class], order = 0, title = "修改用户数据")
@@ -175,8 +179,8 @@ class DataCmd(context: CmdContext) : Cmd(context) {
         user: User,
         @Argument(name = "路径", handler = JsonPathArgHandler::class)
         path: ArrayList<String>,
-        @Argument(name = "值")
-        value: String
+        @Argument(name = "值", handler = JsonArgHandler::class)
+        value: JsonElement
     ): CmdReceipt = set(user, "用户", "${user.name}(${user.id})", path, value)
 
     @Method(name = "set-group", alias = ["sg"], pmsLevel = CmdPermissionLevel.DEBUG, ignoreCheckers = [GroupCmdWorkingChecker::class], order = 1, title = "修改群组数据")
@@ -212,31 +216,19 @@ class DataCmd(context: CmdContext) : Cmd(context) {
     @Suppress("UNCHECKED_CAST")
     companion object {
 
-        private infix fun String.castTo(type: String): Any? {
+        private infix fun String.castTo(type: String): JsonElement {
             return when (type.lowercase()) {
-                "num","number","float","double" -> this.toBigDecimalOrNull()?: throw SyntaxError(-1, "无法将“$this”转换为浮点数")
-                "int","integer","short","long","longlong" -> this.toBigIntegerOrNull()?: throw SyntaxError(-1, "无法将“$this”转换为整数")
-                "str","string","charsequence" -> this
-                "bool","boolean" -> this.toBoolean()
-                "null" -> if (this == "null") return null else throw SyntaxError(-1, "无法将“$this”转换为Null")
+                "num","number","float","double" -> GSON.toJsonTree(this.toBigDecimalOrNull()?: throw SyntaxError(-1, "无法将“$this”转换为浮点数"))
+                "int","integer","short","long","longlong" -> GSON.toJsonTree(this.toBigIntegerOrNull()?: throw SyntaxError(-1, "无法将“$this”转换为整数"))
+                "str","string","charsequence" -> GSON.toJsonTree(this)
+                "bool","boolean" -> GSON.toJsonTree(this.toBoolean())
+                "null" -> if (this == "null") return JsonNull.INSTANCE else throw SyntaxError(-1, "无法将“$this”转换为Null")
                 "array","list" -> if (this == "[]") return JsonArray() else throw SyntaxError(-1, "无法将“$this”转换为Array")
                 "object","obj" -> if (this == "{}") return JsonObject() else throw SyntaxError(-1, "无法将“$this”转换为Object")
                 else -> throw SyntaxError(-1, "未知的类型“$type”")
             }
         }
 
-        private fun defaultCast(input: String): Any? {
-            return input.toBigIntegerOrNull()?:
-                input.toBigDecimalOrNull()?:
-                input.toBooleanStrictOrNull()?:
-                when (input) {
-                    "{}" -> JsonObject()
-                    "[]" -> JsonArray()
-                    "null" -> null
-                    else -> input
-                }
-        }
-
         private fun objectGet(obj: JsonObject, table: TableBuilder) {
             for ((k, v) in obj.entrySet()) {
                 table.tr("$k:").td(formatValue(v))
@@ -265,14 +257,13 @@ class DataCmd(context: CmdContext) : Cmd(context) {
                 when (obj) {
                     is JsonObject -> objectGet(obj, table)
                     is JsonArray -> arrayGet(obj, table)
-                    is JsonNull -> throw NullPointerException()
                     else -> table.tr(formatValue(obj))
                 }
             } else {
                 when (obj) {
                     is JsonObject -> {
                         val key = path[0]
-                        if (key !in obj.keys()) throw NullPointerException()
+                        if (!obj.has(key)) throw NullPointerException()
                         readByPath(obj[key], path.apply { removeAt(0) }, table)
                     }
                     is JsonArray -> {
@@ -293,18 +284,18 @@ class DataCmd(context: CmdContext) : Cmd(context) {
          * 返回 [Pair] (旧数据,新数据)
          */
         @Throws(NullPointerException::class)
-        private fun writeByPathTyped(obj: JsonElement, path: ArrayList<String>, value: Any?): Pair<JsonElement,JsonElement> {
+        private fun writeByPathTyped(obj: JsonElement, path: ArrayList<String>, value: JsonElement): JsonElement {
             when (path.size) {
                 0 -> throw NullPointerException()
                 1 -> {
                     when (obj) {
                         is JsonObject -> {
-                            val oldValue = obj[path[0]]
-                            if (value == null)
+                            val oldValue = obj[path[0]] ?: JsonNull.INSTANCE
+                            if (value is JsonNull)
                                 obj.remove(path[0])
                             else
                                 obj[path[0]] = value
-                            return oldValue to obj[path[0]]
+                            return oldValue
                         }
                         is JsonArray -> {
                             val index = path[0].toIntOrNull()?: throw NullPointerException()
@@ -312,16 +303,16 @@ class DataCmd(context: CmdContext) : Cmd(context) {
                             val oldValue: JsonElement
                             if (index == obj.size()) {
                                 oldValue = JsonNull.INSTANCE
-                                if (value != null)
+                                if (value !is JsonNull)
                                     obj.add(value)
                             } else {
-                                oldValue = obj[index]
-                                if (value == null)
+                                oldValue = obj[index] ?: JsonNull.INSTANCE
+                                if (value is JsonNull)
                                     obj.remove(index)
                                 else
                                     obj[index] = value
                             }
-                            return oldValue to if (value == null) JsonNull.INSTANCE else obj[index]
+                            return oldValue
                         }
                         else -> throw NullPointerException()
                     }
@@ -330,7 +321,7 @@ class DataCmd(context: CmdContext) : Cmd(context) {
                     return when (obj) {
                         is JsonObject -> {
                             val key = path[0]
-                            if (key !in obj.keys()) throw NullPointerException()
+                            if (!obj.has(key)) throw NullPointerException()
                             writeByPathTyped(obj[key], path.apply { removeAt(0) }, value)
                         }
                         is JsonArray -> {

+ 13 - 10
src/main/kotlin/bot_luo_core/cli/commands/DebugCmd.kt

@@ -4,9 +4,7 @@ import bot_luo_core.bot.BotLuo
 import bot_luo_core.cli.*
 import bot_luo_core.cli.annotation.Command
 import bot_luo_core.cli.annotation.Method
-import bot_luo_core.data.Data
-import bot_luo_core.data.Groups
-import bot_luo_core.data.Users
+import bot_luo_core.data.*
 import bot_luo_core.util.TableBuilder
 import bot_luo_core.util.Text.limitStart
 import bot_luo_core.util.Time.relativeTo
@@ -20,22 +18,27 @@ import java.text.DecimalFormat
 )
 class DebugCmd(context: CmdContext) : Cmd(context) {
 
+    @Suppress("UNCHECKED_CAST")
     @Method(name = "", alias = ["show"], pmsLevel = CmdPermissionLevel.DEBUG)
     fun show (): CmdReceipt {
         val table = TableBuilder(4)
         table.th("调试信息 ——").br()
-        table.tr("start_at:").td( BotLuo.startAt relativeTo context.time)
-        table.tr("mem_use:").td(formatMem(Runtime.getRuntime().totalMemory()))
+        table.tr("ST:").td( BotLuo.startAt relativeTo context.time)
+        table.tr("MEM:").td(formatMem(Runtime.getRuntime().totalMemory()))
         table.th()
-        table.prettyLines("active_groups(${Groups.activeGroupsCount}):", Groups.groups.keys) { item, builder ->
-            builder.td(item)
+        val gs = Groups.groups.clone() as HashMap<Long, Group>
+        table.prettyLines("AG(${gs.size}):", gs.values) { item, builder ->
+            builder.td("${item.name}(${item.id})")
         }
         table.th()
-        table.prettyLines("active_users(${Users.activeUsersCount}):", Users.users.keys) { item, builder ->
-            builder.td(item)
+        val us = Users.users.clone() as HashMap<Long, User>
+        table.prettyLines("AU(${us.size}):", us.values) { item, builder ->
+            builder.td("${item.name}(${item.id})")
         }
         table.th()
-        table.prettyLines("saving_data(${Data.savingJobs.size}):",Data.savingJobs.keys) { item, builder ->
+        val sj = Data.savingJobs.clone() as HashMap<out Data, *>
+        table.prettyLines("SD(${sj.size}):",sj.keys) { item, builder ->
+            if (item.isChanged()) builder.td("*") else builder.td()
             builder.td(item::class.simpleName).td(item.filePath.limitStart(20))
         }
         context.print(table.toString())

+ 1 - 1
src/main/kotlin/bot_luo_core/cli/commands/ScheduleCmd.kt

@@ -227,7 +227,7 @@ class ScheduleCmd(context: CmdContext) : Cmd(context) {
             context.withBackendBot { contact ->
                 val cmdRaw = event.cmd.deserializeMiraiCode()
                 val cmdOld = cmdRaw.uploadResource(contact)
-                table.p(cmdOld).br().p("->").br().p(cmd)
+                table.p(cmdOld).br().p("->").br().p(cmd).br()
                 event.cmd = cmd.serializeToMiraiCode()
                 genEventInTable(table, event)
                 contact.sendMessageWithLog(table.toMessage())

+ 59 - 0
src/main/kotlin/bot_luo_core/cli/handlers/JsonArgHandler.kt

@@ -0,0 +1,59 @@
+package bot_luo_core.cli.handlers
+
+import bot_luo_core.cli.ArgHandler
+import bot_luo_core.cli.CmdContext
+import bot_luo_core.cli.MessageReader
+import bot_luo_core.cli.exceptions.HandlerFatal
+import bot_luo_core.cli.exceptions.SyntaxError
+import com.google.gson.JsonElement
+import com.google.gson.JsonParseException
+import com.google.gson.JsonParser
+import com.google.gson.JsonSyntaxException
+import kotlin.reflect.KType
+
+class JsonArgHandler: ArgHandler<JsonElement> {
+
+    override val name = "Json参数解析器"
+
+    override fun handle(
+        reader: MessageReader,
+        pos: Int,
+        argName: String?,
+        type: KType?,
+        context: CmdContext?
+    ): JsonElement {
+        val sb = StringBuilder()
+        var q = 0
+        var p = false
+        while (reader.canRead()) {
+            val c = reader.peek()
+            when  {
+                !p && c in "{[" -> q++
+                !p && c in "}]" -> q--
+                p && c=='\\' -> {
+                    sb.append(reader.read())
+                    if (!reader.canRead()) break
+                }
+                c == '"' -> p = if (p) {
+                    q--
+                    false
+                } else {
+                    q++
+                    true
+                }
+                reader.isWhitespace(c) -> {
+                    if (q == 0) break
+                }
+            }
+            sb.append(reader.read())
+        }
+        val input = sb.toString()
+        try {
+            return JsonParser().parse(input)
+        } catch (e: JsonSyntaxException) {
+            throw SyntaxError(pos, e.localizedMessage)
+        } catch (e: JsonParseException) {
+            throw HandlerFatal(input, argName, pos, type)
+        }
+    }
+}

+ 4 - 0
src/main/kotlin/bot_luo_core/data/Data.kt

@@ -118,6 +118,10 @@ abstract class Data(
     fun markDirty() {
         changed = true
     }
+
+    fun isChanged(): Boolean {
+        return changed
+    }
 }
 
 /**

+ 1 - 1
src/main/kotlin/bot_luo_core/data/User.kt

@@ -18,7 +18,7 @@ import net.mamoe.mirai.message.data.At
 class User internal constructor (
     override val id: Long,
     override var bot: Bot? = null
-) : CmdDataObj("data/users/$id.json", 30000L, true), BotContact {
+) : CmdDataObj("data/users/$id.json", 15000L, true), BotContact {
     override val contactType = BotContactType.Single
     override val defaultData: CmdData get() = CmdData(0,0,0,true)//用户命令默认开启
     override var contact: Contact? = null

+ 1 - 1
src/main/kotlin/bot_luo_core/util/TableBuilder.kt

@@ -119,7 +119,7 @@ class TableBuilder (
             0 -> {}
             1 -> {
                 tr(title)
-                action(content.elementAt(0), this)
+                action(content.first(), this)
             }
             else -> {
                 tr(title)