Permissions

This commit is contained in:
Him188 2020-09-07 21:59:15 +08:00
parent 8e3e328672
commit 1f9705deaf
13 changed files with 245 additions and 189 deletions

View File

@ -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<Friend> = 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(user.id, group.id)
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): MessageReceipt<Group> = sendMessage(PlainText(message))
@ -647,6 +658,9 @@ public open class TempCommandSender internal constructor(
public override val subject: Contact get() = group
public override fun toString(): String = "TempCommandSender($user)"
@ExperimentalPermission
override val identifier: PermissibleIdentifier = AbstractPermissibleIdentifier.ExactTemp(user.id)
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): MessageReceipt<Member> = sendMessage(PlainText(message))

View File

@ -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 {

View File

@ -21,8 +21,13 @@ import net.mamoe.mirai.utils.minutesToMillis
internal object ConsoleDataScope : CoroutineScope by MiraiConsole.childScope("ConsoleDataScope") {
private val data: Array<out PluginData> = arrayOf()
private val configs: Array<out PluginConfig> = arrayOf(ManagersConfig, AutoLoginConfig)
private val data: List<PluginData> = mutableListOf()
private val configs: MutableList<PluginConfig> = mutableListOf(ManagersConfig, AutoLoginConfig)
fun addAndReloadConfig(config: PluginConfig) {
configs.add(config)
ConsoleBuiltInPluginConfigStorage.load(ConsoleBuiltInPluginConfigHolder, config)
}
fun reloadAll() {
data.forEach { dt ->

View File

@ -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<TPermission : Permission, TPermissibleIdentifier> :
PermissionService<TPermission> {
protected abstract val Permissible.identifier: TPermissibleIdentifier
@JvmField
protected val permissions: MutableMap<PermissionIdentifier, TPermission> = ConcurrentHashMap()
@JvmField
protected val grantedPermissionMap: MutableMap<TPermissibleIdentifier, MutableList<PermissionIdentifier>> =
ConcurrentHashMap()
public override fun getGrantedPermissions(permissible: Permissible): Sequence<TPermission> =
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<TPermission : Permission, TPermissibleIdentifier> :
PermissionService<TPermission>,
HotDeploymentSupportPermissionService<TPermission>, AutoSavePluginConfig() {
protected abstract val Permissible.identifier: TPermissibleIdentifier
@JvmField
protected val permissions: MutableMap<PermissionIdentifier, TPermission> = ConcurrentHashMap()
@JvmField
protected val grantedPermissionMap: Value<MutableMap<TPermissibleIdentifier, MutableList<PermissionIdentifier>>> =
value<MutableMap<TPermissibleIdentifier, MutableList<PermissionIdentifier>>>().withEmptyDefault()
public override fun getGrantedPermissions(permissible: Permissible): Sequence<TPermission> =
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<PermissionImpl, LiteralPermissibleIdentifier>() {
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<PermissionImpl>
get() = PermissionImpl::class
override val Permissible.identifier: LiteralPermissibleIdentifier
get() = LiteralPermissibleIdentifier(
"",
when (this) {
is ConsoleCommandSender -> "CONSOLE"
is UserCommandSender -> this.user.id.toString()
else -> ""
}
)
}

View File

@ -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 permissionIdentifier(identifierString: String): PermissionId {
return PermissionId(description.name, identifierString)
}
// region JvmPlugin

View File

@ -9,50 +9,80 @@
package net.mamoe.mirai.console.permission
import net.mamoe.mirai.console.data.AutoSavePluginConfig
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KClass
@ExperimentalPermission
public object AllGrantPermissionService : PermissionService<PermissionImpl> {
private val all = ConcurrentHashMap<PermissionIdentifier, PermissionImpl>()
private val all = ConcurrentHashMap<PermissionId, PermissionImpl>()
override val permissionType: KClass<PermissionImpl>
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<PermissionImpl> = 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<PermissionImpl> {
private val all = ConcurrentHashMap<PermissionIdentifier, PermissionImpl>()
private val all = ConcurrentHashMap<PermissionId, PermissionImpl>()
override val permissionType: KClass<PermissionImpl>
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<PermissionImpl> = 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<PermissionImpl>(),
StorablePermissionService<PermissionImpl> {
@ExperimentalPermission
override val permissionType: KClass<PermissionImpl>
get() = PermissionImpl::class
override val permissions: MutableMap<PermissionId, PermissionImpl> get() = config.permissions
override val grantedPermissionsMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>> get() = config.grantedPermissionMap
override fun createPermission(id: PermissionId, description: String, base: PermissionId?): PermissionImpl =
PermissionImpl(id, description, base)
override val config: StorablePermissionService.ConcurrentSaveData<PermissionImpl> =
StorablePermissionService.ConcurrentSaveData("PermissionService", AutoSavePluginConfig())
}

View File

@ -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<P : Permission> : PermissionService<P> {
public fun grant(permissible: Permissible, permission: P)
public fun deny(permissible: Permissible, permission: P)
}

View File

@ -7,21 +7,87 @@
* 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<out PermissibleIdentifier>
public companion object {
@ExperimentalPermission
public infix fun PermissibleIdentifier.grantedWith(with: PermissibleIdentifier): Boolean {
return allParentsWithSelf().any { it == with }
}
internal fun PermissibleIdentifier.allParentsWithSelf(): Sequence<PermissibleIdentifier> {
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 class ExactGroup(public val groupId: Long) : AbstractPermissibleIdentifier(AnyGroup)
public class AnyMember(public val groupId: Long) : AbstractPermissibleIdentifier(AnyMemberFromAnyGroup)
public object AnyMemberFromAnyGroup : AbstractPermissibleIdentifier(AnyUser)
public class ExactMember(
public val groupId: Long,
public val memberId: Long
) : AbstractPermissibleIdentifier(AnyMember(groupId), ExactUser(memberId))
public object AnyFriend : AbstractPermissibleIdentifier(AnyUser)
public class ExactFriend(
public val id: Long
) : AbstractPermissibleIdentifier(ExactUser(id))
public object AnyTemp : AbstractPermissibleIdentifier(AnyUser)
public class ExactTemp(
public val id: Long
) : AbstractPermissibleIdentifier(ExactUser(id))
public object AnyUser : AbstractPermissibleIdentifier(AnyContact)
public 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) }

View File

@ -15,9 +15,9 @@ package net.mamoe.mirai.console.permission
*/
@ExperimentalPermission
public interface Permission {
public val identifier: PermissionIdentifier
public val id: PermissionId
public val description: String
public val base: PermissionIdentifier?
public val base: PermissionId?
}
/**
@ -25,7 +25,7 @@ public interface Permission {
*/
@ExperimentalPermission
public open class PermissionImpl(
override val identifier: PermissionIdentifier,
override val id: PermissionId,
override val description: String,
override val base: PermissionIdentifier?
override val base: PermissionId?
) : Permission

View File

@ -22,23 +22,23 @@ public abstract class PermissionGroup(
internal var description: String = "<no description given>"
@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 }

View File

@ -16,7 +16,7 @@ import net.mamoe.mirai.console.internal.data.map
@ExperimentalPermission
public data class PermissionIdentifier(
public data class PermissionId(
public val namespace: String,
public val id: String
) {
@ -29,17 +29,17 @@ public data class PermissionIdentifier(
}
}
@Serializer(forClass = PermissionIdentifier::class)
@Serializer(forClass = PermissionId::class)
public object AsClassSerializer
public object AsStringSerializer : KSerializer<PermissionIdentifier> by String.serializer().map(
public object AsStringSerializer : KSerializer<PermissionId> by String.serializer().map(
serializer = { it.namespace + ":" + it.id },
deserializer = { it.split(':').let { (namespace, id) -> PermissionIdentifier(namespace, id) } }
deserializer = { it.split(':').let { (namespace, id) -> PermissionId(namespace, id) } }
)
}
@ExperimentalPermission
public interface PermissionIdentifierNamespace {
@ExperimentalPermission
public fun permissionIdentifier(identifierString: String): PermissionIdentifier
public fun permissionIdentifier(identifierString: String): PermissionId
}

View File

@ -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<P : Permission> {
@ExperimentalPermission
public val permissionType: KClass<P>
@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<P>
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<out Permission> get() = AllGrantPermissionService
private val builtIn: PermissionService<out Permission> get() = BuiltInPermissionService
@get:JvmName("getInstance")
@JvmStatic
@ -51,29 +61,48 @@ public interface PermissionService<P : Permission> {
}
@ExperimentalPermission
public abstract class AbstractPermissionService<P : Permission> : PermissionService<P> {
protected val all: MutableMap<PermissionIdentifier, P> = ConcurrentHashMap<PermissionIdentifier, P>()
public abstract class AbstractConcurrentPermissionService<P : Permission> : PermissionService<P> {
protected abstract val permissions: MutableMap<PermissionId, P>
protected abstract val grantedPermissionsMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
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<P> = 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<P> = sequence<P> {
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)
}

View File

@ -0,0 +1,26 @@
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 java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.CopyOnWriteArrayList
@ExperimentalPermission
public interface StorablePermissionService<P : Permission> : PermissionService<P> {
/**
* The config to be stored
*/
public val config: PluginConfig
@ExperimentalPermission
public class ConcurrentSaveData<P : Permission>(
public override val saveName: String,
delegate: PluginConfig
) : PluginConfig by delegate {
public val permissions: MutableMap<PermissionId, P> by value<MutableMap<PermissionId, P>>(ConcurrentHashMap())
public val grantedPermissionMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>> by
value<MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>>(ConcurrentHashMap()).withDefault { CopyOnWriteArrayList() }
}
}