diff --git a/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt b/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt index 58d4a614b..82abf278a 100644 --- a/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt +++ b/mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt @@ -16,12 +16,16 @@ import kotlinx.coroutines.* 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.PluginDataHolder +import net.mamoe.mirai.console.data.AutoSavePluginDataHolder +import net.mamoe.mirai.console.data.PluginConfig +import net.mamoe.mirai.console.data.PluginData 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.data.builtins.ConsoleDataScopeImpl import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl +import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl import net.mamoe.mirai.console.internal.pluginManagerImpl import net.mamoe.mirai.console.logging.LoggerController import net.mamoe.mirai.console.plugin.Plugin @@ -85,6 +89,18 @@ public interface MiraiConsoleImplementation : CoroutineScope { */ public val builtInPluginLoaders: List>> + /** + * [JvmPluginLoader] 实例. 建议实现为 lazy: + * + * ``` + * override val jvmPluginLoader: JvmPluginLoader by lazy { backendAccess.createDefaultJvmPluginLoader(coroutineContext) } + * ``` + * + * @see BackendAccess.createDefaultJvmPluginLoader + * @since 2.10.0-RC + */ + public val jvmPluginLoader: JvmPluginLoader + /** * 由 Kotlin 用户实现 * @@ -188,6 +204,54 @@ public interface MiraiConsoleImplementation : CoroutineScope { */ public val loggerController: LoggerController get() = LoggerControllerImpl + /////////////////////////////////////////////////////////////////////////// + // ConsoleDataScope + /////////////////////////////////////////////////////////////////////////// + + /** + * Mirai Console 内置的一些 [PluginConfig] 和 [PluginData] 的管理器. + * + * 建议实现为 lazy: + * ``` + * override val consoleDataScope: MiraiConsoleImplementation.ConsoleDataScope by lazy { + * MiraiConsoleImplementation.ConsoleDataScope.createDefault( + * coroutineContext, + * dataStorageForBuiltIns, + * configStorageForBuiltIns + * ) + * } + * ``` + * + * @since 2.10.0-RC + */ + public val consoleDataScope: ConsoleDataScope + + /** + * Mirai Console 内置的一些 [PluginConfig] 和 [PluginData] 的管理器. + * + * @since 2.10.0-RC + */ + @ConsoleFrontEndImplementation + public interface ConsoleDataScope { + public val dataHolder: AutoSavePluginDataHolder + public val configHolder: AutoSavePluginDataHolder + public fun addAndReloadConfig(config: PluginConfig) + public fun reloadAll() + + /** + * @since 2.10.0-RCl + */ + @ConsoleFrontEndImplementation + public companion object { + @JvmStatic + public fun createDefault( + coroutineContext: CoroutineContext, + dataStorage: PluginDataStorage, + configStorage: PluginDataStorage + ): ConsoleDataScope = ConsoleDataScopeImpl(coroutineContext, dataStorage, configStorage) + } + } + /// Hooks & Backend Access /** @@ -231,6 +295,12 @@ public interface MiraiConsoleImplementation : CoroutineScope { // PluginManagerImpl.resolvedPlugins public val resolvedPlugins: MutableList + + /** + * @since 2.10.0-RC + */ + public fun createDefaultJvmPluginLoader(coroutineContext: CoroutineContext): JvmPluginLoader = + BuiltInJvmPluginLoaderImpl(coroutineContext) } /** diff --git a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt index 05de5c4e3..760a247f9 100644 --- a/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt +++ b/mirai-console/backend/mirai-console/src/internal/MiraiConsoleImplementationBridge.kt @@ -31,7 +31,6 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.ConfigurationKey import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.MD5 import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN -import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope import net.mamoe.mirai.console.internal.data.builtins.LoggerConfig import net.mamoe.mirai.console.internal.extension.BuiltInSingletonExtensionSelector import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage @@ -82,8 +81,6 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, override val mainLogger: MiraiLogger by lazy { createLogger("main") } - val consoleDataScope by lazy { ConsoleDataScope(coroutineContext, dataStorageForBuiltIns, dataStorageForBuiltIns) } - init { // TODO: Replace to standard api @Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") diff --git a/mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScope.kt b/mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScopeImpl.kt similarity index 82% rename from mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScope.kt rename to mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScopeImpl.kt index bef16a970..fed628c39 100644 --- a/mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScope.kt +++ b/mirai-console/backend/mirai-console/src/internal/data/builtins/ConsoleDataScopeImpl.kt @@ -10,6 +10,7 @@ package net.mamoe.mirai.console.internal.data.builtins import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.MiraiConsoleImplementation import net.mamoe.mirai.console.data.AutoSavePluginDataHolder import net.mamoe.mirai.console.data.PluginConfig import net.mamoe.mirai.console.data.PluginData @@ -19,23 +20,23 @@ import net.mamoe.mirai.utils.minutesToMillis import kotlin.coroutines.CoroutineContext -internal class ConsoleDataScope( +internal class ConsoleDataScopeImpl( parentCoroutineContext: CoroutineContext, private val dataStorage: PluginDataStorage, private val configStorage: PluginDataStorage, -) : CoroutineScope by parentCoroutineContext.childScope("ConsoleDataScope") { - val dataHolder: AutoSavePluginDataHolder = ConsoleBuiltInPluginDataHolder(this.coroutineContext) - val configHolder: AutoSavePluginDataHolder = ConsoleBuiltInPluginConfigHolder(this.coroutineContext) +) : CoroutineScope by parentCoroutineContext.childScope("ConsoleDataScope"), MiraiConsoleImplementation.ConsoleDataScope { + override val dataHolder: AutoSavePluginDataHolder = ConsoleBuiltInPluginDataHolder(this.coroutineContext) + override val configHolder: AutoSavePluginDataHolder = ConsoleBuiltInPluginConfigHolder(this.coroutineContext) private val data: List = mutableListOf() private val configs: MutableList = mutableListOf(AutoLoginConfig) - fun addAndReloadConfig(config: PluginConfig) { + override fun addAndReloadConfig(config: PluginConfig) { configs.add(config) configStorage.load(configHolder, config) } - fun reloadAll() { + override fun reloadAll() { data.forEach { dt -> dataStorage.load(dataHolder, dt) } diff --git a/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt b/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt index b74ec3bdd..3e489ed36 100644 --- a/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt +++ b/mirai-console/backend/mirai-console/src/internal/plugin/BuiltInJvmPluginLoaderImpl.kt @@ -22,30 +22,36 @@ import net.mamoe.mirai.console.plugin.jvm.* import net.mamoe.mirai.console.plugin.loader.AbstractFilePluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoadException import net.mamoe.mirai.console.plugin.name -import net.mamoe.mirai.utils.childScope import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.castOrNull +import net.mamoe.mirai.utils.childScope import net.mamoe.mirai.utils.verbose import java.io.File import java.nio.file.Path import java.util.concurrent.ConcurrentHashMap +import kotlin.coroutines.CoroutineContext -internal object BuiltInJvmPluginLoaderImpl : - AbstractFilePluginLoader(".jar"), - CoroutineScope by MiraiConsole.childScope("JvmPluginLoader", CoroutineExceptionHandler { _, throwable -> - BuiltInJvmPluginLoaderImpl.logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable) +internal val JvmPluginLoader.implOrNull get() = this.castOrNull() + +internal class BuiltInJvmPluginLoaderImpl( + parentCoroutineContext: CoroutineContext +) : AbstractFilePluginLoader(".jar"), + CoroutineScope by parentCoroutineContext.childScope("JvmPluginLoader", CoroutineExceptionHandler { _, throwable -> + logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable) }), JvmPluginLoader { + companion object { + internal val logger: MiraiLogger = MiraiConsole.createLogger(JvmPluginLoader::class.simpleName!!) + } + override val configStorage: PluginDataStorage get() = MiraiConsoleImplementationBridge.configStorageForJvmPluginLoader - @JvmStatic - internal val logger: MiraiLogger = MiraiConsole.createLogger(JvmPluginLoader::class.simpleName!!) - override val dataStorage: PluginDataStorage get() = MiraiConsoleImplementationBridge.dataStorageForJvmPluginLoader - internal val classLoaders: MutableList = mutableListOf() + override val classLoaders: MutableList = mutableListOf() @Suppress("EXTENSION_SHADOWED_BY_MEMBER") // doesn't matter override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = plugin.description diff --git a/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginInternal.kt b/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginInternal.kt index dfebc38fb..4fac04f23 100644 --- a/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginInternal.kt +++ b/mirai-console/backend/mirai-console/src/internal/plugin/JvmPluginInternal.kt @@ -15,6 +15,7 @@ import kotlinx.coroutines.* import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.data.runCatchingLog import net.mamoe.mirai.console.extension.PluginComponentStorage +import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.data.mkdir import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.permission.Permission @@ -26,7 +27,7 @@ import net.mamoe.mirai.console.plugin.ResourceContainer.Companion.asResourceCont import net.mamoe.mirai.console.plugin.jvm.AbstractJvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad -import net.mamoe.mirai.console.util.NamedSupervisorJob +import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.utils.MiraiLogger import java.io.File import java.io.InputStream @@ -144,15 +145,13 @@ internal abstract class JvmPluginInternal( ) } .plus(parentCoroutineContext) + .plus(CoroutineName("Plugin ${(this as AbstractJvmPlugin).dataHolderName}")) .plus( - NamedSupervisorJob( - "Plugin ${(this as AbstractJvmPlugin).dataHolderName}", - parentCoroutineContext[Job] ?: BuiltInJvmPluginLoaderImpl.coroutineContext[Job]!! - ) + SupervisorJob(parentCoroutineContext[Job] ?: JvmPluginLoader.coroutineContext[Job]!!) ) .also { if (!MiraiConsole.isActive) return@also - BuiltInJvmPluginLoaderImpl.coroutineContext[Job]!!.invokeOnCompletion { + JvmPluginLoader.coroutineContext[Job]!!.invokeOnCompletion { this.cancel() } } diff --git a/mirai-console/backend/mirai-console/src/internal/util/CommonUtils.kt b/mirai-console/backend/mirai-console/src/internal/util/CommonUtils.kt index 9605c6b26..fa9b705c6 100644 --- a/mirai-console/backend/mirai-console/src/internal/util/CommonUtils.kt +++ b/mirai-console/backend/mirai-console/src/internal/util/CommonUtils.kt @@ -12,7 +12,8 @@ package net.mamoe.mirai.console.internal.util import io.github.karlatemp.caller.StackFrame -import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl +import net.mamoe.mirai.console.internal.plugin.implOrNull +import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import kotlin.contracts.InvocationKind import kotlin.contracts.contract @@ -37,7 +38,7 @@ internal inline fun runIgnoreException(block: () -> Unit internal fun StackFrame.findLoader(): ClassLoader? { classInstance?.let { return it.classLoader } return runCatching { - BuiltInJvmPluginLoaderImpl.classLoaders.firstOrNull { it.findClass(className, true) != null } + JvmPluginLoader.implOrNull?.classLoaders?.firstOrNull { it.findClass(className, true) != null } }.getOrNull() } diff --git a/mirai-console/backend/mirai-console/src/internal/util/PluginServiceHelper.kt b/mirai-console/backend/mirai-console/src/internal/util/PluginServiceHelper.kt index 2cd1823fb..a9c150109 100644 --- a/mirai-console/backend/mirai-console/src/internal/util/PluginServiceHelper.kt +++ b/mirai-console/backend/mirai-console/src/internal/util/PluginServiceHelper.kt @@ -12,7 +12,7 @@ package net.mamoe.mirai.console.internal.util import net.mamoe.mirai.console.internal.data.cast -import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl +import net.mamoe.mirai.console.plugin.jvm.JvmPluginLoader import net.mamoe.mirai.utils.createInstanceOrNull import java.lang.reflect.Modifier import java.util.* @@ -39,7 +39,7 @@ internal object PluginServiceHelper { }.let { ServiceList(this, it) } fun ServiceList.loadAllServices(): List { - return delegate.mapNotNull { classLoader.loadService(it) } + return delegate.mapNotNull { classLoader.loadService(it) } } private fun ClassLoader.loadService( @@ -69,7 +69,7 @@ internal object PluginServiceHelper { fun loadAllServicesFromMemoryAndPluginClassLoaders(service: KClass): List { val list = ServiceLoader.load(service.java, this::class.java.classLoader).toList() - return list + BuiltInJvmPluginLoaderImpl.classLoaders.flatMap { it.findServices(service).loadAllServices() } + return list + JvmPluginLoader.classLoaders.flatMap { it.findServices(service).loadAllServices() } } } diff --git a/mirai-console/backend/mirai-console/src/plugin/jvm/JvmPluginLoader.kt b/mirai-console/backend/mirai-console/src/plugin/jvm/JvmPluginLoader.kt index f841ad69f..e9a82be59 100644 --- a/mirai-console/backend/mirai-console/src/plugin/jvm/JvmPluginLoader.kt +++ b/mirai-console/backend/mirai-console/src/plugin/jvm/JvmPluginLoader.kt @@ -10,13 +10,18 @@ package net.mamoe.mirai.console.plugin.jvm import kotlinx.coroutines.CoroutineScope +import me.him188.kotlin.dynamic.delegation.dynamicDelegation import net.mamoe.mirai.console.data.PluginDataStorage +import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl import net.mamoe.mirai.console.plugin.loader.FilePluginLoader +import net.mamoe.mirai.utils.MiraiInternalApi +import net.mamoe.mirai.utils.NotStableForInheritance /** * JVM 插件加载器 */ +@NotStableForInheritance public interface JvmPluginLoader : CoroutineScope, FilePluginLoader { /** * ".jar" @@ -33,7 +38,15 @@ public interface JvmPluginLoader : CoroutineScope, FilePluginLoader + + public companion object BuiltIn : + JvmPluginLoader by (dynamicDelegation { MiraiConsoleImplementationBridge.jvmPluginLoader }) { + @Suppress("EXTENSION_SHADOWED_BY_MEMBER") override fun getPluginDescription(plugin: JvmPlugin): JvmPluginDescription = BuiltInJvmPluginLoaderImpl.run { plugin.description } diff --git a/mirai-console/backend/mirai-console/test/TestMiraiConosle.kt b/mirai-console/backend/mirai-console/test/TestMiraiConosle.kt index ac8f53a09..0d633821a 100644 --- a/mirai-console/backend/mirai-console/test/TestMiraiConosle.kt +++ b/mirai-console/backend/mirai-console/test/TestMiraiConosle.kt @@ -47,6 +47,9 @@ fun initTestEnvironment() { } override val builtInPluginLoaders: List>> = listOf(lazy { JvmPluginLoader }) + override val jvmPluginLoader: JvmPluginLoader by lazy { + backendAccess.createDefaultJvmPluginLoader(coroutineContext) + } override val consoleCommandSender: MiraiConsoleImplementation.ConsoleCommandSenderImpl = object : MiraiConsoleImplementation.ConsoleCommandSenderImpl { override suspend fun sendMessage(message: Message) { @@ -76,6 +79,13 @@ fun initTestEnvironment() { return PlatformLogger(identity) } + override val consoleDataScope: MiraiConsoleImplementation.ConsoleDataScope by lazy { + MiraiConsoleImplementation.ConsoleDataScope.createDefault( + coroutineContext, + dataStorageForBuiltIns, + configStorageForBuiltIns + ) + } override val coroutineContext: CoroutineContext = CoroutineName("Console Main") + SupervisorJob() + CoroutineExceptionHandler { _, throwable -> throwable.printStackTrace() diff --git a/mirai-console/frontend/mirai-console-terminal/src/MiraiConsoleImplementationTerminal.kt b/mirai-console/frontend/mirai-console-terminal/src/MiraiConsoleImplementationTerminal.kt index 4f4190b9d..f4a04142b 100644 --- a/mirai-console/frontend/mirai-console-terminal/src/MiraiConsoleImplementationTerminal.kt +++ b/mirai-console/frontend/mirai-console-terminal/src/MiraiConsoleImplementationTerminal.kt @@ -74,8 +74,17 @@ open class MiraiConsoleImplementationTerminal val coroutineName = coroutineContext[CoroutineName]?.name ?: "" MiraiConsole.mainLogger.error("Exception in coroutine $coroutineName", throwable) }) { + override val jvmPluginLoader: JvmPluginLoader by lazy { backendAccess.createDefaultJvmPluginLoader(coroutineContext) } + override val consoleInput: ConsoleInput get() = ConsoleInputImpl override val isAnsiSupported: Boolean get() = true + override val consoleDataScope: MiraiConsoleImplementation.ConsoleDataScope by lazy { + MiraiConsoleImplementation.ConsoleDataScope.createDefault( + coroutineContext, + dataStorageForBuiltIns, + configStorageForBuiltIns + ) + } override fun createLoginSolver(requesterBot: Long, configuration: BotConfiguration): LoginSolver { LoginSolver.Default?.takeIf { it !is StandardCharImageLoginSolver }?.let { return it }