mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 18:40:15 +08:00
PermissionService fundamental
This commit is contained in:
parent
599c0b6d59
commit
8e3e328672
@ -161,10 +161,6 @@ public interface CommandSender : CoroutineScope, Permissible {
|
||||
*/
|
||||
public val name: String
|
||||
|
||||
@ExperimentalPermission
|
||||
override val identifier: String
|
||||
get() = user?.id?.toString() ?: bot?.id?.toString() ?: error("Internal error: bot user and bot are null")
|
||||
|
||||
/**
|
||||
* 立刻发送一条消息.
|
||||
*
|
||||
|
@ -33,6 +33,9 @@ import net.mamoe.mirai.console.internal.data.builtins.AutoLoginConfig
|
||||
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.plugin.PluginLoader
|
||||
import net.mamoe.mirai.console.plugin.PluginManager
|
||||
import net.mamoe.mirai.console.plugin.center.PluginCenter
|
||||
@ -80,7 +83,7 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
|
||||
override fun createLogger(identity: String?): MiraiLogger = instance.createLogger(identity)
|
||||
|
||||
@OptIn(ConsoleExperimentalAPI::class)
|
||||
@OptIn(ConsoleExperimentalAPI::class, ExperimentalPermission::class)
|
||||
internal fun doStart() {
|
||||
val buildDateFormatted =
|
||||
buildDate.atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
|
||||
@ -102,6 +105,11 @@ internal object MiraiConsoleImplementationBridge : CoroutineScope, MiraiConsoleI
|
||||
mainLogger.info { "Reloading configurations..." }
|
||||
ConsoleDataScope.reloadAll()
|
||||
|
||||
PermissionService // init
|
||||
if (PermissionService.INSTANCE is HotDeploymentSupportPermissionService<*>) {
|
||||
|
||||
}
|
||||
|
||||
BuiltInCommands.registerAll()
|
||||
mainLogger.info { "Prepared built-in commands: ${BuiltInCommands.all.joinToString { it.primaryName }}" }
|
||||
CommandManager
|
||||
|
@ -0,0 +1,101 @@
|
||||
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 -> ""
|
||||
}
|
||||
)
|
||||
}
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
@ExperimentalPermission
|
||||
public object AllGrantPermissionService : PermissionService<PermissionImpl> {
|
||||
private val all = ConcurrentHashMap<PermissionIdentifier, PermissionImpl>()
|
||||
override val permissionType: KClass<PermissionImpl>
|
||||
get() = PermissionImpl::class
|
||||
|
||||
override fun register(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
base: PermissionIdentifier?
|
||||
): PermissionImpl {
|
||||
val new = PermissionImpl(identifier, description, base)
|
||||
if (all.putIfAbsent(identifier, new) != null) {
|
||||
throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}")
|
||||
}
|
||||
return new
|
||||
}
|
||||
|
||||
override fun get(identifier: PermissionIdentifier): PermissionImpl? = all[identifier]
|
||||
override fun getGrantedPermissions(permissible: Permissible): Sequence<PermissionImpl> = all.values.asSequence()
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public object AllDenyPermissionService : PermissionService<PermissionImpl> {
|
||||
private val all = ConcurrentHashMap<PermissionIdentifier, PermissionImpl>()
|
||||
override val permissionType: KClass<PermissionImpl>
|
||||
get() = PermissionImpl::class
|
||||
|
||||
override fun register(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
base: PermissionIdentifier?
|
||||
): PermissionImpl {
|
||||
val new = PermissionImpl(identifier, description, base)
|
||||
if (all.putIfAbsent(identifier, new) != null) {
|
||||
throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}")
|
||||
}
|
||||
return new
|
||||
}
|
||||
|
||||
override fun get(identifier: PermissionIdentifier): PermissionImpl? = all[identifier]
|
||||
override fun getGrantedPermissions(permissible: Permissible): Sequence<PermissionImpl> = emptySequence()
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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 open class HotDeploymentNotSupportedException : Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public open class DuplicatedRegistrationException : Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
/*
|
||||
* 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)
|
||||
}
|
@ -11,10 +11,12 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
/**
|
||||
*
|
||||
* 注意: 请不要自主实现 [Permissible]
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public interface Permissible {
|
||||
public val identifier: String
|
||||
}
|
||||
public interface Permissible
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun Permissible.hasPermission(permission: Permission): Boolean =
|
||||
|
@ -19,3 +19,13 @@ public interface Permission {
|
||||
public val description: String
|
||||
public val base: PermissionIdentifier?
|
||||
}
|
||||
|
||||
/**
|
||||
* [Permission] 的简单实现
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public open class PermissionImpl(
|
||||
override val identifier: PermissionIdentifier,
|
||||
override val description: String,
|
||||
override val base: PermissionIdentifier?
|
||||
) : Permission
|
@ -44,7 +44,7 @@ public abstract class PermissionGroup(
|
||||
apply { this.permissionChecker = permissionChecker }
|
||||
|
||||
public fun build(property: KProperty<*>): Permission {
|
||||
return PermissionService.register(
|
||||
return PermissionService.INSTANCE.register(
|
||||
identifierNamespace.permissionIdentifier(property.name),
|
||||
description,
|
||||
basePermission
|
||||
|
@ -9,15 +9,34 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.KSerializer
|
||||
import kotlinx.serialization.Serializer
|
||||
import kotlinx.serialization.builtins.serializer
|
||||
import net.mamoe.mirai.console.internal.data.map
|
||||
|
||||
|
||||
@Serializable
|
||||
@ExperimentalPermission
|
||||
public data class PermissionIdentifier(
|
||||
public val namespace: String,
|
||||
public val id: String
|
||||
)
|
||||
) {
|
||||
init {
|
||||
require(!namespace.contains(':')) {
|
||||
"':' is not allowed in namespace"
|
||||
}
|
||||
require(!id.contains(':')) {
|
||||
"':' is not allowed in id"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializer(forClass = PermissionIdentifier::class)
|
||||
public object AsClassSerializer
|
||||
|
||||
public object AsStringSerializer : KSerializer<PermissionIdentifier> by String.serializer().map(
|
||||
serializer = { it.namespace + ":" + it.id },
|
||||
deserializer = { it.split(':').let { (namespace, id) -> PermissionIdentifier(namespace, id) } }
|
||||
)
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public interface PermissionIdentifierNamespace {
|
||||
|
@ -11,17 +11,19 @@
|
||||
|
||||
package net.mamoe.mirai.console.permission
|
||||
|
||||
import net.mamoe.mirai.console.data.AutoSavePluginConfig
|
||||
import net.mamoe.mirai.console.data.Value
|
||||
import net.mamoe.mirai.console.data.value
|
||||
import net.mamoe.mirai.console.extensions.PermissionServiceProvider
|
||||
import java.util.concurrent.ConcurrentLinkedQueue
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* [PermissionServiceProvider]
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public interface PermissionService<P : Permission> {
|
||||
@ExperimentalPermission
|
||||
public val permissionType: KClass<P>
|
||||
|
||||
@Throws(DuplicatedRegistrationException::class)
|
||||
public fun register(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
@ -30,99 +32,73 @@ public interface PermissionService<P : Permission> {
|
||||
|
||||
public operator fun get(identifier: PermissionIdentifier): P?
|
||||
|
||||
|
||||
public fun getGrantedPermissions(permissible: Permissible): List<PermissionIdentifier>
|
||||
public fun getGrantedPermissions(permissible: Permissible): Sequence<P>
|
||||
|
||||
|
||||
public fun testPermission(permissible: Permissible, permission: P): Boolean =
|
||||
permissible.getGrantedPermissions().any { it == permission.identifier }
|
||||
permissible.getGrantedPermissions().any { it == permission }
|
||||
|
||||
public companion object {
|
||||
private val builtIn: PermissionService<out Permission> get() = AllGrantPermissionService
|
||||
|
||||
public companion object INSTANCE : PermissionService<Permission> {
|
||||
private val builtIn: PermissionService<out Permission> get() = TODO("PS IMPL")
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private val instance by lazy {
|
||||
PermissionServiceProvider.getExtensions().singleOrNull()?.extension?.instance
|
||||
?: builtIn // TODO: 2020/9/4 ask for further choice
|
||||
as PermissionService<Permission>
|
||||
@get:JvmName("getInstance")
|
||||
@JvmStatic
|
||||
public val INSTANCE: PermissionService<out Permission> by lazy {
|
||||
PermissionServiceProvider.getExtensions().singleOrNull()?.extension?.instance ?: builtIn
|
||||
// TODO: 2020/9/4 ExtensionSelector
|
||||
}
|
||||
|
||||
override fun register(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
base: PermissionIdentifier?
|
||||
): Permission = instance.register(identifier, description, base)
|
||||
|
||||
override fun get(identifier: PermissionIdentifier): Permission? = instance[identifier]
|
||||
override fun getGrantedPermissions(permissible: Permissible): List<PermissionIdentifier> =
|
||||
instance.getGrantedPermissions(permissible)
|
||||
}
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public interface HotDeploymentSupportPermissionService<P : Permission> : PermissionService<P> {
|
||||
public fun grant(permissible: Permissible, permission: P)
|
||||
public fun deny(permissible: Permissible, permission: P)
|
||||
}
|
||||
public abstract class AbstractPermissionService<P : Permission> : PermissionService<P> {
|
||||
protected val all: MutableMap<PermissionIdentifier, P> = ConcurrentHashMap<PermissionIdentifier, P>()
|
||||
|
||||
@ExperimentalPermission
|
||||
public open class HotDeploymentNotSupportedException : Exception {
|
||||
public constructor() : super()
|
||||
public constructor(message: String?) : super(message)
|
||||
public constructor(message: String?, cause: Throwable?) : super(message, cause)
|
||||
public constructor(cause: Throwable?) : super(cause)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* [PermissionServiceProvider]
|
||||
*/
|
||||
@ExperimentalPermission
|
||||
public abstract class AbstractPermissionService<P : Permission> : AutoSavePluginConfig(), PermissionService<P> {
|
||||
@JvmField
|
||||
protected val permissions: ConcurrentLinkedQueue<P> = ConcurrentLinkedQueue()
|
||||
|
||||
@JvmField
|
||||
protected val grantedPermissionMap: Value<MutableMap<String, MutableList<PermissionIdentifier>>> = value()
|
||||
|
||||
public override fun getGrantedPermissions(permissible: Permissible): List<PermissionIdentifier> =
|
||||
grantedPermissionMap.value[permissible.identifier].orEmpty()
|
||||
|
||||
public override operator fun get(identifier: PermissionIdentifier): P? =
|
||||
permissions.find { it.identifier == identifier }
|
||||
|
||||
public override fun testPermission(permissible: Permissible, permission: P): Boolean =
|
||||
permissible.getGrantedPermissions().any { it == permission.identifier }
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun Permissible.getGrantedPermissions(): List<PermissionIdentifier> =
|
||||
PermissionService.run { this.getGrantedPermissions(this@getGrantedPermissions) }
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun Permission.testPermission(permissible: Permissible): Boolean =
|
||||
PermissionService.run { testPermission(permissible, this@testPermission) }
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun PermissionIdentifier.testPermission(permissible: Permissible): Boolean {
|
||||
val p = PermissionService[this] ?: return false
|
||||
return p.testPermission(permissible)
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalPermission::class)
|
||||
private class PermissionServiceImpl : AbstractPermissionService<PermissionServiceImpl.PermissionImpl>() {
|
||||
private val instances: ConcurrentLinkedQueue<PermissionImpl> = ConcurrentLinkedQueue()
|
||||
|
||||
private class PermissionImpl(
|
||||
override val identifier: PermissionIdentifier,
|
||||
override val description: String,
|
||||
override val base: PermissionIdentifier?
|
||||
) : Permission
|
||||
protected abstract fun createPermission(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
base: PermissionIdentifier?
|
||||
): P
|
||||
|
||||
override fun register(
|
||||
identifier: PermissionIdentifier,
|
||||
description: String,
|
||||
base: PermissionIdentifier?
|
||||
): PermissionImpl = PermissionImpl(identifier, description, base)
|
||||
): P {
|
||||
val new = createPermission(identifier, description, base)
|
||||
if (all.putIfAbsent(identifier, new) != null) {
|
||||
throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[identifier]}")
|
||||
}
|
||||
return new
|
||||
}
|
||||
|
||||
override fun get(identifier: PermissionIdentifier): P? = all[identifier]
|
||||
override fun getGrantedPermissions(permissible: Permissible): Sequence<P> = all.values.asSequence()
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun Permissible.getGrantedPermissions(): Sequence<Permission> =
|
||||
PermissionService.INSTANCE.run {
|
||||
getGrantedPermissions(this@getGrantedPermissions)
|
||||
}
|
||||
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun Permission.testPermission(permissible: Permissible): Boolean =
|
||||
PermissionService.INSTANCE.run {
|
||||
require(permissionType.isInstance(this@testPermission)) {
|
||||
"Custom-constructed Permission instance is not allowed. " +
|
||||
"Please obtain Permission from PermissionService.INSTANCE.register or PermissionService.INSTANCE.get"
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
this as PermissionService<Permission>
|
||||
|
||||
testPermission(permissible, this@testPermission)
|
||||
}
|
||||
|
||||
@ExperimentalPermission
|
||||
public inline fun PermissionIdentifier.testPermission(permissible: Permissible): Boolean {
|
||||
val p = PermissionService.INSTANCE[this] ?: return false
|
||||
return p.testPermission(permissible)
|
||||
}
|
@ -18,7 +18,7 @@
|
||||
|
||||
object Versions {
|
||||
const val core = "1.2.2"
|
||||
const val console = "1.0-M4-dev-4"
|
||||
const val console = "1.0-M4-dev-5"
|
||||
const val consoleGraphical = "0.0.7"
|
||||
const val consoleTerminal = "0.1.0"
|
||||
const val consolePure = console
|
||||
|
Loading…
Reference in New Issue
Block a user