PluginCustomCommandSender (#1964)

* PluginCustomCommandSender

* Update doc & remove lazy

* Update CommandSender.kt
This commit is contained in:
微莹·纤绫 2022-06-07 00:10:28 +08:00 committed by GitHub
parent b2c895bc2b
commit 0b67a6783a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 270 additions and 112 deletions

View File

@ -66,6 +66,28 @@ public abstract class net/mamoe/mirai/console/command/AbstractCommandSender : ko
public abstract fun toString ()Ljava/lang/String;
}
public abstract class net/mamoe/mirai/console/command/AbstractPluginCustomCommandSender : net/mamoe/mirai/console/command/AbstractCommandSender, net/mamoe/mirai/console/command/PluginCustomCommandSender {
public fun <init> (Lnet/mamoe/mirai/console/plugin/Plugin;)V
public fun getBot ()Lnet/mamoe/mirai/Bot;
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;
public fun getName ()Ljava/lang/String;
public final fun getOwner ()Lnet/mamoe/mirai/console/plugin/Plugin;
public fun getPermitteeId ()Lnet/mamoe/mirai/console/permission/PermitteeId;
public fun getSubject ()Lnet/mamoe/mirai/contact/Contact;
public fun getUser ()Lnet/mamoe/mirai/contact/User;
public fun isAnsiSupported ()Z
public fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
protected abstract fun sendMessage0 (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun toString ()Ljava/lang/String;
}
public abstract class net/mamoe/mirai/console/command/AbstractPluginCustomCommandSenderJ : net/mamoe/mirai/console/command/AbstractPluginCustomCommandSender {
public fun <init> (Lnet/mamoe/mirai/console/plugin/Plugin;)V
public final fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
protected final fun sendMessage0 (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
protected abstract fun sendMessageImpl (Ljava/lang/String;)V
}
public abstract class net/mamoe/mirai/console/command/AbstractUserCommandSender : net/mamoe/mirai/console/command/AbstractCommandSender, net/mamoe/mirai/console/command/UserCommandSender {
public fun getBot ()Lnet/mamoe/mirai/Bot;
public final fun getName ()Ljava/lang/String;
@ -376,7 +398,7 @@ public final class net/mamoe/mirai/console/command/ConsoleCommandOwner : net/mam
public fun permissionId (Ljava/lang/String;)Lnet/mamoe/mirai/console/permission/PermissionId;
}
public final class net/mamoe/mirai/console/command/ConsoleCommandSender : net/mamoe/mirai/console/command/AbstractCommandSender {
public final class net/mamoe/mirai/console/command/ConsoleCommandSender : net/mamoe/mirai/console/command/AbstractCommandSender, net/mamoe/mirai/console/command/SystemCommandSender {
public static final field INSTANCE Lnet/mamoe/mirai/console/command/ConsoleCommandSender;
public static final field NAME Ljava/lang/String;
public fun getBot ()Ljava/lang/Void;
@ -389,6 +411,7 @@ public final class net/mamoe/mirai/console/command/ConsoleCommandSender : net/ma
public synthetic fun getSubject ()Lnet/mamoe/mirai/contact/Contact;
public fun getUser ()Ljava/lang/Void;
public synthetic fun getUser ()Lnet/mamoe/mirai/contact/User;
public fun isAnsiSupported ()Z
public final fun sendMessage (Ljava/lang/String;)Ljava/lang/Void;
public fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun sendMessage (Lnet/mamoe/mirai/message/data/Message;)Ljava/lang/Void;
@ -528,6 +551,15 @@ public final class net/mamoe/mirai/console/command/OtherClientCommandSenderOnMes
public fun getFromEvent ()Lnet/mamoe/mirai/event/events/OtherClientMessageEvent;
}
public abstract interface class net/mamoe/mirai/console/command/PluginCustomCommandSender : net/mamoe/mirai/console/command/CommandSender, net/mamoe/mirai/console/command/SystemCommandSender {
public abstract fun getOwner ()Lnet/mamoe/mirai/console/plugin/Plugin;
public fun getPermitteeId ()Lnet/mamoe/mirai/console/permission/PermitteeId;
public fun isAnsiSupported ()Z
public abstract fun sendMessage (Ljava/lang/String;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public fun sendMessage (Lnet/mamoe/mirai/message/data/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static synthetic fun sendMessage$suspendImpl (Lnet/mamoe/mirai/console/command/PluginCustomCommandSender;Lnet/mamoe/mirai/message/data/Message;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
}
public abstract class net/mamoe/mirai/console/command/RawCommand : net/mamoe/mirai/console/command/Command {
public fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;Z)V
public synthetic fun <init> (Lnet/mamoe/mirai/console/command/CommandOwner;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Lnet/mamoe/mirai/console/permission/Permission;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V
@ -572,6 +604,10 @@ public final class net/mamoe/mirai/console/command/StrangerCommandSenderOnMessag
public fun getFromEvent ()Lnet/mamoe/mirai/event/events/StrangerMessageEvent;
}
public abstract interface class net/mamoe/mirai/console/command/SystemCommandSender : net/mamoe/mirai/console/command/CommandSender {
public abstract fun isAnsiSupported ()Z
}
public abstract class net/mamoe/mirai/console/command/TempCommandSender : net/mamoe/mirai/console/command/AbstractUserCommandSender, kotlinx/coroutines/CoroutineScope, net/mamoe/mirai/console/command/GroupAwareCommandSender {
public synthetic fun <init> (Lnet/mamoe/mirai/contact/NormalMember;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun getCoroutineContext ()Lkotlin/coroutines/CoroutineContext;

View File

@ -28,8 +28,9 @@ import net.mamoe.mirai.console.internal.data.qualifiedNameOrTip
import net.mamoe.mirai.console.permission.AbstractPermitteeId
import net.mamoe.mirai.console.permission.Permittee
import net.mamoe.mirai.console.permission.PermitteeId
import net.mamoe.mirai.console.util.ConsoleExperimentalApi
import net.mamoe.mirai.console.util.MessageScope
import net.mamoe.mirai.console.plugin.Plugin
import net.mamoe.mirai.console.plugin.name
import net.mamoe.mirai.console.util.*
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.event.events.*
import net.mamoe.mirai.message.MessageReceipt
@ -42,6 +43,8 @@ import kotlin.contracts.InvocationKind
import kotlin.contracts.contract
import kotlin.coroutines.CoroutineContext
// region base interface define
/**
* 指令发送者.
*
@ -64,9 +67,11 @@ import kotlin.coroutines.CoroutineContext
* - [OtherClient.asCommandSender]
*
* ## 实现 [CommandSender]
* Console 前端外, 在任何时候都不要实现 [CommandSender] (包括使用委托). 必须使用上述扩展获取 [CommandSender] 实例.
* 在任何时候都不要实现 [CommandSender] (包括使用委托). 必须使用上述扩展获取 [CommandSender] 实例.
*
* Console 前端可实现 [ConsoleCommandSender]
* 除了以下情况:
* - Console 前端可实现 [ConsoleCommandSender]
* - 插件可继承 [AbstractPluginCustomCommandSender]
*
* ## 子类型
*
@ -74,6 +79,7 @@ import kotlin.coroutines.CoroutineContext
*
* [AbstractCommandSender] 是密封类, 一级子类为:
* - [AbstractUserCommandSender] 代表用户
* - [AbstractPluginCustomCommandSender] 代表插件
* - [ConsoleCommandSender] 代表控制台
*
* 二级子类, 当指令由插件 [主动执行][CommandManager.executeCommand] , 插件应使用 [toCommandSender] [asCommandSender], 因此,
@ -97,35 +103,45 @@ import kotlin.coroutines.CoroutineContext
* CoroutineScope
*
* |
* CommandSender <---------+---------------+-------------------------------+
* | | |
* | | | |
* | UserCommandSender GroupAwareCommandSender CommandSenderOnMessage
* |
* | | | |
* AbstractCommandSender | | |
* | | |
* | sealed | | |
* +-------------+-------------+ | | |
* | | | | |
* | | | | | }
* ConsoleCommandSender AbstractUserCommandSender | | } 一级子类
* | | }
* | sealed | |
* | | |
* +----------------------+ | |
* | | | |
* | +------+------------+---------------+ |
* | | | |
* | | | | }
* FriendCommandSender MemberCommandSender TempCommandSender | } 二级子类
* | }
* | | | |
* | | | | }
* FriendCommandSenderOnMessage MemberCommandSenderOnMessage TempCommandSenderOnMessage | } 三级子类
* | | | | }
* | | | |
* +-----------------------------+----------------------------+---------------+
* +----------> CommandSender <---------+---------------------+---------------------------------------------------+
* | | | |
* | | | | |
* SystemCommandSender <-------+ | UserCommandSender GroupAwareCommandSender CommandSenderOnMessage
* | |
* PluginCustomCommandSender | | | | |
* | | | | |
* | +-------------+ AbstractCommandSender | | |
* | | | | |
* | | | sealed | | |
* | | +---------------+-------------+ | | |
* | | | | | | | |
* | | | | | | | |
* | | | | | | | |
* | | | | | | | |
* | | | | | | | |
* | | | | | | | |
* | | | | | | | | }
* | ConsoleCommandSender | AbstractUserCommandSender | | }
* | | | | } 一级子类
* AbstractPluginCustomCommandSender -------+ | | | }
* | | | }
* | | |
* | | |
* | sealed | |
* | | |
* +----------------------+ | |
* | | | |
* | +------+------------+---------------+ |
* | | | |
* | | | | }
* FriendCommandSender MemberCommandSender TempCommandSender | } 二级子类
* | }
* | | | |
* | | | | }
* FriendCommandSenderOnMessage MemberCommandSenderOnMessage TempCommandSenderOnMessage | } 三级子类
* | | | | }
* | | | |
* +-----------------------------+----------------------------+---------------------+
* ```
*
* ## Scoping: [MessageScope]
@ -137,6 +153,7 @@ import kotlin.coroutines.CoroutineContext
* @see UserCommandSender [User] ([群成员][Member], [好友][Friend])
* @see toCommandSender
* @see asCommandSender
* @see PluginCustomCommandSender 自定义 CommandSender
*/
public interface CommandSender : CoroutineScope, Permittee {
/**
@ -303,6 +320,113 @@ public interface CommandSender : CoroutineScope, Permittee {
}
}
/**
* 一个来自内部系统的命令执行者.
*
* 包括
* - [PluginCustomCommandSender] - 来自插件的命令执行者
* - [ConsoleCommandSender] - 控制台
*/
public sealed interface SystemCommandSender : CommandSender {
/**
* 当前 [SystemCommandSender] 是否支持 Ansi 信息
*
* @see AnsiMessageBuilder
* @see CommandSender.sendAnsiMessage
*/
public val isAnsiSupported: Boolean
}
/**
* 一个来自插件自行实现的 [CommandSender].
*
* [PluginCustomCommandSender] 不一定拥有全部的权限. [PluginCustomCommandSender] 可以以其他身份执行命令.
* 默认情况下 [PluginCustomCommandSender] [ConsoleCommandSender] 的身份执行命令
*
* @see PermitteeId
* @see AbstractPluginCustomCommandSender
*/
public interface PluginCustomCommandSender : CommandSender, SystemCommandSender {
override val isAnsiSupported: Boolean get() = false
override val permitteeId: PermitteeId get() = AbstractPermitteeId.Console
public val owner: Plugin
override suspend fun sendMessage(message: Message): Nothing? {
return sendMessage(message.toString())
}
override suspend fun sendMessage(message: String): Nothing?
}
/**
* 控制台指令执行者. 代表由控制台执行指令
*
* 控制台拥有一切指令的执行权限.
*/
public object ConsoleCommandSender : AbstractCommandSender(), SystemCommandSender {
public const val NAME: String = "ConsoleCommandSender"
public override val bot: Nothing? get() = null
public override val subject: Nothing? get() = null
public override val user: Nothing? get() = null
public override val name: String get() = NAME
public override fun toString(): String = NAME
public override val permitteeId: AbstractPermitteeId.Console = AbstractPermitteeId.Console
public override val coroutineContext: CoroutineContext by lazy { MiraiConsole.childScopeContext(NAME) }
override val isAnsiSupported: Boolean
get() = MiraiConsoleImplementation.getInstance().isAnsiSupported
@JvmBlockingBridge
public override suspend fun sendMessage(message: Message): Nothing? {
MiraiConsoleImplementation.getInstance().consoleCommandSender.sendMessage(message)
return null
}
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): Nothing? {
MiraiConsoleImplementation.getInstance().consoleCommandSender.sendMessage(message)
return null
}
}
/**
* 知道 [Group] 环境的 [UserCommandSender]
*
* 可能的子类:
*
* - [MemberCommandSender] 代表一个 [群员][Member] 执行指令
* - [TempCommandSender] 代表一个 [群员][Member] 通过临时会话执行指令
*/
public interface GroupAwareCommandSender : UserCommandSender {
public val group: Group
}
/**
* 代表一个用户执行指令
*
* @see MemberCommandSender 代表一个 [群员][Member] 执行指令
* @see FriendCommandSender 代表一个 [好友][Friend] 执行指令
* @see TempCommandSender 代表一个 [群员][Member] 通过临时会话执行指令
* @see StrangerCommandSender 代表一个 [陌生人][Stranger] 执行指令
*
* @see CommandSenderOnMessage
*/
public interface UserCommandSender : CommandSender {
/**
* @see MessageEvent.sender
*/
public override val user: User // override nullability
/**
* @see MessageEvent.subject
*/
public override val subject: Contact // override nullability
public override val bot: Bot // override nullability
}
/**
* 所有 [CommandSender] 都必须继承自此对象.
* @see CommandSender 查看更多信息
@ -313,6 +437,9 @@ public sealed class AbstractCommandSender : CommandSender, CoroutineScope {
public abstract override val user: User?
public abstract override fun toString(): String
}
// endregion
// region extension functions
/**
* [this] [ConsoleCommandSender] 时返回 `true`
@ -425,66 +552,23 @@ public inline fun <R> UserCommandSender.foldContext(
}
/**
* 尝试获取 [Group].
* 尝试获取 [Bot].
*
* [GroupAwareCommandSender] 时返回 [GroupAwareCommandSender.group], 否则返回 `null`
* [UserCommandSender] 时返回 [UserCommandSender.bot], 否则返回 `null`
*
* ### 契约
* 本函数定义契约,
* - 若返回非 `null` 实例, Kotlin 编译器认为 [this] [GroupAwareCommandSender] 实例并执行智能类型转换.
* - 若返回 `null`, Kotlin 编译器认为 [this] [FriendCommandSender] 实例并执行智能类型转换.
* - 若返回非 `null` 实例, Kotlin 编译器认为 [this] [UserCommandSender] 实例并执行智能类型转换.
* - 若返回 `null`, Kotlin 编译器认为 [this] [SystemCommandSender] 实例并执行智能类型转换.
*/
public fun CommandSender.getBotOrNull(): Bot? {
contract {
returns(null) implies (this@getBotOrNull is AbstractUserCommandSender)
returnsNotNull() implies (this@getBotOrNull is ConsoleCommandSender)
returns(null) implies (this@getBotOrNull is SystemCommandSender)
returnsNotNull() implies (this@getBotOrNull is UserCommandSender)
}
return this.castOrNull<UserCommandSender>()?.bot
}
/**
* 控制台指令执行者. 代表由控制台执行指令
*
* 控制台拥有一切指令的执行权限.
*/
public object ConsoleCommandSender : AbstractCommandSender() {
public const val NAME: String = "ConsoleCommandSender"
public override val bot: Nothing? get() = null
public override val subject: Nothing? get() = null
public override val user: Nothing? get() = null
public override val name: String get() = NAME
public override fun toString(): String = NAME
public override val permitteeId: AbstractPermitteeId.Console = AbstractPermitteeId.Console
public override val coroutineContext: CoroutineContext by lazy { MiraiConsole.childScopeContext(NAME) }
@JvmBlockingBridge
public override suspend fun sendMessage(message: Message): Nothing? {
MiraiConsoleImplementation.getInstance().consoleCommandSender.sendMessage(message)
return null
}
@JvmBlockingBridge
public override suspend fun sendMessage(message: String): Nothing? {
MiraiConsoleImplementation.getInstance().consoleCommandSender.sendMessage(message)
return null
}
}
/**
* 知道 [Group] 环境的 [UserCommandSender]
*
* 可能的子类:
*
* - [MemberCommandSender] 代表一个 [群员][Member] 执行指令
* - [TempCommandSender] 代表一个 [群员][Member] 通过临时会话执行指令
*/
public interface GroupAwareCommandSender : UserCommandSender {
public val group: Group
}
/**
* 尝试获取 [Group].
*
@ -503,33 +587,14 @@ public fun CommandSender.getGroupOrNull(): Group? {
return this.castOrNull<GroupAwareCommandSender>()?.group
}
// endregion
// region implementations
///////////////////////////////////////////////////////////////////////////
// UserCommandSender
///////////////////////////////////////////////////////////////////////////
/**
* 代表一个用户执行指令
*
* @see MemberCommandSender 代表一个 [群员][Member] 执行指令
* @see FriendCommandSender 代表一个 [好友][Friend] 执行指令
* @see TempCommandSender 代表一个 [群员][Member] 通过临时会话执行指令
* @see StrangerCommandSender 代表一个 [陌生人][Stranger] 执行指令
*
* @see CommandSenderOnMessage
*/
public interface UserCommandSender : CommandSender {
/**
* @see MessageEvent.sender
*/
public override val user: User // override nullability
/**
* @see MessageEvent.subject
*/
public override val subject: Contact // override nullability
public override val bot: Bot // override nullability
}
/**
* [UserCommandSender] 的实现
*/
@ -736,4 +801,57 @@ public class StrangerCommandSenderOnMessage internal constructor(
*/
public class OtherClientCommandSenderOnMessage internal constructor(
public override val fromEvent: OtherClientMessageEvent,
) : OtherClientCommandSender(fromEvent.client), CommandSenderOnMessage<OtherClientMessageEvent>
) : OtherClientCommandSender(fromEvent.client), CommandSenderOnMessage<OtherClientMessageEvent>
// endregion
// region PluginCustomCommandSender implementations
/**
* 所有 [PluginCustomCommandSender] 的父类
*
* Java [AbstractPluginCustomCommandSenderJ]
*/
public abstract class AbstractPluginCustomCommandSender(
final override val owner: Plugin,
) : AbstractCommandSender(), PluginCustomCommandSender {
override val coroutineContext: CoroutineContext by lazy {
if (owner is CoroutineScope) {
return@lazy owner.childScopeContext(name)
}
// Fallback
return@lazy MiraiConsole.childScopeContext("PluginCustomCommandSender-$name")
}
override val name: String get() = owner.name
override fun toString(): String = name
override val isAnsiSupported: Boolean get() = false
override val permitteeId: PermitteeId get() = AbstractPermitteeId.Console
override val bot: Bot? get() = null
override val subject: Contact? get() = null
override val user: User? get() = null
override suspend fun sendMessage(message: String): Nothing? {
sendMessage0(message)
return null
}
protected abstract suspend fun sendMessage0(message: String)
}
@JavaFriendlyApi
public abstract class AbstractPluginCustomCommandSenderJ(
owner: Plugin
) : AbstractPluginCustomCommandSender(owner) {
protected abstract fun sendMessageImpl(message: String)
final override suspend fun sendMessage(message: String): Nothing? {
sendMessageImpl(message)
return null
}
final override suspend fun sendMessage0(message: String) {
sendMessageImpl(message)
}
}
// endregion

View File

@ -10,9 +10,8 @@
package net.mamoe.mirai.console.util
import net.mamoe.mirai.console.MiraiConsoleImplementation
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.ConsoleCommandSender
import net.mamoe.mirai.console.command.SystemCommandSender
import net.mamoe.mirai.console.util.AnsiMessageBuilder.Companion.asAnsiMessageBuilder
import net.mamoe.mirai.console.util.AnsiMessageBuilder.Companion.dropAnsi
import net.mamoe.mirai.contact.Contact
@ -101,8 +100,8 @@ public open class AnsiMessageBuilder public constructor(
@ConsoleExperimentalApi
@JvmStatic
public fun isAnsiSupported(sender: CommandSender): Boolean =
if (sender is ConsoleCommandSender) {
MiraiConsoleImplementation.getInstance().isAnsiSupported
if (sender is SystemCommandSender) {
sender.isAnsiSupported
} else false
/**

View File

@ -19,6 +19,7 @@ import kotlinx.coroutines.flow.firstOrNull
import kotlinx.coroutines.flow.fold
import me.him188.kotlin.jvm.blocking.bridge.JvmBlockingBridge
import net.mamoe.mirai.console.command.CommandSender
import net.mamoe.mirai.console.command.SystemCommandSender
import net.mamoe.mirai.contact.Contact
import net.mamoe.mirai.contact.User
import net.mamoe.mirai.message.data.Message
@ -576,7 +577,11 @@ private class CommandSenderAsMessageScope(
private val sender: CommandSender,
) : MessageScope {
override val realTarget: Any
get() = sender.user ?: sender // ConsoleCommandSender
get() {
val sender = this.sender
if (sender is SystemCommandSender) return sender
return sender.user ?: sender
}
override suspend fun sendMessage(message: Message) {
sender.sendMessage(message)