diff --git a/backend/mirai-console/build.gradle.kts b/backend/mirai-console/build.gradle.kts index f19e05e10..7de97c454 100644 --- a/backend/mirai-console/build.gradle.kts +++ b/backend/mirai-console/build.gradle.kts @@ -6,7 +6,6 @@ import java.time.Instant plugins { kotlin("jvm") kotlin("plugin.serialization") - kotlin("kapt") id("java") `maven-publish` id("com.jfrog.bintray") @@ -81,9 +80,9 @@ dependencies { testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.2.0") - val autoService = "1.0-rc7" - kapt("com.google.auto.service", "auto-service", autoService) - compileOnly("com.google.auto.service", "auto-service-annotations", autoService) +// val autoService = "1.0-rc7" +// kapt("com.google.auto.service", "auto-service", autoService) +// compileOnly("com.google.auto.service", "auto-service-annotations", autoService) } ext.apply { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt index b4549263e..78a17cd26 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/BuiltInCommands.kt @@ -62,17 +62,14 @@ public object BuiltInCommands { public object Managers : CompositeCommand( ConsoleCommandOwner, "managers", - description = "Manage the managers for each bot", - permission = CommandPermission.Console or CommandPermission.Manager + description = "Manage the managers for each bot" ), BuiltInCommand { - @Permission(CommandPermission.Console::class) @SubCommand public suspend fun CommandSender.add(target: User) { target.bot.addManager(target.id) sendMessage("已成功添加 ${target.render()} 为 ${target.bot.render()} 的管理员") } - @Permission(CommandPermission.Console::class) @SubCommand public suspend fun CommandSender.remove(target: User) { target.bot.removeManager(target.id) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt index 2dcca4945..096be5791 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/Command.kt @@ -15,7 +15,11 @@ import net.mamoe.kjbb.JvmBlockingBridge import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand import net.mamoe.mirai.console.command.CommandManager.INSTANCE.register import net.mamoe.mirai.console.command.java.JCommand +import net.mamoe.mirai.console.internal.command.createCommandPermission import net.mamoe.mirai.console.internal.command.isValidSubName +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.Permission +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.SingleMessage @@ -51,7 +55,7 @@ public interface Command { /** * 指令权限 */ - public val permission: CommandPermission + public val permission: Permission /** * 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 @@ -95,13 +99,13 @@ public suspend inline fun Command.onCommand(sender: CommandSender, args: Message * @see CompositeCommand * @see RawCommand */ -public abstract class AbstractCommand @JvmOverloads constructor( +public abstract class AbstractCommand +@JvmOverloads constructor( /** 指令拥有者. */ public override val owner: CommandOwner, vararg names: String, description: String = "", - /** 指令权限 */ - public override val permission: CommandPermission = CommandPermission.Default, + basePermission: PermissionId? = null, /** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */ public override val prefixOptional: Boolean = false ) : Command { @@ -111,4 +115,6 @@ public abstract class AbstractCommand @JvmOverloads constructor( list.firstOrNull { !it.isValidSubName() }?.let { error("Invalid name: $it") } }.toTypedArray() + @OptIn(ExperimentalPermission::class) + public override val permission: Permission by lazy { createCommandPermission(basePermission) } } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandOwner.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandOwner.kt index 49d2715f3..49932f8df 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandOwner.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandOwner.kt @@ -10,6 +10,9 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.console.command.CommandManager.INSTANCE.unregisterAllCommands +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.PermissionId +import net.mamoe.mirai.console.permission.PermissionIdNamespace import net.mamoe.mirai.console.plugin.jvm.JvmPlugin /** @@ -20,9 +23,12 @@ import net.mamoe.mirai.console.plugin.jvm.JvmPlugin * * @see JvmPlugin 是一个 [CommandOwner] */ -public interface CommandOwner +public interface CommandOwner : PermissionIdNamespace /** * 代表控制台所有者. 所有的 mirai-console 内建的指令都属于 [ConsoleCommandOwner]. */ -internal object ConsoleCommandOwner : CommandOwner \ No newline at end of file +internal object ConsoleCommandOwner : CommandOwner { + @ExperimentalPermission + override fun permissionId(id: String): PermissionId = PermissionId("console", id) +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandPermission.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandPermission.kt deleted file mode 100644 index 6ea195f7d..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandPermission.kt +++ /dev/null @@ -1,143 +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("unused", "NOTHING_TO_INLINE", "MemberVisibilityCanBePrivate") - -package net.mamoe.mirai.console.command - -import net.mamoe.mirai.Bot -import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand -import net.mamoe.mirai.console.internal.command.AndCommandPermissionImpl -import net.mamoe.mirai.console.internal.command.OrCommandPermissionImpl -import net.mamoe.mirai.console.util.BotManager.INSTANCE.isManager -import net.mamoe.mirai.contact.isAdministrator -import net.mamoe.mirai.contact.isOperator -import net.mamoe.mirai.contact.isOwner - -/** - * 指令权限. - * - * 在 [CommandManager.executeCommand] 时将会检查权限. - * - * @see Command.permission 从指令获取权限 - */ -public fun interface CommandPermission { - /** - * 判断 [this] 是否拥有这个指令的权限 - * - * @see CommandSender.hasPermission - * @see CommandPermission.testPermission - */ - public fun CommandSender.hasPermission(): Boolean - - - /** - * 满足两个权限其中一个即可使用指令 - */ // no extension for Java - public infix fun or(another: CommandPermission): CommandPermission = OrCommandPermissionImpl(this, another) - - /** - * 同时拥有两个权限才能使用指令 - */ // no extension for Java - public infix fun and(another: CommandPermission): CommandPermission = AndCommandPermissionImpl(this, another) - - - /** - * 任何人都可以使用这个指令 - */ - public object Any : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean = true - } - - /** - * 任何人都不能使用这个指令. 指令只能通过调用 [Command.onCommand] 执行. - */ - public object None : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean = false - } - - /** - * 来自任何 [Bot] 的任何一个管理员或群主都可以使用这个指令 - */ - public object Operator : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean { - return this is MemberCommandSender && this.user.isOperator() - } - } - - /** - * 来自任何 [Bot] 的任何一个群主都可以使用这个指令 - */ - public object GroupOwner : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean { - return this is MemberCommandSender && this.user.isOwner() - } - } - - /** - * 管理员 (不包含群主) 可以使用这个指令 - */ - public object GroupAdmin : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean { - return this is MemberCommandSender && this.user.isAdministrator() - } - } - - /** - * 任何 [Bot] 的 manager 都可以使用这个指令 - */ - public object Manager : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean { - return this is MemberCommandSender && this.user.isManager - } - } - - /** - * 仅控制台能使用和这个指令 - */ - public object Console : CommandPermission { - public override fun CommandSender.hasPermission(): Boolean = this is ConsoleCommandSender - } - - /** - * 默认权限. - * - * @return [Manager] or [Console] - */ - public object Default : CommandPermission by (Manager or Console) -} - -/** - * 判断 [this] 是否拥有权限 [permission] - * - * @see CommandSender.hasPermission - * @see CommandPermission.testPermission - * @see CommandPermission.hasPermission - */ -public inline fun CommandSender.hasPermission(permission: CommandPermission): Boolean = - permission.run { this@hasPermission.hasPermission() } - - -/** - * 判断 [sender] 是否拥有权限 [this] - * - * @see CommandSender.hasPermission - * @see CommandPermission.testPermission - * @see CommandPermission.hasPermission - */ -public inline fun CommandPermission.testPermission(sender: CommandSender): Boolean = this.run { sender.hasPermission() } - -/** - * 判断 [sender] 是否拥有权限 [Command.permission] - * - * @see CommandSender.hasPermission - * @see CommandPermission.testPermission - * @see CommandPermission.hasPermission - */ -public inline fun Command.testPermission(sender: CommandSender): Boolean = sender.hasPermission(this.permission) \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt index c797a967f..af199bcb4 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CommandSender.kt @@ -32,8 +32,10 @@ import net.mamoe.mirai.console.internal.MiraiConsoleImplementationBridge import net.mamoe.mirai.console.internal.command.qualifiedNameOrTip import net.mamoe.mirai.console.internal.data.castOrNull import net.mamoe.mirai.console.internal.plugin.rootCauseOrSelf +import net.mamoe.mirai.console.permission.AbstractPermissibleIdentifier import net.mamoe.mirai.console.permission.ExperimentalPermission import net.mamoe.mirai.console.permission.Permissible +import net.mamoe.mirai.console.permission.PermissibleIdentifier import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScope import net.mamoe.mirai.console.util.CoroutineScopeUtils.childScopeContext @@ -512,6 +514,9 @@ public abstract class ConsoleCommandSender @ConsoleFrontEndImplementation constr public final override val name: String get() = NAME public final override fun toString(): String = NAME + @ExperimentalPermission + public final override val identifier: PermissibleIdentifier = AbstractPermissibleIdentifier.Console + public companion object INSTANCE : ConsoleCommandSender(), CoroutineScope { public const val NAME: String = "ConsoleCommandSender" public override val coroutineContext: CoroutineContext by lazy { MiraiConsole.childScopeContext(NAME) } @@ -607,6 +612,9 @@ public open class FriendCommandSender internal constructor( public override val subject: Contact get() = user public override fun toString(): String = "FriendCommandSender($user)" + @ExperimentalPermission + public override val identifier: PermissibleIdentifier = AbstractPermissibleIdentifier.ExactFriend(user.id) + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) @@ -623,10 +631,13 @@ public open class MemberCommandSender internal constructor( ) : AbstractUserCommandSender(), GroupAwareCommandSender, CoroutineScope by user.childScope("MemberCommandSender") { - public override val group: Group get() = user.group + public final override val group: Group get() = user.group public override val subject: Group get() = group public override fun toString(): String = "MemberCommandSender($user)" + @ExperimentalPermission + public override val identifier: PermissibleIdentifier = AbstractPermissibleIdentifier.ExactMember(group.id, user.id) + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) @@ -647,6 +658,10 @@ public open class TempCommandSender internal constructor( public override val subject: Contact get() = group public override fun toString(): String = "TempCommandSender($user)" + @ExperimentalPermission + public override val identifier: PermissibleIdentifier = + AbstractPermissibleIdentifier.ExactTemp(user.group.id, user.id) + @JvmBlockingBridge public override suspend fun sendMessage(message: String): MessageReceipt = sendMessage(PlainText(message)) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CompositeCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CompositeCommand.kt index c901ea4ca..26a71f9d8 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CompositeCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/CompositeCommand.kt @@ -20,11 +20,12 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.console.command.description.* import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand import net.mamoe.mirai.console.internal.command.CompositeCommandSubCommandAnnotationResolver +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.console.util.ConsoleExperimentalAPI import net.mamoe.mirai.message.data.MessageChain import kotlin.annotation.AnnotationRetention.RUNTIME import kotlin.annotation.AnnotationTarget.FUNCTION -import kotlin.reflect.KClass /** * 复合指令. 指令注册时候会通过反射构造指令解析器. @@ -85,10 +86,10 @@ public abstract class CompositeCommand( owner: CommandOwner, vararg names: String, description: String = "no description available", - permission: CommandPermission = CommandPermission.Default, + basePermission: PermissionId? = null, prefixOptional: Boolean = false, overrideContext: CommandArgumentContext = EmptyCommandArgumentContext -) : Command, AbstractReflectionCommand(owner, names, description, permission, prefixOptional), +) : Command, AbstractReflectionCommand(owner, names, description, basePermission, prefixOptional), CommandArgumentContextAware { /** @@ -112,7 +113,8 @@ public abstract class CompositeCommand( /** 指定子指令要求的权限 */ @Retention(RUNTIME) @Target(FUNCTION) - protected annotation class Permission(val value: KClass) + @ExperimentalPermission + protected annotation class Permission(val value: String) /** 指令描述 */ @Retention(RUNTIME) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt index 57a436a4f..fd1a36515 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/RawCommand.kt @@ -14,6 +14,10 @@ package net.mamoe.mirai.console.command import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand import net.mamoe.mirai.console.command.java.JRawCommand +import net.mamoe.mirai.console.internal.command.createCommandPermission +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.Permission +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.message.data.MessageChain /** @@ -40,10 +44,13 @@ public abstract class RawCommand( /** 指令描述, 用于显示在 [BuiltInCommands.Help] */ public override val description: String = "", /** 指令权限 */ - public override val permission: CommandPermission = CommandPermission.Default, + basePermission: PermissionId? = null, /** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */ public override val prefixOptional: Boolean = false ) : Command { + @OptIn(ExperimentalPermission::class) + public override val permission: Permission by lazy { createCommandPermission(basePermission) } + /** * 在指令被执行时调用. * diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/SimpleCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/SimpleCommand.kt index 12c4a16a2..9c83c9228 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/SimpleCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/SimpleCommand.kt @@ -22,6 +22,7 @@ import net.mamoe.mirai.console.command.description.* import net.mamoe.mirai.console.command.java.JSimpleCommand import net.mamoe.mirai.console.internal.command.AbstractReflectionCommand import net.mamoe.mirai.console.internal.command.SimpleCommandSubCommandAnnotationResolver +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.message.data.MessageChain /** @@ -51,10 +52,10 @@ public abstract class SimpleCommand( owner: CommandOwner, vararg names: String, description: String = "no description available", - permission: CommandPermission = CommandPermission.Default, + basePermission: PermissionId? = null, prefixOptional: Boolean = false, overrideContext: CommandArgumentContext = EmptyCommandArgumentContext -) : Command, AbstractReflectionCommand(owner, names, description, permission, prefixOptional), +) : Command, AbstractReflectionCommand(owner, names, description, basePermission, prefixOptional), CommandArgumentContextAware { /** diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JCompositeCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JCompositeCommand.kt index ee585a8cc..ef400b3c0 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JCompositeCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JCompositeCommand.kt @@ -9,8 +9,13 @@ package net.mamoe.mirai.console.command.java -import net.mamoe.mirai.console.command.* +import net.mamoe.mirai.console.command.BuiltInCommands +import net.mamoe.mirai.console.command.CommandManager +import net.mamoe.mirai.console.command.CommandOwner +import net.mamoe.mirai.console.command.CompositeCommand import net.mamoe.mirai.console.command.description.buildCommandArgumentContext +import net.mamoe.mirai.console.permission.ExperimentalPermission +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.console.util.ConsoleExperimentalAPI /** @@ -64,16 +69,17 @@ import net.mamoe.mirai.console.util.ConsoleExperimentalAPI * @see buildCommandArgumentContext */ @ConsoleExperimentalAPI -public abstract class JCompositeCommand( +public abstract class JCompositeCommand @JvmOverloads constructor( owner: CommandOwner, - vararg names: String -) : CompositeCommand(owner, *names) { + vararg names: String, + basePermission: PermissionId? = null, +) : CompositeCommand(owner, *names, basePermission = basePermission) { /** 指令描述, 用于显示在 [BuiltInCommands.Help] */ public final override var description: String = "" protected set - /** 指令权限 */ - public final override var permission: CommandPermission = CommandPermission.Default + @OptIn(ExperimentalPermission::class) + public final override var permission: net.mamoe.mirai.console.permission.Permission = super.permission protected set /** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JRawCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JRawCommand.kt index d3b3fb87a..f53daf865 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JRawCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JRawCommand.kt @@ -13,6 +13,9 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import net.mamoe.mirai.console.command.* import net.mamoe.mirai.console.command.CommandManager.INSTANCE.execute +import net.mamoe.mirai.console.internal.command.createCommandPermission +import net.mamoe.mirai.console.permission.Permission +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.message.data.SingleMessage @@ -42,14 +45,15 @@ import net.mamoe.mirai.message.data.SingleMessage * * @see JRawCommand */ -public abstract class JRawCommand( +public abstract class JRawCommand @JvmOverloads constructor( /** * 指令拥有者. * @see CommandOwner */ public override val owner: CommandOwner, /** 指令名. 需要至少有一个元素. 所有元素都不能带有空格 */ - public override vararg val names: String + public override vararg val names: String, + basePermission: PermissionId? = null, ) : Command { /** 用法说明, 用于发送给用户 */ public override var usage: String = "" @@ -60,7 +64,7 @@ public abstract class JRawCommand( protected set /** 指令权限 */ - public final override var permission: CommandPermission = CommandPermission.Default + public final override var permission: Permission = createCommandPermission(basePermission) protected set /** 为 `true` 时表示 [指令前缀][CommandManager.commandPrefix] 可选 */ diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JSimpleCommand.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JSimpleCommand.kt index 25d886a55..2f6ce1e4d 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JSimpleCommand.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/command/java/JSimpleCommand.kt @@ -12,9 +12,10 @@ package net.mamoe.mirai.console.command.java import net.mamoe.mirai.console.command.CommandManager import net.mamoe.mirai.console.command.CommandManager.INSTANCE.executeCommand import net.mamoe.mirai.console.command.CommandOwner -import net.mamoe.mirai.console.command.CommandPermission import net.mamoe.mirai.console.command.SimpleCommand import net.mamoe.mirai.console.command.description.CommandArgumentContext +import net.mamoe.mirai.console.permission.Permission +import net.mamoe.mirai.console.permission.PermissionId /** * Java 实现: @@ -41,11 +42,12 @@ import net.mamoe.mirai.console.command.description.CommandArgumentContext */ public abstract class JSimpleCommand( owner: CommandOwner, - vararg names: String -) : SimpleCommand(owner, *names) { + vararg names: String, + basePermission: PermissionId, +) : SimpleCommand(owner, *names, basePermission = basePermission) { public override var description: String = super.description protected set - public override var permission: CommandPermission = super.permission + public override var permission: Permission = super.permission protected set public override var prefixOptional: Boolean = super.prefixOptional protected set diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/AbstractExtensionPoint.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/AbstractExtensionPoint.kt index 81c93c68e..c9b0ca7bd 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/AbstractExtensionPoint.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/AbstractExtensionPoint.kt @@ -21,6 +21,9 @@ import kotlin.contracts.contract import kotlin.internal.LowPriorityInOverloadResolution import kotlin.reflect.KClass +/** + * 表示一个扩展点 + */ @ConsoleExperimentalAPI public open class AbstractExtensionPoint( @ConsoleExperimentalAPI @@ -38,7 +41,7 @@ public open class AbstractExtensionPoint( @Synchronized @ConsoleExperimentalAPI public fun registerExtension(plugin: Plugin, extension: T) { - require(plugin.isEnabled) { "Plugin $plugin must be enabled before registering an extension." } + // require(plugin.isEnabled) { "Plugin $plugin must be enabled before registering an extension." } instances.add(ExtensionRegistry(plugin, extension)) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/Extension.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/Extension.kt index 0c0250174..5eced7d95 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/Extension.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extension/Extension.kt @@ -13,9 +13,17 @@ import net.mamoe.mirai.console.extensions.PermissionServiceProvider import net.mamoe.mirai.console.extensions.PluginLoaderProvider import net.mamoe.mirai.console.util.ConsoleExperimentalAPI +/** + * 表示一个扩展. + * + * Console 许多不容易通过 + */ @ConsoleExperimentalAPI public interface Extension +/** + * 增加一些函数 (方法)的扩展 + */ @ConsoleExperimentalAPI public interface FunctionExtension : Extension diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PermissionServiceProvider.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PermissionServiceProvider.kt index b50eeefae..b0de62886 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PermissionServiceProvider.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PermissionServiceProvider.kt @@ -4,10 +4,13 @@ import net.mamoe.mirai.console.extension.AbstractExtensionPoint import net.mamoe.mirai.console.extension.SingletonExtension import net.mamoe.mirai.console.permission.ExperimentalPermission import net.mamoe.mirai.console.permission.PermissionService -import net.mamoe.mirai.console.util.ConsoleExperimentalAPI +/** + * [权限服务][PermissionService] 提供器. + * + * 此扩展 + */ @ExperimentalPermission -@ConsoleExperimentalAPI public interface PermissionServiceProvider : SingletonExtension> { public companion object ExtensionPoint : AbstractExtensionPoint(PermissionServiceProvider::class) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PostStartupExtension.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PostStartupExtension.kt index 1e8508f6d..ee8a97f45 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PostStartupExtension.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/extensions/PostStartupExtension.kt @@ -12,7 +12,15 @@ package net.mamoe.mirai.console.extensions import net.mamoe.mirai.console.extension.AbstractExtensionPoint import net.mamoe.mirai.console.extension.FunctionExtension +/** + * 在 Console 启动完成后立即在主线程调用的扩展. 用于进行一些必要的延迟初始化. + * + * 这些扩展只会, 且一定会被调用正好一次. + */ public fun interface PostStartupExtension : FunctionExtension { + /** + * 将在 Console 主线程执行. + */ public operator fun invoke() public companion object ExtensionPoint : AbstractExtensionPoint(PostStartupExtension::class) 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 c92678565..e90654632 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 @@ -34,8 +34,8 @@ import net.mamoe.mirai.console.internal.data.builtins.ConsoleDataScope import net.mamoe.mirai.console.internal.plugin.CuiPluginCenter import net.mamoe.mirai.console.internal.plugin.PluginManagerImpl import net.mamoe.mirai.console.permission.ExperimentalPermission -import net.mamoe.mirai.console.permission.HotDeploymentSupportPermissionService import net.mamoe.mirai.console.permission.PermissionService +import net.mamoe.mirai.console.permission.StorablePermissionService import net.mamoe.mirai.console.plugin.PluginLoader import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.center.PluginCenter @@ -102,23 +102,27 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI Bot.botInstances.forEach { kotlin.runCatching { it.close() }.exceptionOrNull()?.let(mainLogger::error) } } - mainLogger.info { "Reloading configurations..." } + mainLogger.verbose { "Loading configurations..." } ConsoleDataScope.reloadAll() - PermissionService // init - if (PermissionService.INSTANCE is HotDeploymentSupportPermissionService<*>) { - + mainLogger.verbose { "Loading PermissionService..." } + PermissionService.INSTANCE.let { ps -> + if (ps is StorablePermissionService<*>) { + ConsoleDataScope.addAndReloadConfig(ps.config) + mainLogger.verbose { "Reloaded PermissionService settings." } + } } + mainLogger.verbose { "Loading built-in commands..." } BuiltInCommands.registerAll() - mainLogger.info { "Prepared built-in commands: ${BuiltInCommands.all.joinToString { it.primaryName }}" } + mainLogger.verbose { "Prepared built-in commands: ${BuiltInCommands.all.joinToString { it.primaryName }}" } CommandManager CommandManagerImpl.commandListener // start - mainLogger.info { "Loading plugins..." } + mainLogger.verbose { "Loading plugins..." } PluginManager PluginManagerImpl.loadEnablePlugins() - mainLogger.info { "${PluginManager.plugins.size} plugin(s) loaded." } + mainLogger.verbose { "${PluginManager.plugins.size} plugin(s) loaded." } mainLogger.info { "mirai-console started successfully." } runBlocking { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CommandPermissionImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CommandPermissionImpl.kt deleted file mode 100644 index 8c98125fb..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CommandPermissionImpl.kt +++ /dev/null @@ -1,32 +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 - */ - -package net.mamoe.mirai.console.internal.command - -import net.mamoe.mirai.console.command.CommandPermission -import net.mamoe.mirai.console.command.CommandSender -import net.mamoe.mirai.console.command.hasPermission - -internal class OrCommandPermissionImpl( - private val first: CommandPermission, - private val second: CommandPermission -) : CommandPermission { - override fun CommandSender.hasPermission(): Boolean { - return this.hasPermission(first) || this.hasPermission(second) - } -} - -internal class AndCommandPermissionImpl( - private val first: CommandPermission, - private val second: CommandPermission -) : CommandPermission { - override fun CommandSender.hasPermission(): Boolean { - return this.hasPermission(first) && this.hasPermission(second) - } -} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CompositeCommandInternal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CompositeCommandInternal.kt index e0c5b78b5..cda7b6fd4 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CompositeCommandInternal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/CompositeCommandInternal.kt @@ -16,11 +16,15 @@ import net.mamoe.mirai.console.command.Command.Companion.primaryName import net.mamoe.mirai.console.command.description.CommandArgumentContext import net.mamoe.mirai.console.command.description.CommandArgumentContextAware import net.mamoe.mirai.console.internal.data.kClassQualifiedNameOrTip +import net.mamoe.mirai.console.permission.* import net.mamoe.mirai.message.data.* import kotlin.reflect.KAnnotatedElement import kotlin.reflect.KClass import kotlin.reflect.KFunction -import kotlin.reflect.full.* +import kotlin.reflect.full.callSuspend +import kotlin.reflect.full.declaredFunctions +import kotlin.reflect.full.findAnnotation +import kotlin.reflect.full.isSubclassOf internal object CompositeCommandSubCommandAnnotationResolver : AbstractReflectionCommand.SubCommandAnnotationResolver { @@ -44,13 +48,13 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor( owner: CommandOwner, names: Array, description: String = "", - permission: CommandPermission = CommandPermission.Default, + basePermission: PermissionId? = null, prefixOptional: Boolean = false ) : Command, AbstractCommand( owner, names = names, description = description, - permission = permission, + basePermission = basePermission, prefixOptional = prefixOptional ), CommandArgumentContextAware { internal abstract val subCommandAnnotationResolver: SubCommandAnnotationResolver @@ -70,7 +74,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor( internal val defaultSubCommand: DefaultSubCommandDescriptor by lazy { DefaultSubCommandDescriptor( "", - permission, + createCommandPermission(basePermission), onCommand = { sender: CommandSender, args: MessageChain -> sender.onDefault(args) } @@ -115,7 +119,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor( internal class DefaultSubCommandDescriptor( val description: String, - val permission: CommandPermission, + val permission: Permission, val onCommand: suspend (sender: CommandSender, rawArgs: MessageChain) -> Unit ) @@ -123,7 +127,7 @@ internal abstract class AbstractReflectionCommand @JvmOverloads constructor( val names: Array, val params: Array>, val description: String, - val permission: CommandPermission, + val permission: Permission, val onCommand: suspend (sender: CommandSender, parsedArgs: Array) -> Boolean, val context: CommandArgumentContext ) { @@ -209,10 +213,6 @@ internal fun Any.flattenCommandComponents(): MessageChain = buildMessageChain { internal inline fun KAnnotatedElement.hasAnnotation(): Boolean = findAnnotation() != null -internal inline fun KClass.getInstance(): T { - return this.objectInstance ?: this.createInstance() -} - internal val KClass<*>.qualifiedNameOrTip: String get() = this.qualifiedName ?: "" internal fun Array.createUsage(baseCommand: AbstractReflectionCommand): String = @@ -246,6 +246,7 @@ internal fun AbstractReflectionCommand.SubCommandDescriptor.createUsage(baseComm appendLine() }.trimEnd() +@OptIn(ExperimentalPermission::class) internal fun AbstractReflectionCommand.createSubCommand( function: KFunction<*>, context: CommandArgumentContext @@ -322,8 +323,8 @@ internal fun AbstractReflectionCommand.createSubCommand( return SubCommandDescriptor( commandName, params, - subDescription, - overridePermission?.value?.getInstance() ?: permission, + subDescription, // overridePermission?.value + overridePermission?.value?.let { PermissionService.INSTANCE[PermissionId.parseFromString(it)] } ?: permission, onCommand = { sender: CommandSender, args: Array -> val result = if (notStatic) { if (hasSenderParam) { diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt index cd8ef90a9..f89fc1731 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/command/internal.kt @@ -10,6 +10,8 @@ package net.mamoe.mirai.console.internal.command import net.mamoe.mirai.console.command.* +import net.mamoe.mirai.console.command.Command.Companion.primaryName +import net.mamoe.mirai.console.permission.* import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.message.data.MessageChain @@ -136,12 +138,17 @@ internal fun Group.fuzzySearchMember( } } +@OptIn(ExperimentalPermission::class) +internal fun Command.createCommandPermission(basePermission: PermissionId?): Permission { + return PermissionService.INSTANCE.register(owner.permissionId(primaryName), description, basePermission) +} //// internal @JvmSynthetic internal inline fun List.dropToTypedArray(n: Int): Array = Array(size - n) { this[n + it] } +@OptIn(ExperimentalPermission::class) @JvmSynthetic @Throws(CommandExecutionException::class) internal suspend fun CommandSender.executeCommandInternal( @@ -150,7 +157,7 @@ internal suspend fun CommandSender.executeCommandInternal( commandName: String, checkPermission: Boolean ): CommandExecuteResult { - if (checkPermission && !command.testPermission(this)) { + if (checkPermission && !command.permission.testPermission(this)) { return CommandExecuteResult.PermissionDenied(command, commandName) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtins/ConsoleDataScope.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtins/ConsoleDataScope.kt index 177dd533d..37899e3d5 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtins/ConsoleDataScope.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/data/builtins/ConsoleDataScope.kt @@ -21,8 +21,13 @@ 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, AutoLoginConfig) + private val data: List = mutableListOf() + private val configs: MutableList = mutableListOf(ManagersConfig, AutoLoginConfig) + + fun addAndReloadConfig(config: PluginConfig) { + configs.add(config) + ConsoleBuiltInPluginConfigStorage.load(ConsoleBuiltInPluginConfigHolder, config) + } fun reloadAll() { data.forEach { dt -> diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/permission/PermissionServiceImpl.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/permission/PermissionServiceImpl.kt deleted file mode 100644 index 1155d9fbe..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/permission/PermissionServiceImpl.kt +++ /dev/null @@ -1,101 +0,0 @@ -package net.mamoe.mirai.console.internal.permission - -import net.mamoe.mirai.console.command.ConsoleCommandSender -import net.mamoe.mirai.console.command.UserCommandSender -import net.mamoe.mirai.console.data.AutoSavePluginConfig -import net.mamoe.mirai.console.data.PluginDataExtensions.withEmptyDefault -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 java.util.concurrent.ConcurrentHashMap -import kotlin.reflect.KClass - -/** - * [PermissionServiceProvider] - */ -@Suppress("RedundantVisibilityModifier") -@ExperimentalPermission -internal abstract class AbstractPermissionService : - PermissionService { - protected abstract val Permissible.identifier: TPermissibleIdentifier - - @JvmField - protected val permissions: MutableMap = ConcurrentHashMap() - - @JvmField - protected val grantedPermissionMap: MutableMap> = - ConcurrentHashMap() - - public override fun getGrantedPermissions(permissible: Permissible): Sequence = - grantedPermissionMap[permissible.identifier]?.asSequence()?.mapNotNull { get(it) }.orEmpty() - - public override operator fun get(identifier: PermissionIdentifier): TPermission? = permissions[identifier] - - public override fun testPermission(permissible: Permissible, permission: TPermission): Boolean = - permissible.getGrantedPermissions().any { it == permission } -} - -/** - * [PermissionServiceProvider] - */ -@Suppress("RedundantVisibilityModifier") -@ExperimentalPermission -internal abstract class AbstractHotDeploymentSupportPermissionService : - PermissionService, - HotDeploymentSupportPermissionService, AutoSavePluginConfig() { - - protected abstract val Permissible.identifier: TPermissibleIdentifier - - @JvmField - protected val permissions: MutableMap = ConcurrentHashMap() - - @JvmField - protected val grantedPermissionMap: Value>> = - value>>().withEmptyDefault() - - public override fun getGrantedPermissions(permissible: Permissible): Sequence = - grantedPermissionMap.value[permissible.identifier]?.asSequence()?.mapNotNull { get(it) }.orEmpty() - - public override operator fun get(identifier: PermissionIdentifier): TPermission? = permissions[identifier] - - public override fun testPermission(permissible: Permissible, permission: TPermission): Boolean = - permissible.getGrantedPermissions().any { it == permission } -} - - -internal data class LiteralPermissibleIdentifier( - val context: String, - val value: String -) - -@OptIn(ExperimentalPermission::class) -private object PermissionServiceImpl : - AbstractHotDeploymentSupportPermissionService() { - - override fun register( - identifier: PermissionIdentifier, - description: String, - base: PermissionIdentifier? - ): PermissionImpl = PermissionImpl(identifier, description, base) - - override fun grant(permissible: Permissible, permission: PermissionImpl) { - grantedPermissionMap.value[permissible.identifier]!!.add(permission.identifier) - } - - override fun deny(permissible: Permissible, permission: PermissionImpl) { - grantedPermissionMap.value[permissible.identifier]!!.remove(permission.identifier) - } - - override val permissionType: KClass - get() = PermissionImpl::class - override val Permissible.identifier: LiteralPermissibleIdentifier - get() = LiteralPermissibleIdentifier( - "", - when (this) { - is ConsoleCommandSender -> "CONSOLE" - is UserCommandSender -> this.user.id.toString() - else -> "" - } - ) -} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt index f4181039a..05c7f5127 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/internal/plugin/JvmPluginInternal.kt @@ -16,7 +16,7 @@ import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.data.runCatchingLog import net.mamoe.mirai.console.internal.data.mkdir import net.mamoe.mirai.console.permission.ExperimentalPermission -import net.mamoe.mirai.console.permission.PermissionIdentifier +import net.mamoe.mirai.console.permission.PermissionId import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.PluginManager import net.mamoe.mirai.console.plugin.PluginManager.INSTANCE.safeLoader @@ -47,8 +47,8 @@ internal abstract class JvmPluginInternal( resourceContainerDelegate.getResourceAsStream(path) @OptIn(ExperimentalPermission::class) - override fun permissionIdentifier(identifierString: String): PermissionIdentifier { - return PermissionIdentifier(description.name, identifierString) + override fun permissionId(id: String): PermissionId { + return PermissionId(description.name, id) } // region JvmPlugin diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt index 464e7a4f6..aa4a36d70 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/BuiltInPermissionServices.kt @@ -9,50 +9,85 @@ package net.mamoe.mirai.console.permission +import net.mamoe.mirai.console.data.AutoSavePluginConfig import java.util.concurrent.ConcurrentHashMap import kotlin.reflect.KClass +import kotlin.reflect.full.createType @ExperimentalPermission public object AllGrantPermissionService : PermissionService { - private val all = ConcurrentHashMap() + private val all = ConcurrentHashMap() override val permissionType: KClass get() = PermissionImpl::class override fun register( - identifier: PermissionIdentifier, + id: PermissionId, description: String, - base: PermissionIdentifier? + base: PermissionId? ): PermissionImpl { - val new = PermissionImpl(identifier, description, base) - if (all.putIfAbsent(identifier, new) != null) { - throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}") + val new = PermissionImpl(id, description, base) + if (all.putIfAbsent(id, new) != null) { + throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[id]}") } return new } - override fun get(identifier: PermissionIdentifier): PermissionImpl? = all[identifier] + override fun get(id: PermissionId): PermissionImpl? = all[id] override fun getGrantedPermissions(permissible: Permissible): Sequence = all.values.asSequence() + override fun grant(permissibleIdentifier: PermissibleIdentifier, permission: PermissionImpl) { + } + + override fun testPermission(permissible: Permissible, permission: PermissionImpl): Boolean = true + override fun deny(permissibleIdentifier: PermissibleIdentifier, permission: PermissionImpl) { + } } @ExperimentalPermission public object AllDenyPermissionService : PermissionService { - private val all = ConcurrentHashMap() + private val all = ConcurrentHashMap() override val permissionType: KClass get() = PermissionImpl::class override fun register( - identifier: PermissionIdentifier, + id: PermissionId, description: String, - base: PermissionIdentifier? + base: PermissionId? ): PermissionImpl { - val new = PermissionImpl(identifier, description, base) - if (all.putIfAbsent(identifier, new) != null) { - throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}") + val new = PermissionImpl(id, description, base) + if (all.putIfAbsent(id, new) != null) { + throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[id]}") } return new } - override fun get(identifier: PermissionIdentifier): PermissionImpl? = all[identifier] + override fun get(id: PermissionId): PermissionImpl? = all[id] override fun getGrantedPermissions(permissible: Permissible): Sequence = emptySequence() + override fun grant(permissibleIdentifier: PermissibleIdentifier, permission: PermissionImpl) { + } + + override fun testPermission(permissible: Permissible, permission: PermissionImpl): Boolean = false + override fun deny(permissibleIdentifier: PermissibleIdentifier, permission: PermissionImpl) { + } } + +@ExperimentalPermission +internal object BuiltInPermissionService : AbstractConcurrentPermissionService(), + StorablePermissionService { + + @ExperimentalPermission + override val permissionType: KClass + get() = PermissionImpl::class + override val permissions: MutableMap get() = config.permissions + override val grantedPermissionsMap: MutableMap> get() = config.grantedPermissionMap + + override fun createPermission(id: PermissionId, description: String, base: PermissionId?): PermissionImpl = + PermissionImpl(id, description, base) + + override val config: StorablePermissionService.ConcurrentSaveData = + StorablePermissionService.ConcurrentSaveData( + PermissionImpl::class.createType(), + "PermissionService", + AutoSavePluginConfig() + ) +} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/HotDeploymentSupportPermissionService.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/HotDeploymentSupportPermissionService.kt deleted file mode 100644 index 607989ece..000000000 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/HotDeploymentSupportPermissionService.kt +++ /dev/null @@ -1,17 +0,0 @@ -/* - * 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.permission - - -@ExperimentalPermission -public interface HotDeploymentSupportPermissionService

