From c3120cf1ac80b6a97a455aeba76296c2a040d983 Mon Sep 17 00:00:00 2001 From: Him188 Date: Sat, 23 May 2020 18:53:54 +0800 Subject: [PATCH] Misc --- backend/mirai-console/build.gradle.kts | 1 + .../net/mamoe/mirai/console/MiraiConsole.kt | 64 ++++++++------- .../net/mamoe/mirai/console/plugins/Plugin.kt | 81 ++----------------- .../mirai/console/plugins/PluginLoader.kt | 1 - .../mirai/console/plugins/PluginManager.kt | 68 ++++++++-------- .../console/plugins/builtin/JvmPlugin.kt | 12 ++- 6 files changed, 86 insertions(+), 141 deletions(-) diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index 4fc131443..b2e0e655f 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -61,6 +61,7 @@ dependencies { api("net.mamoe.yamlkt:yamlkt:0.3.1") api("org.jetbrains:annotations:19.0.0") + api(kotlinx("coroutines-jdk8", Versions.Kotlin.coroutines)) testApi("net.mamoe:mirai-core-qqandroid:${Versions.Mirai.core}") testApi(kotlin("stdlib-jdk8")) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 46cfcef00..82b299f82 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -13,8 +13,8 @@ import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import kotlinx.io.charsets.Charset import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.plugins.JarPluginLoader import net.mamoe.mirai.console.plugins.PluginLoader +import net.mamoe.mirai.console.plugins.builtin.JarPluginLoader import net.mamoe.mirai.utils.DefaultLogger import net.mamoe.mirai.utils.MiraiExperimentalAPI import net.mamoe.mirai.utils.MiraiLogger @@ -23,6 +23,38 @@ import java.io.File import java.io.PrintStream import kotlin.coroutines.CoroutineContext +/** + * mirai 控制台实例. + */ +object MiraiConsole : CoroutineScope, IMiraiConsole { + private lateinit var instance: IMiraiConsole + + /** 由前端调用 */ + internal fun init(instance: IMiraiConsole) { + this.instance = instance + } + + override val build: String get() = instance.build + override val version: String get() = instance.version + override val rootDir: File get() = instance.rootDir + override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd + override val mainLogger: MiraiLogger get() = instance.mainLogger + override val coroutineContext: CoroutineContext get() = instance.coroutineContext + + override val builtInPluginLoaders: List> = instance.builtInPluginLoaders + + init { + DefaultLogger = { identity -> this.newLogger(identity) } + this.coroutineContext[Job]!!.invokeOnCompletion { + Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) } + } + } + + @MiraiExperimentalAPI + fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) +} + + // 前端使用 internal interface IMiraiConsole : CoroutineScope { val build: String @@ -49,36 +81,6 @@ internal interface IMiraiConsole : CoroutineScope { val builtInPluginLoaders: List> } -object MiraiConsole : CoroutineScope, IMiraiConsole { - private lateinit var instance: IMiraiConsole - - /** 由前端调用 */ - internal fun init(instance: IMiraiConsole) { - this.instance = instance - } - - override val build: String get() = instance.build - override val version: String get() = instance.version - override val rootDir: File get() = instance.rootDir - override val frontEnd: MiraiConsoleFrontEnd get() = instance.frontEnd - override val mainLogger: MiraiLogger get() = instance.mainLogger - override val coroutineContext: CoroutineContext get() = instance.coroutineContext - - override val builtInPluginLoaders: List> = instance.builtInPluginLoaders - - init { - DefaultLogger = { identity -> - this.newLogger(identity) - } - this.coroutineContext[Job]!!.invokeOnCompletion { - Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) } - } - } - - @MiraiExperimentalAPI - fun newLogger(identity: String?): MiraiLogger = frontEnd.loggerFor(identity) -} - /** * Included in kotlin stdlib 1.4 */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt index f0df37871..d9ecf24e4 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/Plugin.kt @@ -9,82 +9,17 @@ package net.mamoe.mirai.console.plugins -import kotlinx.serialization.Serializable -import java.io.File - -/** 插件类型 */ -enum class PluginKind { - /** 表示此插件提供一个 [PluginLoader], 应在加载其他 [NORMAL] 类型插件前加载 */ - LOADER, - - /** 表示此插件为一个通常的插件, 按照正常的依赖关系加载. */ - NORMAL -} - -/** - * 插件描述 - */ -interface PluginDescription { - val kind: PluginKind - - val name: String - val author: String - val version: String - val info: String - - /** 指定此插件需要在这些插件之前加载 */ - val loadBefore: List - - /** 此插件依赖的其他插件, 将会在这些插件加载之后加载此插件 */ - val dependencies: List -} - -/** 插件的一个依赖的信息 */ -@Serializable -data class PluginDependency( - /** 依赖插件名 */ - val name: String, - /** - * 依赖版本号 - * @see versionKind 版本号类型 - */ - val version: String, - /** 版本号类型 */ - val versionKind: VersionKind -) { - enum class VersionKind { - /** 要求依赖精确的版本 */ - EXACT, - - /** 要求依赖最低版本 */ - AT_LEAST, - - /** 要求依赖最高版本 */ - AT_MOST - } - - override fun toString(): String { - return "$name ${versionKind.toEnglishString()}v$version" - } -} - - -internal fun PluginDependency.VersionKind.toEnglishString(): String = when (this) { - PluginDependency.VersionKind.EXACT -> "" - PluginDependency.VersionKind.AT_LEAST -> "at least " - PluginDependency.VersionKind.AT_MOST -> "at most " -} - -/** - * 基于文件的插件的描述 - */ -interface FilePluginDescription : PluginDescription { - val file: File -} +import net.mamoe.mirai.console.plugins.builtin.JvmPlugin /** * 表示一个 mirai-console 插件. * * @see JvmPlugin + * @see PluginDescription 插件描述 */ -interface Plugin \ No newline at end of file +interface Plugin { + /** + * 所属插件加载器实例 + */ + val loader: PluginLoader<*, *> +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt index acd31a025..1194b9f03 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginLoader.kt @@ -2,7 +2,6 @@ package net.mamoe.mirai.console.plugins -import net.mamoe.mirai.console.MiraiConsole import java.io.File /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt index d2386f4d8..e91396594 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/PluginManager.kt @@ -5,12 +5,10 @@ package net.mamoe.mirai.console.plugins import kotlinx.atomicfu.locks.withLock import net.mamoe.mirai.console.MiraiConsole import java.io.File -import java.util.* import java.util.concurrent.locks.ReentrantLock -import kotlin.collections.ArrayList -val Plugin.description: PluginDescription get() = TODO() -val

