diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 74d6b379b..48c49ff01 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -8,6 +8,7 @@ */ @file:Suppress("WRONG_MODIFIER_CONTAINING_DECLARATION") +@file:OptIn(ConsoleInternalAPI::class) package net.mamoe.mirai.console @@ -16,18 +17,22 @@ import kotlinx.coroutines.Job import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsole.INSTANCE -import net.mamoe.mirai.console.command.ConsoleCommandOwner import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.plugin.PluginLoader +import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.center.CuiPluginCenter import net.mamoe.mirai.console.plugin.center.PluginCenter import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader +import net.mamoe.mirai.console.setting.SettingStorage import net.mamoe.mirai.console.utils.ConsoleExperimentalAPI +import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.info import java.io.ByteArrayOutputStream import java.io.File import java.io.PrintStream +import java.text.SimpleDateFormat import java.util.* import kotlin.coroutines.CoroutineContext @@ -80,14 +85,14 @@ internal object MiraiConsoleInitializer { /** 由前端调用 */ internal fun init(instance: IMiraiConsole) { this.instance = instance - MiraiConsoleInternal.initialize() + MiraiConsoleInternal.doStart() } } internal object MiraiConsoleBuildConstants { // auto-filled on build (task :mirai-console:fillBuildConstants) @JvmStatic val buildDate: Date = Date(1592799753404L) // 2020-06-22 12:22:33 - const val version: String = "0.5.1" + const val version: String = "1.0-M1" } /** @@ -107,9 +112,10 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso get() = instance.mainLogger override val coroutineContext: CoroutineContext get() = instance.coroutineContext override val builtInPluginLoaders: List> get() = instance.builtInPluginLoaders - override val consoleCommandOwner: ConsoleCommandOwner get() = instance.consoleCommandOwner override val consoleCommandSender: ConsoleCommandSender get() = instance.consoleCommandSender + override val settingStorage: SettingStorage get() = instance.settingStorage + init { DefaultLogger = { identity -> this.newLogger(identity) } } @@ -117,13 +123,23 @@ internal object MiraiConsoleInternal : CoroutineScope, IMiraiConsole, MiraiConso @ConsoleExperimentalAPI override fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) - internal fun initialize() { + internal fun doStart() { + val buildDateFormatted = SimpleDateFormat("yyyy-MM-dd").format(buildDate) + mainLogger.info { "Starting mirai-console..." } + mainLogger.info { "Backend: version $version, built on $buildDateFormatted." } + mainLogger.info { "Frontend ${frontEnd.name}: version $version." } + if (coroutineContext[Job] == null) { throw IllegalMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.") } this.coroutineContext[Job]!!.invokeOnCompletion { Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) } } + + mainLogger.info { "Loading plugins..." } + PluginManager.loadEnablePlugins() + mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." } + mainLogger.info { "mirai-console started successfully." } // Only for initialize } } @@ -155,9 +171,9 @@ internal interface IMiraiConsole : CoroutineScope { */ val builtInPluginLoaders: List> - internal val consoleCommandOwner: ConsoleCommandOwner + val consoleCommandSender: ConsoleCommandSender - internal val consoleCommandSender: ConsoleCommandSender + val settingStorage: SettingStorage } /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt index ec6d47082..ecc88d453 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleFrontEnd.kt @@ -11,15 +11,23 @@ package net.mamoe.mirai.console import net.mamoe.mirai.Bot import net.mamoe.mirai.utils.LoginSolver -import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiLogger /** * 只需要实现一个这个传入 MiraiConsole 就可以绑定 UI 层与 Console 层 * 需要保证线程安全 */ -@MiraiInternalAPI interface MiraiConsoleFrontEnd { + /** + * 名称 + */ + val name: String + + /** + * 版本 + */ + val version: String + fun loggerFor(identity: String?): MiraiLogger /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt index 2ccc8500c..60df456ca 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginLoader.kt @@ -85,4 +85,18 @@ abstract class AbstractFilePluginLoader

( protected abstract fun Sequence.mapToDescription(): List final override fun listPlugins(): List = pluginsFilesSequence().mapToDescription() -} \ No newline at end of file +} + + +// Not yet decided to make public API +internal class DeferredPluginLoader