: PermissionService

{ - public fun grant(permissible: Permissible, permission: P) - public fun deny(permissible: Permissible, permission: P) -} \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permissible.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permissible.kt index f0c1f6383..3b5c53b4e 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permissible.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permissible.kt @@ -7,21 +7,88 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("NOTHING_TO_INLINE", "unused") +@file:Suppress("NOTHING_TO_INLINE", "unused", "MemberVisibilityCanBePrivate") package net.mamoe.mirai.console.permission +import net.mamoe.mirai.console.command.CommandSender + /** + * 可拥有权限的对象. + * + * 典型的实例为 [CommandSender] * * 注意: 请不要自主实现 [Permissible] + * + * @see CommandSender */ @ExperimentalPermission -public interface Permissible +public interface Permissible { + public val identifier: PermissibleIdentifier +} + + +@ExperimentalPermission("Classname is subject to change") +public interface PermissibleIdentifier { + public val parents: Array + + public companion object { + @ExperimentalPermission + public infix fun PermissibleIdentifier.grantedWith(with: PermissibleIdentifier): Boolean { + return allParentsWithSelf().any { it == with } + } + + internal fun PermissibleIdentifier.allParentsWithSelf(): Sequence { + return sequence { + yield(this@allParentsWithSelf) + yieldAll(parents.asSequence()) + } + } + } +} + +/** + * + */ +@ExperimentalPermission +public sealed class AbstractPermissibleIdentifier( + public final override vararg val parents: PermissibleIdentifier +) : PermissibleIdentifier { + public object AnyGroup : AbstractPermissibleIdentifier(AnyContact) + public data class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup) + + public data class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup) + public object AnyMemberFromAnyGroup : AbstractPermissibleIdentifier(AnyUser) + public data class ExactMember( + public val groupId: Long, + public val memberId: Long + ) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId)) + + public object AnyFriend : AbstractPermissibleIdentifier(AnyUser) + public data class ExactFriend( + public val id: Long + ) : AbstractPermissibleIdentifier(ExactUser(id)) + + public object AnyTemp : AbstractPermissibleIdentifier(AnyUser) + public data class ExactTemp( + public val groupId: Long, + public val id: Long + ) : AbstractPermissibleIdentifier(ExactUser(groupId)) // TODO: 2020/9/8 ExactMember ? + + public object AnyUser : AbstractPermissibleIdentifier(AnyContact) + public data class ExactUser( + public val id: Long + ) : AbstractPermissibleIdentifier(AnyUser) + + public object AnyContact : AbstractPermissibleIdentifier() + + public object Console : AbstractPermissibleIdentifier() +} @ExperimentalPermission public inline fun Permissible.hasPermission(permission: Permission): Boolean = PermissionService.run { permission.testPermission(this@hasPermission) } @ExperimentalPermission -public inline fun Permissible.hasPermission(permission: PermissionIdentifier): Boolean = +public inline fun Permissible.hasPermission(permission: PermissionId): Boolean = PermissionService.run { permission.testPermission(this@hasPermission) } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permission.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permission.kt index 4d1a3ff88..f687376cb 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permission.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/Permission.kt @@ -9,23 +9,26 @@ package net.mamoe.mirai.console.permission +import kotlinx.serialization.Serializable + /** * 一个权限节点 */ @ExperimentalPermission public interface Permission { - public val identifier: PermissionIdentifier + public val id: PermissionId public val description: String - public val base: PermissionIdentifier? + public val base: PermissionId? } /** * [Permission] 的简单实现 */ +@Serializable @ExperimentalPermission -public open class PermissionImpl( - override val identifier: PermissionIdentifier, +public class PermissionImpl( + override val id: PermissionId, override val description: String, - override val base: PermissionIdentifier? + override val base: PermissionId? ) : Permission \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionGroup.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionGroup.kt index e898d0c07..115d76175 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionGroup.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionGroup.kt @@ -14,7 +14,7 @@ import kotlin.reflect.KProperty @ExperimentalPermission public abstract class PermissionGroup( - private val identifierNamespace: PermissionIdentifierNamespace, + private val idNamespace: PermissionIdNamespace, ) { @ExperimentalPermission public inner class PermissionBuilder { @@ -22,30 +22,30 @@ public abstract class PermissionGroup( internal var description: String = "" @JvmField - internal var basePermission: PermissionIdentifier? = null + internal var basePermission: PermissionId? = null @JvmField internal var permissionChecker: PermissionChecker? = null public fun description(description: String): PermissionBuilder = apply { this.description = description } - public fun dependsOn(basePermission: PermissionIdentifier?): PermissionBuilder = + public fun dependsOn(basePermission: PermissionId?): PermissionBuilder = apply { this.basePermission = basePermission } public fun dependsOn(basePermission: Permission?): PermissionBuilder = - apply { this.basePermission = basePermission?.identifier } + apply { this.basePermission = basePermission?.id } - public fun basePermission(basePermission: PermissionIdentifier?): PermissionBuilder = + public fun basePermission(basePermission: PermissionId?): PermissionBuilder = apply { this.basePermission = basePermission } public fun basePermission(basePermission: Permission?): PermissionBuilder = - apply { this.basePermission = basePermission?.identifier } + apply { this.basePermission = basePermission?.id } public fun defaults(permissionChecker: PermissionChecker?): PermissionBuilder = apply { this.permissionChecker = permissionChecker } public fun build(property: KProperty<*>): Permission { return PermissionService.INSTANCE.register( - identifierNamespace.permissionIdentifier(property.name), + idNamespace.permissionId(property.name), description, basePermission ) diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionIdentifier.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionId.kt similarity index 61% rename from backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionIdentifier.kt rename to backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionId.kt index b9d7b8d25..a71b29924 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionIdentifier.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionId.kt @@ -10,13 +10,15 @@ package net.mamoe.mirai.console.permission import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable import kotlinx.serialization.Serializer import kotlinx.serialization.builtins.serializer import net.mamoe.mirai.console.internal.data.map +@Serializable @ExperimentalPermission -public data class PermissionIdentifier( +public data class PermissionId( public val namespace: String, public val id: String ) { @@ -29,17 +31,26 @@ public data class PermissionIdentifier( } } - @Serializer(forClass = PermissionIdentifier::class) + @Serializer(forClass = PermissionId::class) public object AsClassSerializer - public object AsStringSerializer : KSerializer by String.serializer().map( + public object AsStringSerializer : KSerializer by String.serializer().map( serializer = { it.namespace + ":" + it.id }, - deserializer = { it.split(':').let { (namespace, id) -> PermissionIdentifier(namespace, id) } } + deserializer = ::parseFromString ) + + public override fun toString(): String { + return "$namespace:$id" + } + + public companion object { + public fun parseFromString(string: String): PermissionId = + string.split(':').let { (namespace, id) -> PermissionId(namespace, id) } + } } @ExperimentalPermission -public interface PermissionIdentifierNamespace { +public interface PermissionIdNamespace { @ExperimentalPermission - public fun permissionIdentifier(identifierString: String): PermissionIdentifier + public fun permissionId(id: String): PermissionId } diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt index 645a50797..bce73ddfc 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/PermissionService.kt @@ -12,7 +12,8 @@ package net.mamoe.mirai.console.permission import net.mamoe.mirai.console.extensions.PermissionServiceProvider -import java.util.concurrent.ConcurrentHashMap +import net.mamoe.mirai.console.permission.PermissibleIdentifier.Companion.grantedWith +import java.util.concurrent.CopyOnWriteArrayList import kotlin.reflect.KClass /** @@ -23,23 +24,32 @@ public interface PermissionService

