From ee8be9799f03d2c189f500b475bbf8e4c7ed919c Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 14 May 2020 15:33:10 +0800 Subject: [PATCH] Command registering, matching, executing --- backend/mirai-console/build.gradle.kts | 2 + .../console/command/JCommandManager.java | 16 -- .../mamoe/mirai/console/utils/BotManager.java | 3 +- .../net/mamoe/mirai/console/MiraiConsole.kt | 15 +- .../mirai/console/center/CuiPluginCenter.kt | 10 +- .../mamoe/mirai/console/command/Command.kt | 205 +++++++++--------- .../mirai/console/command/CommandArgParser.kt | 104 +++++---- .../console/command/CommandDescriptor.kt | 126 +++++++++-- .../mirai/console/command/CommandManager.kt | 120 +++++++++- .../mirai/console/command/CommandParam.kt | 16 +- .../console/command/CommandParserContext.kt | 26 ++- .../mirai/console/command/CommandSender.kt | 7 +- .../mirai/console/command/DefaultCommands.kt | 36 +-- .../mamoe/mirai/console/plugins/PluginBase.kt | 18 +- .../mirai/console/plugins/PluginManagerOld.kt | 19 +- .../mirai/console/plugins/PluginsLoader.kt | 6 +- .../console/utils/MiraiConsoleFrontEnd.kt | 2 +- .../graphical/MiraiConsoleGraphicalLoader.kt | 3 +- settings.gradle | 57 ++--- 19 files changed, 520 insertions(+), 271 deletions(-) delete mode 100644 backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 7ad3bc229..1e48bf4f7 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -40,6 +40,8 @@ dependencies { testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") testApi(kotlin("stdlib")) + testApi(kotlin("test")) + testApi(kotlin("test-junit5")) } version = Versions.Mirai.console diff --git a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java deleted file mode 100644 index 5770709ae..000000000 --- a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/command/JCommandManager.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.mamoe.mirai.console.command; - -// import jdk.jfr.Description; - -public class JCommandManager { - - private JCommandManager() { - - } - - public static CommandManager getInstance() { - return CommandManager.INSTANCE; - } - - -} \ No newline at end of file diff --git a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java index 4b959c40a..080ca51bb 100644 --- a/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java +++ b/backend/mirai-console/src/main/java/net/mamoe/mirai/console/utils/BotManager.java @@ -1,7 +1,6 @@ package net.mamoe.mirai.console.utils; import net.mamoe.mirai.Bot; -import net.mamoe.mirai.console.MiraiConsole; import java.util.List; @@ -12,7 +11,7 @@ import java.util.List; public class BotManager { public static List getManagers(long botAccount) { - Bot bot = MiraiConsole.INSTANCE.getBotOrThrow(botAccount); + Bot bot = Bot.getInstance(botAccount); return getManagers(bot); } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 9c1d59a82..4de54b1fb 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -13,9 +13,10 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.command.CommandManager -import net.mamoe.mirai.console.plugins.PluginManager +import net.mamoe.mirai.console.command.CommandOwner import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd +import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiLogger import java.io.ByteArrayOutputStream import java.io.PrintStream @@ -42,7 +43,7 @@ interface IMiraiConsole : CoroutineScope { val mainLogger: MiraiLogger } -object MiraiConsole : CoroutineScope, IMiraiConsole { +object MiraiConsole : CoroutineScope, IMiraiConsole, CommandOwner { private lateinit var instance: IMiraiConsole /** 由前端调用 */ @@ -58,18 +59,20 @@ object MiraiConsole : CoroutineScope, IMiraiConsole { override val coroutineContext: CoroutineContext get() = instance.coroutineContext init { + DefaultLogger = { + this.newLogger(it) + } this.coroutineContext[Job]!!.invokeOnCompletion { - PluginManager.disablePlugins() - CommandManager.cancel() Bot.botInstances.forEach { it.close() } } } + @MiraiExperimentalAPI + fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) } - internal val Throwable.stacktraceString: String get() = ByteArrayOutputStream().apply { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt index 394f9c2e5..faced21a0 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/center/CuiPluginCenter.kt @@ -7,15 +7,8 @@ import io.ktor.client.HttpClient import io.ktor.client.engine.cio.CIO import io.ktor.client.request.get import io.ktor.util.KtorExperimentalAPI -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.withContext -import net.mamoe.mirai.console.plugins.PluginManager import net.mamoe.mirai.console.utils.retryCatching -import net.mamoe.mirai.console.utils.tryNTimes import java.io.File -import java.io.FileOutputStream -import java.net.HttpURLConnection -import java.net.URL internal object CuiPluginCenter : PluginCenter { @@ -96,6 +89,8 @@ internal object CuiPluginCenter : PluginCenter { } override suspend fun T.downloadPlugin(name: String, progressListener: T.(Float) -> Unit): File { + TODO() + /* val info = findPlugin(name) ?: error("Plugin Not Found") val targetFile = File(PluginManager.pluginsPath, "$name-" + info.version + ".jar") withContext(Dispatchers.IO) { @@ -116,6 +111,7 @@ internal object CuiPluginCenter : PluginCenter { } } return targetFile + */ } override val name: String diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt index 29c9db7de..8c1bf4572 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt @@ -13,129 +13,134 @@ package net.mamoe.mirai.console.command import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext +import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.plugins.PluginBase +import kotlin.reflect.KProperty + +internal const val FOR_BINARY_COMPATIBILITY = "for binary compatibility" /** * 指令 * * @see register 注册这个指令 - * @see registerCommand 注册指令 DSL */ interface Command { - /** - * 指令主名称 - */ - val name: String + val owner: CommandOwner + val descriptor: CommandDescriptor + + /* + @Deprecated(FOR_BINARY_COMPATIBILITY, level = DeprecationLevel.HIDDEN) + suspend fun onCommand(sender: CommandSender, args: List): Boolean { + return true + }*/ /** - * 别名 + * 执行这个指令. */ - val alias: List - - /** - * 描述, 将会显示在 "/help" 指令中 - */ - val description: String - - /** - * 用法说明 - */ - val usage: String - - suspend fun onCommand(sender: CommandSender, args: List): Boolean -} - -abstract class AbstractCommand( - override val name: String, - override val alias: List, - override val description: String, - override val usage: String -) : Command - -/** - * 注册这个指令 - */ -inline fun Command.register(commandOwner: CommandOwner) = CommandManager.register(commandOwner, this) - -internal inline fun registerConsoleCommands(builder: CommandBuilder.() -> Unit): Command { - return CommandBuilder().apply(builder).register(ConsoleCommandOwner) + suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean } /** - * 构造并注册一个指令 + * 指令实际参数列表. 参数顺序与 [Command.descriptor] 的 [CommandDescriptor.params] 相同. */ -inline fun PluginBase.registerCommand(builder: CommandBuilder.() -> Unit): Command { - return CommandBuilder().apply(builder).register(this.asCommandOwner()) -} - - -// for java -@Suppress("unused") -abstract class BlockingCommand( - override val name: String, - override val alias: List = listOf(), - override val description: String = "", - override val usage: String = "" -) : Command { +class CommandArgs private constructor( + @JvmField + internal val values: List, + private val fromCommand: Command +) : List by values { /** - * 最高优先级监听器. + * 获取第一个类型为 [R] 的参数 + */ + @JvmSynthetic + inline fun getReified(): R { + for (value in this) { + if (value is R) { + return value + } + } + error("Cannot find argument typed ${R::class.qualifiedName}") + } + + /** + * 获取名称为 [name] 的参数. * - * 指令调用将优先触发 [Command.onCommand], 若该函数返回 `false`, 则不会调用 [PluginBase.onCommand] - * */ - final override suspend fun onCommand(sender: CommandSender, args: List): Boolean { - return withContext(Dispatchers.IO) { - onCommandBlocking(sender, args) + * 若 [name] 为 `null` 则获取第一个匿名参数 + * @throws NoSuchElementException 找不到这个名称的参数时抛出 + */ + operator fun get(name: String?): Any { + val index = fromCommand.descriptor.params.indexOfFirst { it.name == name } + if (index == -1) { + throw NoSuchElementException("Cannot find argument named $name") + } + return values[index] + } + + /** + * 获取名称为 [name] 的参数. 并强转为 [R]. + * + * 若 [name] 为 `null` 则获取第一个匿名参数 + * @throws IllegalStateException 无法强转时抛出 + */ + fun getAs(name: String?): R { + @Suppress("UNCHECKED_CAST") + return this[name] as? R ?: error("Argument $name has a type $") + } + + /** 获取第一个类型为 [R] 的参数并提供委托 */ + inline operator fun getValue(thisRef: Any?, property: KProperty<*>): R = getReified() + + companion object { + fun parseFrom(command: Command, sender: CommandSender, rawArgs: List): CommandArgs { + val params = command.descriptor.params + + require(rawArgs.size >= params.size) { "No enough rawArgs: required ${params.size}, found only ${rawArgs.size}" } + + command.descriptor.params.asSequence().zip(rawArgs.asSequence()).map { (commandParam, any) -> + command.parserFor(commandParam)?.parse(any, sender) + ?: error("ICould not find a parser for param named ${commandParam.name}") + }.toList().let { bakedArgs -> + return CommandArgs(bakedArgs, command) + } } } - - abstract fun onCommandBlocking(sender: CommandSender, args: List): Boolean } +inline val Command.fullName get() = descriptor.fullName +inline val Command.usage get() = descriptor.usage +inline val Command.params get() = descriptor.params +inline val Command.description get() = descriptor.description +inline val Command.context get() = descriptor.context +inline val Command.aliases get() = descriptor.aliases +inline val Command.permission get() = descriptor.permission +inline val Command.allNames get() = descriptor.allNames + +abstract class PluginCommand( + final override val owner: PluginBase, + descriptor: CommandDescriptor +) : AbstractCommand(descriptor) + +internal abstract class ConsoleCommand( + descriptor: CommandDescriptor +) : AbstractCommand(descriptor) { + final override val owner: MiraiConsole get() = MiraiConsole +} + +sealed class AbstractCommand( + final override val descriptor: CommandDescriptor +) : Command + + /** - * @see registerCommand + * For Java */ -class CommandBuilder @PublishedApi internal constructor() { - var name: String? = null - var alias: List? = null - var description: String = "" - var usage: String = "use /help for help" - - internal var onCommand: (suspend CommandSender.(args: List) -> Boolean)? = null - - fun onCommand(commandProcess: suspend CommandSender.(args: List) -> Boolean) { - onCommand = commandProcess +@Suppress("unused") +abstract class BlockingCommand( + owner: PluginBase, + descriptor: CommandDescriptor +) : PluginCommand(owner, descriptor) { + final override suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean { + return withContext(Dispatchers.IO) { onCommandBlocking(sender, args) } } -} - -// internal - - -internal class AnonymousCommand internal constructor( - override val name: String, - override val alias: List, - override val description: String, - override val usage: String = "", - val onCommand: suspend CommandSender.(args: List) -> Boolean -) : Command { - override suspend fun onCommand(sender: CommandSender, args: List): Boolean { - return onCommand.invoke(sender, args) - } -} - -@PublishedApi -internal fun CommandBuilder.register(commandOwner: CommandOwner): AnonymousCommand { - if (name == null || onCommand == null) { - error("CommandBuilder not complete") - } - if (alias == null) { - alias = listOf() - } - return AnonymousCommand( - name!!, - alias!!, - description, - usage, - onCommand!! - ).also { it.register(commandOwner) } + abstract fun onCommandBlocking(sender: CommandSender, args: CommandArgs): Boolean } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandArgParser.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandArgParser.kt index 28d45513d..91e1ffda4 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandArgParser.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandArgParser.kt @@ -17,8 +17,20 @@ import kotlin.contracts.contract * input is always String */ abstract class CommandArgParser { - abstract fun parse(s: String, sender: CommandSender): T - open fun parse(s: SingleMessage, sender: CommandSender): T = parse(s.content, sender) + abstract fun parse(raw: String, sender: CommandSender): T + open fun parse(raw: SingleMessage, sender: CommandSender): T = parse(raw.content, sender) +} + +fun CommandArgParser.parse(raw: Any, sender: CommandSender): T { + contract { + returns() implies (raw is String || raw is SingleMessage) + } + + return when (raw) { + is String -> parse(raw, sender) + is SingleMessage -> parse(raw, sender) + else -> throw IllegalArgumentException("Illegal raw argument type: ${raw::class.qualifiedName}") + } } @Suppress("unused") @@ -46,7 +58,7 @@ inline fun CommandArgParser<*>.checkArgument( inline fun CommandArgParser( crossinline parser: CommandArgParser.(s: String, sender: CommandSender) -> T ): CommandArgParser = object : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): T = parser(s, sender) + override fun parse(raw: String, sender: CommandSender): T = parser(raw, sender) } @@ -57,41 +69,41 @@ class ParserException(message: String, cause: Throwable? = null) : RuntimeExcept object IntArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Int = - s.toIntOrNull() ?: illegalArgument("无法解析 $s 为整数") + override fun parse(raw: String, sender: CommandSender): Int = + raw.toIntOrNull() ?: illegalArgument("无法解析 $raw 为整数") } object LongArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Long = - s.toLongOrNull() ?: illegalArgument("无法解析 $s 为长整数") + override fun parse(raw: String, sender: CommandSender): Long = + raw.toLongOrNull() ?: illegalArgument("无法解析 $raw 为长整数") } object ShortArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Short = - s.toShortOrNull() ?: illegalArgument("无法解析 $s 为短整数") + override fun parse(raw: String, sender: CommandSender): Short = + raw.toShortOrNull() ?: illegalArgument("无法解析 $raw 为短整数") } object ByteArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Byte = - s.toByteOrNull() ?: illegalArgument("无法解析 $s 为字节") + override fun parse(raw: String, sender: CommandSender): Byte = + raw.toByteOrNull() ?: illegalArgument("无法解析 $raw 为字节") } object DoubleArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Double = - s.toDoubleOrNull() ?: illegalArgument("无法解析 $s 为小数") + override fun parse(raw: String, sender: CommandSender): Double = + raw.toDoubleOrNull() ?: illegalArgument("无法解析 $raw 为小数") } object FloatArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Float = - s.toFloatOrNull() ?: illegalArgument("无法解析 $s 为小数") + override fun parse(raw: String, sender: CommandSender): Float = + raw.toFloatOrNull() ?: illegalArgument("无法解析 $raw 为小数") } object StringArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): String = s + override fun parse(raw: String, sender: CommandSender): String = raw } object BooleanArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Boolean = s.trim().let { str -> + override fun parse(raw: String, sender: CommandSender): Boolean = raw.trim().let { str -> str.equals("true", ignoreCase = true) || str.equals("yes", ignoreCase = true) || str.equals("enabled", ignoreCase = true) @@ -105,11 +117,11 @@ object BooleanArgParser : CommandArgParser() { * errors: String->Int convert, Bot Not Exist */ object ExistBotArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Bot { + override fun parse(raw: String, sender: CommandSender): Bot { val uin = try { - s.toLong() + raw.toLong() } catch (e: Exception) { - error("无法识别QQ UIN$s") + error("无法识别QQ UIN$raw") } return try { Bot.getInstance(uin) @@ -123,8 +135,8 @@ object ExistFriendArgParser : CommandArgParser() { //Bot.friend //friend //~ = self - override fun parse(s: String, sender: CommandSender): Friend { - if (s == "~") { + override fun parse(raw: String, sender: CommandSender): Friend { + if (raw == "~") { if (sender !is BotAware) { illegalArgument("无法解析~作为默认") } @@ -141,20 +153,20 @@ object ExistFriendArgParser : CommandArgParser() { } if (sender is BotAware) { return try { - sender.bot.friends[s.toLong()] + sender.bot.friends[raw.toLong()] } catch (e: NoSuchElementException) { - error("无法找到" + s + "这个好友") + error("无法找到" + raw + "这个好友") } catch (e: NumberFormatException) { - error("无法解析$s") + error("无法解析$raw") } } else { - s.split(".").let { args -> + raw.split(".").let { args -> if (args.size != 2) { - illegalArgument("无法解析 $s, 格式应为 机器人账号.好友账号") + illegalArgument("无法解析 $raw, 格式应为 机器人账号.好友账号") } return try { Bot.getInstance(args[0].toLong()).friends.getOrNull( - args[1].toLongOrNull() ?: illegalArgument("无法解析 $s 为好友") + args[1].toLongOrNull() ?: illegalArgument("无法解析 $raw 为好友") ) ?: illegalArgument("无法找到好友 ${args[1]}") } catch (e: NoSuchElementException) { illegalArgument("无法找到机器人账号 ${args[0]}") @@ -163,28 +175,28 @@ object ExistFriendArgParser : CommandArgParser() { } } - override fun parse(s: SingleMessage, sender: CommandSender): Friend { - if (s is At) { + override fun parse(raw: SingleMessage, sender: CommandSender): Friend { + if (raw is At) { assert(sender is GroupContactCommandSender) - return (sender as BotAware).bot.friends.getOrNull(s.target) ?: illegalArgument("At的对象非Bot好友") + return (sender as BotAware).bot.friends.getOrNull(raw.target) ?: illegalArgument("At的对象非Bot好友") } else { - error("无法解析 $s 为好友") + error("无法解析 $raw 为好友") } } } object ExistGroupArgParser : CommandArgParser() { - override fun parse(s: String, sender: CommandSender): Group { + override fun parse(raw: String, sender: CommandSender): Group { //by default - if ((s == "" || s == "~") && sender is GroupContactCommandSender) { + if ((raw == "" || raw == "~") && sender is GroupContactCommandSender) { return sender.contact as Group } //from bot to group if (sender is BotAware) { val code = try { - s.toLong() + raw.toLong() } catch (e: NoSuchElementException) { - error("无法识别Group Code$s") + error("无法识别Group Code$raw") } return try { sender.bot.getGroup(code) @@ -193,7 +205,7 @@ object ExistGroupArgParser : CommandArgParser() { } } //from console/other - return with(s.split(".")) { + return with(raw.split(".")) { if (this.size != 2) { error("请使用BotQQ号.群号 来表示Bot的一个群") } @@ -213,9 +225,9 @@ object ExistMemberArgParser : CommandArgParser() { //私聊: Group.Member[QQ/名片] //群内: Q号 //群内: 名片 - override fun parse(s: String, sender: CommandSender): Member { + override fun parse(raw: String, sender: CommandSender): Member { if (sender !is BotAware) { - with(s.split(".")) { + with(raw.split(".")) { checkArgument(this.size >= 3) { "无法识别Member, 请使用Bot.Group.Member[QQ/名片]的格式" } @@ -246,12 +258,12 @@ object ExistMemberArgParser : CommandArgParser() { if (sender is GroupContactCommandSender) { val group = sender.contact as Group return try { - group.members[s.toLong()] + group.members[raw.toLong()] } catch (ignored: Exception) { - group.fuzzySearchMember(s) ?: illegalArgument("无法找到成员$s") + group.fuzzySearchMember(raw) ?: illegalArgument("无法找到成员$raw") } } else { - with(s.split(".")) { + with(raw.split(".")) { if (this.size < 2) { illegalArgument("无法识别Member, 请使用Group.Member[QQ/名片]的格式") } @@ -274,12 +286,12 @@ object ExistMemberArgParser : CommandArgParser() { } } - override fun parse(s: SingleMessage, sender: CommandSender): Member { - return if (s is At) { + override fun parse(raw: SingleMessage, sender: CommandSender): Member { + return if (raw is At) { checkArgument(sender is GroupContactCommandSender) - (sender.contact as Group).members[s.target] + (sender.contact as Group).members[raw.target] } else { - illegalArgument("无法识别Member" + s.content) + illegalArgument("无法识别Member" + raw.content) } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandDescriptor.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandDescriptor.kt index e61c2c798..ac509ed74 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandDescriptor.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandDescriptor.kt @@ -2,6 +2,10 @@ package net.mamoe.mirai.console.command +import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.MessageChain +import net.mamoe.mirai.message.data.PlainText +import net.mamoe.mirai.message.data.SingleMessage import kotlin.reflect.KClass /** @@ -11,15 +15,19 @@ class CommandDescriptor( /** * 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令 */ - val fullName: String, + fullName: CommandFullName, /** * 用法说明 */ - val usage: String, + usage: String, /** * 指令参数列表, 有顺序. */ val params: List>, + /** + * 指令说明 + */ + description: String = "", /** * 指令参数解析器环境. */ @@ -27,7 +35,7 @@ class CommandDescriptor( /** * 指令别名 */ - val aliases: Array = arrayOf(), + aliases: Array = arrayOf(), /** * 指令权限 * @@ -35,19 +43,101 @@ class CommandDescriptor( * @see CommandPermission.and 同时要求两个权限 */ val permission: CommandPermission = CommandPermission.Default -) +) { + /** + * 指令别名 + */ + val aliases: Array = aliases.map { it.checkFullName("alias") }.toTypedArray() + + /** + * 指令说明 + */ + val description: String = description.trim() + + /** + * 用法说明 + */ + val usage: String = usage.trim() + + /** + * 包含子命令的全名. 如 "`group kick`", 其中 `kick` 为 `group` 的子命令 + * 元素类型可以为 [Message] 或 [String] + */ + val fullName: CommandFullName = fullName.checkFullName("fullName") + + /** + * `fullName + aliases` + */ + val allNames = arrayOf(fullName, *aliases) + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as CommandDescriptor + + if (!fullName.contentEquals(other.fullName)) return false + if (usage != other.usage) return false + if (params != other.params) return false + if (description != other.description) return false + if (context != other.context) return false + if (!aliases.contentEquals(other.aliases)) return false + if (permission != other.permission) return false + + return true + } + + override fun hashCode(): Int { + var result = fullName.hashCode() + result = 31 * result + usage.hashCode() + result = 31 * result + params.hashCode() + result = 31 * result + description.hashCode() + result = 31 * result + context.hashCode() + result = 31 * result + aliases.contentHashCode() + result = 31 * result + permission.hashCode() + return result + } +} + + +fun Command.checkArgs(args: CommandArgs) = this.descriptor.checkArgs(args) +fun CommandDescriptor.checkArgs(args: CommandArgs) { + require(args.size >= this.params.size) { "No enough args. Required ${params.size}, but given ${args.size}" } + params.forEachIndexed { index, commandParam -> + require(commandParam.type.isInstance(args[index])) { + "Illegal arg #$index, required ${commandParam.type.qualifiedName}, but given ${args[index]::class.qualifiedName}" + } + } +} + +internal fun Any.flattenCommandComponents(): Sequence = when (this) { + is Array<*> -> this.asSequence().flatMap { + it?.flattenCommandComponents() ?: throw java.lang.IllegalArgumentException("unexpected null value") + } + is String -> splitToSequence(' ').filterNot { it.isBlank() } + is PlainText -> content.flattenCommandComponents() + is SingleMessage -> sequenceOf(this) + is MessageChain -> this.asSequence().map { it.flattenCommandComponents() } + else -> throw IllegalArgumentException("Illegal component: $this") +} + +internal fun CommandFullName.checkFullName(errorHint: String): CommandFullName { + return flattenCommandComponents().toList().also { + require(it.isNotEmpty()) { "$errorHint must not be empty" } + }.toTypedArray() +} /** * 构建一个 [CommandDescriptor] */ @Suppress("FunctionName") inline fun CommandDescriptor( - fullName: String, - block: CommandDescriptorBuilder.() -> Unit + vararg fullName: Any, + block: CommandDescriptorBuilder.() -> Unit = {} ): CommandDescriptor = CommandDescriptorBuilder(fullName).apply(block).build() class CommandDescriptorBuilder( - val fullName: String + vararg val fullName: Any ) { @PublishedApi internal var context: CommandParserContext = CommandParserContext.Builtins @@ -62,7 +152,10 @@ class CommandDescriptorBuilder( internal var usage: String = "" @PublishedApi - internal var aliases: MutableList = mutableListOf() + internal var aliases: MutableList = mutableListOf() + + @PublishedApi + internal var description: String = "" /** 增加指令参数解析器列表 */ @JvmSynthetic @@ -91,8 +184,15 @@ class CommandDescriptorBuilder( usage = message } - fun alias(vararg name: String): CommandDescriptorBuilder = apply { - this.aliases.addAll(name) + fun description(description: String): CommandDescriptorBuilder = apply { + this.description = description + } + + /** + * 添加一个别名 + */ + fun alias(vararg fullName: Any): CommandDescriptorBuilder = apply { + this.aliases.add(fullName) } fun param(vararg params: CommandParam<*>): CommandDescriptorBuilder = apply { @@ -105,7 +205,7 @@ class CommandDescriptorBuilder( type: KClass, overrideParser: CommandArgParser? = null ): CommandDescriptorBuilder = apply { - this.params.add(CommandParam(name, type).apply { this.parser = overrideParser }) + this.params.add(CommandParam(name, type).apply { this._overrideParser = overrideParser }) } fun param( @@ -143,7 +243,7 @@ class CommandDescriptorBuilder( } fun build(): CommandDescriptor = - CommandDescriptor(fullName, context, params, usage, aliases.toTypedArray(), permission) + CommandDescriptor(fullName, usage, params, description, context, aliases.toTypedArray(), permission) } @Suppress("NON_PUBLIC_PRIMARY_CONSTRUCTOR_OF_INLINE_CLASS") @@ -154,7 +254,7 @@ inline class ParamBlock internal constructor(@PublishedApi internal val list: Mu /** 指定 [CommandParam.overrideParser] */ infix fun CommandParam.using(parser: CommandArgParser): CommandParam = - this.apply { this.parser = parser } + this.apply { this._overrideParser = parser } /** 覆盖 [CommandArgParser] */ inline infix fun String.using(parser: CommandArgParser): CommandParam = diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt index 17df0bdda..915307de3 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandManager.kt @@ -1,3 +1,121 @@ +@file:Suppress("NOTHING_TO_INLINE") +@file:JvmName("CommandManager") + package net.mamoe.mirai.console.command -object CommandManager \ No newline at end of file +import kotlinx.atomicfu.locks.withLock +import net.mamoe.mirai.message.data.Message +import net.mamoe.mirai.message.data.MessageChain +import java.util.* +import java.util.concurrent.locks.ReentrantLock + +typealias CommandFullName = Array + +interface CommandOwner + +val CommandOwner.registeredCommands: List get() = InternalCommandManager.registeredCommands.filter { it.owner == this } + +fun CommandOwner.unregisterAllCommands() { + for (registeredCommand in registeredCommands) { + registeredCommand.unregister() + } +} + +/** + * 注册一个指令. 若此指令已经注册或有已经注册的指令与 [allNames] 重名, 返回 `false` + */ +fun Command.register(): Boolean = InternalCommandManager.modifyLock.withLock { + with(descriptor) { + if (findDuplicate() != null) { + return false + } + InternalCommandManager.registeredCommands.add(this@register) + for (name in this.allNames) { + InternalCommandManager.nameToCommandMap[name] = this@register + } + return true + } +} + +/** + * 查找是否有重名的指令. 返回重名的指令. + */ +fun Command.findDuplicate(): Command? { + return InternalCommandManager.nameToCommandMap.entries.firstOrNull { (names, _) -> + this.allNames.any { it.contentEquals(names) } + }?.value +} + +/** + * 取消注册这个指令. 若指令未注册, 返回 `false` + */ +fun Command.unregister(): Boolean = InternalCommandManager.modifyLock.withLock { + if (!InternalCommandManager.registeredCommands.contains(this)) { + return false + } + InternalCommandManager.registeredCommands.remove(this) + for (name in this.allNames) { + InternalCommandManager.nameToCommandMap.entries.removeIf { + it.key.contentEquals(this.fullName) + } + } + return true +} + +/** + * 解析并执行一个指令 + * @param args 接受 [String] 或 [Message] + * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + */ +suspend fun CommandSender.executeCommand(vararg args: Any): Boolean { + return args.flattenCommandComponents().toList().executeCommand(this) +} + +/** + * 解析并执行一个指令 + * @return 是否成功解析到指令. 返回 `false` 代表无任何指令匹配 + */ +suspend fun MessageChain.executeAsCommand(sender: CommandSender): Boolean { + return this.flattenCommandComponents().toList().executeCommand(sender) +} + +suspend fun CommandSender.execute(command: Command, args: CommandArgs): Boolean = with(command) { + checkArgs(args) + return onCommand(this@execute, args) +} + +suspend fun Command.execute(sender: CommandSender, args: CommandArgs): Boolean = sender.execute(this, args) +suspend fun Command.execute(sender: CommandSender, vararg args: Any): Boolean = sender.execute(this, args) +suspend fun CommandSender.execute(command: Command, vararg args: Any): Boolean = command.execute(this, args) + + +internal suspend fun List.executeCommand(sender: CommandSender): Boolean { + val command = InternalCommandManager.matchCommand(this) ?: return false + return command.onCommand(sender, CommandArgs.parseFrom(command, sender, this.drop(command.fullName.size))) +} + +internal infix fun CommandFullName.matchesBeginning(list: List): Boolean { + this.forEachIndexed { index, any -> + if (list[index] != any) return false + } + return true +} + +internal object InternalCommandManager { + @JvmField + internal val registeredCommands: MutableList = mutableListOf() + + @JvmField + internal val nameToCommandMap: TreeMap = TreeMap(Comparator.comparingInt { it.size }) + + @JvmField + internal val modifyLock = ReentrantLock() + + + internal fun matchCommand(splitted: List): Command? { + nameToCommandMap.entries.forEach { + if (it.key matchesBeginning splitted) return it.value + } + return null + } +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParam.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParam.kt index edd85f319..9d58feabb 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParam.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParam.kt @@ -20,17 +20,27 @@ data class CommandParam( val type: KClass // exact type ) { constructor(name: String?, type: KClass, parser: CommandArgParser) : this(name, type) { - this.parser = parser + this._overrideParser = parser } + @Suppress("PropertyName") @JvmField - internal var parser: CommandArgParser? = null + internal var _overrideParser: CommandArgParser? = null /** * 覆盖的 [CommandArgParser]. * * 如果非 `null`, 将不会从 [CommandParserContext] 寻找 [CommandArgParser] + * + * @see Command.parserFor */ - val overrideParser: CommandArgParser? get() = parser + val overrideParser: CommandArgParser? get() = _overrideParser } + +fun CommandParam.parserFrom(command: Command): CommandArgParser? = command.parserFor(this) + +fun CommandParam.parserFrom(descriptor: CommandDescriptor): CommandArgParser? = + descriptor.parserFor(this) + +fun CommandParam.parserFrom(context: CommandParserContext): CommandArgParser? = context.parserFor(this) \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt index 502628ef4..4c82e0600 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandParserContext.kt @@ -12,7 +12,7 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.command.AbstractCommandParserContext.Node +import net.mamoe.mirai.console.command.AbstractCommandParserContext.ParserPair import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import kotlin.internal.LowPriorityInOverloadResolution @@ -21,6 +21,7 @@ import kotlin.reflect.KClass /** * [KClass] 到 [CommandArgParser] 的匹配 + * @see AbstractCommandParserContext */ interface CommandParserContext { operator fun get(klass: KClass): CommandArgParser? @@ -44,7 +45,14 @@ interface CommandParserContext { }) } -fun CommandParserContext.parserFor(param: CommandParam): CommandArgParser? = this[param.type] +fun CommandParserContext.parserFor(param: CommandParam): CommandArgParser? = + param.overrideParser ?: this[param.type] + +fun CommandDescriptor.parserFor(param: CommandParam): CommandArgParser? = + param.overrideParser ?: this.context.parserFor(param) + +fun Command.parserFor(param: CommandParam): CommandArgParser? = + param.overrideParser ?: this.descriptor.parserFor(param) /** * 合并两个 [CommandParserContext], [replacer] 将会替换 [this] 中重复的 parser. @@ -56,8 +64,8 @@ operator fun CommandParserContext.plus(replacer: CommandParserContext): CommandP } @Suppress("UNCHECKED_CAST") -open class AbstractCommandParserContext(val list: List>) : CommandParserContext { - class Node( +open class AbstractCommandParserContext(val list: List>) : CommandParserContext { + class ParserPair( val klass: KClass, val parser: CommandArgParser ) @@ -92,10 +100,10 @@ inline fun CommandParserContext(block: CommandParserContextBuilder.() -> Unit): /** * @see CommandParserContext */ -class CommandParserContextBuilder : MutableList> by mutableListOf() { +class CommandParserContextBuilder : MutableList> by mutableListOf() { @JvmName("add") - inline infix fun KClass.with(parser: CommandArgParser): Node<*> = - Node(this, parser) + inline infix fun KClass.with(parser: CommandArgParser): ParserPair<*> = + ParserPair(this, parser) /** * 添加一个指令解析器 @@ -104,7 +112,7 @@ class CommandParserContextBuilder : MutableList> by mutableListOf() { @LowPriorityInOverloadResolution inline infix fun KClass.with( crossinline parser: CommandArgParser.(s: String, sender: CommandSender) -> T - ): Node<*> = Node(this, CommandArgParser(parser)) + ): ParserPair<*> = ParserPair(this, CommandArgParser(parser)) /** * 添加一个指令解析器 @@ -112,7 +120,7 @@ class CommandParserContextBuilder : MutableList> by mutableListOf() { @JvmSynthetic inline infix fun KClass.with( crossinline parser: CommandArgParser.(s: String) -> T - ): Node<*> = Node(this, CommandArgParser { s: String, _: CommandSender -> parser(s) }) + ): ParserPair<*> = ParserPair(this, CommandArgParser { s: String, _: CommandSender -> parser(s) }) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt index 2ea05fb90..b1f3a88dc 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt @@ -11,7 +11,6 @@ package net.mamoe.mirai.console.command import kotlinx.coroutines.runBlocking import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Member import net.mamoe.mirai.message.data.Message @@ -58,11 +57,13 @@ abstract class AbstractCommandSender : CommandSender { */ object ConsoleCommandSender : AbstractCommandSender() { override suspend fun sendMessage(messageChain: Message) { - MiraiConsole.logger("[Command]", 0, messageChain.toString()) + TODO() + // MiraiConsole.logger("[Command]", 0, messageChain.toString()) } override suspend fun sendMessage(message: String) { - MiraiConsole.logger("[Command]", 0, message) + TODO() + // MiraiConsole.logger("[Command]", 0, message) } override suspend fun flushMessage() { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt index 8a27c610c..09198e400 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt @@ -9,22 +9,26 @@ package net.mamoe.mirai.console.command -import kotlinx.coroutines.GlobalScope -import kotlinx.coroutines.launch -import net.mamoe.mirai.Bot -import net.mamoe.mirai.Bot.Companion.botInstances -import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.plugins.PluginManager -import net.mamoe.mirai.console.utils.addManager -import net.mamoe.mirai.console.utils.checkManager -import net.mamoe.mirai.console.utils.managers -import net.mamoe.mirai.console.utils.removeManager -import net.mamoe.mirai.event.subscribeMessages -import net.mamoe.mirai.getFriendOrNull -import net.mamoe.mirai.message.GroupMessageEvent -import net.mamoe.mirai.utils.SimpleLogger -import java.util.* +suspend fun main() { + ConsoleCommandSender.execute(DefaultCommands.Test, "test") +} +internal object DefaultCommands { + + object Test : ConsoleCommand( + CommandDescriptor("test") { + param() + } + ) { + override suspend fun onCommand(sender: CommandSender, args: CommandArgs): Boolean { + val s = args.getReified() + sender.sendMessage(s) + return true + } + } +} + +/* /** * Some defaults commands are recommend to be replaced by plugin provided commands @@ -369,3 +373,5 @@ internal object DefaultCommands { } } } + + */ \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt index 6baf165c5..bfc59ab3d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt @@ -12,13 +12,12 @@ package net.mamoe.mirai.console.plugins import kotlinx.coroutines.* -import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.command.Command +import net.mamoe.mirai.console.command.CommandOwner import net.mamoe.mirai.console.command.CommandSender import net.mamoe.mirai.console.events.EventListener import net.mamoe.mirai.console.scheduler.PluginScheduler import net.mamoe.mirai.utils.MiraiLogger -import net.mamoe.mirai.utils.SimpleLogger import java.io.File import java.io.InputStream import kotlin.coroutines.CoroutineContext @@ -28,15 +27,17 @@ import kotlin.coroutines.EmptyCoroutineContext * 所有插件的基类 */ abstract class PluginBase -@JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope { +@JvmOverloads constructor(coroutineContext: CoroutineContext = EmptyCoroutineContext) : CoroutineScope, CommandOwner { final override val coroutineContext: CoroutineContext = coroutineContext + SupervisorJob() /** * 插件被分配的数据目录。数据目录会与插件名称同名。 */ val dataFolder: File by lazy { + TODO() + /* File(PluginManager.pluginsPath + "/" + PluginManager.lastPluginName) - .also { it.mkdir() } + .also { it.mkdir() }*/ } /** @@ -82,13 +83,15 @@ abstract class PluginBase * 插件的日志 */ val logger: MiraiLogger by lazy { + TODO() + /* SimpleLogger("Plugin $pluginName") { priority, message, e -> val identityString = "[${pluginName}]" MiraiConsole.logger(priority, identityString, 0, message) if (e != null) { MiraiConsole.logger(priority, identityString, 0, e) } - } + }*/ } /** @@ -98,10 +101,13 @@ abstract class PluginBase return try { this.javaClass.classLoader.getResourceAsStream(fileName) } catch (e: Exception) { + TODO() + + /* PluginManager.getFileInJarByName( this.pluginName, fileName - ) + )*/ } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManagerOld.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManagerOld.kt index f391515f1..a8c79d636 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManagerOld.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManagerOld.kt @@ -14,18 +14,18 @@ package net.mamoe.mirai.console.plugins import kotlinx.coroutines.CancellationException import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.command.Command -import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandSender +import net.mamoe.mirai.console.command.description +import net.mamoe.mirai.console.command.unregisterAllCommands import net.mamoe.mirai.console.encodeToString import net.mamoe.mirai.utils.LockFreeLinkedList -import net.mamoe.mirai.utils.SimpleLogger import java.io.File import java.io.InputStream import java.net.JarURLConnection import java.net.URL import java.util.jar.JarFile -val PluginBase.description: PluginDescription get() = PluginManager.getPluginDescription(this) +val PluginBase.description: PluginDescription get() = TODO() object PluginManagerOld { /** @@ -53,9 +53,9 @@ object PluginManagerOld { */ @JvmOverloads fun disablePlugins(throwable: CancellationException? = null) { - CommandManager.clearPluginsCommands() - pluginsSequence.forEach { - it.disable(throwable) + pluginsSequence.forEach { plugin -> + plugin.unregisterAllCommands() + plugin.disable(throwable) } nameToPluginBaseMap.clear() pluginDescriptions.clear() @@ -87,10 +87,7 @@ object PluginManagerOld { File(it).mkdirs() } - private val logger = SimpleLogger("Plugin Manager") { p, message, e -> - MiraiConsole.logger(p, "[Plugin Manager]", 0, message) - MiraiConsole.logger(p, "[Plugin Manager]", 0, e) - } + private val logger = MiraiConsole.newLogger("Plugin Manager") /** * 加载成功的插件, 名字->插件 @@ -351,7 +348,7 @@ object PluginManagerOld { plugin: PluginBase, exception: CancellationException? = null ) { - CommandManager.clearPluginCommands(plugin) + plugin.unregisterAllCommands() plugin.disable(exception) nameToPluginBaseMap.remove(plugin.pluginName) pluginDescriptions.remove(plugin.pluginName) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt index 692e9de59..08051d2cc 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginsLoader.kt @@ -10,7 +10,6 @@ package net.mamoe.mirai.console.plugins import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.utils.SimpleLogger import java.io.File import java.net.URLClassLoader @@ -18,10 +17,7 @@ internal class PluginsLoader(private val parentClassLoader: ClassLoader) { private val loggerName = "PluginsLoader" private val pluginLoaders = linkedMapOf() private val classesCache = mutableMapOf>() - private val logger = SimpleLogger(loggerName) { p, message, e -> - MiraiConsole.logger(p, "[${loggerName}]", 0, message) - MiraiConsole.logger(p, "[${loggerName}]", 0, e) - } + private val logger = MiraiConsole.newLogger(loggerName) /** * 清除所有插件加载器 diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleFrontEnd.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleFrontEnd.kt index d03192a41..f34db8ff3 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleFrontEnd.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleFrontEnd.kt @@ -27,7 +27,7 @@ interface MiraiConsoleFrontEnd { */ val pluginCenter: PluginCenter get() = CuiPluginCenter - fun loggerFor(identity: Long): MiraiLogger + fun loggerFor(identity: String?): MiraiLogger /** * 让 UI 层准备接受新增的一个BOT diff --git a/frontend/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiConsoleGraphicalLoader.kt b/frontend/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiConsoleGraphicalLoader.kt index 551b95f57..529a94d4b 100644 --- a/frontend/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiConsoleGraphicalLoader.kt +++ b/frontend/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiConsoleGraphicalLoader.kt @@ -8,6 +8,7 @@ */ package net.mamoe.mirai.console.graphical +import kotlinx.coroutines.cancel import net.mamoe.mirai.console.MiraiConsole import tornadofx.launch import kotlin.concurrent.thread @@ -24,7 +25,7 @@ class MiraiConsoleGraphicalLoader { this.coreVersion = coreVersion this.consoleVersion = consoleVersion Runtime.getRuntime().addShutdownHook(thread(start = false) { - MiraiConsole.stop() + MiraiConsole.cancel() }) launch() } diff --git a/settings.gradle b/settings.gradle index f03fabaf1..8055fef21 100644 --- a/settings.gradle +++ b/settings.gradle @@ -23,41 +23,46 @@ pluginManagement { rootProject.name = 'mirai-console' +def onlyBackEnd = true + include(':mirai-console') project(':mirai-console').dir = file("backend/mirai-console") -include(':mirai-console-pure') -project(':mirai-console-pure').dir = file("frontend/mirai-console-pure") +if (!onlyBackEnd) { -include(':mirai-console-terminal') -project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal") + include(':mirai-console-pure') + project(':mirai-console-pure').dir = file("frontend/mirai-console-pure") -try{ - def javaVersion = System.getProperty("java.version") - def versionPos = javaVersion.indexOf(".") - def javaVersionNum = javaVersion.substring(0, 1).toInteger() + include(':mirai-console-terminal') + project(':mirai-console-terminal').dir = file("frontend/mirai-console-terminal") - if (javaVersion.startsWith("1.")) { - javaVersionNum = javaVersion.substring(2, 3).toInteger() - } else { - if (versionPos==-1) versionPos = javaVersion.indexOf("-") - if (versionPos==-1){ - println("jdk version unknown") - }else{ - javaVersionNum = javaVersion.substring(0, versionPos).toInteger() + try { + def javaVersion = System.getProperty("java.version") + def versionPos = javaVersion.indexOf(".") + def javaVersionNum = javaVersion.substring(0, 1).toInteger() + + if (javaVersion.startsWith("1.")) { + javaVersionNum = javaVersion.substring(2, 3).toInteger() + } else { + if (versionPos == -1) versionPos = javaVersion.indexOf("-") + if (versionPos == -1) { + println("jdk version unknown") + } else { + javaVersionNum = javaVersion.substring(0, versionPos).toInteger() + } + } + if (javaVersionNum >= 9) { + include(':mirai-console-graphical') + project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical") + } else { + println("jdk版本为 " + javaVersionNum) + println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n") } - } - if (javaVersionNum >= 9) { - include(':mirai-console-graphical') - project(':mirai-console-graphical').dir = file("frontend/mirai-console-graphical") - } else { - println("jdk版本为 "+ javaVersionNum) - println("当前使用的 JDK 版本为 ${System.getProperty("java.version")}, 请使用JDK 9以上版本引入模块 `:mirai-console-graphical`\n") - } -}catch(Exception ignored){ - println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`") + } catch (Exception ignored) { + println("无法确定 JDK 版本, 将不会引入 `:mirai-console-graphical`") + } }