mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-10 12:10:10 +08:00
solve #12
This commit is contained in:
parent
ddd6aa45c3
commit
d78d477e14
@ -10,12 +10,9 @@
|
||||
package net.mamoe.mirai.console
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.console.MiraiConsole.CommandProcessor.processNextCommandLine
|
||||
import net.mamoe.mirai.console.command.CommandManager
|
||||
import net.mamoe.mirai.console.command.CommandSender
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.command.DefaultCommands
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import net.mamoe.mirai.console.utils.MiraiConsoleUI
|
||||
@ -42,7 +39,7 @@ object MiraiConsole {
|
||||
/**
|
||||
* 与前端交互所使用的Logger
|
||||
*/
|
||||
var logger = MiraiConsoleLogger
|
||||
internal var logger = MiraiConsoleLogger
|
||||
|
||||
/**
|
||||
* Console运行路径
|
||||
@ -55,12 +52,12 @@ object MiraiConsole {
|
||||
lateinit var frontEnd: MiraiConsoleUI
|
||||
|
||||
|
||||
/**
|
||||
* 启动Console
|
||||
*/
|
||||
var start = false
|
||||
|
||||
|
||||
/**
|
||||
* 启动Console
|
||||
*/
|
||||
fun start(
|
||||
frontEnd: MiraiConsoleUI,
|
||||
coreVersion: String = "0.0.0",
|
||||
@ -91,7 +88,7 @@ object MiraiConsole {
|
||||
/* 依次启用功能 */
|
||||
DefaultCommands()
|
||||
PluginManager.loadPlugins()
|
||||
CommandProcessor.start()
|
||||
CommandManager.start()
|
||||
|
||||
/* 通知启动完成 */
|
||||
logger("Mirai-console 启动完成")
|
||||
@ -99,6 +96,9 @@ object MiraiConsole {
|
||||
logger("\"/login qq号 qq密码 \" 来登录一个BOT")
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭Console
|
||||
*/
|
||||
fun stop() {
|
||||
PluginManager.disableAllPlugins()
|
||||
try {
|
||||
@ -110,85 +110,82 @@ object MiraiConsole {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
object CommandProcessor : Job by {
|
||||
GlobalScope.launch(start = CoroutineStart.LAZY) {
|
||||
processNextCommandLine()
|
||||
}
|
||||
}() {
|
||||
|
||||
internal class FullCommand(
|
||||
val sender: CommandSender,
|
||||
val commandStr: String
|
||||
@Deprecated("Please use CommandManager directly, this will be removed in later release")
|
||||
object CommandProcessor{
|
||||
@Deprecated("Please use CommandManager directly, this will be removed in later release", ReplaceWith(
|
||||
"CommandManager.runConsoleCommand(command)",
|
||||
"net.mamoe.mirai.console.command.CommandManager"
|
||||
)
|
||||
)
|
||||
|
||||
private val commandChannel: Channel<FullCommand> = Channel()
|
||||
|
||||
suspend fun runConsoleCommand(command: String) {
|
||||
commandChannel.send(
|
||||
FullCommand(ConsoleCommandSender, command)
|
||||
)
|
||||
CommandManager.runConsoleCommand(command)
|
||||
}
|
||||
|
||||
@Deprecated("Please use CommandManager directly, this will be removed in later release", ReplaceWith(
|
||||
"CommandManager.runCommand(sender, command)",
|
||||
"net.mamoe.mirai.console.command.CommandManager"
|
||||
)
|
||||
)
|
||||
suspend fun runCommand(sender: CommandSender, command: String) {
|
||||
commandChannel.send(
|
||||
FullCommand(sender, command)
|
||||
)
|
||||
CommandManager.runCommand(sender,command)
|
||||
}
|
||||
|
||||
fun runConsoleCommandBlocking(command: String) = runBlocking { runConsoleCommand(command) }
|
||||
@Deprecated("Please use CommandManager directly, this will be removed in later release", ReplaceWith(
|
||||
"CommandManager.runConsoleCommand(command)",
|
||||
"net.mamoe.mirai.console.command.CommandManager"
|
||||
)
|
||||
)
|
||||
fun runConsoleCommandBlocking(command: String) = runBlocking { runConsoleCommand(command)}
|
||||
|
||||
|
||||
@Suppress("unused")
|
||||
@Deprecated("Please use CommandManager directly, this will be removed in later release", ReplaceWith(
|
||||
"CommandManager.runCommand(sender, command)",
|
||||
"net.mamoe.mirai.console.command.CommandManager"
|
||||
)
|
||||
)
|
||||
fun runCommandBlocking(sender: CommandSender, command: String) = runBlocking { runCommand(sender, command) }
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun processNextCommandLine() {
|
||||
for (command in commandChannel) {
|
||||
var commandStr = command.commandStr
|
||||
if (!commandStr.startsWith("/")) {
|
||||
commandStr = "/$commandStr"
|
||||
}
|
||||
if (!CommandManager.runCommand(command.sender, commandStr)) {
|
||||
command.sender.sendMessage("未知指令 $commandStr")
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Mirai Console的logger
|
||||
* 它用于适配不同的Console前段
|
||||
*/
|
||||
internal object MiraiConsoleLogger {
|
||||
operator fun invoke(any: Any? = null) {
|
||||
invoke(
|
||||
"[Mirai ${MiraiConsole.version} ${MiraiConsole.build}]",
|
||||
0L,
|
||||
any
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
object MiraiConsoleLogger {
|
||||
operator fun invoke(any: Any? = null) {
|
||||
invoke(
|
||||
"[Mirai $version $build]",
|
||||
0L,
|
||||
any
|
||||
)
|
||||
}
|
||||
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
frontEnd.pushLog(priority, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, e: Exception? = null) {
|
||||
if (e != null) {
|
||||
frontEnd.pushLog(priority, identityStr, identity, "${e.stackTrace}")
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认的pushLog输出为 INFO 类型
|
||||
operator fun invoke(identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(identityStr: String, identity: Long, e: Exception? = null) {
|
||||
if (e != null) {
|
||||
frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "${e.stackTrace}")
|
||||
}
|
||||
operator fun invoke(priority: LogPriority, identityStr: String, identity: Long, e: Exception? = null) {
|
||||
if (e != null) {
|
||||
MiraiConsole.frontEnd.pushLog(priority, identityStr, identity, "${e.stackTrace}")
|
||||
}
|
||||
}
|
||||
|
||||
// 设置默认的pushLog输出为 INFO 类型
|
||||
operator fun invoke(identityStr: String, identity: Long, any: Any? = null) {
|
||||
if (any != null) {
|
||||
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "$any")
|
||||
}
|
||||
}
|
||||
|
||||
operator fun invoke(identityStr: String, identity: Long, e: Exception? = null) {
|
||||
if (e != null) {
|
||||
MiraiConsole.frontEnd.pushLog(LogPriority.INFO, identityStr, identity, "${e.stackTrace}")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -11,9 +11,19 @@
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.channels.Channel
|
||||
import net.mamoe.mirai.console.command.CommandManager.processCommandQueue
|
||||
import net.mamoe.mirai.console.plugins.PluginBase
|
||||
import net.mamoe.mirai.console.plugins.PluginManager
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object CommandManager {
|
||||
|
||||
object CommandManager : Job by {
|
||||
GlobalScope.launch(start = CoroutineStart.LAZY) {
|
||||
processCommandQueue()
|
||||
}
|
||||
}() {
|
||||
private val registeredCommand: MutableMap<String, Command> = mutableMapOf()
|
||||
|
||||
val commands: Collection<Command> get() = registeredCommand.values
|
||||
@ -33,38 +43,122 @@ object CommandManager {
|
||||
fun unregister(command: Command) {
|
||||
(command.alias.asSequence() + command.name).forEach {
|
||||
registeredCommand.remove(it)
|
||||
} // label compilation failed
|
||||
}
|
||||
}
|
||||
|
||||
fun unregister(commandName: String): Boolean {
|
||||
return registeredCommand.remove(commandName) != null
|
||||
}
|
||||
|
||||
/*
|
||||
* Index: MiraiConsole
|
||||
*/
|
||||
internal suspend fun runCommand(sender: CommandSender, fullCommand: String): Boolean {
|
||||
val blocks = fullCommand.split(" ")
|
||||
val commandHead = blocks[0].replace("/", "")
|
||||
if (!registeredCommand.containsKey(commandHead)) {
|
||||
return false
|
||||
|
||||
/**
|
||||
* 指令是单线程运行的
|
||||
*/
|
||||
private val commandDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
|
||||
|
||||
/**
|
||||
* 执行一个指令, 但是如果你想模拟一个指令的执行
|
||||
* 请向下看
|
||||
*
|
||||
* 返回一个指令是否执行成功
|
||||
*/
|
||||
internal suspend fun processCommand(sender: CommandSender, fullCommand: String):Boolean {
|
||||
return withContext(commandDispatcher) {
|
||||
_processCommand(sender, fullCommand)
|
||||
}
|
||||
val args = blocks.drop(1)
|
||||
registeredCommand[commandHead]?.run {
|
||||
try {
|
||||
if (onCommand(sender, blocks.drop(1))) {
|
||||
PluginManager.onCommand(this, sender, args)
|
||||
} else {
|
||||
sender.sendMessage(this.usage)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
sender.sendMessage("在运行指令时出现了未知错误")
|
||||
e.printStackTrace()
|
||||
} finally {
|
||||
(sender as CommandSenderImpl).flushMessage()
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
private suspend fun _processCommand(sender: CommandSender, fullCommand: String): Boolean {
|
||||
val blocks = fullCommand.split(" ")
|
||||
val commandHead = blocks[0].replace("/", "")
|
||||
val args = blocks.drop(1)
|
||||
return registeredCommand[commandHead]?.run {
|
||||
try {
|
||||
return onCommand(sender, blocks.drop(1)).also {
|
||||
if (it) {
|
||||
PluginManager.onCommand(this, sender, args)
|
||||
} else {
|
||||
sender.sendMessage(this.usage)
|
||||
}
|
||||
}
|
||||
}catch (e: Exception){
|
||||
sender.sendMessage("在运行指令时出现了未知错误")
|
||||
e.printStackTrace()
|
||||
false
|
||||
}finally {
|
||||
(sender as CommandSenderImpl).flushMessage()
|
||||
}
|
||||
}?: throw UnknownCommandException(commandHead)
|
||||
}
|
||||
|
||||
|
||||
internal class FullCommand(
|
||||
val sender: CommandSender,
|
||||
val commandStr: String
|
||||
)
|
||||
|
||||
private val commandChannel: Channel<FullCommand> = Channel(Channel.UNLIMITED)
|
||||
|
||||
private tailrec suspend fun processCommandQueue() {
|
||||
val command = commandChannel.receive()
|
||||
try {
|
||||
processCommand(command.sender, command.commandStr)
|
||||
}catch (e:UnknownCommandException){
|
||||
command.sender.sendMessage("未知指令 " + command.commandStr)
|
||||
}catch (e:Throwable){//should never happen
|
||||
e.printStackTrace()
|
||||
}
|
||||
processCommandQueue()
|
||||
}
|
||||
|
||||
/**
|
||||
* runCommand()是最基础的执行指令的方式
|
||||
* 指令将会被加入队列,依次执行
|
||||
* 方法由0.27.0的阻塞模式改为不阻塞(鉴于commandChannel大小无限)
|
||||
*/
|
||||
fun runCommand(sender: CommandSender, command: String) {
|
||||
runBlocking {//it wont be blocking
|
||||
commandChannel.send(
|
||||
FullCommand(sender, command)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
fun runConsoleCommand(command: String) = runCommand(ConsoleCommandSender,command)
|
||||
|
||||
/**
|
||||
* runCommandAnsyc()执行一个指令并返回deferred
|
||||
* 为插队执行
|
||||
*/
|
||||
fun runCommandAsync(pluginBase: PluginBase, sender: CommandSender, command: String):Deferred<Boolean>{
|
||||
return pluginBase.async{
|
||||
processCommand(sender,command)
|
||||
}
|
||||
}
|
||||
|
||||
fun runConsoleCommandAsync(pluginBase: PluginBase, command: String):Deferred<Boolean> = runCommandAsync(pluginBase,ConsoleCommandSender,command)
|
||||
|
||||
/**
|
||||
* dispatchCommand()执行一个指令并等到完成
|
||||
* 为插队执行
|
||||
*/
|
||||
suspend fun dispatchCommand(sender: CommandSender,command: String):Boolean{
|
||||
return processCommand(sender,command)
|
||||
}
|
||||
|
||||
suspend fun dispatchConsoleCommand(command: String):Boolean = dispatchCommand(ConsoleCommandSender,command)
|
||||
|
||||
|
||||
fun dispatchCommandBlocking(sender: CommandSender,command: String):Boolean = runBlocking { dispatchCommand(sender, command) }
|
||||
|
||||
fun dispatchConsoleCommandBlocking(command: String):Boolean = runBlocking { dispatchConsoleCommandBlocking(command) }
|
||||
}
|
||||
|
||||
fun PluginBase.runCommandAsnyc(sender: CommandSender, command: String):Deferred<Boolean> = CommandManager.runCommandAsync(this,sender,command)
|
||||
|
||||
fun PluginBase.runConsoleCommandAsync(command: String):Deferred<Boolean> = CommandManager.runConsoleCommandAsync(this,command)
|
||||
|
||||
|
||||
|
||||
class UnknownCommandException(command: String):Exception("unknown command \"$command\"")
|
@ -1,14 +0,0 @@
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.asCoroutineDispatcher
|
||||
import java.util.concurrent.Executors
|
||||
|
||||
object CommandProcessor {
|
||||
val commandDispatcher = Executors.newFixedThreadPool(1).asCoroutineDispatcher()
|
||||
|
||||
suspend fun runCommand(){
|
||||
Dispatchers.IO
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user