Move Plugin.enable and Plugin.disable into PluginManager for a better java API.

This commit is contained in:
Him188 2020-08-23 17:18:09 +08:00
parent c5389201e1
commit 7ecffb239d
6 changed files with 81 additions and 37 deletions

View File

@ -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<JvmPlugin, JvmPluginDescription>(".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()

View File

@ -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

View File

@ -61,7 +61,7 @@ internal object PluginManagerImpl : PluginManager {
init {
MiraiConsole.coroutineContext[Job]!!.invokeOnCompletion {
plugins.forEach(Plugin::disable)
plugins.forEach { it.disable() }
}
}

View File

@ -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 : Plugin> P.safeLoader: PluginLoader<P, PluginDescription>
get() = this.loader as PluginLoader<P, PluginDescription>
/**
* 支持文件系统存储的扩展.
*

View File

@ -38,7 +38,7 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
*
* console 启动时, [PluginManager] 会获取所有 [PluginDescription], 分析依赖关系, 确认插件加载顺序.
*
* **实现细节:** 此函数*应该* console 启动时被调用一次. 但取决于前端实现不同, 可能由于被一些插件需要, 此函数也可能会被多次调用.
* **实现细节:** 此函数*应该* console 启动时被调用一次. 但取决于前端实现不同, 由于被一些插件需要, 此函数也可能会被多次调用.
*/
public fun listPlugins(): List<D>
@ -52,6 +52,7 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
* @throws PluginLoadException 在加载插件遇到意料之中的错误时抛出 (如无法读取插件信息等).
*
* @see PluginDescription 插件描述
* @see getDescription receiver, 接受参数的版本.
*/
@get:JvmName("getPluginDescription")
@get:Throws(PluginLoadException::class)
@ -71,17 +72,53 @@ public interface PluginLoader<P : Plugin, D : PluginDescription> {
/**
* 启用这个插件.
*
* **实现约定**: 若插件已经启用, 抛出
* **实现细节**: 此函数可抛出 [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 <D : PluginDescription, P : Plugin> PluginLoader<in P, out D>.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)

View File

@ -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 : Plugin> P.safeLoader: PluginLoader<P, PluginDescription>
get() = this.loader as PluginLoader<P, PluginDescription>
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 : Plugin> P.safeLoader: PluginLoader<P, PluginDescription> get() = PluginManagerImpl.run { safeLoader }
}
}