P.loader: PluginLoader get() = TODO() +val Plugin.description: PluginDescription + get() = PluginManager.resolvedPlugins.firstOrNull { it == this }?.description ?: error("Plugin is unloaded") inline fun PluginLoader<*, *>.register() = PluginManager.registerPluginLoader(this) inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoader(this) @@ -18,19 +16,18 @@ inline fun PluginLoader<*, *>.unregister() = PluginManager.unregisterPluginLoade object PluginManager { val pluginsDir = File(MiraiConsole.rootDir, "plugins").apply { mkdir() } - class LoaderNode

( - val loader: PluginLoader, - val loadedPlugins: MutableList

= mutableListOf() - ) - - private val _pluginLoaders: MutableSet> = mutableSetOf() + private val _pluginLoaders: MutableList> = mutableListOf() private val loadersLock: ReentrantLock = ReentrantLock() - private val resolvedPlugins: LinkedList = LinkedList() + @JvmField + internal val resolvedPlugins: MutableList = mutableListOf() + /** + * 已加载的插件列表 + */ @JvmStatic val plugins: List - get() = _pluginLoaders.flatMap { it.loadedPlugins } + get() = resolvedPlugins.toList() /** * 内建的插件加载器列表. 由 [MiraiConsole] 初始化 @@ -42,16 +39,21 @@ object PluginManager { /** * 由插件创建的 [PluginLoader] */ - val pluginLoaders: List> get() = _pluginLoaders.map { it.loader } + @JvmStatic + val pluginLoaders: List> + get() = _pluginLoaders.toList() @JvmStatic fun registerPluginLoader(loader: PluginLoader<*, *>): Boolean = loadersLock.withLock { - _pluginLoaders.add(LoaderNode(loader)) + if (_pluginLoaders.any { it::class == loader }) { + return false + } + _pluginLoaders.add(loader) } @JvmStatic fun unregisterPluginLoader(loader: PluginLoader<*, *>) = loadersLock.withLock { - _pluginLoaders.removeAll { it.loader == loader } + _pluginLoaders.remove(loader) } @@ -80,7 +82,7 @@ object PluginManager { @Suppress("UNCHECKED_CAST") @Throws(PluginMissingDependencyException::class) internal fun loadEnablePlugins() { - val all = loadAndEnableLoaderProviders() + pluginLoaders.listAllPlugins().flatMap { it.second } + val all = loadAndEnableLoaderProviders() + _pluginLoaders.listAllPlugins().flatMap { it.second } for ((loader, desc) in all.sortByDependencies()) { loader.loadPluginAndEnable(desc) @@ -116,7 +118,7 @@ object PluginManager { private fun List.sortByDependencies(): List { val resolved = ArrayList(this.size) - fun D.canBeLoad(): Boolean = this.dependencies.all { it in resolved } + fun D.canBeLoad(): Boolean = this.dependencies.all { it.isOptional || it in resolved } fun List.consumeLoadable(): List { val (canBeLoad, cannotBeLoad) = this.partition { it.canBeLoad() } @@ -124,7 +126,8 @@ object PluginManager { return cannotBeLoad } - fun List.filterIsMissing(): List = this.filterNot { it in resolved } + fun List.filterIsMissing(): List = + this.filterNot { it.isOptional || it in resolved } tailrec fun List.doSort() { if (this.isEmpty()) return @@ -147,6 +150,21 @@ 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) +} + +open class PluginResolutionException : Exception { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} + + internal data class PluginDescriptionWithLoader( @JvmField val loader: PluginLoader<*, PluginDescription>, // easier type @JvmField val delegate: PluginDescription @@ -164,17 +182,3 @@ internal fun PluginDescription.wrapWith(loader: PluginLoader<*, *>): PluginDescr internal operator fun List.contains(dependency: PluginDependency): Boolean = any { it.name == dependency.name } - -class PluginMissingDependencyException : Exception { - constructor() : super() - constructor(message: String?) : super(message) - constructor(message: String?, cause: Throwable?) : super(message, cause) - constructor(cause: Throwable?) : super(cause) -} - -open class PluginResolutionException : Exception { - constructor() : super() - constructor(message: String?) : super(message) - constructor(message: String?, cause: Throwable?) : super(message, cause) - constructor(cause: Throwable?) : super(cause) -} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt index 7adbd6940..9dda35f2b 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugins/builtin/JvmPlugin.kt @@ -17,6 +17,7 @@ import kotlinx.coroutines.Job import kotlinx.coroutines.SupervisorJob import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.plugins.Plugin +import net.mamoe.mirai.console.plugins.PluginLoader import net.mamoe.mirai.console.utils.JavaPluginScheduler import net.mamoe.mirai.utils.MiraiLogger import kotlin.coroutines.CoroutineContext @@ -36,6 +37,9 @@ interface JvmPlugin : Plugin, CoroutineScope { /** 插件描述 */ val description: JvmPluginDescription + /** 所属插件加载器实例 */ + override val loader: PluginLoader<*, *> get() = JarPluginLoader + @JvmDefault fun onLoad() { } @@ -53,8 +57,8 @@ interface JvmPlugin : Plugin, CoroutineScope { * Java 插件的父类 */ abstract class JavaPlugin @JvmOverloads constructor( - coroutineContext: CoroutineContext = EmptyCoroutineContext -) : JvmPlugin, JvmPluginImpl(coroutineContext) { + parentCoroutineContext: CoroutineContext = EmptyCoroutineContext +) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { /** * Java API Scheduler @@ -64,8 +68,8 @@ abstract class JavaPlugin @JvmOverloads constructor( } abstract class KotlinPlugin @JvmOverloads constructor( - coroutineContext: CoroutineContext = EmptyCoroutineContext -) : JvmPlugin, JvmPluginImpl(coroutineContext) { + parentCoroutineContext: CoroutineContext = EmptyCoroutineContext +) : JvmPlugin, JvmPluginImpl(parentCoroutineContext) { // that's it }