Rearrange implementations

This commit is contained in:
Him188 2020-09-08 21:35:30 +08:00
parent 5cfaef0fcd
commit 485e7ec9f7
9 changed files with 136 additions and 223 deletions

View File

@ -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 net.mamoe.mirai.console.permission.PermissibleIdentifier.Companion.grantedWith
import java.util.concurrent.CopyOnWriteArrayList
@ExperimentalPermission
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(
id: PermissionId,
description: String,
base: PermissionId?
): P
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 DuplicatedPermissionRegistrationException("Duplicated Permission registry. new: $instance, old: ${permissions[id]}")
}
return instance
}
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) }
}
}
}

View File

@ -36,7 +36,7 @@ public object AllGrantPermissionService : PermissionService<PermissionImpl> {
): PermissionImpl { ): PermissionImpl {
val new = PermissionImpl(id, description, base) val new = PermissionImpl(id, description, base)
if (all.putIfAbsent(id, new) != null) { if (all.putIfAbsent(id, new) != null) {
throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[id]}") throw DuplicatedPermissionRegistrationException("Duplicated Permission registry: ${all[id]}")
} }
return new return new
} }
@ -64,7 +64,7 @@ public object AllDenyPermissionService : PermissionService<PermissionImpl> {
): PermissionImpl { ): PermissionImpl {
val new = PermissionImpl(id, description, base) val new = PermissionImpl(id, description, base)
if (all.putIfAbsent(id, new) != null) { if (all.putIfAbsent(id, new) != null) {
throw DuplicatedRegistrationException("Duplicated Permission registry: ${all[id]}") throw DuplicatedPermissionRegistrationException("Duplicated Permission registry: ${all[id]}")
} }
return new return new
} }
@ -80,7 +80,7 @@ public object AllDenyPermissionService : PermissionService<PermissionImpl> {
} }
@ExperimentalPermission @ExperimentalPermission
public object BuiltInPermissionService : AbstractConcurrentPermissionService<PermissionImpl>(), internal object BuiltInPermissionService : AbstractConcurrentPermissionService<PermissionImpl>(),
PermissionService<PermissionImpl> { PermissionService<PermissionImpl> {
@ExperimentalPermission @ExperimentalPermission

View File

@ -7,19 +7,12 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("unused")
package net.mamoe.mirai.console.permission package net.mamoe.mirai.console.permission
@ExperimentalPermission @ExperimentalPermission
public open class HotDeploymentNotSupportedException : Exception { public open class DuplicatedPermissionRegistrationException : 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() : super()
public constructor(message: String?) : super(message) public constructor(message: String?) : super(message)
public constructor(message: String?, cause: Throwable?) : super(message, cause) public constructor(message: String?, cause: Throwable?) : super(message, cause)

View File

@ -26,69 +26,3 @@ import net.mamoe.mirai.console.command.CommandSender
public interface Permissible { public interface Permissible {
public val identifier: PermissibleIdentifier 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 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: PermissionId): Boolean =
PermissionService.run { permission.testPermission(this@hasPermission) }

View File

@ -0,0 +1,57 @@
@file:Suppress("unused")
package net.mamoe.mirai.console.permission
@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 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()
}

View File

@ -1,84 +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
import net.mamoe.mirai.console.command.CommandSender
import kotlin.reflect.KProperty
@ExperimentalPermission
public abstract class PermissionGroup(
private val idNamespace: PermissionIdNamespace,
) {
@ExperimentalPermission
public inner class PermissionBuilder {
@JvmField
internal var description: String = "<no description given>"
@JvmField
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: PermissionId?): PermissionBuilder =
apply { this.basePermission = basePermission }
public fun dependsOn(basePermission: Permission?): PermissionBuilder =
apply { this.basePermission = basePermission?.id }
public fun basePermission(basePermission: PermissionId?): PermissionBuilder =
apply { this.basePermission = basePermission }
public fun basePermission(basePermission: Permission?): PermissionBuilder =
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(
idNamespace.permissionId(property.name),
description,
basePermission
)
}
}
public infix fun String.dependsOn(permission: Permission): PermissionBuilder {
return PermissionBuilder().apply { description(this@dependsOn);dependsOn(permission) }
}
public infix fun PermissionBuilder.defaults(permission: PermissionChecker): PermissionBuilder {
return apply { defaults(permission) }
}
public infix fun PermissionBuilder.defaults(permission: CommandSender.() -> Boolean): PermissionBuilder {
return apply { defaults(permission) }
}
public infix fun String.defaults(permission: PermissionChecker): PermissionBuilder {
return PermissionBuilder().apply { defaults(permission) }
}
public operator fun String.invoke(block: PermissionBuilder.() -> Unit): PermissionBuilder {
return PermissionBuilder().apply(block)
}
public operator fun String.provideDelegate(thisRef: PermissionGroup, property: KProperty<*>): Permission =
PermissionBuilder().apply { description(this@provideDelegate) }.build(property)
public operator fun Permission.getValue(thisRef: PermissionGroup, property: KProperty<*>): Permission = this
public operator fun PermissionBuilder.getValue(thisRef: PermissionGroup, property: KProperty<*>): Permission =
this.build(property)
}

View File

@ -49,8 +49,3 @@ public data class PermissionId(
} }
} }
@ExperimentalPermission
public interface PermissionIdNamespace {
@ExperimentalPermission
public fun permissionId(id: String): PermissionId
}

