Skip to content

Commit 3e86458

Browse files
committed
(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
1 parent 6f67a41 commit 3e86458

25 files changed

+551
-309
lines changed

mirai-console/backend/mirai-console/src/MiraiConsole.kt

+3-6
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ public interface MiraiConsole : CoroutineScope {
162162
*
163163
* 调用 [Bot.login] 可登录.
164164
*
165-
* @see Bot.botInstances 获取现有 [Bot] 实例列表
165+
* @see Bot.instances 获取现有 [Bot] 实例列表
166166
* @see BotConfigurationAlterer ExtensionPoint
167167
*/
168168
// don't static
@@ -225,11 +225,8 @@ public interface MiraiConsole : CoroutineScope {
225225
configuration()
226226
}
227227

228-
config = GlobalComponentStorage.run {
229-
BotConfigurationAlterer.foldExtensions(config) { acc, extension ->
230-
extension.alterConfiguration(id, acc)
231-
232-
}
228+
config = GlobalComponentStorage.foldExtensions(BotConfigurationAlterer, config) { acc, extension ->
229+
extension.alterConfiguration(id, acc)
233230
}
234231

235232
return when (password) {

mirai-console/backend/mirai-console/src/MiraiConsoleImplementation.kt

+4-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import net.mamoe.mirai.console.extension.ComponentStorage
2525
import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge
2626
import net.mamoe.mirai.console.internal.command.CommandManagerImpl
2727
import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScopeImpl
28-
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
2928
import net.mamoe.mirai.console.internal.logging.LoggerControllerImpl
3029
import net.mamoe.mirai.console.internal.plugin.BuiltInJvmPluginLoaderImpl
3130
import net.mamoe.mirai.console.internal.pluginManagerImpl
@@ -317,6 +316,9 @@ public interface MiraiConsoleImplementation : CoroutineScope {
317316
@ConsoleFrontEndImplementation
318317
public interface BackendAccess {
319318
// GlobalComponentStorage
319+
/**
320+
* 在 Mirai Console 第一个 phase 之后会包含内建 storages.
321+
*/
320322
public val globalComponentStorage: ComponentStorage
321323

322324
// PluginManagerImpl.resolvedPlugins
@@ -365,7 +367,7 @@ public interface MiraiConsoleImplementation : CoroutineScope {
365367
@ConsoleFrontEndImplementation
366368
public companion object {
367369
private val backendAccessInstance = object : BackendAccess {
368-
override val globalComponentStorage: ComponentStorage get() = GlobalComponentStorage
370+
override val globalComponentStorage: ComponentStorage get() = getBridge().globalComponentStorage
369371
override val resolvedPlugins: MutableList<Plugin> get() = MiraiConsole.pluginManagerImpl.resolvedPlugins
370372
}
371373

mirai-console/backend/mirai-console/src/command/BuiltInCommands.kt

+2-1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
2828
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.*
2929
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.MD5
3030
import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig.Account.PasswordKind.PLAIN
31+
import net.mamoe.mirai.console.internal.extension.GlobalComponentStorage
3132
import net.mamoe.mirai.console.internal.permission.BuiltInPermissionService
3233
import net.mamoe.mirai.console.internal.pluginManagerImpl
3334
import net.mamoe.mirai.console.internal.util.autoHexToBytes
@@ -484,7 +485,7 @@ public object BuiltInCommands {
484485
lightYellow()
485486
"Built In Permission Service"
486487
} else {
487-
val plugin = PermissionServiceProvider.providerPlugin
488+
val plugin = GlobalComponentStorage.getPreferredExtension(PermissionServiceProvider).plugin
488489
if (plugin == null) {
489490
PermissionService.INSTANCE.toString()
490491
} else {

mirai-console/backend/mirai-console/src/command/parse/CommandCallParser.kt

+3-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2021 Mamoe Technologies and contributors.
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
33
*
44
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
55
* 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 {
4444
*/
4545
@JvmStatic
4646
public fun MessageChain.parseCommandCall(sender: CommandSender): CommandCall? {
47-
GlobalComponentStorage.run {
48-
CommandCallParserProvider.useExtensions { provider ->
49-
provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
50-
}
47+
GlobalComponentStorage.useEachExtensions(CommandCallParserProvider) { provider ->
48+
provider.instance.parse(sender, this@parseCommandCall)?.let { return it }
5149
}
5250
return null
5351
}

mirai-console/backend/mirai-console/src/command/parse/SpaceSeparatedCommandCallParser.kt

+8-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2021 Mamoe Technologies and contributors.
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
33
*
44
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
55
* 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
1212
import net.mamoe.mirai.console.command.CommandSender
1313
import net.mamoe.mirai.console.command.descriptor.ExperimentalCommandDescriptors
1414
import net.mamoe.mirai.console.extensions.CommandCallParserProvider
15-
import net.mamoe.mirai.console.extensions.CommandCallParserProviderImpl
1615
import net.mamoe.mirai.console.internal.command.flattenCommandComponents
1716
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
1817
import net.mamoe.mirai.message.data.MessageChain
@@ -22,6 +21,13 @@ import net.mamoe.mirai.message.data.content
2221
@ConsoleExperimentalApi
2322
@ExperimentalCommandDescriptors
2423
public object SpaceSeparatedCommandCallParser : CommandCallParser {
24+
25+
@ConsoleExperimentalApi
26+
@ExperimentalCommandDescriptors
27+
public object Provider : CommandCallParserProvider {
28+
override val instance: CommandCallParser get() = SpaceSeparatedCommandCallParser
29+
}
30+
2531
override fun parse(caller: CommandSender, message: MessageChain): CommandCall? {
2632
val flatten = message.flattenCommandComponents().filterIsInstance<MessageContent>()
2733
if (flatten.isEmpty()) return null
@@ -31,6 +37,4 @@ public object SpaceSeparatedCommandCallParser : CommandCallParser {
3137
valueArguments = flatten.drop(1).map(::DefaultCommandValueArgument)
3238
)
3339
}
34-
35-
public object Provider : CommandCallParserProvider by CommandCallParserProviderImpl(SpaceSeparatedCommandCallParser)
3640
}

mirai-console/backend/mirai-console/src/command/resolve/BuiltInCommandCallResolver.kt

+7-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2021 Mamoe Technologies and contributors.
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
33
*
44
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
55
* 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
1515
import net.mamoe.mirai.console.command.parse.CommandCall
1616
import net.mamoe.mirai.console.command.parse.CommandValueArgument
1717
import net.mamoe.mirai.console.command.parse.DefaultCommandValueArgument
18+
import net.mamoe.mirai.console.extensions.CommandCallResolverProvider
1819
import net.mamoe.mirai.console.internal.data.classifierAsKClass
1920
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
2021
import net.mamoe.mirai.console.util.safeCast
@@ -27,6 +28,11 @@ import net.mamoe.mirai.message.data.toMessageChain
2728
@ConsoleExperimentalApi
2829
@ExperimentalCommandDescriptors
2930
public object BuiltInCommandCallResolver : CommandCallResolver {
31+
32+
internal object Provider : CommandCallResolverProvider {
33+
override val instance: CommandCallResolver = BuiltInCommandCallResolver
34+
}
35+
3036
override fun resolve(call: CommandCall): CommandResolveResult {
3137
val callee = CommandManager.matchCommand(call.calleeName)
3238
?: return CommandResolveResult(CommandExecuteResult.UnresolvedCommand(call))

mirai-console/backend/mirai-console/src/command/resolve/CommandCallInterceptor.kt

+21-27
Original file line numberDiff line numberDiff line change
@@ -66,15 +66,13 @@ public interface CommandCallInterceptor {
6666
*/
6767
@JvmStatic
6868
public fun Message.intercepted(caller: CommandSender): InterceptResult<Message> {
69-
GlobalComponentStorage.run {
70-
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
71-
val intercepted = ext.instance.interceptBeforeCall(acc, caller)
72-
intercepted?.fold(
73-
onIntercepted = { return intercepted },
74-
otherwise = { it }
75-
) ?: acc
76-
}.let { InterceptResult(it) }
77-
}
69+
return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
70+
val intercepted = ext.instance.interceptBeforeCall(acc, caller)
71+
intercepted?.fold(
72+
onIntercepted = { return intercepted },
73+
otherwise = { it }
74+
) ?: acc
75+
}.let { InterceptResult(it) }
7876
}
7977

8078
/**
@@ -83,15 +81,13 @@ public interface CommandCallInterceptor {
8381
*/
8482
@JvmStatic
8583
public fun CommandCall.intercepted(): InterceptResult<CommandCall> {
86-
GlobalComponentStorage.run {
87-
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
88-
val intercepted = ext.instance.interceptCall(acc)
89-
intercepted?.fold(
90-
onIntercepted = { return intercepted },
91-
otherwise = { it }
92-
) ?: acc
93-
}.let { InterceptResult(it) }
94-
}
84+
return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
85+
val intercepted = ext.instance.interceptCall(acc)
86+
intercepted?.fold(
87+
onIntercepted = { return intercepted },
88+
otherwise = { it }
89+
) ?: acc
90+
}.let { InterceptResult(it) }
9591
}
9692

9793
/**
@@ -100,15 +96,13 @@ public interface CommandCallInterceptor {
10096
*/
10197
@JvmStatic
10298
public fun ResolvedCommandCall.intercepted(): InterceptResult<ResolvedCommandCall> {
103-
GlobalComponentStorage.run {
104-
return CommandCallInterceptorProvider.foldExtensions(this@intercepted) { acc, ext ->
105-
val intercepted = ext.instance.interceptResolvedCall(acc)
106-
intercepted?.fold(
107-
onIntercepted = { return intercepted },
108-
otherwise = { it }
109-
) ?: acc
110-
}.let { InterceptResult(it) }
111-
}
99+
return GlobalComponentStorage.foldExtensions(CommandCallInterceptorProvider, this@intercepted) { acc, ext ->
100+
val intercepted = ext.instance.interceptResolvedCall(acc)
101+
intercepted?.fold(
102+
onIntercepted = { return intercepted },
103+
otherwise = { it }
104+
) ?: acc
105+
}.let { InterceptResult(it) }
112106
}
113107
}
114108
}

mirai-console/backend/mirai-console/src/command/resolve/CommandCallResolver.kt

+4-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2021 Mamoe Technologies and contributors.
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
33
*
44
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
55
* 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 {
7676
@ConsoleExperimentalApi
7777
@ExperimentalCommandDescriptors
7878
public fun CommandCall.resolve(): CommandResolveResult {
79-
GlobalComponentStorage.run {
80-
val instance =
81-
CommandCallResolverProvider.findSingletonInstance(CommandCallResolverProvider.builtinImplementation)
82-
return instance.resolve(this@resolve)
83-
}
79+
return GlobalComponentStorage.getExtensions(CommandCallResolverProvider).first()
80+
.extension.instance
81+
.resolve(this@resolve)
8482
}
8583
}
8684
}
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2021 Mamoe Technologies and contributors.
2+
* Copyright 2019-2022 Mamoe Technologies and contributors.
33
*
44
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
55
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
@@ -9,27 +9,99 @@
99

1010
package net.mamoe.mirai.console.extension
1111

12+
import net.mamoe.mirai.console.ConsoleFrontEndImplementation
13+
import net.mamoe.mirai.console.MiraiConsoleImplementation
1214
import net.mamoe.mirai.console.plugin.Plugin
1315
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin
1416
import net.mamoe.mirai.console.plugin.jvm.JvmPlugin.Companion.onLoad
17+
import net.mamoe.mirai.utils.MiraiExperimentalApi
18+
import java.util.stream.Stream
1519

1620
/**
1721
* 组件容器, 容纳 [Plugin] 注册的 [Extension].
1822
*
23+
* 插件可在 [JvmPlugin.onLoad] 时提供扩展. 前端可在 [MiraiConsoleImplementation.BackendAccess.globalComponentStorage] 获取全局组件容器.
24+
* 目前未允许获取全局组件容器. 如有需求请 [提交 issues](https://github.com/mamoe/mirai/issues/new/choose).
25+
*
26+
* 实现细节: 线程安全.
27+
*
1928
* @see Extension
2029
* @see JvmPlugin.onLoad
2130
*/
2231
public interface ComponentStorage {
23-
public fun <T : Extension> contribute(
24-
extensionPoint: ExtensionPoint<T>,
32+
33+
/**
34+
* 注册一个扩展
35+
*/
36+
public fun <E : Extension> contribute(
37+
extensionPoint: ExtensionPoint<E>,
2538
plugin: Plugin,
26-
extensionInstance: T,
27-
)
39+
extensionInstance: E,
40+
) // 2.11: E changed to T (only naming)
2841

29-
public fun <T : Extension> contribute(
30-
extensionPoint: ExtensionPoint<T>,
42+
/**
43+
* 注册一个扩展. [lazyInstance] 将会在 [getExtensions] 时才会计算.
44+
*/
45+
public fun <E : Extension> contribute(
46+
extensionPoint: ExtensionPoint<E>,
3147
plugin: Plugin,
32-
lazyInstance: () -> T,
33-
)
48+
lazyInstance: () -> E,
49+
) // 2.11: E changed to T (only naming)
50+
51+
/**
52+
* 获取优先级最高的 [ExtensionPoint] 扩展实例. 在未找到任何注册的实例时抛出 [NoSuchElementException].
53+
*
54+
* @since 2.11
55+
*/
56+
@MiraiExperimentalApi
57+
public fun <E : Extension> getPreferredExtension(
58+
extensionPoint: ExtensionPoint<E>,
59+
): ExtensionRegistry<E> {
60+
return getExtensions(extensionPoint).firstOrNull()
61+
?: throw NoSuchElementException("No extension registered for $extensionPoint")
62+
}
63+
64+
/**
65+
* 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Sequence] 以 [Extension.priority] 倒序排序.
66+
*
67+
* @since 2.11
68+
*/
69+
public fun <E : Extension> getExtensions(
70+
extensionPoint: ExtensionPoint<E>,
71+
): Sequence<ExtensionRegistry<E>>
72+
73+
/**
74+
* 获取注册的 [ExtensionPoint] 扩展实例列表. 返回的 [Stream] 以 [Extension.priority] 倒序排序.
75+
*
76+
* @since 2.11
77+
*/
78+
public fun <E : Extension> getExtensionsStream(
79+
extensionPoint: ExtensionPoint<E>,
80+
): Stream<ExtensionRegistry<E>>
3481
}
3582

83+
/**
84+
* 仅前端实现可用
85+
*/
86+
@ConsoleFrontEndImplementation
87+
public interface ComponentStorageInternal : ComponentStorage {
88+
89+
/**
90+
* 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]). [lazyInstance] 将会在 [getExtensions] 时才会计算.
91+
*/
92+
public fun <E : Extension> contributeConsole(
93+
extensionPoint: ExtensionPoint<E>,
94+
lazyInstance: () -> E,
95+
)
96+
97+
/**
98+
* 注册一个由 Mirai Console 实现的扩展 (因此没有相关 [Plugin]).
99+
*/
100+
public fun <E : Extension> contributeConsole(
101+
extensionPoint: ExtensionPoint<E>,
102+
instance: E,
103+
) {
104+
@Suppress("USELESS_CAST") // bug
105+
contributeConsole(extensionPoint, { instance } as () -> E)
106+
}
107+
}

0 commit comments

Comments
 (0)