mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-13 20:02:57 +08:00
Implement MiraiConsole bootstrap and plugin loading
This commit is contained in:
parent
442d7ee0ce
commit
01fd1b3b6e
@ -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<PluginLoader<*, *>> 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<PluginLoader<*, *>>
|
||||
|
||||
internal val consoleCommandOwner: ConsoleCommandOwner
|
||||
val consoleCommandSender: ConsoleCommandSender
|
||||
|
||||
internal val consoleCommandSender: ConsoleCommandSender
|
||||
val settingStorage: SettingStorage
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -85,4 +85,18 @@ abstract class AbstractFilePluginLoader<P : Plugin, D : PluginDescription>(
|
||||
protected abstract fun Sequence<File>.mapToDescription(): List<D>
|
||||
|
||||
final override fun listPlugins(): List<D> = pluginsFilesSequence().mapToDescription()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Not yet decided to make public API
|
||||
internal class DeferredPluginLoader<P : Plugin, D : PluginDescription>(
|
||||
initializer: () -> PluginLoader<P, D>
|
||||
) : PluginLoader<P, D> {
|
||||
private val instance by lazy(initializer)
|
||||
|
||||
override fun listPlugins(): List<D> = 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)
|
||||
}
|
||||
|
@ -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<PluginLoader<*, *>> = mutableListOf()
|
||||
private val loadersLock: ReentrantLock = ReentrantLock()
|
||||
private val logger = MiraiConsole.newLogger("PluginManager")
|
||||
|
||||
@JvmField
|
||||
internal val resolvedPlugins: MutableList<Plugin> = mutableListOf()
|
||||
@ -70,13 +73,33 @@ object PluginManager {
|
||||
// region LOADING
|
||||
|
||||
private fun <P : Plugin, D : PluginDescription> PluginLoader<P, D>.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 <P : Plugin, D : PluginDescription> PluginLoader<P, D>.loadPluginAndEnable(description: D) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return this.enable(loadPluginNoEnable(description.unwrap()))
|
||||
private fun <P : Plugin, D : PluginDescription> PluginLoader<P, D>.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<PluginDescriptionWithLoader>.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<Plugin, PluginDescription>
|
||||
|
||||
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()
|
||||
|
@ -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<PluginLoader<*, *>> = 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()
|
||||
})
|
||||
}
|
||||
|
@ -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<MyClass> {
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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<PluginLoader<*, *>> = 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<PluginLoader<*, *>> = 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
|
||||
}
|
@ -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<String>?) {
|
||||
@ -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())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user