diff --git a/backend/mirai-console/src/MiraiConsoleImplementation.kt b/backend/mirai-console/src/MiraiConsoleImplementation.kt index 443d66551..428ca1b97 100644 --- a/backend/mirai-console/src/MiraiConsoleImplementation.kt +++ b/backend/mirai-console/src/MiraiConsoleImplementation.kt @@ -17,9 +17,13 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.data.PluginDataStorage +import net.mamoe.mirai.console.extension.ComponentStorage import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge +import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl +import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl import net.mamoe.mirai.console.logging.LoggerController +import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader import net.mamoe.mirai.console.util.ConsoleInput @@ -185,7 +189,42 @@ public interface MiraiConsoleImplementation : CoroutineScope { public val loggerController: LoggerController get() = LoggerControllerImpl + /// Hooks & Backend Access + /** + * 后端 在 [phase] 阶段执行前会调用此方法, 如果此方法抛出了一个错误会直接中断 console 初始化 + */ + public fun prePhase(phase: String) {} + + /** + * 后端 在 [phase] 阶段执行后会调用此方法, 如果此方法抛出了一个错误会直接中断 console 初始化 + */ + public fun postPhase(phase: String) {} + + /** 后端在 [start] 前会调用此方法 */ + public fun preStart() {} + + /** 后端在 [start] 后会调用此方法 */ + public fun postStart() {} + + /** + * 用于提供前端访问后端内部实现 + */ + @ConsoleFrontEndImplementation + public interface BackendAccess { + // GlobalComponentStorage + public val globalComponentStorage: ComponentStorage + // PluginManagerImpl.resolvedPlugins + public val resolvedPlugins: MutableList + } + + public val backendAccess: BackendAccess get() = backendAccessInstance + public companion object { + private val backendAccessInstance = object : BackendAccess { + override val globalComponentStorage: ComponentStorage get() = GlobalComponentStorage + override val resolvedPlugins: MutableList get() = PluginManagerImpl.resolvedPlugins + } + internal lateinit var instance: MiraiConsoleImplementation private val initLock = ReentrantLock() diff --git a/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt b/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt index 8658ea516..2bdb53b0c 100644 --- a/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt +++ b/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt @@ -16,7 +16,10 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.coroutines.runBlocking import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.* +import net.mamoe.mirai.console.MalformedMiraiConsoleImplementationError +import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.MiraiConsoleFrontEndDescription +import net.mamoe.mirai.console.MiraiConsoleImplementation import net.mamoe.mirai.console.command.BuiltInCommands import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.ConsoleCommandSender @@ -104,8 +107,9 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI @Suppress("RemoveRedundantBackticks") internal fun doStart() { + instance.preStart() - phase `setup logger controller`@{ + phase("setup logger controller") { if (loggerController === LoggerControllerImpl) { // Reload LoggerConfig. ConsoleDataScope.addAndReloadConfig(LoggerConfig) @@ -113,7 +117,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI } } - phase `greeting`@{ + phase("greeting") { val buildDateFormatted = buildDate.atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) @@ -122,7 +126,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI mainLogger.info { frontEndDescription.render() } } - phase `check coroutineContext`@{ + phase("check coroutineContext") { if (coroutineContext[Job] == null) { throw MalformedMiraiConsoleImplementationError("The coroutineContext given to MiraiConsole must have a Job in it.") } @@ -139,13 +143,13 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI // start - phase `load configurations`@{ + phase("load configurations") { mainLogger.verbose { "Loading configurations..." } ConsoleDataScope.addAndReloadConfig(CommandConfig) ConsoleDataScope.reloadAll() } - phase `initialize all plugins`@{ + phase("initialize all plugins") { PluginManager // init mainLogger.verbose { "Loading JVM plugins..." } @@ -158,13 +162,13 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI } } - phase `load all plugins`@{ + phase("load all plugins") { PluginManagerImpl.loadPlugins(PluginManagerImpl.scanPluginsUsingPluginLoadersIncludingThoseFromPluginLoaderProvider()) mainLogger.verbose { "${PluginManager.plugins.size} plugin(s) loaded." } } - phase `load SingletonExtensionSelector`@{ + phase("load SingletonExtensionSelector") { SingletonExtensionSelector.init() val instance = SingletonExtensionSelector.instance if (instance is BuiltInSingletonExtensionSelector) { @@ -173,7 +177,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI } - phase `load PermissionService`@{ + phase("load PermissionService") { mainLogger.verbose { "Loading PermissionService..." } PermissionService.INSTANCE.let { ps -> @@ -188,7 +192,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI runIgnoreException { ConsoleCommandSender.permit(RootPermission) } } - phase `prepare commands`@{ + phase("prepare commands") { mainLogger.verbose { "Loading built-in commands..." } BuiltInCommands.registerAll() mainLogger.info { "Prepared built-in commands: ${BuiltInCommands.all.joinToString { it.primaryName }}" } @@ -196,7 +200,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI // CommandManagerImpl.commandListener // start } - phase `enable plugins`@{ + phase("enable plugins") { mainLogger.verbose { "Enabling plugins..." } PluginManagerImpl.enableAllLoadedPlugins() @@ -208,7 +212,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI mainLogger.info { "${PluginManagerImpl.plugins.size} plugin(s) enabled." } } - phase `auto-login bots`@{ + phase("auto-login bots") { runBlocking { val accounts = AutoLoginConfig.accounts.toList() for (account in accounts) { @@ -259,10 +263,14 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI } } - GlobalComponentStorage.run { - PostStartupExtension.useExtensions { it() } // exceptions thrown will be caught by caller of `doStart`. + phase("finally post") { + GlobalComponentStorage.run { + PostStartupExtension.useExtensions { it() } // exceptions thrown will be caught by caller of `doStart`. + } } + instance.postStart() + mainLogger.info { "mirai-console started successfully." } } @@ -275,10 +283,20 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI * 表示一个初始化阶段, 无实际作用. */ @ILoveOmaeKumikoForever - private inline fun phase(block: () -> Unit) { + private inline fun phase(phase: String, block: () -> Unit) { contract { callsInPlace(block, InvocationKind.EXACTLY_ONCE) } + prePhase(phase) block() + postPhase(phase) + } + + override fun prePhase(phase: String) { + instance.prePhase(phase) + } + + override fun postPhase(phase: String) { + instance.postPhase(phase) } } \ No newline at end of file