This commit is contained in:
jiahua.liu 2020-03-21 01:59:26 +08:00
parent ddd6aa45c3
commit d78d477e14
3 changed files with 189 additions and 112 deletions

View File

@ -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}")
}
}
}

View File

@ -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\"")

View File

@ -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
}
}