View File

@ -7,13 +7,10 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE * https://github.com/mamoe/mirai/blob/master/LICENSE
*/ */
@file:Suppress("unused")
package net.mamoe.mirai.console.permission package net.mamoe.mirai.console.permission
import net.mamoe.mirai.console.command.CommandSender
@ExperimentalPermission @ExperimentalPermission
public fun interface PermissionChecker { public interface PermissionIdNamespace {
public fun CommandSender.testPermission(): Boolean @ExperimentalPermission
public fun permissionId(id: String): PermissionId
} }

View File

@ -13,8 +13,6 @@ package net.mamoe.mirai.console.permission
import net.mamoe.mirai.console.extension.SingletonExtensionPoint.Companion.findSingleton import net.mamoe.mirai.console.extension.SingletonExtensionPoint.Companion.findSingleton
import net.mamoe.mirai.console.extensions.PermissionServiceProvider import net.mamoe.mirai.console.extensions.PermissionServiceProvider
import net.mamoe.mirai.console.permission.PermissibleIdentifier.Companion.grantedWith
import java.util.concurrent.CopyOnWriteArrayList
import kotlin.reflect.KClass import kotlin.reflect.KClass
/** /**
@ -37,7 +35,7 @@ public interface PermissionService<P : Permission> {
/////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////
@Throws(DuplicatedRegistrationException::class) @Throws(DuplicatedPermissionRegistrationException::class)
public fun register( public fun register(
id: PermissionId, id: PermissionId,
description: String, description: String,
@ -59,59 +57,23 @@ public interface PermissionService<P : Permission> {
} }
@ExperimentalPermission @ExperimentalPermission
public abstract class AbstractConcurrentPermissionService<P : Permission> : PermissionService<P> { public inline fun Permissible.hasPermission(permission: Permission): Boolean =
protected abstract val permissions: MutableMap<PermissionId, P> PermissionService.run { permission.testPermission(this@hasPermission) }
protected abstract val grantedPermissionsMap: MutableMap<PermissionId, MutableCollection<PermissibleIdentifier>>
protected abstract fun createPermission( @ExperimentalPermission
id: PermissionId, public inline fun Permissible.hasPermission(permission: PermissionId): Boolean =
description: String, PermissionService.run { permission.testPermission(this@hasPermission) }
base: PermissionId?
): P
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 instance
}
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) }
}
}
}
@JvmSynthetic
@ExperimentalPermission @ExperimentalPermission
public inline fun Permissible.getGrantedPermissions(): Sequence<Permission> = public inline fun Permissible.getGrantedPermissions(): Sequence<Permission> =
PermissionService.INSTANCE.run { PermissionService.INSTANCE.run {
getGrantedPermissions(this@getGrantedPermissions) getGrantedPermissions(this@getGrantedPermissions)
} }
@JvmSynthetic
@ExperimentalPermission @ExperimentalPermission
public inline fun Permission.testPermission(permissible: Permissible): Boolean = public fun Permission.testPermission(permissible: Permissible): Boolean =
PermissionService.INSTANCE.run { PermissionService.INSTANCE.run {
require(permissionType.isInstance(this@testPermission)) { require(permissionType.isInstance(this@testPermission)) {
"Custom-constructed Permission instance is not allowed. " + "Custom-constructed Permission instance is not allowed. " +
@ -124,8 +86,9 @@ public inline fun Permission.testPermission(permissible: Permissible): Boolean =
testPermission(permissible, this@testPermission) testPermission(permissible, this@testPermission)
} }
@JvmSynthetic
@ExperimentalPermission @ExperimentalPermission
public inline fun PermissionId.testPermission(permissible: Permissible): Boolean { public fun PermissionId.testPermission(permissible: Permissible): Boolean {
val p = PermissionService.INSTANCE[this] ?: return false val p = PermissionService.INSTANCE[this] ?: return false
return p.testPermission(permissible) return p.testPermission(permissible)
} }