From 5a5d45778a102be238d0f1f2fbd31cabf9d4127c Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 28 Aug 2020 11:31:07 +0800 Subject: [PATCH] Support loading PluginLoaders by ServiceLoader for each plugin; Rearrange implementations --- .../net/mamoe/mirai/console/MiraiConsole.kt | 2 +- .../MiraiConsoleImplementationBridge.kt | 2 +- .../internal/data/builtin/BotManagerImpl.kt | 46 ++++++++ .../internal/data/builtin/ConsoleDataScope.kt | 52 +++++++++ .../internal/plugin/JarPluginLoaderImpl.kt | 4 +- .../internal/plugin/PluginManagerImpl.kt | 40 ++++++- .../console/internal/plugin/PluginsLoader.kt | 2 +- .../console/internal/util/BotManagerImpl.kt | 107 ------------------ .../mirai/console/plugin/PluginLoader.kt | 12 +- .../mirai/console/plugin/PluginManager.kt | 6 +- .../mirai/console/plugin/jvm/KotlinPlugin.kt | 2 - .../mirai/console/util/CoroutineScopeUtils.kt | 37 ++++++ 12 files changed, 191 insertions(+), 121 deletions(-) create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/BotManagerImpl.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/ConsoleDataScope.kt delete mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt create mode 100644 backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/CoroutineScopeUtils.kt 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 644df4076..acfc72ad0 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 @@ -19,7 +19,7 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.console.MiraiConsole.INSTANCE import net.mamoe.mirai.console.MiraiConsoleImplementation.Companion.start import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge -import net.mamoe.mirai.console.internal.util.childScopeContext +import net.mamoe.mirai.console.internal.data.builtin.childScopeContext import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.center.PluginCenter diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt index 362304152..1e9f2c85d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/MiraiConsoleImplementationBridge.kt @@ -24,9 +24,9 @@ import net.mamoe.mirai.console.command.Command.Companion.primaryName import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.command.CommandManagerImpl +import net.mamoe.mirai.console.internal.data.builtin.ConsoleDataScope import net.mamoe.mirai.console.internal.plugin.CuiPluginCenter import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl -import net.mamoe.mirai.console.internal.util.ConsoleDataScope import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.center.PluginCenter diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/BotManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/BotManagerImpl.kt new file mode 100644 index 000000000..d25e27e1f --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/BotManagerImpl.kt @@ -0,0 +1,46 @@ +/* + * Copyright 2019-2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:Suppress("MemberVisibilityCanBePrivate") + +package net.mamoe.mirai.console.internal.data.builtin + +import net.mamoe.mirai.Bot +import net.mamoe.mirai.console.data.AutoSavePluginConfig +import net.mamoe.mirai.console.data.PluginDataExtensions.mapKeys +import net.mamoe.mirai.console.data.PluginDataExtensions.withEmptyDefault +import net.mamoe.mirai.console.data.getValue +import net.mamoe.mirai.console.data.value +import net.mamoe.mirai.console.util.BotManager +import net.mamoe.mirai.contact.User + +internal object BotManagerImpl : BotManager { + override val User.isManager: Boolean get() = this.id in ManagersConfig[this.bot] + + override fun Bot.removeManager(id: Long): Boolean { + return ManagersConfig[this].remove(id) + } + + override val Bot.managers: List + get() = ManagersConfig[this].toList() + + override fun Bot.addManager(id: Long): Boolean { + return ManagersConfig[this].add(id) + } +} + +internal object ManagersConfig : AutoSavePluginConfig() { + override val saveName: String + get() = "Managers" + + private val managers by value>>().withEmptyDefault() + .mapKeys(Bot::getInstance, Bot::id) + + internal operator fun get(bot: Bot): MutableSet = managers[bot]!! +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/ConsoleDataScope.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/ConsoleDataScope.kt new file mode 100644 index 000000000..ee6ea5af0 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtin/ConsoleDataScope.kt @@ -0,0 +1,52 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.console.internal.data.builtin + +import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.console.MiraiConsole +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.internal.MiraiConsoleImplementationBridge +import net.mamoe.mirai.utils.minutesToMillis + + +internal object ConsoleDataScope : CoroutineScope by MiraiConsole.childScope("ConsoleDataScope") { + private val data: Array = arrayOf() + private val configs: Array = arrayOf(ManagersConfig) + + fun reloadAll() { + data.forEach { dt -> + ConsoleBuiltInPluginDataStorage.load(ConsoleBuiltInPluginDataHolder, dt) + } + configs.forEach { config -> + ConsoleBuiltInPluginConfigStorage.load(ConsoleBuiltInPluginConfigHolder, config) + } + } +} + +internal object ConsoleBuiltInPluginDataHolder : AutoSavePluginDataHolder, + CoroutineScope by ConsoleDataScope.childScope("ConsoleBuiltInPluginDataHolder") { + override val autoSaveIntervalMillis: LongRange = 1.minutesToMillis..10.minutesToMillis + override val name: String get() = "ConsoleBuiltIns" +} + +internal object ConsoleBuiltInPluginConfigHolder : AutoSavePluginDataHolder, + CoroutineScope by ConsoleDataScope.childScope("ConsoleBuiltInPluginConfigHolder") { + override val autoSaveIntervalMillis: LongRange = 1.minutesToMillis..10.minutesToMillis + override val name: String get() = "ConsoleBuiltIns" +} + +internal object ConsoleBuiltInPluginDataStorage : + PluginDataStorage by MiraiConsoleImplementationBridge.dataStorageForBuiltIns + +internal object ConsoleBuiltInPluginConfigStorage : + PluginDataStorage by MiraiConsoleImplementationBridge.configStorageForBuiltIns \ No newline at end of file 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 d2f1ff495..022ec0dce 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 @@ -18,11 +18,11 @@ import net.mamoe.mirai.console.data.PluginDataStorage import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.data.createInstanceOrNull -import net.mamoe.mirai.console.internal.util.childScopeContext import net.mamoe.mirai.console.plugin.AbstractFilePluginLoader import net.mamoe.mirai.console.plugin.PluginLoadException import net.mamoe.mirai.console.plugin.jvm.* import net.mamoe.mirai.console.util.ConsoleExperimentalAPI +import net.mamoe.mirai.console.util.childScopeContext import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.yamlkt.Yaml import java.io.File @@ -48,7 +48,7 @@ internal object JarPluginLoaderImpl : logger.error("Unhandled Jar plugin exception: ${throwable.message}", throwable) }) - private val classLoader: PluginsLoader = PluginsLoader(this.javaClass.classLoader) + internal val classLoader: PluginsLoader = PluginsLoader(this.javaClass.classLoader) init { // delayed coroutineContext[Job]!!.invokeOnCompletion { 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 cd294f064..2702a3db9 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 @@ -15,18 +15,23 @@ import kotlinx.atomicfu.locks.withLock import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Job import net.mamoe.mirai.console.MiraiConsole +import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.data.cast import net.mamoe.mirai.console.internal.data.mkdir -import net.mamoe.mirai.console.internal.util.childScope import net.mamoe.mirai.console.plugin.* import net.mamoe.mirai.console.plugin.description.PluginDependency import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.description.PluginKind import net.mamoe.mirai.console.plugin.jvm.JvmPlugin +import net.mamoe.mirai.console.util.childScope +import net.mamoe.mirai.utils.error import net.mamoe.mirai.utils.info import java.io.File import java.nio.file.Path +import java.util.* import java.util.concurrent.locks.ReentrantLock +import kotlin.collections.ArrayList +import kotlin.streams.asSequence internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsole.childScope("PluginManager") { @@ -123,8 +128,37 @@ internal object PluginManagerImpl : PluginManager, CoroutineScope by MiraiConsol @Suppress("UNCHECKED_CAST") @Throws(PluginMissingDependencyException::class) internal fun loadEnablePlugins() { - (loadAndEnableLoaderProviders() + _pluginLoaders.listAllPlugins().flatMap { it.second }) - .sortByDependencies().loadAndEnableAllInOrder() + loadAndEnableLoaderProviders() + loadPluginLoaderProvidedByPlugins() + loadersLock.withLock { + _pluginLoaders.listAllPlugins().flatMap { it.second } + .sortByDependencies().loadAndEnableAllInOrder() + } + } + + private fun loadPluginLoaderProvidedByPlugins() { + loadersLock.withLock { + JarPluginLoaderImpl.classLoader.pluginLoaders.asSequence() + .flatMap { (name, pluginClassLoader) -> + ServiceLoader.load(PluginLoader::class.java, pluginClassLoader) + .stream().asSequence() + .associateBy { name } + .asSequence() + } + .forEach { (name, provider) -> + val pluginLoader = kotlin.runCatching { + provider.get() + }.getOrElse { + logger.error( + { "Could not load PluginLoader ${it::class.qualifiedNameOrTip} from plugin $name" }, + it + ) + return@forEach + } + _pluginLoaders.add(pluginLoader) + logger.info { "Successfully loaded PluginLoader ${pluginLoader::class.qualifiedNameOrTip} from plugin $name" } + } + } } private fun List.loadAndEnableAllInOrder() { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginsLoader.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginsLoader.kt index b34ede497..bbda38f37 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginsLoader.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/PluginsLoader.kt @@ -15,7 +15,7 @@ import java.net.URLClassLoader internal class PluginsLoader(private val parentClassLoader: ClassLoader) { private val loggerName = "PluginsLoader" - private val pluginLoaders = linkedMapOf() + internal val pluginLoaders = linkedMapOf() private val classesCache = mutableMapOf>() private val logger = MiraiConsole.newLogger(loggerName) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt deleted file mode 100644 index 1ad40eaba..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/util/BotManagerImpl.kt +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright 2019-2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AFFERO GENERAL PUBLIC LICENSE version 3 license that can be found via the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -@file:Suppress("MemberVisibilityCanBePrivate") - -package net.mamoe.mirai.console.internal.util - -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.Job -import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.MiraiConsole -import net.mamoe.mirai.console.data.* -import net.mamoe.mirai.console.data.PluginDataExtensions.mapKeys -import net.mamoe.mirai.console.data.PluginDataExtensions.withEmptyDefault -import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge -import net.mamoe.mirai.console.internal.plugin.NamedSupervisorJob -import net.mamoe.mirai.console.util.BotManager -import net.mamoe.mirai.contact.User -import net.mamoe.mirai.utils.minutesToMillis -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext - -internal object BotManagerImpl : BotManager { - /** - * 判断此用户是否为 console 管理员 - */ - override val User.isManager: Boolean get() = this.id in ManagersConfig[this.bot] - - override fun Bot.removeManager(id: Long): Boolean { - return ManagersConfig[this].remove(id) - } - - override val Bot.managers: List - get() = ManagersConfig[this].toList() - - override fun Bot.addManager(id: Long): Boolean { - return ManagersConfig[this].add(id) - } -} - -@ValueName("Managers") -internal object ManagersConfig : AutoSavePluginConfig() { - override val saveName: String - get() = "Managers" - private val managers by value>>().withEmptyDefault() - .mapKeys(Bot::getInstance, Bot::id) - - internal operator fun get(bot: Bot): MutableSet = managers[bot]!! -} - - -internal fun CoroutineContext.overrideWithSupervisorJob(name: String? = null): CoroutineContext = - this + NamedSupervisorJob(name ?: "", this[Job]) - -internal fun CoroutineScope.childScope( - name: String? = null, - context: CoroutineContext = EmptyCoroutineContext -): CoroutineScope = - CoroutineScope(this.childScopeContext(name, context)) - -internal fun CoroutineScope.childScopeContext( - name: String? = null, - context: CoroutineContext = EmptyCoroutineContext -): CoroutineContext = - this.coroutineContext.overrideWithSupervisorJob(name) + context.let { - if (name != null) it + CoroutineName(name) - else it - } - -internal object ConsoleDataScope : CoroutineScope by MiraiConsole.childScope("ConsoleDataScope") { - private val data: Array = arrayOf() - private val configs: Array = arrayOf(ManagersConfig) - - fun reloadAll() { - data.forEach { dt -> - ConsoleBuiltInPluginDataStorage.load(ConsoleBuiltInPluginDataHolder, dt) - } - configs.forEach { config -> - ConsoleBuiltInPluginConfigStorage.load(ConsoleBuiltInPluginConfigHolder, config) - } - } -} - -internal object ConsoleBuiltInPluginDataHolder : AutoSavePluginDataHolder, - CoroutineScope by ConsoleDataScope.childScope("ConsoleBuiltInPluginDataHolder") { - override val autoSaveIntervalMillis: LongRange = 1.minutesToMillis..10.minutesToMillis - override val name: String get() = "ConsoleBuiltIns" -} - -internal object ConsoleBuiltInPluginConfigHolder : AutoSavePluginDataHolder, - CoroutineScope by ConsoleDataScope.childScope("ConsoleBuiltInPluginConfigHolder") { - override val autoSaveIntervalMillis: LongRange = 1.minutesToMillis..10.minutesToMillis - override val name: String get() = "ConsoleBuiltIns" -} - -internal object ConsoleBuiltInPluginDataStorage : - PluginDataStorage by MiraiConsoleImplementationBridge.dataStorageForBuiltIns - -internal object ConsoleBuiltInPluginConfigStorage : - PluginDataStorage by MiraiConsoleImplementationBridge.configStorageForBuiltIns \ No newline at end of file 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 3b09bca81..5a383cb08 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 @@ -17,6 +17,7 @@ import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.register import net.mamoe.mirai.console.plugin.description.PluginDescription import net.mamoe.mirai.console.plugin.jvm.JarPluginLoader import java.io.File +import java.util.* /** * 插件加载器. @@ -25,11 +26,16 @@ import java.io.File * * 有关插件的依赖和已加载的插件列表由 [PluginManager] 维护. * - * ### 内建加载器 + * ## 内建加载器 * - [JarPluginLoader] Jar 插件加载器 * - * ### 扩展加载器 - * 插件被允许扩展一个加载器。 可通过 [PluginManager.register] + * ## 扩展加载器 + * 插件被允许扩展一个加载器. + * Console 使用 [ServiceLoader] 加载 [PluginLoader] 的实例. + * 插件也可通过 [PluginManager.register] 手动注册, 然而这是不推荐的. + * + * ### 实现扩展加载器 + * 直接实现接口 [PluginLoader] 或 [FilePluginLoader], 并添加 [ServiceLoader] 相关资源文件即可. * * @see JarPluginLoader Jar 插件加载器 * @see PluginManager.register 注册一个扩展的插件加载器 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 577497d9a..94ef436af 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 @@ -14,8 +14,10 @@ package net.mamoe.mirai.console.plugin import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl import net.mamoe.mirai.console.plugin.description.PluginDescription +import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import java.io.File import java.nio.file.Path +import java.util.* /** * 插件管理器. @@ -102,10 +104,11 @@ public interface PluginManager { public val pluginLoaders: List> /** - * 注册一个扩展的插件加载器 + * 手动注册一个扩展的插件加载器. 在启动时会通过 [ServiceLoader] 加载, 但也可以手动注册. * * @see PluginLoader 插件加载器 */ + @ConsoleExperimentalAPI public fun PluginLoader<*, *>.register(): Boolean /** @@ -113,6 +116,7 @@ public interface PluginManager { * * @see PluginLoader 插件加载器 */ + @ConsoleExperimentalAPI public fun PluginLoader<*, *>.unregister(): Boolean /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt index 9ce496c43..6b418b552 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/KotlinPlugin.kt @@ -11,7 +11,6 @@ package net.mamoe.mirai.console.plugin.jvm -import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext @@ -27,7 +26,6 @@ public abstract class KotlinPlugin @JvmOverloads constructor( /** * 在内存动态加载的插件. 此为预览版本 API. */ -@ConsoleExperimentalAPI public abstract class KotlinMemoryPlugin @JvmOverloads constructor( description: JvmPluginDescription, parentCoroutineContext: CoroutineContext = EmptyCoroutineContext diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/CoroutineScopeUtils.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/CoroutineScopeUtils.kt new file mode 100644 index 000000000..a5e6360b6 --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/util/CoroutineScopeUtils.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +@file:JvmName("CoroutineScopeUtils") + +package net.mamoe.mirai.console.util + +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job +import net.mamoe.mirai.console.internal.plugin.NamedSupervisorJob +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +internal fun CoroutineContext.overrideWithSupervisorJob(name: String? = null): CoroutineContext = + this + NamedSupervisorJob(name ?: "", this[Job]) + +internal fun CoroutineScope.childScope( + name: String? = null, + context: CoroutineContext = EmptyCoroutineContext +): CoroutineScope = + CoroutineScope(this.childScopeContext(name, context)) + +internal fun CoroutineScope.childScopeContext( + name: String? = null, + context: CoroutineContext = EmptyCoroutineContext +): CoroutineContext = + this.coroutineContext.overrideWithSupervisorJob(name) + context.let { + if (name != null) it + CoroutineName(name) + else it + }