( + initializer: () -> PluginLoader +) : PluginLoader { + private val instance by lazy(initializer) + + override fun listPlugins(): List = instance.listPlugins() + override val P.description: D get() = instance.run { description } + override fun load(description: D): P = instance.load(description) + override fun enable(plugin: P) = instance.enable(plugin) + override fun disable(plugin: P) = instance.disable(plugin) +} diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt index 5b94228c5..9140403c0 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/PluginManager.kt @@ -7,12 +7,13 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("NOTHING_TO_INLINE") +@file:Suppress("NOTHING_TO_INLINE", "unused") package net.mamoe.mirai.console.plugin import kotlinx.atomicfu.locks.withLock import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.utils.info import java.io.File import java.util.concurrent.locks.ReentrantLock @@ -26,8 +27,10 @@ object PluginManager { val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() } val pluginsDataFolder = File(MiraiConsole.rootDir, "data").apply { mkdir() } + @Suppress("ObjectPropertyName") private val _pluginLoaders: MutableList> = mutableListOf() private val loadersLock: ReentrantLock = ReentrantLock() + private val logger = MiraiConsole.newLogger("PluginManager") @JvmField internal val resolvedPlugins: MutableList = mutableListOf() @@ -70,13 +73,33 @@ object PluginManager { // region LOADING private fun

PluginLoader.loadPluginNoEnable(description: D): P { - // TODO: 2020/5/23 HANDLE INITIALIZATION EXCEPTION - return this.load(description).also { resolvedPlugins.add(it) } + return kotlin.runCatching { + this.load(description).also { resolvedPlugins.add(it) } + }.fold( + onSuccess = { + logger.info { "Successfully loaded plugin ${description.name}" } + it + }, + onFailure = { + logger.info { "Cannot load plugin ${description.name}" } + throw it + } + ) } - private fun

PluginLoader.loadPluginAndEnable(description: D) { - @Suppress("UNCHECKED_CAST") - return this.enable(loadPluginNoEnable(description.unwrap())) + private fun

PluginLoader.enablePlugin(plugin: Plugin) { + kotlin.runCatching { + @Suppress("UNCHECKED_CAST") + this.enable(plugin as P) + }.fold( + onSuccess = { + logger.info { "Successfully enabled plugin ${plugin.description.name}" } + }, + onFailure = { + logger.info { "Cannot enable plugin ${plugin.description.name}" } + throw it + } + ) } /** @@ -93,10 +116,15 @@ object PluginManager { @Suppress("UNCHECKED_CAST") @Throws(PluginMissingDependencyException::class) internal fun loadEnablePlugins() { - val all = loadAndEnableLoaderProviders() + _pluginLoaders.listAllPlugins().flatMap { it.second } + (loadAndEnableLoaderProviders() + _pluginLoaders.listAllPlugins().flatMap { it.second }) + .sortByDependencies().loadAndEnableAllInOrder() + } - for ((loader, desc) in all.sortByDependencies()) { - loader.loadPluginAndEnable(desc) + private fun List.loadAndEnableAllInOrder() { + return this.map { (loader, desc) -> + loader to loader.loadPluginNoEnable(desc) + }.forEach { (loader, plugin) -> + loader.enablePlugin(plugin) } } @@ -112,9 +140,7 @@ object PluginManager { .onEach { (loader, descriptions) -> loader as PluginLoader - for (it in descriptions.filter { it.kind == PluginKind.LOADER }.sortByDependencies()) { - loader.loadPluginAndEnable(it) - } + descriptions.filter { it.kind == PluginKind.LOADER }.sortByDependencies().loadAndEnableAllInOrder() } .flatMap { it.second.asSequence() } @@ -161,12 +187,7 @@ object PluginManager { // endregion } -class PluginMissingDependencyException : PluginResolutionException { - constructor() : super() - constructor(message: String?) : super(message) - constructor(message: String?, cause: Throwable?) : super(message, cause) - constructor(cause: Throwable?) : super(cause) -} +class PluginMissingDependencyException(message: String?) : PluginResolutionException(message) open class PluginResolutionException : Exception { constructor() : super() diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt index fc1414ae3..b971d3be5 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/TestMiraiConosle.kt @@ -14,10 +14,12 @@ import kotlinx.coroutines.runBlocking import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.withTimeout import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.command.ConsoleCommandOwner import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader +import net.mamoe.mirai.console.setting.MemorySettingStorage +import net.mamoe.mirai.console.setting.SettingStorage +import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.LoginSolver @@ -28,6 +30,7 @@ import kotlin.coroutines.CoroutineContext import kotlin.coroutines.resume import kotlin.test.assertNotNull +@OptIn(ConsoleInternalAPI::class) fun initTestEnvironment() { MiraiConsoleInitializer.init(object : IMiraiConsole { override val rootDir: File = createTempDir() @@ -39,10 +42,10 @@ fun initTestEnvironment() { } override val mainLogger: MiraiLogger = DefaultLogger("main") override val builtInPluginLoaders: List> = listOf(JarPluginLoader) - override val consoleCommandOwner: ConsoleCommandOwner = object : ConsoleCommandOwner() {} override val consoleCommandSender: ConsoleCommandSender = object : ConsoleCommandSender() { override suspend fun sendMessage(message: Message) = println(message) } + override val settingStorage: SettingStorage get() = MemorySettingStorage override val coroutineContext: CoroutineContext = SupervisorJob() }) } diff --git a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommand.kt b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommand.kt index a16a58594..ca9bbbfab 100644 --- a/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommand.kt +++ b/backend/mirai-console/src/test/kotlin/net/mamoe/mirai/console/command/TestCommand.kt @@ -27,7 +27,7 @@ import org.junit.jupiter.api.Test import kotlin.test.* object TestCompositeCommand : CompositeCommand( - ConsoleCommandOwner.instance, + ConsoleCommandOwner, "testComposite", "tsC" ) { @SubCommand @@ -44,7 +44,7 @@ object TestSimpleCommand : RawCommand(owner, "testSimple", "tsS") { } internal val sender by lazy { ConsoleCommandSender.instance } -internal val owner by lazy { ConsoleCommandOwner.instance } +internal val owner by lazy { ConsoleCommandOwner } internal class TestCommand { companion object { @@ -61,7 +61,7 @@ internal class TestCommand { assertTrue(TestCompositeCommand.register()) assertFalse(TestCompositeCommand.register()) - assertEquals(1, ConsoleCommandOwner.instance.registeredCommands.size) + assertEquals(1, ConsoleCommandOwner.registeredCommands.size) assertEquals(1, InternalCommandManager.registeredCommands.size) assertEquals(2, InternalCommandManager.requiredPrefixCommandMap.size) @@ -131,14 +131,16 @@ internal class TestCommand { fun `composite sub command resolution conflict`() { runBlocking { val composite = object : CompositeCommand( - ConsoleCommandOwner.instance, + ConsoleCommandOwner, "tr" ) { + @Suppress("UNUSED_PARAMETER") @SubCommand fun mute(seconds: Int) { Testing.ok(1) } + @Suppress("UNUSED_PARAMETER") @SubCommand fun mute(seconds: Int, arg2: Int) { Testing.ok(2) @@ -164,7 +166,7 @@ internal class TestCommand { ) val composite = object : CompositeCommand( - ConsoleCommandOwner.instance, + ConsoleCommandOwner, "test", overrideContext = CommandParserContext { add(object : CommandArgParser { diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt index a363e5e03..3677a65f6 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/ConsoleUtils.kt @@ -16,7 +16,7 @@ import org.jline.reader.impl.completer.NullCompleter import org.jline.terminal.Terminal import org.jline.terminal.TerminalBuilder -object ConsoleUtils { +internal object ConsoleUtils { val lineReader: LineReader val terminal: Terminal @@ -24,10 +24,10 @@ object ConsoleUtils { init { val dumb = System.getProperty("java.class.path") - .contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null + .contains("idea_rt.jar") || System.getProperty("mirai.idea") !== null || System.getenv("mirai.idea") !== null terminal = TerminalBuilder.builder() - .dumb(dumb) + .jansi(true) .build() lineReader = LineReaderBuilder.builder() .terminal(terminal) diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt index cc444d5ca..d3c790fea 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsoleFrontEndPure.kt @@ -7,12 +7,26 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress( + "INVISIBLE_MEMBER", + "INVISIBLE_REFERENCE", + "CANNOT_OVERRIDE_INVISIBLE_MEMBER", + "INVISIBLE_SETTER", + "INVISIBLE_GETTER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING", + "EXPOSED_SUPER_CLASS" +) + package net.mamoe.mirai.console.pure //import net.mamoe.mirai.console.command.CommandManager //import net.mamoe.mirai.console.utils.MiraiConsoleFrontEnd +import kotlinx.coroutines.suspendCancellableCoroutine import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.MiraiConsoleBuildConstants import net.mamoe.mirai.console.MiraiConsoleFrontEnd +import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.utils.DefaultLoginSolver import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.MiraiLogger @@ -21,6 +35,7 @@ import org.fusesource.jansi.Ansi import java.text.SimpleDateFormat import java.util.* import java.util.concurrent.ConcurrentHashMap +import kotlin.coroutines.resume private val ANSI_RESET = Ansi().reset().toString() @@ -30,6 +45,13 @@ internal val LoggerCreator: (identity: String?) -> MiraiLogger = { }) } +/** + * mirai-console-pure 前端实现 + * + * @see MiraiConsolePure 后端实现 + * @see MiraiConsolePureLoader CLI 入口点 + */ +@ConsoleInternalAPI @Suppress("unused") object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { private val globalLogger = LoggerCreator("Mirai") @@ -53,7 +75,10 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { val sdf by lazy { SimpleDateFormat("HH:mm:ss") } - + override val name: String + get() = "Pure" + override val version: String + get() = MiraiConsoleBuildConstants.version override fun loggerFor(identity: String?): MiraiLogger { identity?.apply { @@ -74,7 +99,9 @@ object MiraiConsoleFrontEndPure : MiraiConsoleFrontEnd { .toString() ) } - return ConsoleUtils.lineReader.readLine("> ") + return suspendCancellableCoroutine { + it.resume(ConsoleUtils.lineReader.readLine("> ")) + } } override fun createLoginSolver(): LoginSolver { diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt index 0cb890027..d73b6a8b7 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePure.kt @@ -15,32 +15,58 @@ "INVISIBLE_SETTER", "INVISIBLE_GETTER", "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", - "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING" + "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER_WARNING", + "EXPOSED_SUPER_CLASS" ) +@file:OptIn(ConsoleInternalAPI::class) package net.mamoe.mirai.console.pure import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.console.IMiraiConsole import net.mamoe.mirai.console.MiraiConsoleFrontEnd +import net.mamoe.mirai.console.MiraiConsoleInitializer +import net.mamoe.mirai.console.command.ConsoleCommandSender +import net.mamoe.mirai.console.plugin.DeferredPluginLoader import net.mamoe.mirai.console.plugin.PluginLoader -import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader +import net.mamoe.mirai.console.setting.MultiFileSettingStorage +import net.mamoe.mirai.console.setting.SettingStorage +import net.mamoe.mirai.console.utils.ConsoleInternalAPI import net.mamoe.mirai.utils.MiraiLogger import java.io.File -import java.util.* -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext -private val delegateScope = CoroutineScope(EmptyCoroutineContext) - -object MiraiConsolePure : IMiraiConsole { - override val builtInPluginLoaders: List> = LinkedList() - override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure - override val mainLogger: MiraiLogger = DefaultLogger("Console") - override val rootDir: File = File("./test/console").also { - it.mkdirs() +/** + * mirai-console-pure 后端实现 + * + * @see MiraiConsoleFrontEndPure 前端实现 + * @see MiraiConsolePureLoader CLI 入口点 + */ +class MiraiConsolePure @JvmOverloads constructor( + override val rootDir: File = File("."), + override val builtInPluginLoaders: List> = listOf(DeferredPluginLoader { JarPluginLoader }), + override val frontEnd: MiraiConsoleFrontEnd = MiraiConsoleFrontEndPure, + override val mainLogger: MiraiLogger = frontEnd.loggerFor("Console"), + override val consoleCommandSender: ConsoleCommandSender = ConsoleCommandSenderImpl, + override val settingStorage: SettingStorage = MultiFileSettingStorage(rootDir) +) : IMiraiConsole, CoroutineScope by CoroutineScope(SupervisorJob()) { + init { + rootDir.mkdir() + require(rootDir.isDirectory) { "rootDir ${rootDir.absolutePath} is not a directory" } + } + + companion object { + @Volatile + @JvmStatic + private var started: Boolean = false + + @JvmStatic + fun MiraiConsolePure.start() = synchronized(this) { + check(!started) { "mirai-console is already started and can't be restarted." } + MiraiConsoleInitializer.init(MiraiConsolePure()) + started = true + } } - override val coroutineContext: CoroutineContext - get() = delegateScope.coroutineContext } \ No newline at end of file diff --git a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt index 18c9a8dfd..64ffb127d 100644 --- a/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt +++ b/frontend/mirai-console-pure/src/main/kotlin/net/mamoe/mirai/console/pure/MiraiConsolePureLoader.kt @@ -16,17 +16,23 @@ "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPER", "INVISIBLE_ABSTRACT_MEMBER_FROM_SUPE_WARNING" ) +@file:OptIn(ConsoleInternalAPI::class) package net.mamoe.mirai.console.pure -import net.mamoe.mirai.console.MiraiConsoleInitializer +import kotlinx.coroutines.isActive import net.mamoe.mirai.console.command.CommandExecuteStatus import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.command.executeCommandDetailed +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.utils.DefaultLogger import kotlin.concurrent.thread +/** + * mirai-console-pure CLI 入口点 + */ object MiraiConsolePureLoader { @JvmStatic fun main(args: Array?) { @@ -36,18 +42,21 @@ object MiraiConsolePureLoader { internal fun startup() { - MiraiConsoleInitializer.init(MiraiConsolePure) startConsoleThread() + MiraiConsolePure().start() } internal fun startConsoleThread() { thread(name = "Console", isDaemon = false) { val consoleLogger = DefaultLogger("Console") kotlinx.coroutines.runBlocking { - while (true) { + while (isActive) { val next = MiraiConsoleFrontEndPure.requestInput("") + if (next.isBlank()) { + continue + } consoleLogger.debug("INPUT> $next") - val result = ConsoleCS.executeCommandDetailed(next) + val result = ConsoleCommandSenderImpl.executeCommandDetailed(next) when (result.status) { CommandExecuteStatus.SUCCESSFUL -> { } @@ -65,7 +74,7 @@ internal fun startConsoleThread() { } } -object ConsoleCS : ConsoleCommandSender() { +internal object ConsoleCommandSenderImpl : ConsoleCommandSender() { override suspend fun sendMessage(message: Message) { ConsoleUtils.lineReader.printAbove(message.contentToString()) }