mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-27 00:30:17 +08:00
Add allRegisteredCommands;
Add val MiraiConsole.job; Implement command listening; Add simple built-in commands
This commit is contained in:
parent
108e425082
commit
2fd7c6aec7
@ -17,7 +17,10 @@ import kotlinx.coroutines.Job
|
|||||||
import kotlinx.io.charsets.Charset
|
import kotlinx.io.charsets.Charset
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.MiraiConsole.INSTANCE
|
import net.mamoe.mirai.console.MiraiConsole.INSTANCE
|
||||||
|
import net.mamoe.mirai.console.command.BuiltInCommands
|
||||||
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
import net.mamoe.mirai.console.command.ConsoleCommandSender
|
||||||
|
import net.mamoe.mirai.console.command.internal.InternalCommandManager
|
||||||
|
import net.mamoe.mirai.console.command.primaryName
|
||||||
import net.mamoe.mirai.console.plugin.PluginLoader
|
import net.mamoe.mirai.console.plugin.PluginLoader
|
||||||
import net.mamoe.mirai.console.plugin.PluginManager
|
import net.mamoe.mirai.console.plugin.PluginManager
|
||||||
import net.mamoe.mirai.console.plugin.center.CuiPluginCenter
|
import net.mamoe.mirai.console.plugin.center.CuiPluginCenter
|
||||||
@ -75,6 +78,11 @@ interface MiraiConsole : CoroutineScope {
|
|||||||
companion object INSTANCE : MiraiConsole by MiraiConsoleInternal
|
companion object INSTANCE : MiraiConsole by MiraiConsoleInternal
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取 [MiraiConsole] 的 [Job]
|
||||||
|
*/
|
||||||
|
val MiraiConsole.job: Job
|
||||||
|
get() = this.coroutineContext[Job] ?: error("Internal error: Job not found in MiraiConsole.coroutineContext")
|
||||||
|
|
||||||
//// internal
|
//// internal
|
||||||
|
|
||||||
@ -132,10 +140,14 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso
|
|||||||
if (coroutineContext[Job] == null) {
|
if (coroutineContext[Job] == null) {
|
||||||
throw IllegalMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.")
|
throw IllegalMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.")
|
||||||
}
|
}
|
||||||
this.coroutineContext[Job]!!.invokeOnCompletion {
|
job.invokeOnCompletion {
|
||||||
Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) }
|
Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuiltInCommands.registerAll()
|
||||||
|
mainLogger.info { "Preparing built-in commands: ${BuiltInCommands.all.joinToString { it.primaryName }}" }
|
||||||
|
InternalCommandManager.commandListener // start
|
||||||
|
|
||||||
mainLogger.info { "Loading plugins..." }
|
mainLogger.info { "Loading plugins..." }
|
||||||
PluginManager.loadEnablePlugins()
|
PluginManager.loadEnablePlugins()
|
||||||
mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." }
|
mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." }
|
||||||
|
@ -9,12 +9,114 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.command
|
package net.mamoe.mirai.console.command
|
||||||
|
|
||||||
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
|
import kotlinx.coroutines.runBlocking
|
||||||
|
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 kotlin.concurrent.thread
|
||||||
|
import kotlin.system.exitProcess
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加一个 [Bot] 实例到全局 Bot 列表, 但不登录.
|
||||||
|
*/
|
||||||
|
fun MiraiConsole.addBot(id: Long, password: String): Bot {
|
||||||
|
return Bot(id, password) {
|
||||||
|
fileBasedDeviceInfo()
|
||||||
|
this.loginSolver = this@addBot.frontEnd.createLoginSolver()
|
||||||
|
redirectNetworkLogToDirectory()
|
||||||
|
redirectBotLogToDirectory()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
interface BuiltInCommand : Command
|
interface BuiltInCommand : Command
|
||||||
|
|
||||||
@ConsoleExperimentalAPI
|
|
||||||
object BuiltInCommands
|
@Suppress("unused")
|
||||||
|
object BuiltInCommands {
|
||||||
|
|
||||||
|
val all: Array<out Command> by lazy {
|
||||||
|
this::class.nestedClasses.mapNotNull { it.objectInstance as? Command }.toTypedArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun registerAll() {
|
||||||
|
BuiltInCommands::class.nestedClasses.forEach {
|
||||||
|
(it.objectInstance as? Command)?.register()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Help : SimpleCommand(
|
||||||
|
ConsoleCommandOwner, "help", "?",
|
||||||
|
description = "Gets help about the console."
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
Runtime.getRuntime().addShutdownHook(thread(false) {
|
||||||
|
runBlocking { Stop.execute(ConsoleCommandSender.instance) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Handler
|
||||||
|
suspend fun CommandSender.handle() {
|
||||||
|
sendMessage("现在有指令: ${allRegisteredCommands.joinToString { it.primaryName }}")
|
||||||
|
sendMessage("帮助还没写, 将就一下")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Stop : SimpleCommand(
|
||||||
|
ConsoleCommandOwner, "stop", "shutdown", "exit",
|
||||||
|
description = "Stop the whole world."
|
||||||
|
) {
|
||||||
|
init {
|
||||||
|
Runtime.getRuntime().addShutdownHook(thread(false) {
|
||||||
|
runBlocking { Stop.execute(ConsoleCommandSender.instance) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@Handler
|
||||||
|
suspend fun CommandSender.handle() {
|
||||||
|
sendMessage("Stopping mirai-console")
|
||||||
|
kotlin.runCatching {
|
||||||
|
MiraiConsole.job.cancel()
|
||||||
|
}.fold(
|
||||||
|
onSuccess = { sendMessage("mirai-console stopped successfully.") },
|
||||||
|
onFailure = {
|
||||||
|
MiraiConsole.mainLogger.error(it)
|
||||||
|
sendMessage(it.localizedMessage ?: it.message ?: it.toString())
|
||||||
|
}
|
||||||
|
)
|
||||||
|
exitProcess(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object Login : SimpleCommand(
|
||||||
|
ConsoleCommandOwner, "login",
|
||||||
|
description = "Log in a bot account."
|
||||||
|
) {
|
||||||
|
@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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"test"
|
||||||
|
} else ""
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
|
@ -53,6 +53,12 @@ object ConsoleCommandOwner : CommandOwner()
|
|||||||
*/
|
*/
|
||||||
val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
|
val CommandOwner.registeredCommands: List<Command> get() = InternalCommandManager.registeredCommands.filter { it.owner == this }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有已经注册了指令列表.
|
||||||
|
* @see JCommandManager.getRegisteredCommands Java 方法
|
||||||
|
*/
|
||||||
|
val allRegisteredCommands: List<Command> get() = InternalCommandManager.registeredCommands.toList() // copy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 指令前缀, 如 '/'
|
* 指令前缀, 如 '/'
|
||||||
* @see JCommandManager.getCommandPrefix Java 方法
|
* @see JCommandManager.getCommandPrefix Java 方法
|
||||||
|
@ -14,9 +14,10 @@ package net.mamoe.mirai.console.command
|
|||||||
import kotlinx.coroutines.runBlocking
|
import kotlinx.coroutines.runBlocking
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.console.MiraiConsoleInternal
|
import net.mamoe.mirai.console.MiraiConsoleInternal
|
||||||
|
import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI
|
||||||
import net.mamoe.mirai.console.utils.JavaFriendlyAPI
|
import net.mamoe.mirai.console.utils.JavaFriendlyAPI
|
||||||
import net.mamoe.mirai.contact.*
|
import net.mamoe.mirai.contact.*
|
||||||
import net.mamoe.mirai.message.MessageEvent
|
import net.mamoe.mirai.message.*
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.message.data.PlainText
|
import net.mamoe.mirai.message.data.PlainText
|
||||||
|
|
||||||
@ -83,6 +84,12 @@ fun User.asCommandSender(): UserCommandSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 表示由 [MessageEvent] 触发的指令
|
||||||
|
*/
|
||||||
|
interface MessageEventContextAware<E : MessageEvent> : MessageEventExtensions<User, Contact> {
|
||||||
|
val fromEvent: E
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代表一个用户私聊机器人执行指令
|
* 代表一个用户私聊机器人执行指令
|
||||||
@ -99,7 +106,7 @@ sealed class UserCommandSender : CommandSender, BotAwareCommandSender {
|
|||||||
*/
|
*/
|
||||||
abstract val subject: Contact
|
abstract val subject: Contact
|
||||||
|
|
||||||
final override val bot: Bot get() = user.bot
|
override val bot: Bot get() = user.bot
|
||||||
|
|
||||||
final override suspend fun sendMessage(message: Message) {
|
final override suspend fun sendMessage(message: Message) {
|
||||||
subject.sendMessage(message)
|
subject.sendMessage(message)
|
||||||
@ -110,15 +117,46 @@ sealed class UserCommandSender : CommandSender, BotAwareCommandSender {
|
|||||||
* 代表一个用户私聊机器人执行指令
|
* 代表一个用户私聊机器人执行指令
|
||||||
* @see Friend.asCommandSender
|
* @see Friend.asCommandSender
|
||||||
*/
|
*/
|
||||||
class FriendCommandSender(override val user: Friend) : UserCommandSender() {
|
open class FriendCommandSender(final override val user: Friend) : UserCommandSender() {
|
||||||
override val subject: Contact get() = user
|
override val subject: Contact get() = user
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代表一个用户私聊机器人执行指令
|
||||||
|
* @see Friend.asCommandSender
|
||||||
|
*/
|
||||||
|
class FriendCommandSenderOnMessage(override val fromEvent: FriendMessageEvent) : FriendCommandSender(fromEvent.sender),
|
||||||
|
MessageEventContextAware<FriendMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||||
|
override val subject: Contact get() = super.subject
|
||||||
|
override val bot: Bot get() = super.bot
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代表一个群成员执行指令.
|
||||||
|
* @see Member.asCommandSender
|
||||||
|
*/
|
||||||
|
open class MemberCommandSender(final override val user: Member) : UserCommandSender() {
|
||||||
|
inline val group: Group get() = user.group
|
||||||
|
override val subject: Contact get() = group
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 代表一个群成员在群内执行指令.
|
* 代表一个群成员在群内执行指令.
|
||||||
* @see Member.asCommandSender
|
* @see Member.asCommandSender
|
||||||
*/
|
*/
|
||||||
class MemberCommandSender(override val user: Member) : UserCommandSender() {
|
class MemberCommandSenderOnMessage(override val fromEvent: GroupMessageEvent) : MemberCommandSender(fromEvent.sender),
|
||||||
inline val group: Group get() = user.group
|
MessageEventContextAware<GroupMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||||
override val subject: Contact get() = group
|
override val subject: Contact get() = super.subject
|
||||||
|
override val bot: Bot get() = super.bot
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 代表一个群成员通过临时会话私聊机器人执行指令.
|
||||||
|
* @see Member.asCommandSender
|
||||||
|
*/
|
||||||
|
@ConsoleExperimentalAPI
|
||||||
|
class TempCommandSenderOnMessage(override val fromEvent: TempMessageEvent) : MemberCommandSender(fromEvent.sender),
|
||||||
|
MessageEventContextAware<TempMessageEvent>, MessageEventExtensions<User, Contact> by fromEvent {
|
||||||
|
override val subject: Contact get() = super.subject
|
||||||
|
override val bot: Bot get() = super.bot
|
||||||
}
|
}
|
@ -9,9 +9,15 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.console.command.internal
|
package net.mamoe.mirai.console.command.internal
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import net.mamoe.mirai.console.MiraiConsole
|
||||||
import net.mamoe.mirai.console.command.*
|
import net.mamoe.mirai.console.command.*
|
||||||
|
import net.mamoe.mirai.console.job
|
||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.Member
|
import net.mamoe.mirai.contact.Member
|
||||||
|
import net.mamoe.mirai.event.Listener
|
||||||
|
import net.mamoe.mirai.event.subscribeAlways
|
||||||
|
import net.mamoe.mirai.message.MessageEvent
|
||||||
import java.util.concurrent.locks.ReentrantLock
|
import java.util.concurrent.locks.ReentrantLock
|
||||||
|
|
||||||
|
|
||||||
@ -22,7 +28,7 @@ internal infix fun Array<String>.matchesBeginning(list: List<Any>): Boolean {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
internal object InternalCommandManager {
|
internal object InternalCommandManager : CoroutineScope by CoroutineScope(MiraiConsole.job) {
|
||||||
const val COMMAND_PREFIX = "/"
|
const val COMMAND_PREFIX = "/"
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
@ -56,6 +62,18 @@ internal object InternalCommandManager {
|
|||||||
}
|
}
|
||||||
return optionalPrefixCommandMap[rawCommand.toLowerCase()]
|
return optionalPrefixCommandMap[rawCommand.toLowerCase()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal val commandListener: Listener<MessageEvent> by lazy {
|
||||||
|
@Suppress("RemoveExplicitTypeArguments")
|
||||||
|
subscribeAlways<MessageEvent>(
|
||||||
|
concurrency = Listener.ConcurrencyKind.CONCURRENT,
|
||||||
|
priority = Listener.EventPriority.HIGH
|
||||||
|
) {
|
||||||
|
if (this.sender.asCommandSender().executeCommand(message) != null) {
|
||||||
|
intercept()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal infix fun Array<out String>.intersectsIgnoringCase(other: Array<out String>): Boolean {
|
internal infix fun Array<out String>.intersectsIgnoringCase(other: Array<out String>): Boolean {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
object Versions {
|
object Versions {
|
||||||
const val core = "1.1-EA"
|
const val core = "1.1-EA"
|
||||||
const val console = "1.1-dev-1"
|
const val console = "1.0-dev-1"
|
||||||
const val consoleGraphical = "0.0.7"
|
const val consoleGraphical = "0.0.7"
|
||||||
const val consoleTerminal = "0.1.0"
|
const val consoleTerminal = "0.1.0"
|
||||||
const val consolePure = "0.1.0"
|
const val consolePure = "0.1.0"
|
||||||
|
Loading…
Reference in New Issue
Block a user