Plan for redesigning of MessageSource

This commit is contained in:
Him188 2020-03-29 13:34:54 +08:00
parent 6d5b3086f6
commit b6c24e008d
19 changed files with 90 additions and 15 deletions

View File

@ -163,6 +163,7 @@ internal abstract class QQAndroidBotBase constructor(
TODO("not implemented")
}
@ExperimentalMessageSource
override suspend fun recall(source: MessageSource) {
if (source.senderId != uin && source.groupId != 0L) {
getGroup(source.groupId).checkBotPermissionOperator()
@ -382,8 +383,9 @@ internal abstract class QQAndroidBotBase constructor(
val data = chain.calculateValidationDataForGroup(
sequenceId = client.atomicNextMessageSequenceId(),
time = time.toInt(),
random = Random.nextInt().absoluteValue.toULong().toLong(),
group
random = Random.nextInt().absoluteValue.toUInt(),
groupCode,
group.botAsMember.nameCardOrNick
)
val response =

View File

@ -278,7 +278,7 @@ internal class GroupImpl(
check(!isBotMuted) { "bot is muted. Remaining seconds=$botMuteRemaining" }
val event = GroupMessageSendEvent(this, message.asMessageChain()).broadcast()
if (event.isCancelled) {
throw EventCancelledException("cancelled by FriendMessageSendEvent")
throw EventCancelledException("cancelled by GroupMessageSendEvent")
}
lateinit var source: MessageSourceFromSendGroup
bot.network.run {

View File

@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.qqandroid.contact
import kotlinx.coroutines.launch

View File

@ -8,6 +8,7 @@
*/
@file:OptIn(MiraiInternalAPI::class, LowLevelAPI::class)
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.qqandroid.contact

View File

@ -7,6 +7,8 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_OVERRIDE")
package net.mamoe.mirai.qqandroid.message
import kotlinx.coroutines.CoroutineScope
@ -146,7 +148,7 @@ internal abstract class MessageSourceFromSend : MessageSource {
}
private val elems by lazy {
originalMessage.toRichTextElems(groupId != 0L)
originalMessage.toRichTextElems(groupId != 0L, true)
}
private fun toJceDataImplForFriend(): ImMsgBody.SourceMsg {

View File

@ -7,6 +7,7 @@
* https://github.com/mamoe/mirai/blob/master/LICENSE
*/
@file: OptIn(MiraiExperimentalAPI::class, MiraiInternalAPI::class, LowLevelAPI::class, ExperimentalUnsignedTypes::class)
@file:Suppress("EXPERIMENTAL_API_USAGE")
package net.mamoe.mirai.qqandroid.message

View File

@ -52,7 +52,7 @@ internal fun MessageChain.calculateValidationDataForGroup(
groupCode: Long,
botMemberNameCard: String
): MessageValidationData {
val richTextElems = this.toRichTextElems(true)
val richTextElems = this.toRichTextElems(true, false)
val msgTransmit = MsgTransmit.PbMultiMsgTransmit(
msg = listOf(

View File

@ -319,7 +319,7 @@ internal class MessageSvc {
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(false)
elems = message.toRichTextElems(false, true)
)
),
msgSeq = source.sequenceId,
@ -372,7 +372,7 @@ internal class MessageSvc {
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems(true)
elems = message.toRichTextElems(true, true)
)
),
msgSeq = client.atomicNextMessageSequenceId(),

View File

@ -7,6 +7,7 @@ import kotlinx.coroutines.io.ByteReadChannel
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.ExperimentalMessageSource
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
@ -152,6 +153,7 @@ actual abstract class Bot actual constructor() : CoroutineScope, LowLevelBotAPIA
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
actual abstract suspend fun recall(source: MessageSource)

View File

@ -5,6 +5,7 @@ import net.mamoe.mirai.contact.PermissionDeniedException
import net.mamoe.mirai.contact.recall
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.ExperimentalMessageSource
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
@ -61,6 +62,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
*
* @see Bot.recall (扩展函数) 接受参数 [MessageChain]
*/
@ExperimentalMessageSource
@JvmName("recall")
fun __recallBlockingForJava__(source: MessageSource) {
runBlocking { recall(source) }
@ -88,6 +90,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
* @param millis 延迟的时间, 单位为毫秒
* @see recall
*/
@ExperimentalMessageSource
@JvmName("recallIn")
fun __recallIn_MemberForJava__(source: MessageSource, millis: Long) {
runBlocking { recallIn(source, millis) }
@ -148,6 +151,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
/**
* 异步调用 [__recallBlockingForJava__]
*/
@ExperimentalMessageSource
@JvmName("recallAsync")
fun __recallAsyncForJava__(source: MessageSource): Future<Unit> {
return future { recall(source) }

View File

@ -29,7 +29,8 @@ import net.mamoe.mirai.utils.unsafeWeakRef
*/
@Suppress("FunctionName")
@OptIn(MiraiInternalAPI::class)
actual open class MessageReceipt<C : Contact> actual constructor(
actual open class MessageReceipt<C : Contact> @OptIn(ExperimentalMessageSource::class)
actual constructor(
actual val source: MessageSource,
target: C,
private val botAsMember: Member?
@ -56,6 +57,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* @see Bot.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@OptIn(ExperimentalMessageSource::class)
actual suspend fun recall() {
@Suppress("BooleanLiteralArgument")
if (_isRecalled.compareAndSet(false, true)) {
@ -82,7 +84,8 @@ actual open class MessageReceipt<C : Contact> actual constructor(
if (_isRecalled.compareAndSet(false, true)) {
return when (val contact = target) {
is QQ,
is Group -> contact.bot.recallIn(source, millis)
is Group,
-> contact.bot.recallIn(source, millis)
else -> error("Unknown contact type")
}
} else error("message is already or planned to be recalled")
@ -92,6 +95,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* [确保 sequenceId可用][MessageSource.ensureSequenceIdAvailable] 然后引用这条消息.
* @see MessageChain.quote 引用一条消息
*/
@OptIn(ExperimentalMessageSource::class)
actual open suspend fun quote(): QuoteReplyToSend {
this.source.ensureSequenceIdAvailable()
@OptIn(LowLevelAPI::class)
@ -105,6 +109,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
*
* @see MessageChain.quote 引用一条消息
*/
@OptIn(ExperimentalMessageSource::class)
@LowLevelAPI
@Suppress("FunctionName")
actual fun _unsafeQuote(): QuoteReplyToSend {

View File

@ -19,6 +19,7 @@ import kotlinx.coroutines.launch
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.ExperimentalMessageSource
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
@ -33,6 +34,7 @@ import kotlin.jvm.JvmSynthetic
/**
* 登录, 返回 [this]
*/
@JvmSynthetic
suspend inline fun <B : Bot> B.alsoLogin(): B = also { login() }
// 任何人都能看到这个方法
@ -167,6 +169,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
abstract suspend fun recall(source: MessageSource)
@ -223,6 +226,7 @@ expect abstract class Bot() : CoroutineScope, LowLevelBotAPIAccessor {
* @throws PermissionDeniedException [Bot] 无权限操作时
* @see Bot.recall
*/
@JvmSynthetic
suspend inline fun Bot.recall(message: MessageChain) = this.recall(message[MessageSource])
/**
@ -233,6 +237,7 @@ suspend inline fun Bot.recall(message: MessageChain) = this.recall(message[Messa
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
@JvmSynthetic
inline fun Bot.recallIn(
source: MessageSource,
millis: Long,
@ -249,6 +254,7 @@ inline fun Bot.recallIn(
* @param coroutineContext 额外的 [CoroutineContext]
* @see recall
*/
@JvmSynthetic
inline fun Bot.recallIn(
message: MessageChain,
millis: Long,
@ -265,15 +271,20 @@ inline fun Bot.recallIn(
*
* @param cause 原因. null 时视为正常关闭, null 时视为异常关闭
*/
@JvmSynthetic
suspend inline fun Bot.closeAndJoin(cause: Throwable? = null) {
close(cause)
coroutineContext[Job]?.join()
}
@JvmSynthetic
inline fun Bot.containsFriend(id: Long): Boolean = this.friends.contains(id)
@JvmSynthetic
inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id)
@JvmSynthetic
inline fun Bot.getFriendOrNull(id: Long): QQ? = this.friends.getOrNull(id)
@JvmSynthetic
inline fun Bot.getGroupOrNull(id: Long): Group? = this.groups.getOrNull(id)

View File

@ -15,12 +15,16 @@ import net.mamoe.mirai.LowLevelAPI
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.recallIn
import kotlin.jvm.JvmSynthetic
/**
* 发送消息后得到的回执. 可用于撤回.
*
* 此对象持有 [Contact] 的弱引用, [Bot] 离线后将会释放引用, 届时 [target] 将无法访问.
*
* @param source 指代发送出去的消息
* @param target 消息发送对象
*
* @see Group.sendMessage 发送群消息, 返回回执此对象
* @see QQ.sendMessage 发送群消息, 返回回执此对象
*
@ -28,11 +32,15 @@ import net.mamoe.mirai.recallIn
* @see MessageReceipt.sourceSequenceId 源序列号
* @see MessageReceipt.sourceTime 源时间
*/
expect open class MessageReceipt<C : Contact>(
expect open class MessageReceipt<C : Contact> @OptIn(ExperimentalMessageSource::class) constructor(
source: MessageSource,
target: C,
botAsMember: Member?
) {
/**
* 指代发送出去的消息
*/
@ExperimentalMessageSource
val source: MessageSource
/**
@ -90,6 +98,8 @@ expect open class MessageReceipt<C : Contact>(
*
* @see MessageSource.id
*/
@get:JvmSynthetic
@ExperimentalMessageSource
inline val MessageReceipt<*>.sourceId: Long get() = this.source.id
/**
@ -97,6 +107,8 @@ inline val MessageReceipt<*>.sourceId: Long get() = this.source.id
*
* @see MessageSource.sequenceId
*/
@get:JvmSynthetic
@ExperimentalMessageSource
inline val MessageReceipt<*>.sourceSequenceId: Int get() = this.source.sequenceId
/**
@ -104,6 +116,8 @@ inline val MessageReceipt<*>.sourceSequenceId: Int get() = this.source.sequenceI
*
* @see MessageSource.time
*/
@get:JvmSynthetic
@ExperimentalMessageSource
inline val MessageReceipt<*>.sourceTime: Long get() = this.source.time
suspend inline fun MessageReceipt<out Contact>.quoteReply(message: Message) {

View File

@ -127,6 +127,7 @@ inline fun <reified M : Message> MessageChain.any(): Boolean = this.any { it is
/**
* 获取第一个 [M] 类型的 [Message] 实例
*/
@OptIn(ExperimentalMessageSource::class)
@JvmSynthetic
@Suppress("UNCHECKED_CAST")
fun <M : Message> MessageChain.firstOrNull(key: Message.Key<M>): M? = when (key) {

View File

@ -19,6 +19,12 @@ import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic
/**
* MessageSource 正计划于 0.32 0.33 或之后进行 API 不兼容的重写.
*/
@RequiresOptIn(message = "MessageSource 正计划于 0.32 或 0.33 或之后进行 API 不兼容的重写", level = RequiresOptIn.Level.WARNING)
annotation class ExperimentalMessageSource
/**
* 消息源, 它存在于 [MessageChain] , 用于表示这个消息的来源.
*
@ -29,6 +35,7 @@ import kotlin.jvm.JvmSynthetic
* @see Bot.recall 撤回一条消息
* @see MessageSource.quote 引用这条消息, 创建 [MessageChain]
*/
@ExperimentalMessageSource
interface MessageSource : Message, MessageMetadata {
companion object Key : Message.Key<MessageSource>
@ -82,6 +89,7 @@ interface MessageSource : Message, MessageMetadata {
* 序列号. 若是机器人发出去的消息, 请先 [确保 sequenceId 可用][MessageSource.ensureSequenceIdAvailable]
* @see MessageSource.id
*/
@ExperimentalMessageSource
@get:JvmSynthetic
inline val MessageSource.sequenceId: Int
get() = (this.id shr 32).toInt()
@ -90,6 +98,7 @@ inline val MessageSource.sequenceId: Int
* 消息随机数. 由服务器或客户端指定后不能更改. 它是消息 id 的一部分.
* @see MessageSource.id
*/
@ExperimentalMessageSource
@get:JvmSynthetic
inline val MessageSource.messageRandom: Int
get() = this.id.toInt()
@ -98,24 +107,33 @@ inline val MessageSource.messageRandom: Int
/**
* 消息 id.
*
* 仅接收到的消息才可以获取这个 id.
*
* @see MessageSource.id
*/
@ExperimentalMessageSource
@get:JvmSynthetic
inline val MessageChain.id: Long
get() = this[MessageSource].id
/**
* 消息序列号, 可能来自服务器也可以发送时赋值, 不唯一.
*
* 仅接收到的消息才可以获取这个序列号.
*
* @see MessageSource.id
*/
@ExperimentalMessageSource
@get:JvmSynthetic
inline val MessageChain.sequenceId: Int
get() = this[MessageSource].sequenceId
get() = this.getOrNull(MessageSource)?.sequenceId ?: error("Only MessageChain from server has sequenceId")
/**
* 消息随机数. 由服务器或客户端指定后不能更改. 它是消息 id 的一部分.
* @see MessageSource.id
*/
@ExperimentalMessageSource
@get:JvmSynthetic
inline val MessageChain.messageRandom: Int
get() = this[MessageSource].messageRandom
get() = this.getOrNull(MessageSource)?.messageRandom ?: error("Only MessageChain from server has sequenceId")

View File

@ -29,6 +29,7 @@ import kotlin.jvm.JvmName
* 总是使用 [quote] 来构造这个实例.
*/
open class QuoteReply
@OptIn(ExperimentalMessageSource::class)
@MiraiInternalAPI constructor(val source: MessageSource) : Message, MessageMetadata {
companion object Key : Message.Key<QuoteReply>
@ -39,7 +40,7 @@ open class QuoteReply
* 用于发送的引用回复.
* 总是使用 [quote] 来构造实例.
*/
@OptIn(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class, ExperimentalMessageSource::class)
sealed class QuoteReplyToSend
@MiraiInternalAPI constructor(source: MessageSource) : QuoteReply(source) {
class ToGroup(source: MessageSource, val sender: QQ) : QuoteReplyToSend(source) {
@ -53,7 +54,7 @@ sealed class QuoteReplyToSend
* 引用这条消息.
* @see sender 消息发送人.
*/
@OptIn(MiraiInternalAPI::class)
@OptIn(MiraiInternalAPI::class, ExperimentalMessageSource::class)
fun MessageChain.quote(sender: QQ?): QuoteReplyToSend {
this.firstOrNull<MessageSource>()?.let {
return it.quote(sender)
@ -65,6 +66,7 @@ fun MessageChain.quote(sender: QQ?): QuoteReplyToSend {
* 引用这条消息.
* @see from 消息来源. 若是好友发送
*/
@ExperimentalMessageSource
@OptIn(MiraiInternalAPI::class)
fun MessageSource.quote(from: QQ?): QuoteReplyToSend {
return if (this.groupId != 0L) {

View File

@ -7,6 +7,7 @@ import kotlinx.coroutines.io.ByteReadChannel
import net.mamoe.mirai.contact.*
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.ExperimentalMessageSource
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
@ -162,6 +163,7 @@ actual abstract class Bot actual constructor() : CoroutineScope, LowLevelBotAPIA
* @see _lowLevelRecallFriendMessage 低级 API
* @see _lowLevelRecallGroupMessage 低级 API
*/
@ExperimentalMessageSource
@JvmSynthetic
actual abstract suspend fun recall(source: MessageSource)

View File

@ -5,6 +5,7 @@ import net.mamoe.mirai.contact.PermissionDeniedException
import net.mamoe.mirai.contact.recall
import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.message.MessageReceipt
import net.mamoe.mirai.message.data.ExperimentalMessageSource
import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.message.data.MessageChain
import net.mamoe.mirai.message.data.MessageSource
@ -61,6 +62,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
*
* @see Bot.recall (扩展函数) 接受参数 [MessageChain]
*/
@ExperimentalMessageSource
@JvmName("recall")
fun __recallBlockingForJava__(source: MessageSource) {
runBlocking { recall(source) }
@ -88,6 +90,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
* @param millis 延迟的时间, 单位为毫秒
* @see recall
*/
@ExperimentalMessageSource
@JvmName("recallIn")
fun __recallIn_MemberForJava__(source: MessageSource, millis: Long) {
runBlocking { recallIn(source, millis) }
@ -148,6 +151,7 @@ actual abstract class BotJavaFriendlyAPI actual constructor() {
/**
* 异步调用 [__recallBlockingForJava__]
*/
@ExperimentalMessageSource
@JvmName("recallAsync")
fun __recallAsyncForJava__(source: MessageSource): Future<Unit> {
return future { recall(source) }

View File

@ -29,7 +29,8 @@ import net.mamoe.mirai.utils.unsafeWeakRef
*/
@Suppress("FunctionName")
@OptIn(MiraiInternalAPI::class)
actual open class MessageReceipt<C : Contact> actual constructor(
actual open class MessageReceipt<C : Contact> @OptIn(ExperimentalMessageSource::class)
actual constructor(
actual val source: MessageSource,
target: C,
private val botAsMember: Member?
@ -56,6 +57,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* @see Bot.recall
* @throws IllegalStateException 当此消息已经被撤回或正计划撤回时
*/
@OptIn(ExperimentalMessageSource::class)
actual suspend fun recall() {
@Suppress("BooleanLiteralArgument")
if (_isRecalled.compareAndSet(false, true)) {
@ -84,6 +86,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
* [确保 sequenceId可用][MessageSource.ensureSequenceIdAvailable] 然后引用这条消息.
* @see MessageChain.quote 引用一条消息
*/
@OptIn(ExperimentalMessageSource::class)
actual open suspend fun quote(): QuoteReplyToSend {
this.source.ensureSequenceIdAvailable()
@OptIn(LowLevelAPI::class)
@ -97,6 +100,7 @@ actual open class MessageReceipt<C : Contact> actual constructor(
*
* @see MessageChain.quote 引用一条消息
*/
@OptIn(ExperimentalMessageSource::class)
@LowLevelAPI
@Suppress("FunctionName")
actual fun _unsafeQuote(): QuoteReplyToSend {