diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt index 10de0f8a6..2c91bc820 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JarPluginLoaderImpl.kt @@ -13,6 +13,7 @@ import kotlinx.coroutines.* import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge +import net.mamoe.mirai.console.internal.data.createInstanceOrNull import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader import net.mamoe.mirai.console.plugin.PluginLoadException import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader @@ -25,7 +26,6 @@ import net.mamoe.yamlkt.Yaml import java.io.File import java.net.URI import kotlin.coroutines.CoroutineContext -import kotlin.reflect.full.createInstance internal object JarPluginLoaderImpl : AbstractFilePluginLoader(".jar"), @@ -90,14 +90,14 @@ internal object JarPluginLoaderImpl : jarFile = file ).kotlin.run { objectInstance - ?: kotlin.runCatching { createInstance() }.getOrNull() + ?: createInstanceOrNull() ?: (java.constructors + java.declaredConstructors) .firstOrNull { it.parameterCount == 0 } ?.apply { kotlin.runCatching { isAccessible = true } } ?.newInstance() - } ?: error("No Kotlin object or public no-arg constructor found") + } ?: error("No Kotlin object or public no-arg constructor found for $mainClassName") - check(main is JvmPlugin) { "The main class of Jar plugin must extend JvmPlugin, recommending JavaPlugin or KotlinPlugin" } + check(main is JvmPlugin) { "The main class of Jar plugin must extend JvmPlugin, recommended JavaPlugin or KotlinPlugin" } if (main is JvmPluginInternal) { main._description = description @@ -110,6 +110,7 @@ internal object JarPluginLoaderImpl : } override fun enable(plugin: JvmPlugin) { + if (plugin.isEnabled) throw IllegalStateException("Plugin is already enabled") ensureActive() if (plugin is JvmPluginInternal) { plugin.internalOnEnable() @@ -117,6 +118,8 @@ internal object JarPluginLoaderImpl : } override fun disable(plugin: JvmPlugin) { + if (!plugin.isEnabled) throw IllegalStateException("Plugin is already disabled") + if (plugin is JvmPluginInternal) { plugin.internalOnDisable() } else plugin.onDisable() diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt index e05cb3b9d..0e8ab5709 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt @@ -16,10 +16,10 @@ import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.internal.data.mkdir import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.PluginManager +import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.safeLoader import net.mamoe.mirai.console.plugin.ResourceContainer.Companion.asResourceContainer import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPluginDescription -import net.mamoe.mirai.console.plugin.safeLoader import net.mamoe.mirai.utils.MiraiLogger import java.io.InputStream import java.nio.file.Path diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt index d39deb81f..b9c73a879 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginManagerImpl.kt @@ -61,7 +61,7 @@ internal object PluginManagerImpl : PluginManager { init { MiraiConsole.coroutineContext[Job]!!.invokeOnCompletion { - plugins.forEach(Plugin::disable) + plugins.forEach { it.disable() } } } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt index 5280d5e0b..a8b6cb198 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/Plugin.kt @@ -12,6 +12,8 @@ package net.mamoe.mirai.console.plugin import net.mamoe.mirai.console.command.CommandOwner +import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.disable +import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.enable import net.mamoe.mirai.console.plugin.dsecription.PluginDescription import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.util.ConsoleExperimentalAPI @@ -21,6 +23,10 @@ import java.nio.file.Path /** * 表示一个 mirai-console 插件. * + * @see PluginManager.enable 启用一个插件 + * @see PluginManager.disable 禁用一个插件 + * @see PluginManager.description 获取一个插件的 [描述][PluginDescription] + * * @see PluginDescription 插件描述, 需由 [PluginLoader] 帮助提供([PluginLoader.description]) * @see JvmPlugin Java, Kotlin 或其他 JVM 平台插件 * @see PluginFileExtensions 支持文件系统存储的扩展 @@ -31,8 +37,8 @@ public interface Plugin : CommandOwner { /** * 判断此插件是否已启用 * - * @see disable 关闭这个插件 - * @see enable 启用这个插件 + * @see PluginManager.enable 启用一个插件 + * @see PluginManager.disable 禁用一个插件 */ public val isEnabled: Boolean @@ -42,33 +48,6 @@ public interface Plugin : CommandOwner { public val loader: PluginLoader<*, *> } -/** - * 获取插件描述 - */ -public val Plugin.description: PluginDescription get() = safeLoader.getDescription(this) - -/** - * 禁用这个插件 - * - * @see PluginLoader.disable - */ -public fun Plugin.disable(): Unit = safeLoader.disable(this) - -/** - * 启用这个插件 - * - * @see PluginLoader.enable - */ -public fun Plugin.enable(): Unit = safeLoader.enable(this) - -/** - * 经过泛型类型转换的 [PluginLoader] - */ -@get:JvmSynthetic -@Suppress("UNCHECKED_CAST") -public inline val

P.safeLoader: PluginLoader - get() = this.loader as PluginLoader - /** * 支持文件系统存储的扩展. * 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 d4d0f60fe..05bd7cc8d 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 @@ -38,7 +38,7 @@ public interface PluginLoader

{ * * 在 console 启动时, [PluginManager] 会获取所有 [PluginDescription], 分析依赖关系, 确认插件加载顺序. * - * **实现细节:** 此函数只*应该*在 console 启动时被调用一次. 但取决于前端实现不同, 或可能由于被一些插件需要, 此函数也可能会被多次调用. + * **实现细节:** 此函数*只应该*在 console 启动时被调用一次. 但取决于前端实现不同, 或由于被一些插件需要, 此函数也可能会被多次调用. */ public fun listPlugins(): List @@ -52,6 +52,7 @@ public interface PluginLoader

{ * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等). * * @see PluginDescription 插件描述 + * @see getDescription 无 receiver, 接受参数的版本. */ @get:JvmName("getPluginDescription") @get:Throws(PluginLoadException::class) @@ -71,17 +72,53 @@ public interface PluginLoader

{ /** * 启用这个插件. * - * **实现约定**: 若插件已经启用, 抛出 + * **实现细节**: 此函数可抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误. + * 当异常发生时, 插件将会直接被放弃加载, 并影响依赖它的其他插件. + * + * @throws IllegalStateException 当插件已经启用时抛出 + * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等). */ + @Throws(IllegalStateException::class, PluginLoadException::class) public fun enable(plugin: P) + + /** + * 禁用这个插件. + * + * **实现细节**: 此函数可抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误. + * 当异常发生时, 插件将会直接被放弃加载, 并影响依赖它的其他插件. + * + * @throws IllegalStateException 当插件已经禁用时抛出 + * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如找不到主类等). + */ + @Throws(IllegalStateException::class, PluginLoadException::class) public fun disable(plugin: P) } +/** + * 获取此插件的描述. + * + * **实现细节**: 此函数只允许抛出 [PluginLoadException] 作为正常失败原因, 其他任意异常都属于意外错误. + * + * 若在 console 启动并加载所有插件的过程中, 本函数抛出异常, 则会放弃此插件的加载, 并影响依赖它的其他插件. + * + * @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等). + * + * @see PluginDescription 插件描述 + * @see PluginLoader.description + */ @Suppress("UNCHECKED_CAST") @JvmSynthetic public inline fun PluginLoader.getDescription(plugin: P): D = plugin.description +/** + * 在加载插件过程中遇到的意料之中的问题. + * + * @see PluginLoader.load + * @see PluginLoader.enable + * @see PluginLoader.disable + * @see PluginLoader.description + */ public open class PluginLoadException : RuntimeException { public constructor() : super() public constructor(message: String?) : super(message) 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 2921bf7a8..5f7796a18 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 @@ -89,11 +89,36 @@ public interface PluginManager { */ public val Plugin.description: PluginDescription + /** + * 禁用这个插件 + * + * @see PluginLoader.disable + */ + public fun Plugin.disable(): Unit = safeLoader.disable(this) + + /** + * 启用这个插件 + * + * @see PluginLoader.enable + */ + public fun Plugin.enable(): Unit = safeLoader.enable(this) + + /** + * 经过泛型类型转换的 [PluginLoader] + */ + @get:JvmSynthetic + @Suppress("UNCHECKED_CAST") + public val

P.safeLoader: PluginLoader + get() = this.loader as PluginLoader + public companion object INSTANCE : PluginManager by PluginManagerImpl { // due to Kotlin's bug public override val Plugin.description: PluginDescription get() = PluginManagerImpl.run { description } public override fun PluginLoader<*, *>.register(): Boolean = PluginManagerImpl.run { register() } public override fun PluginLoader<*, *>.unregister(): Boolean = PluginManagerImpl.run { unregister() } + public override fun Plugin.disable(): Unit = PluginManagerImpl.run { disable() } + public override fun Plugin.enable(): Unit = PluginManagerImpl.run { enable() } + public override val

P.safeLoader: PluginLoader get() = PluginManagerImpl.run { safeLoader } } }