diff --git a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt index 25aebf0ed..9da5cf122 100644 --- a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt +++ b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalLoader.kt @@ -1,5 +1,6 @@ package net.mamoe.mirai.console +import net.mamoe.mirai.console.pure.MiraiConsoleUIPure import kotlin.concurrent.thread class MiraiConsoleTerminalLoader { diff --git a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt index 8998c0b83..ebefb9e1a 100644 --- a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt +++ b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt @@ -19,6 +19,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.cleanPage import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.drawLog import net.mamoe.mirai.console.MiraiConsoleTerminalUI.LoggerDrawer.redrawLogs +import net.mamoe.mirai.console.utils.MiraiConsoleUI import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.createCharImg import net.mamoe.mirai.utils.writeChannel @@ -129,9 +130,7 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { requestResult = input requesting = false } else { - MiraiConsole.CommandListener.commandChannel.send( - commandBuilder.toString() - ) + MiraiConsole.CommandProcessor.runConsoleCommand(commandBuilder.toString()) } } diff --git a/mirai-console/build.gradle.kts b/mirai-console/build.gradle.kts index f9eab16b4..6937c46ee 100644 --- a/mirai-console/build.gradle.kts +++ b/mirai-console/build.gradle.kts @@ -24,7 +24,7 @@ fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version" tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar>() { manifest { - attributes["Main-Class"] = "net.mamoe.mirai.console.MiraiConsolePureLoader" + attributes["Main-Class"] = "net.mamoe.mirai.console.pure.MiraiConsolePureLoader" } } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 145b458ba..19dc0335b 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -14,16 +14,17 @@ import kotlinx.coroutines.channels.Channel import net.mamoe.mirai.Bot import net.mamoe.mirai.api.http.MiraiHttpAPIServer import net.mamoe.mirai.api.http.generateSessionKey -import net.mamoe.mirai.console.MiraiConsole.CommandListener.processNextCommandLine +import net.mamoe.mirai.console.MiraiConsole.CommandProcessor.processNextCommandLine +import net.mamoe.mirai.console.command.* import net.mamoe.mirai.console.plugins.PluginManager import net.mamoe.mirai.console.plugins.loadAsConfig import net.mamoe.mirai.console.plugins.withDefaultWrite import net.mamoe.mirai.console.plugins.withDefaultWriteSave +import net.mamoe.mirai.console.utils.MiraiConsoleUI +import net.mamoe.mirai.console.utils.checkManager import net.mamoe.mirai.contact.sendMessage -import net.mamoe.mirai.utils.DeviceInfo -import net.mamoe.mirai.utils.FileBasedDeviceInfo +import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.utils.SimpleLogger -import net.mamoe.mirai.utils.SystemDeviceInfo import net.mamoe.mirai.utils.cryptor.ECDH import java.io.File import java.security.Security @@ -31,8 +32,18 @@ import java.util.* object MiraiConsole { - val bots - get() = Bot.instances + /** + * 发布的版本号 统一修改位置 + */ + val version = "v0.01" + var coreVersion = "v0.18.0" + val build = "Alpha" + + + /** + * 获取从Console登陆上的Bot, Bots + * */ + val bots get() = Bot.instances fun getBotByUIN(uin: Long): Bot? { bots.forEach { @@ -43,50 +54,64 @@ object MiraiConsole { return null } - val pluginManager: PluginManager - get() = PluginManager + /** + * PluginManager + */ + val pluginManager: PluginManager get() = PluginManager + /** + * 与前端交互所使用的Logger + */ var logger = UIPushLogger + /** + * Console运行路径 + */ var path: String = System.getProperty("user.dir") - private val version = "v0.01" - private var coreVersion = "v0.18.0" - private val build = "Zeta" - - private var allDown = false - + /** + * Console前端接口 + */ lateinit var frontEnd: MiraiConsoleUI + + + /** + * 启动Console + */ + var start = false + fun start( frontEnd: MiraiConsoleUI ) { + if (start) { + return + } + start = true + + /* 加载ECDH */ try { ECDH() } catch (ignored: Exception) { - } - Security.removeProvider("BC") + //Security.removeProvider("BC") + + /* 初始化前端 */ this.frontEnd = frontEnd - frontEnd.pushVersion( - version, build, coreVersion - ) - logger("Mirai-console [$version $build | core version $coreVersion] is still in testing stage, majority feature is available") - logger( - "Mirai-console now running under " + System.getProperty( - "user.dir" - ) - ) + frontEnd.pushVersion(version, build, coreVersion) + logger("Mirai-console [$version $build | core version $coreVersion] is still in testing stage, major features are available") + logger("Mirai-console now running under $path") logger("Get news in github: https://github.com/mamoe/mirai") logger("Mirai为开源项目,请自觉遵守开源项目协议") logger("Powered by Mamoe Technologies and contributors") - + /* 依次启用功能 */ DefaultCommands() HTTPAPIAdaptar() pluginManager.loadPlugins() - CommandListener.start() + CommandProcessor.start() + /* 通知启动完成 */ logger("Mirai-console 启动完成") logger("\"/login qqnumber qqpassword \" to login a bot") logger("\"/login qq号 qq密码 \" 来登录一个BOT") @@ -94,7 +119,6 @@ object MiraiConsole { fun stop() { PluginManager.disableAllPlugins() - allDown = true try { bots.forEach { it.get()?.close() @@ -104,218 +128,44 @@ object MiraiConsole { } } - object HTTPAPIAdaptar { - operator fun invoke() { - if (MiraiProperties.HTTP_API_ENABLE) { - if (MiraiProperties.HTTP_API_AUTH_KEY.startsWith("InitKey")) { - logger("请尽快更改初始生成的HTTP API AUTHKEY") - } - logger("正在启动HTTPAPI; 端口=" + MiraiProperties.HTTP_API_PORT) - MiraiHttpAPIServer.logger = SimpleLogger("HTTP API") { _, message, e -> - logger("[Mirai HTTP API]", 0, message) - } - MiraiHttpAPIServer.start( - MiraiProperties.HTTP_API_PORT, - MiraiProperties.HTTP_API_AUTH_KEY - ) - logger("HTTPAPI启动完成; 端口= " + MiraiProperties.HTTP_API_PORT) - } - } - } - - /** - * Defaults Commands are recommend to be replaced by plugin provided commands - */ - object DefaultCommands { - operator fun invoke() { - registerCommand { - name = "login" - description = "Mirai-Console default bot login command" - onCommand { - if (it.size < 2) { - logger("\"/login qqnumber qqpassword \" to login a bot") - logger("\"/login qq号 qq密码 \" 来登录一个BOT") - return@onCommand false - } - val qqNumber = it[0].toLong() - val qqPassword = it[1] - logger("[Bot Login]", 0, "login...") - try { - frontEnd.prePushBot(qqNumber) - val bot = Bot(qqNumber, qqPassword) { - this.loginSolver = frontEnd.createLoginSolver() - this.botLoggerSupplier = { - SimpleLogger("BOT $qqNumber]") { _, message, e -> - logger("[BOT $qqNumber]", qqNumber, message) - if (e != null) { - logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ - e.printStackTrace() - } - } - } - this.networkLoggerSupplier = { - SimpleLogger("BOT $qqNumber") { _, message, e -> - logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ - if (e != null) { - logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ - e.printStackTrace() - } - } - } - } - bot.login() - logger( - "[Bot Login]", - 0, - "$qqNumber login successes" - ) - frontEnd.pushBot(bot) - } catch (e: Exception) { - logger( - "[Bot Login]", - 0, - "$qqNumber login failed -> " + e.message - ) - } - true - } - } - - registerCommand { - name = "status" - description = "Mirai-Console default status command" - onCommand { - when (it.size) { - 0 -> { - logger("当前有" + bots.size + "个BOT在线") - } - 1 -> { - val bot = it[0] - var find = false - bots.forEach { - if (it.get()?.uin.toString().contains(bot)) { - find = true - logger("" + it.get()?.uin + ": 在线中; 好友数量:" + it.get()?.qqs?.size + "; 群组数量:" + it.get()?.groups?.size) - } - } - if (!find) { - logger("没有找到BOT$bot") - } - } - } - true - } - } - - - registerCommand { - name = "say" - description = "Mirai-Console default say command" - onCommand { - if (it.size < 2) { - logger("say [好友qq号或者群号] [文本消息] //将默认使用第一个BOT") - logger("say [bot号] [好友qq号或者群号] [文本消息]") - return@onCommand false - } - val bot: Bot? = if (it.size == 2) { - if (bots.size == 0) { - logger("还没有BOT登录") - return@onCommand false - } - bots[0].get() - } else { - getBotByUIN(it[0].toLong()) - } - if (bot == null) { - logger("没有找到BOT") - return@onCommand false - } - val target = it[it.size - 2].toLong() - val message = it[it.size - 1] - try { - val contact = bot[target] - runBlocking { - contact.sendMessage(message) - logger("消息已推送") - } - } catch (e: NoSuchElementException) { - logger("没有找到群或好友 号码为${target}") - return@onCommand false - } - true - } - } - - - registerCommand { - name = "plugins" - alias = listOf("plugin") - description = "show all plugins" - onCommand { - PluginManager.getAllPluginDescriptions().let { - println("loaded " + it.size + " plugins") - it.forEach { - logger("\t" + it.name + " v" + it.version + " by" + it.author + " " + it.info) - } - true - } - } - } - - registerCommand { - name = "command" - alias = listOf("commands", "help", "helps") - description = "show all commands" - onCommand { - CommandManager.getCommands().let { - println("currently have " + it.size + " commands") - it.toSet().forEach { - logger("\t" + it.name + " :" + it.description) - } - } - true - } - } - - registerCommand { - name = "about" - description = "About Mirai-Console" - onCommand { - logger("v$version $build is still in testing stage, majority feature is available") - logger( - "now running under " + System.getProperty( - "user.dir" - ) - ) - logger("在Github中获取项目最新进展: https://github.com/mamoe/mirai") - logger("Mirai为开源项目,请自觉遵守开源项目协议") - logger("Powered by Mamoe Technologies and contributors") - true - } - } - - } - } - - object CommandListener : Job by { + object CommandProcessor : Job by { GlobalScope.launch(start = CoroutineStart.LAZY) { processNextCommandLine() } }() { - val commandChannel: Channel<String> = Channel() - suspend fun processNextCommandLine() { - if (allDown) { - return - } + internal class FullCommand( + val sender: CommandSender, + val commandStr: String + ) + + private val commandChannel: Channel<FullCommand> = Channel() + + suspend fun runConsoleCommand(command: String) { + commandChannel.send( + FullCommand(ConsoleCommandSender, command) + ) + } + + suspend fun runCommand(sender: CommandSender, command: String) { + commandChannel.send( + FullCommand(sender, command) + ) + } + + fun runConsoleCommandBlocking(command: String) = runBlocking { runConsoleCommand(command) } + + fun runCommandBlocking(sender: CommandSender, command: String) = runBlocking { runCommand(sender, command) } + + private suspend fun processNextCommandLine() { for (command in commandChannel) { - var fullCommand = command - if (!fullCommand.startsWith("/")) { - fullCommand = "/$fullCommand" + var commandStr = command.commandStr + if (!commandStr.startsWith("/")) { + commandStr = "/$commandStr" } - if (!CommandManager.runCommand(ConsoleCommandSender, fullCommand)) { - logger("未知指令 $fullCommand") + if (!CommandManager.runCommand(command.sender, commandStr)) { + logger("未知指令 $commandStr") } } } @@ -337,16 +187,35 @@ object MiraiConsole { } } - object MiraiProperties { - var config = File("$path/mirai.properties").loadAsConfig() +} - var HTTP_API_ENABLE: Boolean by config.withDefaultWrite { true } - var HTTP_API_PORT: Int by config.withDefaultWrite { 8080 } - var HTTP_API_AUTH_KEY: String by config.withDefaultWriteSave { - "InitKey" + generateSessionKey() +object MiraiProperties { + var config = File("${MiraiConsole.path}/mirai.properties").loadAsConfig() + + var HTTP_API_ENABLE: Boolean by config.withDefaultWrite { true } + var HTTP_API_PORT: Int by config.withDefaultWrite { 8080 } + var HTTP_API_AUTH_KEY: String by config.withDefaultWriteSave { + "InitKey" + generateSessionKey() + } +} + +object HTTPAPIAdaptar { + operator fun invoke() { + if (MiraiProperties.HTTP_API_ENABLE) { + if (MiraiProperties.HTTP_API_AUTH_KEY.startsWith("InitKey")) { + MiraiConsole.logger("请尽快更改初始生成的HTTP API AUTHKEY") + } + MiraiConsole.logger("正在启动HTTPAPI; 端口=" + MiraiProperties.HTTP_API_PORT) + MiraiHttpAPIServer.logger = SimpleLogger("HTTP API") { _, message, e -> + MiraiConsole.logger("[Mirai HTTP API]", 0, message) + } + MiraiHttpAPIServer.start( + MiraiProperties.HTTP_API_PORT, + MiraiProperties.HTTP_API_AUTH_KEY + ) + MiraiConsole.logger("HTTPAPI启动完成; 端口= " + MiraiProperties.HTTP_API_PORT) } } - } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt similarity index 66% rename from mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt rename to mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt index e5e1f53ad..53e7f5175 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/Command.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt @@ -7,17 +7,23 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console +package net.mamoe.mirai.console.command import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext -import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.plugins.PluginManager import net.mamoe.mirai.contact.Contact -import net.mamoe.mirai.contact.QQ +import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.sendMessage +import net.mamoe.mirai.message.GroupMessage +import net.mamoe.mirai.message.MessageReceipt import net.mamoe.mirai.message.data.MessageChain +import net.mamoe.mirai.message.data.quote +import net.mamoe.mirai.message.data.toMessage +import net.mamoe.mirai.utils.MiraiExperimentalAPI +import java.lang.StringBuilder object CommandManager { private val registeredCommand: MutableMap<String, Command> = mutableMapOf() @@ -50,7 +56,10 @@ object CommandManager { registeredCommand.remove(commandName) } - suspend fun runCommand(sender: CommandSender, fullCommand: String): Boolean { + /* + * Index: MiraiConsole + * */ + internal suspend fun runCommand(sender: CommandSender, fullCommand: String): Boolean { val blocks = fullCommand.split(" ") val commandHead = blocks[0].replace("/", "") if (!registeredCommand.containsKey(commandHead)) { @@ -58,12 +67,19 @@ object CommandManager { } val args = blocks.subList(1, blocks.size) registeredCommand[commandHead]?.run { - if (onCommand( - sender, - blocks.subList(1, blocks.size) - ) - ) { - PluginManager.onCommand(this, args) + try { + if (onCommand( + sender, + blocks.subList(1, blocks.size) + ) + ) { + PluginManager.onCommand(this, args) + } + } catch (e: Exception) { + sender.sendMessage("在运行指令时出现了未知错误") + e.printStackTrace() + } finally { + (sender as CommandSenderImpl).flushMessage() } } return true @@ -72,25 +88,46 @@ object CommandManager { } interface CommandSender { + /** + * 立刻发送一条Message + */ suspend fun sendMessage(messageChain: MessageChain) suspend fun sendMessage(message: String) + /** + * 写入要发送的内容 所有内容最后会被以一条发出, 不管成功与否 + */ + fun appendMessage(message: String) fun sendMessageBlocking(messageChain: MessageChain) = runBlocking { sendMessage(messageChain) } fun sendMessageBlocking(message: String) = runBlocking { sendMessage(message) } } -object ConsoleCommandSender : CommandSender { - override suspend fun sendMessage(messageChain: MessageChain) { - MiraiConsole.logger(messageChain.toString()) +abstract class CommandSenderImpl : CommandSender { + private val builder = StringBuilder() + + override fun appendMessage(message: String) { + builder.append(message).append("\n") } - override suspend fun sendMessage(message: String) { - MiraiConsole.logger(message) + internal suspend fun flushMessage() { + if (!builder.isEmpty()) { + sendMessage(builder.toString().removeSuffix("\n")) + } } } -class ContactCommandSender(val contact: Contact) : CommandSender { +object ConsoleCommandSender : CommandSenderImpl() { + override suspend fun sendMessage(messageChain: MessageChain) { + MiraiConsole.logger("[Command]", 0, messageChain.toString()) + } + + override suspend fun sendMessage(message: String) { + MiraiConsole.logger("[Command]", 0, message) + } +} + +open class ContactCommandSender(val contact: Contact) : CommandSenderImpl() { override suspend fun sendMessage(messageChain: MessageChain) { contact.sendMessage(messageChain) } @@ -100,6 +137,20 @@ class ContactCommandSender(val contact: Contact) : CommandSender { } } +/** + * 弃用中 + * */ +class GroupCommandSender(val toQuote: GroupMessage, contact: Contact) : ContactCommandSender(contact) { + @MiraiExperimentalAPI + override suspend fun sendMessage(message: String) { + toQuote.quoteReply(message) + } + + @MiraiExperimentalAPI + override suspend fun sendMessage(messageChain: MessageChain) { + toQuote.quoteReply(messageChain) + } +} interface Command { val name: String @@ -163,7 +214,12 @@ class CommandBuilder internal constructor() { if (alias == null) { alias = listOf() } - return AnonymousCommand(name!!, alias!!, description, onCommand!!).also { it.register() } + return AnonymousCommand( + name!!, + alias!!, + description, + onCommand!! + ).also { it.register() } } } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt new file mode 100644 index 000000000..fcc9afffa --- /dev/null +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/DefaultCommands.kt @@ -0,0 +1,272 @@ +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.console.plugins.PluginManager +import net.mamoe.mirai.console.utils.addManager +import net.mamoe.mirai.console.utils.checkManager +import net.mamoe.mirai.console.utils.getManagers +import net.mamoe.mirai.console.utils.removeManager +import net.mamoe.mirai.contact.sendMessage +import net.mamoe.mirai.event.subscribeMessages +import net.mamoe.mirai.message.GroupMessage +import net.mamoe.mirai.utils.SimpleLogger +import java.lang.StringBuilder +import java.util.NoSuchElementException + + +/** + * Some defaults commands are recommend to be replaced by plugin provided commands + */ + +object DefaultCommands { + operator fun invoke() { + registerCommand { + name = "manager" + description = "Add a manager" + onCommand { it -> + if (this !is ConsoleCommandSender) { + sendMessage("请在后台使用该指令") + return@onCommand false + } + if (it.size < 2) { + MiraiConsole.logger("[Bot Manager]", 0, "/manager add [bot ID] [Manager ID]") + MiraiConsole.logger("[Bot Manager]", 0, "/manager remove [bot ID] [Manager ID]") + MiraiConsole.logger("[Bot Manager]", 0, "/manager list [bot ID]") + return@onCommand true + } + val botId = try { + it[1].toLong() + } catch (e: Exception) { + MiraiConsole.logger("[Bot Manager]", 0, it[1] + " 不是一个Bot的ID") + return@onCommand false + } + val bot = MiraiConsole.getBotByUIN(botId) + if (bot == null) { + MiraiConsole.logger("[Bot Manager]", 0, "$botId 没有在Console中登陆") + return@onCommand false + } + when (it[0]) { + "add" -> { + if (it.size < 3) { + MiraiConsole.logger("[Bot Manager]", 0, "/manager add [bot ID] [Manager ID]") + return@onCommand true + } + val adminID = try { + it[2].toLong() + } catch (e: Exception) { + MiraiConsole.logger("[Bot Manager]", 0, it[2] + " 不是一个ID") + return@onCommand false + } + bot.addManager(adminID) + MiraiConsole.logger("[Bot Manager]", 0, it[2] + "增加成功") + } + "remove" -> { + if (it.size < 3) { + MiraiConsole.logger("[Bot Manager]", 0, "/manager remove [bot ID] [Manager ID]") + return@onCommand true + } + val adminID = try { + it[2].toLong() + } catch (e: Exception) { + MiraiConsole.logger("[Bot Manager]", 0, it[1] + " 不是一个ID") + return@onCommand false + } + if (!bot.checkManager(adminID)) { + MiraiConsole.logger("[Bot Manager]", 0, it[2] + "本身不是一个Manager") + return@onCommand true + } + bot.removeManager(adminID) + MiraiConsole.logger("[Bot Manager]", 0, it[2] + "移除成功") + } + "list" -> { + bot.getManagers().forEach { + MiraiConsole.logger("[Bot Manager]", 0, " -> $it") + } + } + } + return@onCommand true + } + } + + registerCommand { + name = "login" + description = "机器人登陆" + onCommand { + if (this !is ConsoleCommandSender) { + sendMessage("请在后台使用该指令") + return@onCommand false + } + if (it.size < 2) { + MiraiConsole.logger("\"/login qqnumber qqpassword \" to login a bot") + MiraiConsole.logger("\"/login qq号 qq密码 \" 来登录一个BOT") + return@onCommand false + } + val qqNumber = it[0].toLong() + val qqPassword = it[1] + MiraiConsole.logger("[Bot Login]", 0, "login...") + try { + MiraiConsole.frontEnd.prePushBot(qqNumber) + val bot = Bot(qqNumber, qqPassword) { + this.loginSolver = MiraiConsole.frontEnd.createLoginSolver() + this.botLoggerSupplier = { + SimpleLogger("BOT $qqNumber]") { _, message, e -> + MiraiConsole.logger("[BOT $qqNumber]", qqNumber, message) + if (e != null) { + MiraiConsole.logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ + e.printStackTrace() + } + } + } + this.networkLoggerSupplier = { + SimpleLogger("BOT $qqNumber") { _, message, e -> + MiraiConsole.logger("[NETWORK]", qqNumber, message)//因为在一页 所以可以不打QQ + if (e != null) { + MiraiConsole.logger("[NETWORK ERROR]", qqNumber, e.toString())//因为在一页 所以可以不打QQ + e.printStackTrace() + } + } + } + } + bot.login() + bot.subscribeMessages { + contains("test") { + if (this is GroupMessage) { + quoteReply("Hello $senderName") + } else { + reply("Hello!") + } + } + this.startsWith("/") { + if (bot.checkManager(this.sender.id)) { + val sender = ContactCommandSender(this.subject) + MiraiConsole.CommandProcessor.runCommand( + sender, it + ) + } + } + } + sendMessage("$qqNumber login successes") + MiraiConsole.frontEnd.pushBot(bot) + + } catch (e: Exception) { + sendMessage("$qqNumber login failed -> " + e.message) + } + true + } + } + + registerCommand { + name = "status" + description = "获取状态" + onCommand { + when (it.size) { + 0 -> { + sendMessage("当前有" + MiraiConsole.bots.size + "个BOT在线") + } + 1 -> { + val bot = it[0] + var find = false + MiraiConsole.bots.forEach { + if (it.get()?.uin.toString().contains(bot)) { + find = true + appendMessage("" + it.get()?.uin + ": 在线中; 好友数量:" + it.get()?.qqs?.size + "; 群组数量:" + it.get()?.groups?.size) + } + } + if (!find) { + sendMessage("没有找到BOT$bot") + } + } + } + true + } + } + + + registerCommand { + name = "say" + description = "聊天功能演示" + onCommand { + if (it.size < 2) { + MiraiConsole.logger("say [好友qq号或者群号] [文本消息] //将默认使用第一个BOT") + MiraiConsole.logger("say [bot号] [好友qq号或者群号] [文本消息]") + return@onCommand false + } + val bot: Bot? = if (it.size == 2) { + if (MiraiConsole.bots.size == 0) { + MiraiConsole.logger("还没有BOT登录") + return@onCommand false + } + MiraiConsole.bots[0].get() + } else { + MiraiConsole.getBotByUIN(it[0].toLong()) + } + if (bot == null) { + MiraiConsole.logger("没有找到BOT") + return@onCommand false + } + val target = it[it.size - 2].toLong() + val message = it[it.size - 1] + try { + val contact = bot[target] + runBlocking { + contact.sendMessage(message) + MiraiConsole.logger("消息已推送") + } + } catch (e: NoSuchElementException) { + MiraiConsole.logger("没有找到群或好友 号码为${target}") + return@onCommand false + } + true + } + } + + + registerCommand { + name = "plugins" + alias = listOf("plugin") + description = "获取插件列表" + onCommand { + PluginManager.getAllPluginDescriptions().let { + it.forEach { + appendMessage("\t" + it.name + " v" + it.version + " by" + it.author + " " + it.info) + } + appendMessage("加载了" + it.size + "个插件") + true + } + } + } + + registerCommand { + name = "command" + alias = listOf("commands", "help", "helps") + description = "获取指令列表" + onCommand { + CommandManager.getCommands().let { + var size = 0 + it.toSet().forEach { + ++size + appendMessage("-> " + it.name + " :" + it.description) + } + appendMessage("""共有${size}条指令""") + } + true + } + } + + registerCommand { + name = "about" + description = "About Mirai-Console" + onCommand { + appendMessage("v${MiraiConsole.version} ${MiraiConsole.build} is still in testing stage, major features are available") + appendMessage("now running under ${MiraiConsole.path}") + appendMessage("在Github中获取项目最新进展: https://github.com/mamoe/mirai") + appendMessage("Mirai为开源项目,请自觉遵守开源项目协议") + appendMessage("Powered by Mamoe Technologies and contributors") + true + } + } + + } +} \ No newline at end of file diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt index 57ed757fe..2eb025df2 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/ConfigSection.kt @@ -21,6 +21,7 @@ import org.yaml.snakeyaml.Yaml import java.io.File import java.util.* import java.util.concurrent.ConcurrentHashMap +import kotlin.collections.LinkedHashMap import kotlin.properties.ReadWriteProperty import kotlin.reflect.KClass import kotlin.reflect.KProperty @@ -211,7 +212,15 @@ fun <T : Any> Config._smartCast(propertyName: String, _class: KClass<T>): T { interface ConfigSection : Config, MutableMap<String, Any> { override fun getConfigSection(key: String): ConfigSection { - return (get(key) ?: error("ConfigSection does not contain $key ")) as ConfigSection + val content = get(key) ?: error("ConfigSection does not contain $key ") + if (content is ConfigSection) { + return content + } + return ConfigSectionDelegation( + Collections.synchronizedMap( + (get(key) ?: error("ConfigSection does not contain $key ")) as LinkedHashMap<String, Any> + ) + ) } override fun getString(key: String): String { diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt index c39764518..dd526deee 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginBase.kt @@ -9,7 +9,7 @@ package net.mamoe.mirai.console.plugins -import net.mamoe.mirai.console.Command +import net.mamoe.mirai.console.command.Command import kotlinx.coroutines.* import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.utils.DefaultLogger diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsolePureLoader.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt similarity index 80% rename from mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsolePureLoader.kt rename to mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index b367e92d1..deac0fce0 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsolePureLoader.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -1,5 +1,6 @@ -package net.mamoe.mirai.console +package net.mamoe.mirai.console.pure +import net.mamoe.mirai.console.MiraiConsole import kotlin.concurrent.thread class MiraiConsolePureLoader { diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleUIPure.kt similarity index 89% rename from mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt rename to mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleUIPure.kt index a2fc693ac..388f5551e 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUIPure.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleUIPure.kt @@ -7,11 +7,12 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console +package net.mamoe.mirai.console.pure import kotlinx.coroutines.delay -import kotlinx.coroutines.runBlocking import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.utils.MiraiConsoleUI import net.mamoe.mirai.utils.DefaultLoginSolver import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.LoginSolverInputReader @@ -29,9 +30,7 @@ class MiraiConsoleUIPure : MiraiConsoleUI { requestStr = input requesting = false } else { - runBlocking { - MiraiConsole.CommandListener.commandChannel.send(input) - } + MiraiConsole.CommandProcessor.runConsoleCommandBlocking(input) } } } diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt new file mode 100644 index 000000000..51e9082c3 --- /dev/null +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/BotHelper.kt @@ -0,0 +1,41 @@ +package net.mamoe.mirai.console.utils + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.MiraiProperties +import net.mamoe.mirai.console.utils.BotManagers.BOT_MANAGERS +import net.mamoe.mirai.console.plugins.ConfigSection +import net.mamoe.mirai.console.plugins.ConfigSectionImpl +import net.mamoe.mirai.console.plugins.loadAsConfig +import net.mamoe.mirai.console.plugins.withDefaultWriteSave +import java.io.File + +object BotManagers { + val config = File("${MiraiConsole.path}/bot.yml").loadAsConfig() + val BOT_MANAGERS: ConfigSection by config.withDefaultWriteSave { ConfigSectionImpl() } +} + +fun Bot.addManager(long: Long) { + BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>()) + BOT_MANAGERS[this.uin.toString()] = + (BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList<Long>).apply { add(long) } + BotManagers.config.save() +} + +fun Bot.removeManager(long: Long) { + BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>()) + BOT_MANAGERS[this.uin.toString()] = + (BOT_MANAGERS.getLongList(this.uin.toString()) as MutableList<Long>).apply { add(long) } + BotManagers.config.save() +} + +fun Bot.getManagers(): List<Long> { + BOT_MANAGERS.putIfAbsent(this.uin.toString(), mutableListOf<Long>()) + return BOT_MANAGERS.getLongList(this.uin.toString()) +} + +fun Bot.checkManager(long: Long): Boolean { + return this.getManagers().contains(long) +} + + diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleUI.kt similarity index 97% rename from mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt rename to mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleUI.kt index fd90d8d82..a82d8a0bc 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleUI.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/utils/MiraiConsoleUI.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.console +package net.mamoe.mirai.console.utils import net.mamoe.mirai.Bot import net.mamoe.mirai.utils.LoginSolver