mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-14 07:10:09 +08:00
Support TempMessage
This commit is contained in:
parent
fc8714de5f
commit
2053ab198c
@ -46,6 +46,7 @@ import net.mamoe.mirai.qqandroid.network.highway.HighwayHelper
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.LongMsg
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.utils.*
|
||||
import net.mamoe.mirai.qqandroid.utils.MiraiPlatformUtils
|
||||
import net.mamoe.mirai.qqandroid.utils.encodeToString
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
|
||||
@ -327,6 +328,22 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
is MessageSourceFromTempImpl,
|
||||
is MessageSourceToTempImpl
|
||||
-> network.run {
|
||||
check(source.fromId == this@QQAndroidBotBase.id) {
|
||||
"can only recall a message sent by bot"
|
||||
}
|
||||
source as MessageSourceToTempImpl
|
||||
PbMessageSvc.PbMsgWithDraw.createForTempMessage(
|
||||
bot.client,
|
||||
source.target.group.id,
|
||||
source.targetId,
|
||||
source.sequenceId,
|
||||
source.id,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
is OfflineMessageSource -> network.run {
|
||||
when (source.kind) {
|
||||
OfflineMessageSource.Kind.FRIEND -> {
|
||||
@ -341,6 +358,19 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
OfflineMessageSource.Kind.TEMP -> {
|
||||
check(source.fromId == this@QQAndroidBotBase.id) {
|
||||
"can only recall a message sent by bot"
|
||||
}
|
||||
PbMessageSvc.PbMsgWithDraw.createForTempMessage(
|
||||
bot.client,
|
||||
source.targetId, // groupUin
|
||||
source.targetId, // memberUin
|
||||
source.sequenceId,
|
||||
source.id,
|
||||
source.time
|
||||
).sendAndExpect<PbMessageSvc.PbMsgWithDraw.Response>()
|
||||
}
|
||||
OfflineMessageSource.Kind.GROUP -> {
|
||||
PbMessageSvc.PbMsgWithDraw.createForGroupMessage(
|
||||
bot.client,
|
||||
|
@ -11,6 +11,8 @@
|
||||
|
||||
package net.mamoe.mirai.qqandroid.contact
|
||||
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.launch
|
||||
import net.mamoe.mirai.LowLevelAPI
|
||||
import net.mamoe.mirai.contact.*
|
||||
@ -25,10 +27,15 @@ import net.mamoe.mirai.event.events.MemberSpecialTitleChangeEvent
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.OfflineFriendImage
|
||||
import net.mamoe.mirai.message.data.asMessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.message.MessageSourceToTempImpl
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.StTroopMemberInfo
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.contracts.ExperimentalContracts
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.jvm.JvmSynthetic
|
||||
|
||||
@ -42,6 +49,8 @@ internal class MemberImpl constructor(
|
||||
) : Member() {
|
||||
override val group: GroupImpl by group.unsafeWeakRef()
|
||||
|
||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||
|
||||
// region QQ delegate
|
||||
override val id: Long = qq.id
|
||||
override val nick: String = qq.nick
|
||||
@ -61,7 +70,23 @@ internal class MemberImpl constructor(
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<Member> {
|
||||
return sendMessageImpl(message).also {
|
||||
logMessageSent(message)
|
||||
} as MessageReceipt<Member>
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun sendMessageImpl(message: Message): MessageReceipt<Member> {
|
||||
lateinit var source: MessageSourceToTempImpl
|
||||
bot.network.run {
|
||||
check(
|
||||
MessageSvc.PbSendMsg.createToTemp(
|
||||
bot.client,
|
||||
this@MemberImpl,
|
||||
message.asMessageChain()
|
||||
) {
|
||||
source = it
|
||||
}.sendAndExpect<MessageSvc.PbSendMsg.Response>() is MessageSvc.PbSendMsg.Response.SUCCESS
|
||||
) { "send message failed" }
|
||||
}
|
||||
return MessageReceipt(source, this, null)
|
||||
}
|
||||
|
||||
@JvmSynthetic
|
||||
@ -205,6 +230,15 @@ internal class MemberImpl constructor(
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal fun Member.checkIsMemberImpl(): MemberImpl {
|
||||
contract {
|
||||
returns() implies (this@checkIsMemberImpl is MemberImpl)
|
||||
}
|
||||
check(this is MemberImpl) { "A Member instance is not instance of MemberImpl. Don't interlace two protocol implementations together!" }
|
||||
return this
|
||||
}
|
||||
|
||||
@OptIn(LowLevelAPI::class)
|
||||
internal class MemberInfoImpl(
|
||||
jceInfo: StTroopMemberInfo,
|
||||
|
@ -110,6 +110,71 @@ internal class MessageSourceFromFriendImpl(
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageSourceFromTempImpl(
|
||||
override val bot: Bot,
|
||||
private val msg: MsgComm.Msg
|
||||
) : OnlineMessageSource.Incoming.FromTemp(), MessageSourceImpl {
|
||||
override val sequenceId: Int get() = msg.msgHead.msgSeq
|
||||
private val isRecalled: AtomicBoolean = atomic(false)
|
||||
override var isRecalledOrPlanned: Boolean
|
||||
get() = isRecalled.value
|
||||
set(value) {
|
||||
isRecalled.value = value
|
||||
}
|
||||
override val id: Int get() = msg.msgBody.richText.attr!!.random
|
||||
override val time: Int get() = msg.msgHead.msgTime
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
msg.toMessageChain(
|
||||
bot,
|
||||
groupIdOrZero = 0,
|
||||
onlineSource = false
|
||||
)
|
||||
}
|
||||
override val target: Bot get() = bot
|
||||
override val sender: Member get() = with(msg.msgHead) {
|
||||
bot.getGroup(c2cTmpMsgHead!!.groupUin)[fromUin]
|
||||
}
|
||||
|
||||
private val elems by lazy {
|
||||
msg.msgBody.richText.elems.toMutableList().also {
|
||||
if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
|
||||
}
|
||||
}
|
||||
|
||||
internal fun toJceDataImplForTemp(): ImMsgBody.SourceMsg {
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(msg.msgHead.msgSeq),
|
||||
senderUin = msg.msgHead.fromUin,
|
||||
toUin = msg.msgHead.toUin,
|
||||
flag = 1,
|
||||
elems = msg.msgBody.richText.elems,
|
||||
type = 0,
|
||||
time = msg.msgHead.msgTime,
|
||||
pbReserve = SourceMsg.ResvAttr(
|
||||
origUids = id.toULong().toLong()
|
||||
).toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
srcMsg = MsgComm.Msg(
|
||||
msgHead = MsgComm.MsgHead(
|
||||
fromUin = msg.msgHead.fromUin, // qq
|
||||
toUin = msg.msgHead.toUin, // group
|
||||
msgType = msg.msgHead.msgType, // 82?
|
||||
c2cCmd = msg.msgHead.c2cCmd,
|
||||
msgSeq = msg.msgHead.msgSeq,
|
||||
msgTime = msg.msgHead.msgTime,
|
||||
msgUid = id.toULong().toLong(), // ok
|
||||
// groupInfo = MsgComm.GroupInfo(groupCode = msg.msgHead.groupInfo.groupCode),
|
||||
isSrcMsg = true
|
||||
),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = elems
|
||||
)
|
||||
)
|
||||
).toByteArray(MsgComm.Msg.serializer())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageSourceFromGroupImpl(
|
||||
override val bot: Bot,
|
||||
private val msg: MsgComm.Msg
|
||||
@ -168,7 +233,11 @@ internal class OfflineMessageSourceImplByMsg( // from other sources' originalMes
|
||||
override val targetId: Long
|
||||
get() = delegate.msgHead.groupInfo?.groupCode ?: delegate.msgHead.toUin
|
||||
override val originalMessage: MessageChain by lazy {
|
||||
delegate.toMessageChain(bot, delegate.msgHead.groupInfo?.groupCode ?: 0, false)
|
||||
delegate.toMessageChain(bot,
|
||||
groupIdOrZero = delegate.msgHead.groupInfo?.groupCode ?: 0,
|
||||
onlineSource = false,
|
||||
isTemp = delegate.msgHead.c2cTmpMsgHead != null
|
||||
)
|
||||
}
|
||||
override val sequenceId: Int
|
||||
get() = delegate.msgHead.msgSeq
|
||||
@ -283,7 +352,63 @@ internal class MessageSourceToFriendImpl(
|
||||
).toByteArray(MsgComm.Msg.serializer())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageSourceToTempImpl(
|
||||
override val sequenceId: Int,
|
||||
override val id: Int,
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
override val target: Member
|
||||
) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceImpl {
|
||||
override val bot: Bot
|
||||
get() = sender
|
||||
private val isRecalled: AtomicBoolean = atomic(false)
|
||||
override var isRecalledOrPlanned: Boolean
|
||||
get() = isRecalled.value
|
||||
set(value) {
|
||||
isRecalled.value = value
|
||||
}
|
||||
private val elems by lazy {
|
||||
originalMessage.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
}
|
||||
|
||||
fun toJceDataImplForTemp(): ImMsgBody.SourceMsg {
|
||||
val messageUid: Long = sequenceId.toLong().shl(32) or id.toLong().and(0xffFFffFF)
|
||||
return ImMsgBody.SourceMsg(
|
||||
origSeqs = listOf(sequenceId),
|
||||
senderUin = fromId,
|
||||
toUin = targetId,
|
||||
flag = 1,
|
||||
elems = elems,
|
||||
type = 0,
|
||||
time = time,
|
||||
pbReserve = SourceMsg.ResvAttr(
|
||||
origUids = messageUid
|
||||
).toByteArray(SourceMsg.ResvAttr.serializer()),
|
||||
srcMsg = MsgComm.Msg(
|
||||
msgHead = MsgComm.MsgHead(
|
||||
fromUin = fromId, // qq
|
||||
toUin = targetId, // group
|
||||
msgType = 9, // 82?
|
||||
c2cCmd = 11,
|
||||
msgSeq = sequenceId,
|
||||
msgTime = time,
|
||||
msgUid = messageUid, // ok
|
||||
// groupInfo = MsgComm.GroupInfo(groupCode = delegate.msgHead.groupInfo.groupCode),
|
||||
isSrcMsg = true
|
||||
),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = elems.toMutableList().also {
|
||||
if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
|
||||
}
|
||||
)
|
||||
)
|
||||
).toByteArray(MsgComm.Msg.serializer())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
internal class MessageSourceToGroupImpl(
|
||||
|
@ -42,8 +42,10 @@ internal fun MessageChain.toRichTextElems(forGroup: Boolean, withGeneralFlags: B
|
||||
is OfflineMessageSourceImplBySourceMsg -> elements.add(ImMsgBody.Elem(srcMsg = source.delegate))
|
||||
is MessageSourceToFriendImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForFriend()))
|
||||
is MessageSourceToGroupImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForGroup()))
|
||||
is MessageSourceToTempImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForTemp()))
|
||||
is MessageSourceFromFriendImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForFriend()))
|
||||
is MessageSourceFromGroupImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForGroup()))
|
||||
is MessageSourceFromTempImpl -> elements.add(ImMsgBody.Elem(srcMsg = source.toJceDataImplForTemp()))
|
||||
else -> error("unsupported MessageSource implementation: ${source::class.simpleName}")
|
||||
}
|
||||
}
|
||||
@ -176,15 +178,15 @@ private val PB_RESERVE_FOR_DOUTU = "78 00 90 01 01 F8 01 00 A0 02 00 C8 02 00".h
|
||||
private val PB_RESERVE_FOR_ELSE = "78 00 F8 01 00 C8 02 00".hexToBytes()
|
||||
|
||||
@OptIn(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
|
||||
internal fun MsgComm.Msg.toMessageChain(bot: Bot, groupIdOrZero: Long, onlineSource: Boolean): MessageChain {
|
||||
internal fun MsgComm.Msg.toMessageChain(bot: Bot, groupIdOrZero: Long, onlineSource: Boolean, isTemp: Boolean = false): MessageChain {
|
||||
val elements = this.msgBody.richText.elems
|
||||
|
||||
return buildMessageChain(elements.size + 1) {
|
||||
if (onlineSource) {
|
||||
if (groupIdOrZero != 0L) {
|
||||
+MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
} else {
|
||||
+MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
when {
|
||||
isTemp -> +MessageSourceFromTempImpl(bot, this@toMessageChain)
|
||||
groupIdOrZero != 0L -> +MessageSourceFromGroupImpl(bot, this@toMessageChain)
|
||||
else -> +MessageSourceFromFriendImpl(bot, this@toMessageChain)
|
||||
}
|
||||
} else {
|
||||
+OfflineMessageSourceImplByMsg(this@toMessageChain, bot)
|
||||
|
@ -20,6 +20,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.qqandroid.utils._miraiContentToString
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.qqandroid.utils.io.serialization.writeProtoBuf
|
||||
@ -73,6 +74,38 @@ internal class PbMessageSvc {
|
||||
)
|
||||
}
|
||||
|
||||
fun createForTempMessage(
|
||||
client: QQAndroidClient,
|
||||
groupUin: Long,
|
||||
toUin: Long,
|
||||
messageSequenceId: Int, // 56639
|
||||
messageRandom: Int, // 921878719
|
||||
time: Int
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbMsgWithDrawReq.serializer(),
|
||||
MsgSvc.PbMsgWithDrawReq(
|
||||
c2cWithDraw = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq(
|
||||
subCmd = 1,
|
||||
msgInfo = listOf(
|
||||
MsgSvc.PbC2CMsgWithDrawReq.MsgInfo(
|
||||
fromUin = client.bot.id,
|
||||
toUin = toUin,
|
||||
msgSeq = messageSequenceId,
|
||||
msgUid = 1000000000000000000L or messageRandom.toULong().toLong(),
|
||||
msgTime = time.toLong(),
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun createForFriendMessage(
|
||||
client: QQAndroidClient,
|
||||
toUin: Long,
|
||||
|
@ -19,6 +19,7 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import net.mamoe.mirai.LowLevelAPI
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
@ -27,14 +28,13 @@ import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||
import net.mamoe.mirai.event.events.MemberJoinEvent
|
||||
import net.mamoe.mirai.getFriendOrNull
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.TempMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.contact.GroupImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl
|
||||
import net.mamoe.mirai.qqandroid.contact.checkIsQQImpl
|
||||
import net.mamoe.mirai.qqandroid.message.MessageSourceToFriendImpl
|
||||
import net.mamoe.mirai.qqandroid.message.MessageSourceToGroupImpl
|
||||
import net.mamoe.mirai.qqandroid.message.toMessageChain
|
||||
import net.mamoe.mirai.qqandroid.message.toRichTextElems
|
||||
import net.mamoe.mirai.qqandroid.message.*
|
||||
import net.mamoe.mirai.qqandroid.network.MultiPacketByIterable
|
||||
import net.mamoe.mirai.qqandroid.network.Packet
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
@ -236,16 +236,38 @@ internal class MessageSvc {
|
||||
} else return@mapNotNull null
|
||||
}
|
||||
}
|
||||
84 -> { // 群验证
|
||||
141 -> {
|
||||
val tmpHead = msg.msgHead.c2cTmpMsgHead ?: return@mapNotNull null
|
||||
val member = bot.getGroupByUinOrNull(tmpHead.groupUin)?.getOrNull(msg.msgHead.fromUin)
|
||||
?: return@mapNotNull null
|
||||
|
||||
member.checkIsMemberImpl()
|
||||
|
||||
if (msg.msgHead.fromUin == bot.id || !bot.firstLoginSucceed) {
|
||||
return@mapNotNull null
|
||||
}
|
||||
|
||||
member.lastMessageSequence.loop { instant ->
|
||||
if (msg.msgHead.msgSeq > instant) {
|
||||
if (member.lastMessageSequence.compareAndSet(instant, msg.msgHead.msgSeq)) {
|
||||
return@mapNotNull TempMessage(
|
||||
member,
|
||||
msg.toMessageChain(bot, groupIdOrZero = 0, onlineSource = true, isTemp = true)
|
||||
)
|
||||
}
|
||||
} else return@mapNotNull null
|
||||
}
|
||||
}
|
||||
84 -> { // 请求入群验证
|
||||
bot.network.run {
|
||||
NewContact.SystemMsgNewGroup(bot.client).sendWithoutExpect()
|
||||
|
||||
// 处理后要向服务器提交已阅,否则登陆时会重复收到事件
|
||||
NewContact.Del(bot.client, msg.msgHead).sendWithoutExpect()
|
||||
}
|
||||
return@mapNotNull null
|
||||
return@mapNotNull null
|
||||
}
|
||||
187 -> { // 好友验证
|
||||
187 -> { // 请求加好友验证
|
||||
bot.network.run {
|
||||
NewContact.SystemMsgNewFriend(bot.client).sendWithoutExpect()
|
||||
|
||||
@ -360,6 +382,53 @@ internal class MessageSvc {
|
||||
}
|
||||
|
||||
|
||||
inline fun createToTemp(
|
||||
client: QQAndroidClient,
|
||||
member: Member,
|
||||
message: MessageChain,
|
||||
sourceCallback: (MessageSourceToTempImpl) -> Unit
|
||||
): OutgoingPacket {
|
||||
val source = MessageSourceToTempImpl(
|
||||
id = Random.nextInt().absoluteValue,
|
||||
sender = client.bot,
|
||||
target = member,
|
||||
time = currentTimeSeconds.toInt(),
|
||||
sequenceId = client.atomicNextMessageSequenceId(),
|
||||
originalMessage = message
|
||||
)
|
||||
sourceCallback(source)
|
||||
return createToTemp(client, member.group.id, member.id, message, source)
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送临时消息
|
||||
*/
|
||||
private fun createToTemp(
|
||||
client: QQAndroidClient,
|
||||
groupUin: Long,
|
||||
toUin: Long,
|
||||
message: MessageChain,
|
||||
source: MessageSourceToTempImpl
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
|
||||
routingHead = MsgSvc.RoutingHead(
|
||||
grpTmp = MsgSvc.GrpTmp(groupUin, toUin)
|
||||
),
|
||||
contentHead = MsgComm.ContentHead(pkgNum = 1),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = message.toRichTextElems(forGroup = false, withGeneralFlags = true)
|
||||
)
|
||||
),
|
||||
msgSeq = source.sequenceId,
|
||||
msgRand = source.id,
|
||||
syncCookie = SyncCookie(time = source.time.toULong().toLong()).toByteArray(SyncCookie.serializer())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
inline fun createToGroup(
|
||||
client: QQAndroidClient,
|
||||
group: Group,
|
||||
|
@ -28,6 +28,7 @@ import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
*
|
||||
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see Member.sendMessage 发送临时消息, 返回回执(此对象)
|
||||
*
|
||||
* @see MessageReceipt.sourceId 源 id
|
||||
* @see MessageReceipt.sourceTime 源时间
|
||||
@ -45,7 +46,7 @@ actual constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送目标, 为 [Group] 或 [QQ]
|
||||
* 发送目标, 为 [Group] 或 [QQ] 或 [Member]
|
||||
*/
|
||||
actual val target: C by target.unsafeWeakRef()
|
||||
|
||||
|
@ -30,6 +30,7 @@ import kotlin.jvm.JvmSynthetic
|
||||
*
|
||||
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see Member.sendMessage 发送临时消息, 返回回执(此对象)
|
||||
*
|
||||
* @see MessageReceipt.sourceId 源 id
|
||||
* @see MessageReceipt.sourceTime 源时间
|
||||
@ -45,7 +46,7 @@ expect open class MessageReceipt<out C : Contact>(
|
||||
val source: OnlineMessageSource.Outgoing
|
||||
|
||||
/**
|
||||
* 发送目标, 为 [Group] 或 [QQ]
|
||||
* 发送目标, 为 [Group] 或 [QQ] 或 [Member]
|
||||
*/
|
||||
val target: C
|
||||
|
||||
|
@ -0,0 +1,22 @@
|
||||
package net.mamoe.mirai.message
|
||||
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.OnlineMessageSource
|
||||
import net.mamoe.mirai.message.data.source
|
||||
import net.mamoe.mirai.utils.getValue
|
||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
|
||||
class TempMessage(
|
||||
sender: Member,
|
||||
override val message: MessageChain
|
||||
) : ContactMessage(), BroadcastControllable {
|
||||
override val sender: Member by sender.unsafeWeakRef()
|
||||
override val bot: Bot get() = sender.bot
|
||||
override val subject: Member get() = sender
|
||||
override val source: OnlineMessageSource.Incoming.FromTemp get() = message.source as OnlineMessageSource.Incoming.FromTemp
|
||||
|
||||
override fun toString(): String = "TempMessage(sender=${sender.id} from group(${sender.group.id}), message=$message)"
|
||||
}
|
@ -75,11 +75,11 @@ sealed class MessageSource : Message, MessageMetadata, ConstrainSingle<OnlineMes
|
||||
|
||||
/**
|
||||
* 发送目标.
|
||||
* 当 [OnlineMessageSource.Outgoing] 时为发信 [目标好友][QQ.id] 或 [群][Group.id]
|
||||
* 当 [OnlineMessageSource.Outgoing] 时为发信 [目标好友][QQ.id] 或 [群][Group.id] 或 [临时消息][Member.id]
|
||||
* 当 [OnlineMessageSource.Incoming] 时为 [机器人][Bot.id]
|
||||
* 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] 或 [群][Group.id] (取决于 [OfflineMessageSource.kind])
|
||||
* 当 [OfflineMessageSource] 时为 [机器人][Bot.id], 发信 [目标好友][QQ.id] 或 [群][Group.id] 或 [临时消息][Member.id] (取决于 [OfflineMessageSource.kind])
|
||||
*/
|
||||
abstract val targetId: Long // groupCode / friendUin
|
||||
abstract val targetId: Long // groupCode / friendUin / memberUin
|
||||
|
||||
/**
|
||||
* 原消息内容.
|
||||
@ -127,10 +127,10 @@ sealed class OnlineMessageSource : MessageSource() {
|
||||
abstract val target: Any
|
||||
|
||||
/**
|
||||
* 消息主体. 群消息时为 [Group]. 好友消息时为 [QQ].
|
||||
* 消息主体. 群消息时为 [Group]. 好友消息时为 [QQ], 临时消息为 [Member]
|
||||
* 不论是机器人接收的消息还是发送的消息, 此属性都指向机器人能进行回复的目标.
|
||||
*/
|
||||
abstract val subject: Contact // Group or QQ
|
||||
abstract val subject: Contact
|
||||
|
||||
/**
|
||||
* 由 [机器人主动发送消息][Contact.sendMessage] 产生的 [MessageSource]
|
||||
@ -156,6 +156,15 @@ sealed class OnlineMessageSource : MessageSource() {
|
||||
// final override fun toString(): String = "OnlineMessageSource.ToFriend(target=${target.id})"
|
||||
}
|
||||
|
||||
abstract class ToTemp : Outgoing() {
|
||||
companion object Key : Message.Key<ToTemp> {
|
||||
override val typeName: String get() = "OnlineMessageSource.Outgoing.ToTemp"
|
||||
}
|
||||
|
||||
abstract override val target: Member
|
||||
final override val subject: Member get() = target
|
||||
}
|
||||
|
||||
abstract class ToGroup : Outgoing() {
|
||||
companion object Key : Message.Key<ToGroup> {
|
||||
override val typeName: String get() = "OnlineMessageSource.Outgoing.ToGroup"
|
||||
@ -193,6 +202,16 @@ sealed class OnlineMessageSource : MessageSource() {
|
||||
// final override fun toString(): String = "OnlineMessageSource.FromFriend(from=${sender.id})"
|
||||
}
|
||||
|
||||
abstract class FromTemp : Incoming() {
|
||||
companion object Key : Message.Key<FromTemp> {
|
||||
override val typeName: String
|
||||
get() = "OnlineMessageSource.Incoming.FromTemp"
|
||||
}
|
||||
|
||||
abstract override val sender: Member
|
||||
final override val subject: Member get() = sender
|
||||
}
|
||||
|
||||
abstract class FromGroup : Incoming() {
|
||||
companion object Key : Message.Key<FromGroup> {
|
||||
override val typeName: String
|
||||
@ -215,10 +234,17 @@ inline fun MessageSource.isAboutGroup(): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
inline fun MessageSource.isAboutTemp(): Boolean {
|
||||
return when(this) {
|
||||
is OnlineMessageSource -> subject is Member
|
||||
is OfflineMessageSource -> kind == OfflineMessageSource.Kind.TEMP
|
||||
}
|
||||
}
|
||||
|
||||
// inline for future removal
|
||||
inline fun MessageSource.isAboutFriend(): Boolean {
|
||||
return when (this) {
|
||||
is OnlineMessageSource -> subject !is Group
|
||||
is OnlineMessageSource -> subject !is Group && subject !is Member
|
||||
is OfflineMessageSource -> kind == OfflineMessageSource.Kind.FRIEND
|
||||
}
|
||||
}
|
||||
@ -267,7 +293,8 @@ abstract class OfflineMessageSource : MessageSource() {
|
||||
|
||||
enum class Kind {
|
||||
GROUP,
|
||||
FRIEND
|
||||
FRIEND,
|
||||
TEMP
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,6 +28,7 @@ import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
*
|
||||
* @see Group.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see QQ.sendMessage 发送群消息, 返回回执(此对象)
|
||||
* @see Member.sendMessage 发送临时消息, 返回回执(此对象)
|
||||
*
|
||||
* @see MessageReceipt.sourceId 源 id
|
||||
* @see MessageReceipt.sourceTime 源时间
|
||||
@ -45,7 +46,7 @@ actual constructor(
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送目标, 为 [Group] 或 [QQ]
|
||||
* 发送目标, 为 [Group] 或 [QQ] 或 [Member]
|
||||
*/
|
||||
actual val target: C by target.unsafeWeakRef()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user