{ @ExperimentalPermission public val permissionType: KClass

- @Throws(DuplicatedRegistrationException::class) - public fun register( - identifier: PermissionIdentifier, - description: String, - base: PermissionIdentifier? = null - ): P + /////////////////////////////////////////////////////////////////////////// - public operator fun get(identifier: PermissionIdentifier): P? + public operator fun get(id: PermissionId): P? public fun getGrantedPermissions(permissible: Permissible): Sequence

- public fun testPermission(permissible: Permissible, permission: P): Boolean = permissible.getGrantedPermissions().any { it == permission } + + /////////////////////////////////////////////////////////////////////////// + + @Throws(DuplicatedRegistrationException::class) + public fun register( + id: PermissionId, + description: String, + base: PermissionId? = null + ): P + + /////////////////////////////////////////////////////////////////////////// + + public fun grant(permissibleIdentifier: PermissibleIdentifier, permission: P) + public fun deny(permissibleIdentifier: PermissibleIdentifier, permission: P) + public companion object { - private val builtIn: PermissionService get() = AllGrantPermissionService + private val builtIn: PermissionService get() = BuiltInPermissionService @get:JvmName("getInstance") @JvmStatic @@ -51,29 +61,48 @@ public interface PermissionService

{ } @ExperimentalPermission -public abstract class AbstractPermissionService

: PermissionService

{ - protected val all: MutableMap = ConcurrentHashMap() +public abstract class AbstractConcurrentPermissionService

: PermissionService

{ + protected abstract val permissions: MutableMap + protected abstract val grantedPermissionsMap: MutableMap> protected abstract fun createPermission( - identifier: PermissionIdentifier, + id: PermissionId, description: String, - base: PermissionIdentifier? + base: PermissionId? ): P - override fun register( - identifier: PermissionIdentifier, - description: String, - base: PermissionIdentifier? - ): P { - val new = createPermission(identifier, description, base) - if (all.putIfAbsent(identifier, new) != null) { - throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}") + override fun get(id: PermissionId): P? = permissions[id] + + override fun register(id: PermissionId, description: String, base: PermissionId?): P { + grantedPermissionsMap[id] = CopyOnWriteArrayList() // mutations are not quite often performed + val instance = createPermission(id, description, base) + if (permissions.putIfAbsent(id, instance) != null) { + throw DuplicatedRegistrationException("Duplicated Permission registry. new: $instance, old: ${permissions[id]}") } - return new + return instance } - override fun get(identifier: PermissionIdentifier): P? = all[identifier] - override fun getGrantedPermissions(permissible: Permissible): Sequence

= all.values.asSequence() + override fun grant(permissibleIdentifier: PermissibleIdentifier, permission: P) { + val id = permission.id + grantedPermissionsMap[id]?.add(permissibleIdentifier) + ?: error("Bad PermissionService implementation: grantedPermissionsMap[id] is null.") + } + + override fun deny(permissibleIdentifier: PermissibleIdentifier, permission: P) { + grantedPermissionsMap[permission.id]?.remove(permissibleIdentifier) + } + + public override fun getGrantedPermissions(permissible: Permissible): Sequence

= sequence

{ + for ((permissionIdentifier, permissibleIdentifiers) in grantedPermissionsMap) { + val myIdentifier = permissible.identifier + + val granted = + if (permissibleIdentifiers.isEmpty()) false + else permissibleIdentifiers.any { myIdentifier grantedWith it } + + if (granted) get(permissionIdentifier)?.let { yield(it) } + } + } } @ExperimentalPermission @@ -98,7 +127,7 @@ public inline fun Permission.testPermission(permissible: Permissible): Boolean = } @ExperimentalPermission -public inline fun PermissionIdentifier.testPermission(permissible: Permissible): Boolean { +public inline fun PermissionId.testPermission(permissible: Permissible): Boolean { val p = PermissionService.INSTANCE[this] ?: return false return p.testPermission(permissible) } \ No newline at end of file diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/StorablePermissionService.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/StorablePermissionService.kt new file mode 100644 index 000000000..f0b37efba --- /dev/null +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/permission/StorablePermissionService.kt @@ -0,0 +1,52 @@ +package net.mamoe.mirai.console.permission + +import net.mamoe.mirai.console.data.PluginConfig +import net.mamoe.mirai.console.data.PluginDataExtensions.withDefault +import net.mamoe.mirai.console.data.value +import net.mamoe.mirai.console.data.valueFromKType +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList +import kotlin.reflect.KType +import kotlin.reflect.KTypeProjection +import kotlin.reflect.KVariance +import kotlin.reflect.full.createType + +@ExperimentalPermission +public interface StorablePermissionService

: PermissionService

{ + /** + * The config to be stored + */ + public val config: PluginConfig + + @ExperimentalPermission + public class ConcurrentSaveData

private constructor( + permissionType: KType, + public override val saveName: String, + delegate: PluginConfig, + @Suppress("UNUSED_PARAMETER") primaryConstructorMark: Any? + ) : PluginConfig by delegate { + public val permissions: MutableMap + by valueFromKType>( + MutableMap::class.createType( + listOf( + KTypeProjection(KVariance.INVARIANT, PermissionId::class.createType()), + KTypeProjection(KVariance.INVARIANT, permissionType), + ) + ), + ConcurrentHashMap() + ) + + public val grantedPermissionMap: MutableMap> + by value>>(ConcurrentHashMap()) + .withDefault { CopyOnWriteArrayList() } + + public companion object { + @JvmStatic + public operator fun

invoke( + permissionType: KType, + saveName: String, + delegate: PluginConfig, + ): ConcurrentSaveData

= ConcurrentSaveData(permissionType, saveName, delegate, null) + } + } +} diff --git a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt index 82ba0b863..b6ce680a7 100644 --- a/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt +++ b/backend/mirai-console/src/main/kotlin/net/mamoe/mirai/console/plugin/jvm/JvmPlugin.kt @@ -22,7 +22,7 @@ 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.permission.ExperimentalPermission -import net.mamoe.mirai.console.permission.PermissionIdentifierNamespace +import net.mamoe.mirai.console.permission.PermissionIdNamespace import net.mamoe.mirai.console.plugin.Plugin import net.mamoe.mirai.console.plugin.PluginFileExtensions import net.mamoe.mirai.console.plugin.ResourceContainer @@ -45,7 +45,7 @@ import net.mamoe.mirai.utils.MiraiLogger */ @OptIn(ExperimentalPermission::class) public interface JvmPlugin : Plugin, CoroutineScope, - PluginFileExtensions, ResourceContainer, AutoSavePluginDataHolder, PermissionIdentifierNamespace { + PluginFileExtensions, ResourceContainer, AutoSavePluginDataHolder, PermissionIdNamespace { /** 日志 */ public val logger: MiraiLogger diff --git a/frontend/mirai-console-pure/build.gradle.kts b/frontend/mirai-console-pure/build.gradle.kts index 9f9428196..3639b0a7b 100644 --- a/frontend/mirai-console-pure/build.gradle.kts +++ b/frontend/mirai-console-pure/build.gradle.kts @@ -1,7 +1,6 @@ plugins { kotlin("jvm") kotlin("plugin.serialization") - kotlin("kapt") id("java") `maven-publish` id("com.jfrog.bintray") @@ -46,10 +45,10 @@ dependencies { testApi(project(":mirai-console")) - val autoService = "1.0-rc7" - kapt("com.google.auto.service", "auto-service", autoService) - compileOnly("com.google.auto.service", "auto-service-annotations", autoService) - testCompileOnly("com.google.auto.service", "auto-service-annotations", autoService) +// val autoService = "1.0-rc7" +// kapt("com.google.auto.service", "auto-service", autoService) +// compileOnly("com.google.auto.service", "auto-service-annotations", autoService) +// testCompileOnly("com.google.auto.service", "auto-service-annotations", autoService) } ext.apply {