(ABI change) Rewrite ComponentStorage: order extensions by property priority. Remove builtinImplementations and contribute them at the first initialization phase instead.

Close #1888, fix #1860.

Add `ComponentStorageInternal` for frontend to provide components.

Deprecate:
- SingletonExtension
- SingletonExtensionPoint
- AbstractSingletonExtensionPoint
- SingletonExtensionSelector
- CommandCallInterceptorProviderImpl
- CommandCallInterceptorProviderImplLazy
- CommandCallParserProviderImpl
- CommandCallParserProviderImplLazy
- CommandCallResolverProviderImpl
- CommandCallResolverProviderImplLazy

ABI breaking change:
- `PermissionServiceProvider`: supertype changed
- `CommandCallResolverProvider.ExtensionPoint`: supertype changed
- `PermissionServiceProvider.ExtensionPoint`: supertype changed
This commit is contained in:
Him188 2022-02-17 16:28:25 +00:00
parent 96e943c33f
commit 835059c44c
25 changed files with 554 additions and 312 deletions

View File

@ -162,7 +162,7 @@ public interface MiraiConsole : CoroutineScope {
* *
* 调用 [Bot.login] 可登录. * 调用 [Bot.login] 可登录.
* *
* @see Bot.botInstances 获取现有 [Bot] 实例列表 * @see Bot.instances 获取现有 [Bot] 实例列表
* @see BotConfigurationAlterer ExtensionPoint * @see BotConfigurationAlterer ExtensionPoint
*/ */
// don't static // don't static
@ -225,11 +225,8 @@ public interface MiraiConsole : CoroutineScope {
configuration() configuration()
} }
config = GlobalComponentStorage.run { config = GlobalComponentStorage.foldExtensions(BotConfigurationAlterer, config) { acc, extension ->
BotConfigurationAlterer.foldExtensions(config) { acc, extension -> extension.alterConfiguration(id, acc)
extension.alterConfiguration(id, acc)
}
} }
return when (password) { return when (password) {

View File

@ -25,7 +25,6 @@ import net.mamoe.mirai.console.extension.ComponentStorage
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.internal.command.CommandManagerImpl import net.mamoe.mirai.console.internal.command.CommandManagerImpl
import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScopeImpl 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.logging.LoggerControllerImpl
import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
import net.mamoe.mirai.console.internal.pluginManagerImpl import net.mamoe.mirai.console.internal.pluginManagerImpl
@ -317,6 +316,9 @@ public interface MiraiConsoleImplementation : CoroutineScope {
@ConsoleFrontEndImplementation @ConsoleFrontEndImplementation
public interface BackendAccess { public interface BackendAccess {
// GlobalComponentStorage // GlobalComponentStorage
/**
* Mirai Console 第一个 phase 之后会包含内建 storages.
*/
public val globalComponentStorage: ComponentStorage public val globalComponentStorage: ComponentStorage
// PluginManagerImpl.resolvedPlugins // PluginManagerImpl.resolvedPlugins
@ -365,7 +367,7 @@ public interface MiraiConsoleImplementation : CoroutineScope {
@ConsoleFrontEndImplementation @ConsoleFrontEndImplementation
public companion object { public companion object {
private val backendAccessInstance = object : BackendAccess { private val backendAccessInstance = object : BackendAccess {
override val globalComponentStorage: ComponentStorage get() = GlobalComponentStorage override val globalComponentStorage: ComponentStorage get() = getBridge().globalComponentStorage
override val resolvedPlugins: MutableList<Plugin> get() = MiraiConsole.pluginManagerImpl.resolvedPlugins override val resolvedPlugins: MutableList<Plugin> get() = MiraiConsole.pluginManagerImpl.resolvedPlugins
} }

View File

@ -28,6 +28,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.* import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.*
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.MD5 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.AutoLoginConfig.Account.PasswordKind.PLAIN
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
import net.mamoe.mirai.console.internal.pluginManagerImpl import net.mamoe.mirai.console.internal.pluginManagerImpl
import net.mamoe.mirai.console.internal.util.autoHexToBytes import net.mamoe.mirai.console.internal.util.autoHexToBytes
@ -484,7 +485,7 @@ public object BuiltInCommands {
lightYellow() lightYellow()
"Built In Permission Service" "Built In Permission Service"
} else { } else {
val plugin = PermissionServiceProvider.providerPlugin val plugin = GlobalComponentStorage.getPreferredExtension(PermissionServiceProvider).plugin
if (plugin == null) { if (plugin == null) {
PermissionService.INSTANCE.toString() PermissionService.INSTANCE.toString()
} else { } else {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -44,10 +44,8 @@ public interface CommandCallParser {
*/ */
@JvmStatic @JvmStatic
public fun MessageChain.parseCommandCall(sender: CommandSender): CommandCall? { public fun MessageChain.parseCommandCall(sender: CommandSender): CommandCall? {
GlobalComponentStorage.run { GlobalComponentStorage.useEachExtensions(CommandCallParserProvider) { provider ->
CommandCallParserProvider.useExtensions { provider -> provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
}
} }
return null return null
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -12,7 +12,6 @@ package net.mamoe.mirai.console.command.parse
import net.mamoe.mirai.console.command.CommandSender import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.extensions.CommandCallParserProvider import net.mamoe.mirai.console.extensions.CommandCallParserProvider
import net.mamoe.mirai.console.extensions.CommandCallParserProviderImpl
import net.mamoe.mirai.console.internal.command.flattenCommandComponents import net.mamoe.mirai.console.internal.command.flattenCommandComponents
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.MessageChain
@ -22,6 +21,13 @@ import net.mamoe.mirai.message.data.content
@ConsoleExperimentalApi @ConsoleExperimentalApi
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public object SpaceSeparatedCommandCallParser : CommandCallParser { public object SpaceSeparatedCommandCallParser : CommandCallParser {
@ConsoleExperimentalApi
@ExperimentalCommandDescriptors
public object Provider : CommandCallParserProvider {
override val instance: CommandCallParser get() = SpaceSeparatedCommandCallParser
}
override fun parse(caller: CommandSender, message: MessageChain): CommandCall? { override fun parse(caller: CommandSender, message: MessageChain): CommandCall? {
val flatten = message.flattenCommandComponents().filterIsInstance<MessageContent>() val flatten = message.flattenCommandComponents().filterIsInstance<MessageContent>()
if (flatten.isEmpty()) return null if (flatten.isEmpty()) return null
@ -31,6 +37,4 @@ public object SpaceSeparatedCommandCallParser : CommandCallParser {
valueArguments = flatten.drop(1).map(::DefaultCommandValueArgument) valueArguments = flatten.drop(1).map(::DefaultCommandValueArgument)
) )
} }
public object Provider : CommandCallParserProvider by CommandCallParserProviderImpl(SpaceSeparatedCommandCallParser)
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -15,6 +15,7 @@ import net.mamoe.mirai.console.command.descriptor.ArgumentAcceptance.Companion.i
import net.mamoe.mirai.console.command.parse.CommandCall import net.mamoe.mirai.console.command.parse.CommandCall
import net.mamoe.mirai.console.command.parse.CommandValueArgument import net.mamoe.mirai.console.command.parse.CommandValueArgument
import net.mamoe.mirai.console.command.parse.DefaultCommandValueArgument import net.mamoe.mirai.console.command.parse.DefaultCommandValueArgument
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
import net.mamoe.mirai.console.internal.data.classifierAsKClass import net.mamoe.mirai.console.internal.data.classifierAsKClass
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.safeCast import net.mamoe.mirai.console.util.safeCast
@ -27,6 +28,11 @@ import net.mamoe.mirai.message.data.toMessageChain
@ConsoleExperimentalApi @ConsoleExperimentalApi
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public object BuiltInCommandCallResolver : CommandCallResolver { public object BuiltInCommandCallResolver : CommandCallResolver {
internal object Provider : CommandCallResolverProvider {
override val instance: CommandCallResolver = BuiltInCommandCallResolver
}
override fun resolve(call: CommandCall): CommandResolveResult { override fun resolve(call: CommandCall): CommandResolveResult {
val callee = CommandManager.matchCommand(call.calleeName) val callee = CommandManager.matchCommand(call.calleeName)
?: return CommandResolveResult(CommandExecuteResult.UnresolvedCommand(call)) ?: return CommandResolveResult(CommandExecuteResult.UnresolvedCommand(call))

View File

@ -66,15 +66,13 @@ public interface CommandCallInterceptor {
*/ */
@JvmStatic @JvmStatic
public fun Message.intercepted(caller: CommandSender): InterceptResult<Message> { public fun Message.intercepted(caller: CommandSender): InterceptResult<Message> {
GlobalComponentStorage.run { return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext -> val intercepted = ext.instance.interceptBeforeCall(acc, caller)
val intercepted = ext.instance.interceptBeforeCall(acc, caller) intercepted?.fold(
intercepted?.fold( onIntercepted = { return intercepted },
onIntercepted = { return intercepted }, otherwise = { it }
otherwise = { it } ) ?: acc
) ?: acc }.let { InterceptResult(it) }
}.let { InterceptResult(it) }
}
} }
/** /**
@ -83,15 +81,13 @@ public interface CommandCallInterceptor {
*/ */
@JvmStatic @JvmStatic
public fun CommandCall.intercepted(): InterceptResult<CommandCall> { public fun CommandCall.intercepted(): InterceptResult<CommandCall> {
GlobalComponentStorage.run { return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext -> val intercepted = ext.instance.interceptCall(acc)
val intercepted = ext.instance.interceptCall(acc) intercepted?.fold(
intercepted?.fold( onIntercepted = { return intercepted },
onIntercepted = { return intercepted }, otherwise = { it }
otherwise = { it } ) ?: acc
) ?: acc }.let { InterceptResult(it) }
}.let { InterceptResult(it) }
}
} }
/** /**
@ -100,15 +96,13 @@ public interface CommandCallInterceptor {
*/ */
@JvmStatic @JvmStatic
public fun ResolvedCommandCall.intercepted(): InterceptResult<ResolvedCommandCall> { public fun ResolvedCommandCall.intercepted(): InterceptResult<ResolvedCommandCall> {
GlobalComponentStorage.run { return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext -> val intercepted = ext.instance.interceptResolvedCall(acc)
val intercepted = ext.instance.interceptResolvedCall(acc) intercepted?.fold(
intercepted?.fold( onIntercepted = { return intercepted },
onIntercepted = { return intercepted }, otherwise = { it }
otherwise = { it } ) ?: acc
) ?: acc }.let { InterceptResult(it) }
}.let { InterceptResult(it) }
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -76,11 +76,9 @@ public interface CommandCallResolver {
@ConsoleExperimentalApi @ConsoleExperimentalApi
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public fun CommandCall.resolve(): CommandResolveResult { public fun CommandCall.resolve(): CommandResolveResult {
GlobalComponentStorage.run { return GlobalComponentStorage.getExtensions(CommandCallResolverProvider).first()
val instance = .extension.instance
CommandCallResolverProvider.findSingletonInstance(CommandCallResolverProvider.builtinImplementation) .resolve(this@resolve)
return instance.resolve(this@resolve)
}
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -9,27 +9,99 @@
package net.mamoe.mirai.console.extension package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
import net.mamoe.mirai.console.MiraiConsoleImplementation
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
import net.mamoe.mirai.utils.MiraiExperimentalApi
import java.util.stream.Stream
/** /**
* 组件容器, 容纳 [Plugin] 注册的 [Extension]. * 组件容器, 容纳 [Plugin] 注册的 [Extension].
* *
* 插件可在 [JvmPlugin.onLoad] 时提供扩展. 前端可在 [MiraiConsoleImplementation.BackendAccess.globalComponentStorage] 获取全局组件容器.
* 目前未允许获取全局组件容器. 如有需求请 [提交 issues](https://github.com/mamoe/mirai/issues/new/choose).
*
* 实现细节: 线程安全.
*
* @see Extension * @see Extension
* @see JvmPlugin.onLoad * @see JvmPlugin.onLoad
*/ */
public interface ComponentStorage { public interface ComponentStorage {
public fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin,
extensionInstance: T,
)
public fun <T : Extension> contribute( /**
extensionPoint: ExtensionPoint<T>, * 注册一个扩展
*/
public fun <E : Extension> contribute(
extensionPoint: ExtensionPoint<E>,
plugin: Plugin, plugin: Plugin,
lazyInstance: () -> T, extensionInstance: E,
) ) // 2.11: E changed to T (only naming)
/**
* 注册一个扩展. [lazyInstance] 将会在 [getExtensions] 时才会计算.
*/
public fun <E : Extension> contribute(
extensionPoint: ExtensionPoint<E>,
plugin: Plugin,
lazyInstance: () -> E,
) // 2.11: E changed to T (only naming)
/**
* 获取优先级最高的 [ExtensionPoint] 扩展实例. 在未找到任何注册的实例时抛出 [NoSuchElementException].
*
* @since 2.11
*/
@MiraiExperimentalApi
public fun <E : Extension> getPreferredExtension(
extensionPoint: ExtensionPoint<E>,
): ExtensionRegistry<E> {
return getExtensions(extensionPoint).firstOrNull()
?: throw NoSuchElementException("No extension registered for $extensionPoint")
}
/**
* 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Sequence] [Extension.priority] 倒序排序.
*
* @since 2.11
*/
public fun <E : Extension> getExtensions(
extensionPoint: ExtensionPoint<E>,
): Sequence<ExtensionRegistry<E>>
/**
* 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Stream] [Extension.priority] 倒序排序.
*
* @since 2.11
*/
public fun <E : Extension> getExtensionsStream(
extensionPoint: ExtensionPoint<E>,
): Stream<ExtensionRegistry<E>>
} }
/**
* 仅前端实现可用
*/
@ConsoleFrontEndImplementation
public interface ComponentStorageInternal : ComponentStorage {
/**
* 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]). [lazyInstance] 将会在 [getExtensions] 时才会计算.
*/
public fun <E : Extension> contributeConsole(
extensionPoint: ExtensionPoint<E>,
lazyInstance: () -> E,
)
/**
* 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]).
*/
public fun <E : Extension> contributeConsole(
extensionPoint: ExtensionPoint<E>,
instance: E,
) {
@Suppress("USELESS_CAST") // bug
contributeConsole(extensionPoint, { instance } as () -> E)
}
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -9,12 +9,15 @@
package net.mamoe.mirai.console.extension package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
import net.mamoe.mirai.console.extensions.PermissionServiceProvider import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.extensions.PluginLoaderProvider import net.mamoe.mirai.console.extensions.PluginLoaderProvider
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.utils.DeprecatedSinceMirai
/** /**
* 表示一个扩展. * 表示一个扩展.
@ -37,7 +40,18 @@ import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
* *
* @see ComponentStorage * @see ComponentStorage
*/ */
public interface Extension public interface Extension {
/**
* 优先级. 越高越先使用. 内嵌的 [SpaceSeparatedCommandCallParser] 拥有优先级 0.
*
* 若两个 [InstanceExtension] 有相同的优先级, 将会优先使用内嵌的实现, 再按 [ComponentStorage.contribute] 顺序依次使用.
*
* @since 2.11
*/ // https://github.com/mamoe/mirai/issues/1860
@ConsoleExperimentalApi
public val priority: Int
get() = 0
}
/** /**
* 增加一些函数 (方法)的扩展 * 增加一些函数 (方法)的扩展
@ -51,6 +65,8 @@ public interface FunctionExtension : Extension
* *
* @see PermissionServiceProvider * @see PermissionServiceProvider
*/ */
@Deprecated("Please use InstanceExtension instead.", replaceWith = ReplaceWith("InstanceExtension"))
@DeprecatedSinceMirai(warningSince = "2.11")
public interface SingletonExtension<T> : Extension { public interface SingletonExtension<T> : Extension {
public val instance: T public val instance: T
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -12,13 +12,15 @@
package net.mamoe.mirai.console.extension package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.util.ConsoleExperimentalApi import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.utils.DeprecatedSinceMirai
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
* [Extension] 的伴生对象实现. * 表示一个扩展接入点(扩展类型). Kotlin [Extension] 的伴生对象实现, Java 可通过静态字段提供.
*
* [注册扩展][ComponentStorage.contribute]时需要提供其 [ExtensionPoint], [ExtensionPoint] 也可以用于获取所有注册的扩展 ([ComponentStorage.getExtensions]).
* *
* @see AbstractExtensionPoint * @see AbstractExtensionPoint
*/ */
@ -37,6 +39,8 @@ public abstract class AbstractExtensionPoint<T : Extension>(
/** /**
* 表示一个 [SingletonExtension] [ExtensionPoint] * 表示一个 [SingletonExtension] [ExtensionPoint]
*/ */
@Deprecated("Please use InstanceExtensionPoint instead.", replaceWith = ReplaceWith("InstanceExtensionPoint"))
@DeprecatedSinceMirai(warningSince = "2.11")
public interface SingletonExtensionPoint<T : SingletonExtension<*>> : ExtensionPoint<T> public interface SingletonExtensionPoint<T : SingletonExtension<*>> : ExtensionPoint<T>
/** /**
@ -55,34 +59,56 @@ public abstract class AbstractInstanceExtensionPoint<E : InstanceExtension<T>, T
* @since 2.10 * @since 2.10
*/ */
@ConsoleExperimentalApi @ConsoleExperimentalApi
constructor( public constructor(
extensionType: KClass<E>, extensionType: KClass<E>
/**
* 内建的实现列表.
*/
@ConsoleExperimentalApi
public vararg val builtinImplementations: () -> E,
) : AbstractExtensionPoint<E>(extensionType) { ) : AbstractExtensionPoint<E>(extensionType) {
/** /**
* @since 2.10 * @since 2.10
*/ */
@Deprecated(
"Default(builtin) implementations are not allowed any more. " +
"For plugin authors, provide them with lower priority when plugin being loaded(through the ComponentScope). " +
"For frontend implementers, provide them by `BackendAccess.globalComponentScope.contribute`. ",
replaceWith = ReplaceWith("AbstractInstanceExtensionPoint(extensionType)"),
level = DeprecationLevel.ERROR,
)
@DeprecatedSinceMirai(errorSince = "2.11") // for removal
@ConsoleExperimentalApi @ConsoleExperimentalApi
public constructor(extensionType: KClass<E>) : this( public constructor(
extensionType, extensionType: KClass<E>,
builtinImplementations = arrayOf<() -> E>() as Array<out () -> E> /**
) // to avoid resolution ambiguity * 内建的实现列表.
*/
builtinImplementations: () -> E,
) : this(extensionType)
/** /**
* @since 2.0 * @since 2.0
*/ */
@ConsoleExperimentalApi @Deprecated(
"Default(builtin) implementations are not allowed any more. " +
"For plugin authors, provide them with lower priority when plugin being loaded(through the ComponentScope). " +
"For frontend implementers, provide them by `BackendAccess.globalComponentScope.contribute`. ",
replaceWith = ReplaceWith("AbstractInstanceExtensionPoint(extensionType)"),
level = DeprecationLevel.ERROR
)
@DeprecatedSinceMirai(errorSince = "2.11") // for removal
@ConsoleExperimentalApi // was experimental since 2.0
public constructor(extensionType: KClass<E>, vararg builtinImplementations: E) : this( public constructor(extensionType: KClass<E>, vararg builtinImplementations: E) : this(
extensionType, extensionType,
builtinImplementations = builtinImplementations.map { { it } }.toTypedArray()
) )
} }
@Deprecated(
"Please use AbstractInstanceExtensionPoint instead.",
replaceWith = ReplaceWith(
"AbstractInstanceExtension",
"net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint"
)
)
@DeprecatedSinceMirai(warningSince = "2.11")
@Suppress("DEPRECATION")
public abstract class AbstractSingletonExtensionPoint<E : SingletonExtension<T>, T> public abstract class AbstractSingletonExtensionPoint<E : SingletonExtension<T>, T>
/** /**
* @since 2.10 * @since 2.10
@ -111,12 +137,6 @@ constructor(
* [SingletonExtensionSelector] 选择后的实例. * [SingletonExtensionSelector] 选择后的实例.
*/ */
@ConsoleExperimentalApi @ConsoleExperimentalApi
public open val selectedInstance: T by lazy { public open val selectedInstance: T
GlobalComponentStorage.run { get() = throw UnsupportedOperationException("SingletonExtension has been deprecated.")
this@AbstractSingletonExtensionPoint.findSingletonInstance(
extensionType,
builtinImplementation
)
}
}
} }

View File

@ -0,0 +1,46 @@
/*
* Copyright 2019-2022 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/dev/LICENSE
*/
package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.utils.NotStableForInheritance
/**
* 一个已经注册的 [Extension]. 可通过 [ComponentStorage.getExtensions] 获得.
*
* @since 2.11
*/
@NotStableForInheritance
public interface ExtensionRegistry<E : Extension> {
/**
* 提供该 [ExtensionRegistry] 的插件. 若为 `null` 则表示由 Mirai Console 内置或者由前端实现.
*/
public val plugin: Plugin?
/**
* [Extension] 实例.
*/
public val extension: E
}
internal inline val <T> ExtensionRegistry<out InstanceExtension<T>>.instance get() = extension.instance
internal class ExtensionRegistryImpl<E : Extension> internal constructor(
/**
* 提供该 [ExtensionRegistry] 的插件. 若为 `null` 则表示由 Mirai Console 内置或者由前端实现.
*/
override val plugin: Plugin?,
/**
* [Extension] 实例.
*/
extensionInitializer: () -> E,
) : ExtensionRegistry<E> {
override val extension: E by lazy(extensionInitializer)
}

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -13,19 +13,25 @@ import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.resolve.CommandCallInterceptor import net.mamoe.mirai.console.command.resolve.CommandCallInterceptor
import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
import net.mamoe.mirai.console.extension.InstanceExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.utils.DeprecatedSinceMirai
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandCallInterceptorProvider : InstanceExtension<CommandCallInterceptor> { public interface CommandCallInterceptorProvider : InstanceExtension<CommandCallInterceptor> {
@ExperimentalCommandDescriptors
public companion object ExtensionPoint : public companion object ExtensionPoint :
AbstractInstanceExtensionPoint<CommandCallInterceptorProvider, CommandCallInterceptor>( AbstractInstanceExtensionPoint<CommandCallInterceptorProvider, CommandCallInterceptor>(
CommandCallInterceptorProvider::class CommandCallInterceptorProvider::class
) )
} }
@Deprecated("Deprecated for removal. Please implement your own CommandCallInterceptorProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallInterceptorProviderImpl(override val instance: CommandCallInterceptor) : public class CommandCallInterceptorProviderImpl(override val instance: CommandCallInterceptor) :
CommandCallInterceptorProvider CommandCallInterceptorProvider
@Deprecated("Deprecated for removal. Please implement your own CommandCallInterceptorProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallInterceptorProviderImplLazy(initializer: () -> CommandCallInterceptor) : public class CommandCallInterceptorProviderImplLazy(initializer: () -> CommandCallInterceptor) :
CommandCallInterceptorProvider { CommandCallInterceptorProvider {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -11,26 +11,27 @@ package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.CommandCallParser import net.mamoe.mirai.console.command.parse.CommandCallParser
import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
import net.mamoe.mirai.console.extension.InstanceExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.utils.DeprecatedSinceMirai
/** /**
* The provider of [CommandCallParser] * The provider of [CommandCallParser]
*/ */
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandCallParserProvider : InstanceExtension<CommandCallParser> { public interface CommandCallParserProvider : InstanceExtension<CommandCallParser> {
@ExperimentalCommandDescriptors
public companion object ExtensionPoint : public companion object ExtensionPoint :
AbstractInstanceExtensionPoint<CommandCallParserProvider, CommandCallParser>( AbstractInstanceExtensionPoint<CommandCallParserProvider, CommandCallParser>(CommandCallParserProvider::class)
CommandCallParserProvider::class,
SpaceSeparatedCommandCallParser.Provider
)
} }
@Deprecated("Deprecated for removal. Please implement your own CommandCallParserProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallParserProviderImpl(override val instance: CommandCallParser) : CommandCallParserProvider public class CommandCallParserProviderImpl(override val instance: CommandCallParser) : CommandCallParserProvider
@Deprecated("Deprecated for removal. Please implement your own CommandCallParserProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallParserProviderImplLazy(initializer: () -> CommandCallParser) : CommandCallParserProvider { public class CommandCallParserProviderImplLazy(initializer: () -> CommandCallParser) : CommandCallParserProvider {
override val instance: CommandCallParser by lazy(initializer) override val instance: CommandCallParser by lazy(initializer)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -10,23 +10,26 @@
package net.mamoe.mirai.console.extensions package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.resolve.BuiltInCommandCallResolver
import net.mamoe.mirai.console.command.resolve.CommandCallResolver import net.mamoe.mirai.console.command.resolve.CommandCallResolver
import net.mamoe.mirai.console.extension.AbstractSingletonExtensionPoint import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
import net.mamoe.mirai.console.extension.SingletonExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.utils.DeprecatedSinceMirai
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public interface CommandCallResolverProvider : SingletonExtension<CommandCallResolver> { public interface CommandCallResolverProvider : InstanceExtension<CommandCallResolver> {
@ExperimentalCommandDescriptors
public companion object ExtensionPoint : public companion object ExtensionPoint :
AbstractSingletonExtensionPoint<CommandCallResolverProvider, CommandCallResolver>( AbstractInstanceExtensionPoint<CommandCallResolverProvider, CommandCallResolver>(CommandCallResolverProvider::class)
CommandCallResolverProvider::class,
{ BuiltInCommandCallResolver }
)
} }
@Deprecated("Deprecated for removal. Please implement your own CommandCallResolverProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallResolverProviderImpl(override val instance: CommandCallResolver) : CommandCallResolverProvider public class CommandCallResolverProviderImpl(override val instance: CommandCallResolver) : CommandCallResolverProvider
@Deprecated("Deprecated for removal. Please implement your own CommandCallResolverProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for removal.
@ExperimentalCommandDescriptors @ExperimentalCommandDescriptors
public class CommandCallResolverProviderImplLazy(initializer: () -> CommandCallResolver) : CommandCallResolverProvider { public class CommandCallResolverProviderImplLazy(initializer: () -> CommandCallResolver) : CommandCallResolverProvider {
override val instance: CommandCallResolver by lazy(initializer) override val instance: CommandCallResolver by lazy(initializer)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -9,55 +9,35 @@
package net.mamoe.mirai.console.extensions package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.extension.AbstractSingletonExtensionPoint import net.mamoe.mirai.console.extension.AbstractInstanceExtensionPoint
import net.mamoe.mirai.console.extension.SingletonExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
import net.mamoe.mirai.console.permission.PermissionService import net.mamoe.mirai.console.permission.PermissionService
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.utils.DeprecatedSinceMirai
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
/** /**
* [权限服务][PermissionService] 提供器. * [权限服务][PermissionService] 提供器.
* *
* 当插件注册 [PermissionService] , 默认会使用插件的 [PermissionService]. * 当插件注册 [PermissionService] , 默认会使用插件的 [PermissionService].
*/ */
public interface PermissionServiceProvider : SingletonExtension<PermissionService<*>> { public interface PermissionServiceProvider : InstanceExtension<PermissionService<*>> {
public companion object ExtensionPoint : public companion object ExtensionPoint :
AbstractSingletonExtensionPoint<PermissionServiceProvider, PermissionService<*>>( AbstractInstanceExtensionPoint<PermissionServiceProvider, PermissionService<*>>(PermissionServiceProvider::class)
PermissionServiceProvider::class, // ! BREAKING CHANGE MADE IN 2.11: supertype changed from AbstractSingletonExtensionPoint to AbstractInstanceExtensionPoint
{ BuiltInPermissionService() }
) {
internal var permissionServiceOk = false
@ConsoleExperimentalApi
public val providerPlugin: Plugin? by lazy {
GlobalComponentStorage.run {
val instance = PermissionService.INSTANCE
if (instance is BuiltInPermissionService) return@lazy null
PermissionServiceProvider.getExtensions().find { it.extension.instance === instance }?.plugin
}
}
@ConsoleExperimentalApi
override val selectedInstance: PermissionService<*>
get() {
if (!permissionServiceOk) {
error("PermissionService not yet loaded")
}
return super.selectedInstance
}
}
} }
/** /**
* @see PermissionServiceProvider * @see PermissionServiceProvider
*/ */
@Deprecated("Please implement your own PermissionServiceProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
public class PermissionServiceProviderImpl(override val instance: PermissionService<*>) : PermissionServiceProvider public class PermissionServiceProviderImpl(override val instance: PermissionService<*>) : PermissionServiceProvider
/** /**
* @see PermissionServiceProvider * @see PermissionServiceProvider
*/ */
@Deprecated("Please implement your own PermissionServiceProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
public class PermissionServiceProviderImplLazy(initializer: () -> PermissionService<*>) : PermissionServiceProvider { public class PermissionServiceProviderImplLazy(initializer: () -> PermissionService<*>) : PermissionServiceProvider {
override val instance: PermissionService<*> by lazy(initializer) override val instance: PermissionService<*> by lazy(initializer)
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -14,6 +14,7 @@ import net.mamoe.mirai.console.extension.Extension
import net.mamoe.mirai.console.extension.InstanceExtension import net.mamoe.mirai.console.extension.InstanceExtension
import net.mamoe.mirai.console.extension.PluginComponentStorage import net.mamoe.mirai.console.extension.PluginComponentStorage
import net.mamoe.mirai.console.plugin.loader.PluginLoader import net.mamoe.mirai.console.plugin.loader.PluginLoader
import net.mamoe.mirai.utils.DeprecatedSinceMirai
/** /**
* 提供扩展 [PluginLoader] * 提供扩展 [PluginLoader]
@ -30,8 +31,12 @@ public interface PluginLoaderProvider : InstanceExtension<PluginLoader<*, *>> {
public companion object ExtensionPoint : AbstractExtensionPoint<PluginLoaderProvider>(PluginLoaderProvider::class) public companion object ExtensionPoint : AbstractExtensionPoint<PluginLoaderProvider>(PluginLoaderProvider::class)
} }
@Deprecated("Please implement your own PluginLoaderProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
public class PluginLoaderProviderImpl(override val instance: PluginLoader<*, *>) : PluginLoaderProvider public class PluginLoaderProviderImpl(override val instance: PluginLoader<*, *>) : PluginLoaderProvider
@Deprecated("Please implement your own PluginLoaderProvider.")
@DeprecatedSinceMirai(warningSince = "2.11") // for hidden.
public class PluginLoaderProviderImplLazy(initializer: () -> PluginLoader<*, *>) : PluginLoaderProvider { public class PluginLoaderProviderImplLazy(initializer: () -> PluginLoader<*, *>) : PluginLoaderProvider {
override val instance: PluginLoader<*, *> by lazy(initializer) override val instance: PluginLoader<*, *> by lazy(initializer)
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -7,18 +7,17 @@
* https://github.com/mamoe/mirai/blob/dev/LICENSE * https://github.com/mamoe/mirai/blob/dev/LICENSE
*/ */
@file:Suppress("DEPRECATION")
package net.mamoe.mirai.console.extensions package net.mamoe.mirai.console.extensions
import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.MiraiConsole
import net.mamoe.mirai.console.extension.AbstractExtensionPoint import net.mamoe.mirai.console.extension.*
import net.mamoe.mirai.console.extension.Extension
import net.mamoe.mirai.console.extension.FunctionExtension
import net.mamoe.mirai.console.extension.SingletonExtension
import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl
import net.mamoe.mirai.console.internal.extension.ExtensionRegistry
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.name import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.utils.DeprecatedSinceMirai
import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.info
import kotlin.reflect.KClass import kotlin.reflect.KClass
@ -27,10 +26,20 @@ import kotlin.reflect.KClass
* *
* 如有多个 [SingletonExtensionSelector] 注册, 将会停止服务器. * 如有多个 [SingletonExtensionSelector] 注册, 将会停止服务器.
*/ */
@Deprecated(
"Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
level = DeprecationLevel.WARNING
)
@DeprecatedSinceMirai(warningSince = "2.11")
public interface SingletonExtensionSelector : FunctionExtension { public interface SingletonExtensionSelector : FunctionExtension {
/** /**
* 表示一个插件注册的 [Extension] * 表示一个插件注册的 [Extension]
*/ */
@Deprecated(
"Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
level = DeprecationLevel.WARNING
)
@DeprecatedSinceMirai(warningSince = "2.11")
public data class Registry<T : Extension>( public data class Registry<T : Extension>(
val plugin: Plugin?, val plugin: Plugin?,
val extension: T, val extension: T,
@ -44,6 +53,11 @@ public interface SingletonExtensionSelector : FunctionExtension {
candidates: Collection<Registry<T>>, candidates: Collection<Registry<T>>,
): T? ): T?
@Deprecated(
"Order of extensions is now determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
level = DeprecationLevel.WARNING
)
@DeprecatedSinceMirai(warningSince = "2.11")
public companion object ExtensionPoint : public companion object ExtensionPoint :
AbstractExtensionPoint<SingletonExtensionSelector>(SingletonExtensionSelector::class) { AbstractExtensionPoint<SingletonExtensionSelector>(SingletonExtensionSelector::class) {
@ -53,16 +67,22 @@ public interface SingletonExtensionSelector : FunctionExtension {
internal fun init() { internal fun init() {
check(instanceField == null) { "Internal error: reinitialize SingletonExtensionSelector" } check(instanceField == null) { "Internal error: reinitialize SingletonExtensionSelector" }
val instances = GlobalComponentStorage.run { SingletonExtensionSelector.getExtensions() } val instances = GlobalComponentStorage.getExtensions(ExtensionPoint).toList()
instanceField = when { instanceField = when {
instances.isEmpty() -> SingletonExtensionSelectorImpl instances.isEmpty() -> SingletonExtensionSelectorImpl
instances.size == 1 -> { instances.size == 1 -> {
instances.single().also { (plugin, ext) -> instances.single().also { registry ->
MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: $ext from ${plugin?.name ?: "<builtin>"}" } MiraiConsole.mainLogger.info { "Loaded SingletonExtensionSelector: ${registry.extension} from ${registry.plugin?.name ?: "<builtin>"}" }
}.extension }.extension
} }
else -> { else -> {
error("Found too many SingletonExtensionSelectors: ${instances.joinToString { (p, i) -> "'$i' from '${p?.name ?: "<builtin>"}'" }}. Check your plugins and ensure there is only one external SingletonExtensionSelectors") val hint = instances.joinToString { reg ->
"'${reg.extension}' from '${reg.plugin?.name ?: "<builtin>"}'"
}
error(
"Found too many SingletonExtensionSelectors: $hint. " +
"Check your plugins and ensure there is only one external SingletonExtensionSelectors"
)
} }
} }
} }

View File

@ -22,9 +22,13 @@ import net.mamoe.mirai.console.MiraiConsoleImplementation
import net.mamoe.mirai.console.command.BuiltInCommands import net.mamoe.mirai.console.command.BuiltInCommands
import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandManager
import net.mamoe.mirai.console.command.ConsoleCommandSender import net.mamoe.mirai.console.command.ConsoleCommandSender
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
import net.mamoe.mirai.console.command.parse.SpaceSeparatedCommandCallParser
import net.mamoe.mirai.console.command.resolve.BuiltInCommandCallResolver
import net.mamoe.mirai.console.extensions.CommandCallParserProvider
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
import net.mamoe.mirai.console.extensions.PermissionServiceProvider import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.extensions.PostStartupExtension import net.mamoe.mirai.console.extensions.PostStartupExtension
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
import net.mamoe.mirai.console.internal.command.CommandConfig import net.mamoe.mirai.console.internal.command.CommandConfig
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig 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.ConfigurationKey
@ -32,7 +36,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.Pa
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN
import net.mamoe.mirai.console.internal.data.builtins.LoggerConfig import net.mamoe.mirai.console.internal.data.builtins.LoggerConfig
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.extension.SingletonExtensionSelectorImpl import net.mamoe.mirai.console.internal.extension.GlobalComponentStorageImpl
import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl
import net.mamoe.mirai.console.internal.logging.MiraiConsoleLogger import net.mamoe.mirai.console.internal.logging.MiraiConsoleLogger
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
@ -77,6 +81,9 @@ internal class MiraiConsoleImplementationBridge(
override val version: SemVersion by MiraiConsoleBuildConstants::version override val version: SemVersion by MiraiConsoleBuildConstants::version
override val pluginManager: PluginManagerImpl by lazy { PluginManagerImpl(coroutineContext) } override val pluginManager: PluginManagerImpl by lazy { PluginManagerImpl(coroutineContext) }
// used internally
val globalComponentStorage: GlobalComponentStorageImpl by lazy { GlobalComponentStorageImpl() }
override val mainLogger: MiraiLogger by lazy { createLogger("main") } override val mainLogger: MiraiLogger by lazy { createLogger("main") }
init { init {
@ -99,6 +106,15 @@ internal class MiraiConsoleImplementationBridge(
internal fun doStart() { internal fun doStart() {
externalImplementation.preStart() externalImplementation.preStart()
@OptIn(ExperimentalCommandDescriptors::class)
phase("register builtin componenets") {
GlobalComponentStorage.run {
contributeConsole(CommandCallParserProvider, SpaceSeparatedCommandCallParser.Provider)
contributeConsole(CommandCallResolverProvider, BuiltInCommandCallResolver.Provider)
contributeConsole(PermissionServiceProvider, BuiltInPermissionService.Provider())
}
}
phase("setup logger controller") { phase("setup logger controller") {
if (loggerController === LoggerControllerImpl) { if (loggerController === LoggerControllerImpl) {
// Reload LoggerConfig. // Reload LoggerConfig.
@ -159,25 +175,30 @@ internal class MiraiConsoleImplementationBridge(
mainLogger.verbose { "${PluginManager.plugins.size} plugin(s) loaded." } mainLogger.verbose { "${PluginManager.plugins.size} plugin(s) loaded." }
} }
phase("load SingletonExtensionSelector") { // phase("load SingletonExtensionSelector") {
SingletonExtensionSelector.init() // SingletonExtensionSelector.init()
val instance = SingletonExtensionSelector.instance // val instance = SingletonExtensionSelector.instance
if (instance is SingletonExtensionSelectorImpl) { // if (instance is SingletonExtensionSelectorImpl) {
consoleDataScope.addAndReloadConfig(instance.config) // consoleDataScope.addAndReloadConfig(instance.config)
} // }
} // }
phase("load PermissionService") { phase("load PermissionService") {
mainLogger.verbose { "Loading PermissionService..." } mainLogger.verbose { "Loading PermissionService..." }
PermissionServiceProvider.permissionServiceOk = true
PermissionService.INSTANCE.let { ps -> PermissionService.INSTANCE.let { ps ->
if (ps is BuiltInPermissionService) { if (ps is BuiltInPermissionService) {
consoleDataScope.addAndReloadConfig(ps.config) consoleDataScope.addAndReloadConfig(ps.config)
mainLogger.verbose { "Reloaded PermissionService settings." } mainLogger.verbose { "Reloaded PermissionService settings." }
} else { } else {
mainLogger.info { "Loaded PermissionService from plugin ${PermissionServiceProvider.providerPlugin?.name}" } mainLogger.info {
"Loaded PermissionService from plugin ${
GlobalComponentStorage.getPreferredExtension(
PermissionServiceProvider
).plugin?.name
}"
}
} }
} }
@ -258,9 +279,7 @@ internal class MiraiConsoleImplementationBridge(
} }
phase("finally post") { phase("finally post") {
GlobalComponentStorage.run { globalComponentStorage.useEachExtensions(PostStartupExtension) { it.invoke() }
PostStartupExtension.useExtensions { it() } // exceptions thrown will be caught by caller of `doStart`.
}
} }
externalImplementation.postStart() externalImplementation.postStart()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -10,140 +10,116 @@
package net.mamoe.mirai.console.internal.extension package net.mamoe.mirai.console.internal.extension
import net.mamoe.mirai.console.extension.* import net.mamoe.mirai.console.extension.*
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
import net.mamoe.mirai.console.extensions.SingletonExtensionSelector.ExtensionPoint.selectSingleton
import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.name import net.mamoe.mirai.console.plugin.name
import java.util.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet import java.util.stream.Stream
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.reflect.KClass
internal class GlobalComponentStorageImpl : AbstractConcurrentComponentStorage()
// source compatibility for <2.11
internal val GlobalComponentStorage get() = MiraiConsoleImplementationBridge.globalComponentStorage
/** /**
* The [ComponentStorage] containing all components provided by Mirai Console internals and installed plugins. * thread-safe.
*/ */
internal object GlobalComponentStorage : AbstractConcurrentComponentStorage() internal abstract class AbstractConcurrentComponentStorage : ComponentStorage, ComponentStorageInternal {
internal interface ExtensionRegistry<out E : Extension> { ///////////////////////////////////////////////////////////////////////////
val plugin: Plugin? // registry implementation
val extension: E ///////////////////////////////////////////////////////////////////////////
operator fun component1(): Plugin? { /**
return this.plugin * For each [ExtensionPoint]. thread-safe.
} */
internal class Registries<T : Extension> {
@Volatile
private var data: MutableCollection<ExtensionRegistry<T>> = ArrayList()
private val lock = Any()
operator fun component2(): E { fun register(registry: ExtensionRegistry<T>) {
return this.extension synchronized(lock) {
} val list = PriorityQueue(
} data.size + 1,
Comparator.comparing<ExtensionRegistry<T>, Int> { it.extension.priority }.reversed()
internal class LazyExtensionRegistry<out E : Extension>(
override val plugin: Plugin?,
initializer: () -> E,
) : ExtensionRegistry<E> {
override val extension: E by lazy { initializer() }
}
internal data class DataExtensionRegistry<out E : Extension>(
override val plugin: Plugin?,
override val extension: E,
) : ExtensionRegistry<E>
internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
private val instances: MutableMap<ExtensionPoint<*>, MutableSet<ExtensionRegistry<*>>> = ConcurrentHashMap()
@Suppress("UNCHECKED_CAST")
internal fun <T : Extension> ExtensionPoint<out T>.getExtensions(): Set<ExtensionRegistry<T>> {
val userDefined = instances.getOrPut(this, ::CopyOnWriteArraySet) as Set<ExtensionRegistry<T>>
val builtins = if (this is AbstractInstanceExtensionPoint<*, *>) {
this.builtinImplementations.mapTo(HashSet()) { instance ->
DataExtensionRegistry(
null,
instance()
) )
} as Set<ExtensionRegistry<T>> list.addAll(data)
} else null list.add(registry)
data = list
return builtins?.plus(userDefined) ?: userDefined }
}
// unused for now
internal fun removeExtensionsRegisteredByPlugin(plugin: Plugin) {
instances.forEach { (_, u) ->
u.removeAll { it.plugin == plugin }
} }
/**
* @return thread-safe Sequence
*/
fun asSequence(): Sequence<ExtensionRegistry<T>> = data.asSequence()
/**
* @return thread-safe Sequence
*/
fun asStream(): Stream<ExtensionRegistry<T>> = data.stream()
} }
private val registries: MutableMap<ExtensionPoint<*>, Registries<*>> = ConcurrentHashMap()
private fun <T : Extension> getRegistries(ep: ExtensionPoint<T>): Registries<T> {
@Suppress("UNCHECKED_CAST")
return registries.getOrPut(ep) { Registries<T>() } as Registries<T>
}
private fun <T : Extension> registerExtension(ep: ExtensionPoint<T>, registry: ExtensionRegistry<T>) {
getRegistries(ep).register(registry)
}
///////////////////////////////////////////////////////////////////////////
// public API implementation
///////////////////////////////////////////////////////////////////////////
internal fun mergeWith(another: AbstractConcurrentComponentStorage) { internal fun mergeWith(another: AbstractConcurrentComponentStorage) {
for ((ep, list) in another.instances) { another.registries.forEach { (ep, registries) ->
for (extensionRegistry in list) { for (extensionRegistry in registries.asSequence()) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
ep as ExtensionPoint<Extension> ep as ExtensionPoint<Extension>
this.contribute(ep, extensionRegistry.plugin, lazyInstance = { extensionRegistry.extension }) registerExtension(ep, ExtensionRegistryImpl(extensionRegistry.plugin) { extensionRegistry.extension })
} }
} }
} }
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.() -> Unit) { internal inline fun <T : Extension> useEachExtensions(
return withExtensions { _ -> block() } extensionPoint: ExtensionPoint<T>,
} block: ExtensionRegistry<T>.(instance: T) -> Unit
) {
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE") contract { callsInPlace(block) }
@kotlin.internal.LowPriorityInOverloadResolution getExtensions(extensionPoint).forEach { registry ->
internal inline fun <T : Extension> ExtensionPoint<out T>.withExtensions(block: T.(plugin: Plugin?) -> Unit) { val plugin = registry.plugin
contract { val extension = registry.extension
callsInPlace(block)
}
for ((plugin, extension) in this.getExtensions()) {
kotlin.runCatching { kotlin.runCatching {
block.invoke(extension, plugin) block.invoke(registry, registry.extension)
}.getOrElse { throwable -> }.getOrElse { throwable ->
throwExtensionException(extension, plugin, throwable) extensionPoint.throwExtensionException(extension, plugin, throwable)
} }
} }
} }
internal inline fun <reified E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(builtin: E): E = internal inline fun <T : Extension, E> foldExtensions(
findSingleton(E::class, builtin) extensionPoint: ExtensionPoint<T>,
internal fun <E : SingletonExtension<*>> ExtensionPoint<out E>.findSingleton(type: KClass<E>, builtin: E): E {
val candidates = this.getExtensions()
return when (candidates.size) {
0 -> builtin
1 -> candidates.single().extension
else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates) ?: builtin
}
}
internal inline fun <reified E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(noinline default: () -> T): T =
findSingletonInstance(E::class, default)
internal fun <E : SingletonExtension<T>, T> ExtensionPoint<out E>.findSingletonInstance(
type: KClass<E>,
default: () -> T,
): T {
val candidates = this.getExtensions()
return when (candidates.size) {
0 -> default()
1 -> candidates.single().extension.instance
else -> SingletonExtensionSelector.instance.selectSingleton(type, candidates)?.instance ?: default()
}
}
internal inline fun <T : Extension, E> ExtensionPoint<out T>.foldExtensions(
initial: E, initial: E,
block: (acc: E, extension: T) -> E, block: (acc: E, extension: T) -> E,
): E { ): E {
contract { contract { callsInPlace(block) }
callsInPlace(block)
}
var e: E = initial var e: E = initial
for ((plugin, extension) in this.getExtensions()) { getExtensions(extensionPoint).forEach { registry ->
val plugin = registry.plugin
val extension = registry.extension
kotlin.runCatching { kotlin.runCatching {
e = block.invoke(e, extension) e = block.invoke(e, extension)
}.getOrElse { throwable -> }.getOrElse { throwable ->
throwExtensionException(extension, plugin, throwable) extensionPoint.throwExtensionException(extension, plugin, throwable)
} }
} }
return e return e
@ -153,52 +129,38 @@ internal abstract class AbstractConcurrentComponentStorage : ComponentStorage {
extension: T, extension: T,
plugin: Plugin?, plugin: Plugin?,
throwable: Throwable, throwable: Throwable,
) { ): Nothing {
throw ExtensionException( throw ExtensionException(
"Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin?.name ?: "<builtin>"}', registered for '${this.extensionType.qualifiedName}'", "Exception while executing extension '${extension.kClassQualifiedNameOrTip}' provided by plugin '${plugin?.name ?: "<builtin>"}', registered for '${this.extensionType.qualifiedName}'",
throwable throwable
) )
} }
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T) -> Unit): Unit = override fun <E : Extension> contribute(
withExtensions(block) extensionPoint: ExtensionPoint<E>,
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
@kotlin.internal.LowPriorityInOverloadResolution
internal inline fun <T : Extension> ExtensionPoint<T>.useExtensions(block: (extension: T, plugin: Plugin?) -> Unit): Unit =
withExtensions(block)
override fun <T : Extension> contribute(
extensionPoint: ExtensionPoint<T>,
plugin: Plugin, plugin: Plugin,
extensionInstance: T, extensionInstance: E,
) { ) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance)) registerExtension(extensionPoint, ExtensionRegistryImpl(plugin) { extensionInstance })
} }
@JvmName("contribute1") override fun <E : Extension> contributeConsole(extensionPoint: ExtensionPoint<E>, lazyInstance: () -> E) {
fun <T : Extension> contribute( registerExtension(extensionPoint, ExtensionRegistryImpl(null, lazyInstance))
extensionPoint: ExtensionPoint<T>,
plugin: Plugin?,
extensionInstance: T,
) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(DataExtensionRegistry(plugin, extensionInstance))
} }
override fun <T : Extension> contribute( override fun <E : Extension> contribute(
extensionPoint: ExtensionPoint<T>, extensionPoint: ExtensionPoint<E>,
plugin: Plugin, plugin: Plugin,
lazyInstance: () -> T, lazyInstance: () -> E,
) { ) {
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance)) registerExtension(extensionPoint, ExtensionRegistryImpl(plugin, lazyInstance))
} }
@JvmName("contribute1") override fun <E : Extension> getExtensions(extensionPoint: ExtensionPoint<E>): Sequence<ExtensionRegistry<E>> {
fun <T : Extension> contribute( return getRegistries(extensionPoint).asSequence()
extensionPoint: ExtensionPoint<T>, }
plugin: Plugin?,
lazyInstance: () -> T, override fun <E : Extension> getExtensionsStream(extensionPoint: ExtensionPoint<E>): Stream<ExtensionRegistry<E>> {
) { return getRegistries(extensionPoint).asStream()
instances.getOrPut(extensionPoint, ::CopyOnWriteArraySet).add(LazyExtensionRegistry(plugin, lazyInstance))
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -18,9 +18,16 @@ import net.mamoe.mirai.console.extensions.SingletonExtensionSelector
import net.mamoe.mirai.console.internal.data.kClassQualifiedName import net.mamoe.mirai.console.internal.data.kClassQualifiedName
import net.mamoe.mirai.console.plugin.name import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.util.ConsoleInput import net.mamoe.mirai.console.util.ConsoleInput
import net.mamoe.mirai.utils.DeprecatedSinceMirai
import net.mamoe.mirai.utils.info import net.mamoe.mirai.utils.info
import kotlin.reflect.KClass import kotlin.reflect.KClass
@Suppress("DEPRECATION")
@Deprecated(
"Order of extensions is not determined by its priority property since 2.11. SingletonExtensionSelector is not needed anymore. ",
level = DeprecationLevel.WARNING
)
@DeprecatedSinceMirai(warningSince = "2.11")
internal object SingletonExtensionSelectorImpl : SingletonExtensionSelector { internal object SingletonExtensionSelectorImpl : SingletonExtensionSelector {
internal val config: SaveData = SaveData() internal val config: SaveData = SaveData()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -14,6 +14,7 @@ import net.mamoe.mirai.console.data.AutoSavePluginConfig
import net.mamoe.mirai.console.data.PluginDataExtensions import net.mamoe.mirai.console.data.PluginDataExtensions
import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault
import net.mamoe.mirai.console.data.value import net.mamoe.mirai.console.data.value
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.permission.* import net.mamoe.mirai.console.permission.*
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArraySet import java.util.concurrent.CopyOnWriteArraySet
@ -100,6 +101,12 @@ internal class AllDenyPermissionService : PermissionService<PermissionImpl> {
internal class BuiltInPermissionService : AbstractConcurrentPermissionService<PermissionImpl>(), internal class BuiltInPermissionService : AbstractConcurrentPermissionService<PermissionImpl>(),
PermissionService<PermissionImpl> { PermissionService<PermissionImpl> {
class Provider : PermissionServiceProvider {
override val instance: PermissionService<*> by lazy {
BuiltInPermissionService()
}
}
override val permissionType: KClass<PermissionImpl> override val permissionType: KClass<PermissionImpl>
get() = PermissionImpl::class get() = PermissionImpl::class
override val permissions: ConcurrentHashMap<PermissionId, PermissionImpl> = ConcurrentHashMap() override val permissions: ConcurrentHashMap<PermissionId, PermissionImpl> = ConcurrentHashMap()

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@ -160,12 +160,10 @@ internal class PluginManagerImpl(
internal fun initExternalPluginLoaders(): Int { internal fun initExternalPluginLoaders(): Int {
var count = 0 var count = 0
GlobalComponentStorage.run { GlobalComponentStorage.useEachExtensions(PluginLoaderProvider) {
PluginLoaderProvider.useExtensions { ext, plugin -> logger.info { "Loaded PluginLoader ${extension.instance} from ${plugin?.name ?: "<builtin>"}" }
logger.info { "Loaded PluginLoader ${ext.instance} from ${plugin?.name ?: "<builtin>"}" } _pluginLoaders.add(extension.instance)
_pluginLoaders.add(ext.instance) count++
count++
}
} }
return count return count
} }

View File

@ -1,10 +1,10 @@
/* /*
* Copyright 2019-2021 Mamoe Technologies and contributors. * Copyright 2019-2022 Mamoe Technologies and contributors.
* *
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. * 此源代码的使用受 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. * 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 * https://github.com/mamoe/mirai/blob/dev/LICENSE
*/ */
@file:Suppress("NOTHING_TO_INLINE", "unused", "MemberVisibilityCanBePrivate") @file:Suppress("NOTHING_TO_INLINE", "unused", "MemberVisibilityCanBePrivate")
@ -13,7 +13,9 @@ package net.mamoe.mirai.console.permission
import net.mamoe.mirai.console.compiler.common.ResolveContext import net.mamoe.mirai.console.compiler.common.ResolveContext
import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.COMMAND_NAME import net.mamoe.mirai.console.compiler.common.ResolveContext.Kind.COMMAND_NAME
import net.mamoe.mirai.console.extension.instance
import net.mamoe.mirai.console.extensions.PermissionServiceProvider import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.permission.checkType import net.mamoe.mirai.console.internal.permission.checkType
import net.mamoe.mirai.console.permission.Permission.Companion.parentsWithSelf import net.mamoe.mirai.console.permission.Permission.Companion.parentsWithSelf
import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.Plugin
@ -140,14 +142,12 @@ public interface PermissionService<P : Permission> {
public companion object { public companion object {
/** /**
* [PermissionService] 实例 * 选用的 [PermissionService] 实例.
*
* @see PermissionServiceProvider.selectedInstance
*/ */
@get:JvmName("getInstance") @get:JvmName("getInstance")
@JvmStatic @JvmStatic
public val INSTANCE: PermissionService<out Permission> public val INSTANCE: PermissionService<out Permission>
get() = PermissionServiceProvider.selectedInstance get() = GlobalComponentStorage.getPreferredExtension(PermissionServiceProvider).instance
/** /**
* 获取一个权限, 失败时抛出 [NoSuchElementException] * 获取一个权限, 失败时抛出 [NoSuchElementException]

View File

@ -0,0 +1,80 @@
/*
* Copyright 2019-2022 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/dev/LICENSE
*/
package net.mamoe.mirai.console.extension
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorageImpl
import net.mamoe.mirai.console.testFramework.AbstractConsoleInstanceTest
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
internal class GlobalComponentStorageTest : AbstractConsoleInstanceTest() {
class MyInstance
class MyExtension(override val instance: MyInstance, override val priority: Int) : InstanceExtension<MyInstance> {
companion object EP : AbstractInstanceExtensionPoint<MyExtension, MyInstance>(MyExtension::class)
}
@Test
fun `can register`() {
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
GlobalComponentStorage.getExtensionsList(MyExtension).run {
assertEquals(2, size)
}
}
@Test
fun `can contribute`() {
GlobalComponentStorage.contribute(MyExtension, mockPlugin, MyExtension(MyInstance(), 1))
GlobalComponentStorage.contribute(MyExtension, mockPlugin, MyExtension(MyInstance(), 2))
GlobalComponentStorage.getExtensionsList(MyExtension).run {
assertEquals(2, size)
}
}
@Test
fun `can sort by priority`() {
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
GlobalComponentStorage.getExtensionsList(MyExtension).run {
assertEquals(2, size)
assertEquals(2, first().extension.priority)
assertEquals(1, get(1).extension.priority)
}
}
@Test
fun `can sort by priority 2`() {
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
GlobalComponentStorage.getExtensionsList(MyExtension).run {
assertEquals(2, size)
assertEquals(2, first().extension.priority)
assertEquals(1, get(1).extension.priority)
}
}
@Test
fun `can fold`() {
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 2))
GlobalComponentStorage.contributeConsole(MyExtension, MyExtension(MyInstance(), 1))
val list = GlobalComponentStorage.foldExtensions(MyExtension, listOf<MyExtension>()) { acc, extension ->
acc + extension
}
assertEquals(2, list.size)
assertEquals(2, list.first().priority)
assertEquals(1, list[1].priority)
}
}
private fun <T : Extension> GlobalComponentStorageImpl.getExtensionsList(ep: ExtensionPoint<T>): List<ExtensionRegistry<T>> {
return getExtensions(ep).toList()
}