mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
Fix builtin commands and frontend-pure command processing
This commit is contained in:
parent
58eac01cad
commit
56a01c23fe
@ -9,13 +9,20 @@
|
||||
|
||||
package net.mamoe.mirai.console.command
|
||||
|
||||
import kotlinx.coroutines.cancelAndJoin
|
||||
import kotlinx.coroutines.isActive
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.alsoLogin
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.job
|
||||
import net.mamoe.mirai.console.stacktraceString
|
||||
import net.mamoe.mirai.event.selectMessagesUnit
|
||||
import net.mamoe.mirai.utils.DirectoryLogger
|
||||
import net.mamoe.mirai.utils.weeksToMillis
|
||||
import java.io.File
|
||||
import kotlin.concurrent.thread
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
@ -24,15 +31,44 @@ import kotlin.system.exitProcess
|
||||
*/
|
||||
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()
|
||||
// redirectBotLogToDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
interface BuiltInCommand : Command
|
||||
@Suppress("EXPOSED_SUPER_INTERFACE")
|
||||
interface BuiltInCommand : Command, BuiltInCommandInternal
|
||||
|
||||
// for identification
|
||||
internal interface BuiltInCommandInternal : Command
|
||||
|
||||
@Suppress("unused")
|
||||
object BuiltInCommands {
|
||||
@ -50,7 +86,7 @@ object BuiltInCommands {
|
||||
object Help : SimpleCommand(
|
||||
ConsoleCommandOwner, "help",
|
||||
description = "Gets help about the console."
|
||||
) {
|
||||
), BuiltInCommand {
|
||||
init {
|
||||
Runtime.getRuntime().addShutdownHook(thread(false) {
|
||||
runBlocking { Stop.execute(ConsoleCommandSender.instance) }
|
||||
@ -67,18 +103,23 @@ object BuiltInCommands {
|
||||
object Stop : SimpleCommand(
|
||||
ConsoleCommandOwner, "stop", "shutdown", "exit",
|
||||
description = "Stop the whole world."
|
||||
) {
|
||||
), BuiltInCommand {
|
||||
init {
|
||||
Runtime.getRuntime().addShutdownHook(thread(false) {
|
||||
if (!MiraiConsole.isActive) {
|
||||
return@thread
|
||||
}
|
||||
runBlocking { Stop.execute(ConsoleCommandSender.instance) }
|
||||
})
|
||||
}
|
||||
|
||||
private val closingLock = Mutex()
|
||||
|
||||
@Handler
|
||||
suspend fun CommandSender.handle() {
|
||||
suspend fun CommandSender.handle(): Unit = closingLock.withLock {
|
||||
sendMessage("Stopping mirai-console")
|
||||
kotlin.runCatching {
|
||||
MiraiConsole.job.cancel()
|
||||
MiraiConsole.job.cancelAndJoin()
|
||||
}.fold(
|
||||
onSuccess = { sendMessage("mirai-console stopped successfully.") },
|
||||
onFailure = {
|
||||
@ -93,26 +134,27 @@ object BuiltInCommands {
|
||||
object Login : SimpleCommand(
|
||||
ConsoleCommandOwner, "login",
|
||||
description = "Log in a bot account."
|
||||
) {
|
||||
), BuiltInCommand {
|
||||
@Handler
|
||||
suspend fun CommandSender.handle(id: Long, password: String) {
|
||||
sendMessage(
|
||||
kotlin.runCatching {
|
||||
MiraiConsole.addBot(id, password).alsoLogin()
|
||||
}.fold(
|
||||
onSuccess = { "${it.nick} ($id) Login succeed" },
|
||||
onFailure = { throwable ->
|
||||
"Login failed: ${throwable.localizedMessage ?: throwable.message}" +
|
||||
if (this is MessageEventContextAware<*>) {
|
||||
this.fromEvent.selectMessagesUnit {
|
||||
"stacktrace" reply {
|
||||
throwable.stacktraceString
|
||||
}
|
||||
|
||||
kotlin.runCatching {
|
||||
MiraiConsole.addBot(id, password).alsoLogin()
|
||||
}.fold(
|
||||
onSuccess = { sendMessage("${it.nick} ($id) Login succeed") },
|
||||
onFailure = { throwable ->
|
||||
sendMessage("Login failed: ${throwable.localizedMessage ?: throwable.message ?: throwable.toString()}" +
|
||||
if (this is MessageEventContextAware<*>) {
|
||||
this.fromEvent.selectMessagesUnit {
|
||||
"stacktrace" reply {
|
||||
throwable.stacktraceString
|
||||
}
|
||||
"test"
|
||||
} else ""
|
||||
}
|
||||
)
|
||||
}
|
||||
"test"
|
||||
} else "")
|
||||
|
||||
throw throwable
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -34,6 +34,9 @@ abstract class SimpleCommand @JvmOverloads constructor(
|
||||
) : Command, AbstractReflectionCommand(owner, names, description, permission, prefixOptional),
|
||||
CommandParserContextAware {
|
||||
|
||||
override val usage: String
|
||||
get() = super.usage
|
||||
|
||||
/**
|
||||
* 标注指令处理器
|
||||
*/
|
||||
@ -47,7 +50,7 @@ abstract class SimpleCommand @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
@Deprecated("prohibited", level = DeprecationLevel.HIDDEN)
|
||||
final override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) = error("shouldn't be reached")
|
||||
override suspend fun CommandSender.onDefault(rawArgs: Array<out Any>) = sendMessage(usage)
|
||||
|
||||
final override suspend fun CommandSender.onCommand(args: Array<out Any>) {
|
||||
subCommands.single().parseAndExecute(this, args, false)
|
||||
|
@ -54,7 +54,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
@Suppress("PropertyName")
|
||||
internal var _usage: String = "<not yet initialized>"
|
||||
|
||||
final override val usage: String // initialized by subCommand reflection
|
||||
override val usage: String // initialized by subCommand reflection
|
||||
get() = _usage
|
||||
|
||||
abstract suspend fun CommandSender.onDefault(rawArgs: Array<out Any>)
|
||||
@ -125,9 +125,10 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
argsWithSubCommandNameNotRemoved: Array<out Any>,
|
||||
removeSubName: Boolean
|
||||
) {
|
||||
if (!onCommand(
|
||||
val args = parseArgs(sender, argsWithSubCommandNameNotRemoved, if (removeSubName) names.size else 0)
|
||||
if (args == null || !onCommand(
|
||||
sender,
|
||||
parseArgs(sender, argsWithSubCommandNameNotRemoved, if (removeSubName) names.size else 0)
|
||||
args
|
||||
)
|
||||
) {
|
||||
sender.sendMessage(usage)
|
||||
@ -136,8 +137,10 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor(
|
||||
|
||||
@JvmField
|
||||
internal val bakedSubNames: Array<Array<String>> = names.map { it.bakeSubName() }.toTypedArray()
|
||||
private fun parseArgs(sender: CommandSender, rawArgs: Array<out Any>, offset: Int): Array<out Any> {
|
||||
require(rawArgs.size >= offset + this.params.size) { "No enough args. Required ${params.size}, but given ${rawArgs.size - offset}" }
|
||||
private fun parseArgs(sender: CommandSender, rawArgs: Array<out Any>, offset: Int): Array<out Any>? {
|
||||
if (rawArgs.size < offset + this.params.size)
|
||||
return null
|
||||
//require(rawArgs.size >= offset + this.params.size) { "No enough args. Required ${params.size}, but given ${rawArgs.size - offset}" }
|
||||
|
||||
return Array(this.params.size) { index ->
|
||||
val param = params[index]
|
||||
|
@ -8,7 +8,7 @@
|
||||
*/
|
||||
|
||||
object Versions {
|
||||
const val core = "1.1-EA"
|
||||
const val core = "1.0.3"
|
||||
const val console = "1.0-dev-1"
|
||||
const val consoleGraphical = "0.0.7"
|
||||
const val consoleTerminal = "0.1.0"
|
||||
|
@ -32,6 +32,7 @@ dependencies {
|
||||
compileAndRuntime("net.mamoe:mirai-core:${Versions.core}")
|
||||
compileAndRuntime(kotlin("stdlib")) // embedded by core
|
||||
|
||||
runtimeOnly("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
testApi("net.mamoe:mirai-core-qqandroid:${Versions.core}")
|
||||
testApi(project(":mirai-console"))
|
||||
}
|
||||
|
@ -22,14 +22,12 @@ package net.mamoe.mirai.console.pure
|
||||
|
||||
import kotlinx.coroutines.isActive
|
||||
import net.mamoe.mirai.console.MiraiConsole
|
||||
import net.mamoe.mirai.console.command.CommandExecuteStatus
|
||||
import net.mamoe.mirai.console.command.CommandPrefix
|
||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||
import net.mamoe.mirai.console.command.executeCommandDetailed
|
||||
import net.mamoe.mirai.console.command.*
|
||||
import net.mamoe.mirai.console.job
|
||||
import net.mamoe.mirai.console.pure.MiraiConsolePure.Companion.start
|
||||
import net.mamoe.mirai.console.utils.ConsoleInternalAPI
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.content
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import kotlin.concurrent.thread
|
||||
|
||||
@ -50,43 +48,63 @@ internal fun startup() {
|
||||
}
|
||||
|
||||
internal fun startConsoleThread() {
|
||||
thread(name = "Console", isDaemon = false) {
|
||||
thread(name = "Console Input") {
|
||||
val consoleLogger = DefaultLogger("Console")
|
||||
kotlinx.coroutines.runBlocking {
|
||||
while (isActive) {
|
||||
val next = MiraiConsoleFrontEndPure.requestInput("").let {
|
||||
if (it.startsWith(CommandPrefix)) {
|
||||
it
|
||||
} else CommandPrefix + it
|
||||
}
|
||||
if (next.isBlank()) {
|
||||
continue
|
||||
}
|
||||
consoleLogger.debug("INPUT> $next")
|
||||
val result = ConsoleCommandSenderImpl.executeCommandDetailed(next)
|
||||
when (result.status) {
|
||||
CommandExecuteStatus.SUCCESSFUL -> {
|
||||
try {
|
||||
kotlinx.coroutines.runBlocking {
|
||||
while (isActive) {
|
||||
val next = MiraiConsoleFrontEndPure.requestInput("").let {
|
||||
when {
|
||||
it.startsWith(CommandPrefix) -> {
|
||||
it
|
||||
}
|
||||
it == "?" -> CommandPrefix + BuiltInCommands.Help.primaryName
|
||||
else -> CommandPrefix + it
|
||||
}
|
||||
}
|
||||
CommandExecuteStatus.EXECUTION_EXCEPTION -> {
|
||||
if (next.isBlank()) {
|
||||
continue
|
||||
}
|
||||
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
||||
consoleLogger.warning("Unknown command: ${result.commandName}")
|
||||
}
|
||||
CommandExecuteStatus.PERMISSION_DENIED -> {
|
||||
consoleLogger.warning("Permission denied.")
|
||||
consoleLogger.debug("INPUT> $next")
|
||||
val result = ConsoleCommandSenderImpl.executeCommandDetailed(next)
|
||||
when (result.status) {
|
||||
CommandExecuteStatus.SUCCESSFUL -> {
|
||||
}
|
||||
CommandExecuteStatus.EXECUTION_EXCEPTION -> {
|
||||
result.exception?.printStackTrace()
|
||||
}
|
||||
CommandExecuteStatus.COMMAND_NOT_FOUND -> {
|
||||
consoleLogger.warning("Unknown command: ${result.commandName}")
|
||||
}
|
||||
CommandExecuteStatus.PERMISSION_DENIED -> {
|
||||
consoleLogger.warning("Permission denied.")
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e: InterruptedException) {
|
||||
return@thread
|
||||
}
|
||||
}.let { thread ->
|
||||
MiraiConsole.job.invokeOnCompletion {
|
||||
thread.interrupt()
|
||||
runCatching {
|
||||
thread.interrupt()
|
||||
}.exceptionOrNull()?.printStackTrace()
|
||||
runCatching {
|
||||
ConsoleUtils.terminal.close()
|
||||
}.exceptionOrNull()?.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal object ConsoleCommandSenderImpl : ConsoleCommandSender() {
|
||||
override suspend fun sendMessage(message: Message) {
|
||||
ConsoleUtils.lineReader.printAbove(message.contentToString())
|
||||
kotlin.runCatching {
|
||||
ConsoleUtils.lineReader.printAbove(message.contentToString())
|
||||
}.onFailure {
|
||||
println(message.content)
|
||||
it.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user