Fix various bugs

This commit is contained in:
Him188 2020-08-22 01:38:32 +08:00
parent c8854b3391
commit 74353d1aaf
6 changed files with 57 additions and 61 deletions

View File

@ -11,65 +11,28 @@ package net.mamoe.mirai.console.command
import kotlinx.coroutines.cancel import kotlinx.coroutines.cancel
import kotlinx.coroutines.cancelAndJoin import kotlinx.coroutines.cancelAndJoin
import kotlinx.coroutines.launch
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.sync.withLock
import net.mamoe.mirai.Bot
import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.command.Command.Companion.primaryName
import net.mamoe.mirai.console.command.CommandManagerImpl.allRegisteredCommands import net.mamoe.mirai.console.command.CommandManagerImpl.allRegisteredCommands
import net.mamoe.mirai.console.command.CommandManagerImpl.register import net.mamoe.mirai.console.command.CommandManagerImpl.register
import net.mamoe.mirai.event.selectMessagesUnit import net.mamoe.mirai.console.util.ConsoleExperimentalAPI
import net.mamoe.mirai.utils.DirectoryLogger import net.mamoe.mirai.message.nextMessageOrNull
import net.mamoe.mirai.utils.weeksToMillis import net.mamoe.mirai.utils.secondsToMillis
import java.io.File
import kotlin.concurrent.thread import kotlin.concurrent.thread
import kotlin.system.exitProcess import kotlin.system.exitProcess
/**
* 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
*/
public fun MiraiConsole.addBot(id: Long, password: String): Bot {
return Bot(id, password) {
/**
* 重定向 [网络日志][networkLoggerSupplier] 到指定目录. 若目录不存在将会自动创建 ([File.mkdirs])
* @see DirectoryLogger
* @see redirectNetworkLogToDirectory
*/
fun redirectNetworkLogToDirectory(
dir: File = File("logs"),
retain: Long = 1.weeksToMillis,
identity: (bot: Bot) -> String = { "Net ${it.id}" }
) {
require(!dir.isFile) { "dir must not be a file" }
dir.mkdirs()
networkLoggerSupplier = { DirectoryLogger(identity(it), dir, retain) }
}
fun redirectBotLogToDirectory(
dir: File = File("logs"),
retain: Long = 1.weeksToMillis,
identity: (bot: Bot) -> String = { "Net ${it.id}" }
) {
require(!dir.isFile) { "dir must not be a file" }
dir.mkdirs()
botLoggerSupplier = { DirectoryLogger(identity(it), dir, retain) }
}
fileBasedDeviceInfo()
this.loginSolver = this@addBot.frontEnd.createLoginSolver()
redirectNetworkLogToDirectory()
// redirectBotLogToDirectory()
}
}
@ConsoleExperimentalAPI
@Suppress("EXPOSED_SUPER_INTERFACE") @Suppress("EXPOSED_SUPER_INTERFACE")
public interface BuiltInCommand : Command, BuiltInCommandInternal public interface BuiltInCommand : Command, BuiltInCommandInternal
// for identification // for identification
internal interface BuiltInCommandInternal : Command internal interface BuiltInCommandInternal : Command
@ConsoleExperimentalAPI
@Suppress("unused") @Suppress("unused")
public object BuiltInCommands { public object BuiltInCommands {
@ -89,8 +52,9 @@ public object BuiltInCommands {
), BuiltInCommand { ), BuiltInCommand {
@Handler @Handler
public suspend fun CommandSender.handle() { public suspend fun CommandSender.handle() {
sendMessage("现在有指令: ${allRegisteredCommands.joinToString { it.primaryName }}") sendMessage(allRegisteredCommands.joinToString {
sendMessage("帮助还没写, 将就一下") it.usage + "\n\n"
})
} }
} }
@ -130,22 +94,20 @@ public object BuiltInCommands {
), BuiltInCommand { ), BuiltInCommand {
@Handler @Handler
public suspend fun CommandSender.handle(id: Long, password: String) { public suspend fun CommandSender.handle(id: Long, password: String) {
kotlin.runCatching { kotlin.runCatching {
MiraiConsole.addBot(id, password).alsoLogin() MiraiConsole.addBot(id, password).alsoLogin()
}.fold( }.fold(
onSuccess = { sendMessage("${it.nick} ($id) Login succeed") }, onSuccess = { sendMessage("${it.nick} ($id) Login successful") },
onFailure = { throwable -> onFailure = { throwable ->
sendMessage( sendMessage(
"Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" + "Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
if (this is MessageEventContextAware<*>) { if (this is MessageEventContextAware<*>) {
this.fromEvent.selectMessagesUnit { CommandManagerImpl.launch {
"stacktrace" reply { fromEvent.nextMessageOrNull(60.secondsToMillis) { it.message.contentEquals("stacktrace") }
throwable.stackTraceToString()
} }
} "\n 1 分钟内发送 stacktrace 以获取堆栈信息"
"test" } else ""
} else "") )
throw throwable throw throwable
} }

View File

@ -58,6 +58,9 @@ public interface CommandManager {
* @return * @return
* 若已有重名指令, [override] `false`, 返回 `false`; * 若已有重名指令, [override] `false`, 返回 `false`;
* 若已有重名指令, [override] `true`, 覆盖原有指令并返回 `true`. * 若已有重名指令, [override] `true`, 覆盖原有指令并返回 `true`.
*
*
* 注意: [内建指令][BuiltInCommands] 也可以被覆盖.
*/ */
public fun Command.register(override: Boolean = false): Boolean public fun Command.register(override: Boolean = false): Boolean

View File

@ -19,6 +19,8 @@ import net.mamoe.mirai.event.Listener
import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.message.MessageEvent import net.mamoe.mirai.message.MessageEvent
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageContent
import net.mamoe.mirai.message.data.content
import java.util.concurrent.locks.ReentrantLock import java.util.concurrent.locks.ReentrantLock
internal object CommandManagerImpl : CommandManager, CoroutineScope by CoroutineScope(MiraiConsole.job) { internal object CommandManagerImpl : CommandManager, CoroutineScope by CoroutineScope(MiraiConsole.job) {
@ -60,7 +62,7 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by Coroutine
concurrency = Listener.ConcurrencyKind.CONCURRENT, concurrency = Listener.ConcurrencyKind.CONCURRENT,
priority = Listener.EventPriority.HIGH priority = Listener.EventPriority.HIGH
) { ) {
if (this.sender.asCommandSender().executeCommand(message) != null) { if (this.toCommandSender().executeCommand(message) != null) {
intercept() intercept()
} }
} }
@ -129,7 +131,8 @@ internal object CommandManagerImpl : CommandManager, CoroutineScope by Coroutine
override suspend fun CommandSender.executeCommand(message: MessageChain): Command? { override suspend fun CommandSender.executeCommand(message: MessageChain): Command? {
if (message.isEmpty()) return null if (message.isEmpty()) return null
return matchAndExecuteCommandInternal(message, message[0].toString().substringBefore(' ')) val msg = message.filterIsInstance<MessageContent>()
return matchAndExecuteCommandInternal(msg, msg[0].content.substringBefore(' '))
} }
override suspend fun Command.execute(sender: CommandSender, args: MessageChain, checkPermission: Boolean) { override suspend fun Command.execute(sender: CommandSender, args: MessageChain, checkPermission: Boolean) {

View File

@ -10,9 +10,10 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.console.command.Command.Companion.primaryName import net.mamoe.mirai.console.command.Command.Companion.primaryName
import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand
/** /**
* [executeCommand] , [CommandSender] 未拥有 [Command.permission] 所要求的权限时抛出的异常. * [CommandManager.executeCommand] , [CommandSender] 未拥有 [Command.permission] 所要求的权限时抛出的异常.
* *
* 总是作为 [CommandExecutionException.cause]. * 总是作为 [CommandExecutionException.cause].
*/ */

View File

@ -12,7 +12,7 @@ package net.mamoe.mirai.console.command
/** /**
* 无参数解析, 接收原生参数的指令. * 无参数解析, 接收原生参数的指令.
*/ */
public abstract class RawCommand( public abstract class RawCommand @JvmOverloads constructor(
public override val owner: CommandOwner, public override val owner: CommandOwner,
public override vararg val names: String, public override vararg val names: String,
public override val usage: String = "<no usages given>", public override val usage: String = "<no usages given>",

View File

@ -17,13 +17,40 @@
package net.mamoe.mirai.console.command package net.mamoe.mirai.console.command
import net.mamoe.mirai.console.command.description.CommandArgumentContext import net.mamoe.mirai.console.command.description.*
import net.mamoe.mirai.console.command.description.CommandArgumentContextAware
import net.mamoe.mirai.console.command.description.EmptyCommandArgumentContext
import net.mamoe.mirai.console.command.description.plus
import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand
import net.mamoe.mirai.console.internal.command.SimpleCommandSubCommandAnnotationResolver import net.mamoe.mirai.console.internal.command.SimpleCommandSubCommandAnnotationResolver
/**
* 简单指令. 参数支持自动解析. [CommandArgumentParser]
*
* Kotlin 实现:
* ```
* object MySimpleCommand : SimpleCommand(
* MyPlugin, "tell",
* description = "Message somebody",
* usage = "/tell <target> <message>"
* ) {
* @Handler
* suspend fun CommandSender.onCommand(target: User, message: String) {
* target.sendMessage(message)
* }
* }
* ```
*
* Java 实现:
* ```java
* public final class MySimpleCommand extends SimpleCommand {
* private MySimpleCommand() {
* super(MyPlugin.INSTANCE, new String[]{ "tell" }, "Message somebody", "/tell <target> <message>")
* }
* @Handler
* public void onCommand(CommandSender sender, User target, String message) {
* target.sendMessage(message)
* }
* }
* ```
*/
public abstract class SimpleCommand @JvmOverloads constructor( public abstract class SimpleCommand @JvmOverloads constructor(
owner: CommandOwner, owner: CommandOwner,
vararg names: String, vararg names: String,