outgoingSourceImpl.kt 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. /*
  2. * Copyright 2019-2021 Mamoe Technologies and contributors.
  3. *
  4. * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  5. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  6. *
  7. * https://github.com/mamoe/mirai/blob/master/LICENSE
  8. */
  9. @file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_OVERRIDE", "INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
  10. package net.mamoe.mirai.internal.message
  11. import kotlinx.coroutines.CompletableDeferred
  12. import kotlinx.coroutines.CoroutineScope
  13. import kotlinx.coroutines.Deferred
  14. import kotlinx.coroutines.ExperimentalCoroutinesApi
  15. import kotlinx.serialization.Serializable
  16. import net.mamoe.mirai.Bot
  17. import net.mamoe.mirai.Mirai
  18. import net.mamoe.mirai.contact.*
  19. import net.mamoe.mirai.event.asyncFromEventOrNull
  20. import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
  21. import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
  22. import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
  23. import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg.SendGroupMessageReceipt
  24. import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
  25. import net.mamoe.mirai.message.data.MessageChain
  26. import net.mamoe.mirai.message.data.MessageSource
  27. import net.mamoe.mirai.message.data.OnlineMessageSource
  28. import net.mamoe.mirai.utils.toLongUnsigned
  29. import java.util.concurrent.atomic.AtomicBoolean
  30. private fun <T> T.toJceDataImpl(subject: ContactOrBot?): ImMsgBody.SourceMsg
  31. where T : MessageSourceInternal, T : MessageSource {
  32. val elements = originalMessage.toRichTextElems(subject, withGeneralFlags = true)
  33. val pdReserve = SourceMsg.ResvAttr(
  34. origUids = sequenceIds.zip(internalIds)
  35. .map { (seq, internal) -> seq.toLong().shl(32) or internal.toLongUnsigned() }
  36. )
  37. return ImMsgBody.SourceMsg(
  38. origSeqs = sequenceIds,
  39. senderUin = fromId,
  40. toUin = targetId,
  41. flag = 1,
  42. elems = elements,
  43. type = 0,
  44. time = time,
  45. pbReserve = pdReserve.toByteArray(SourceMsg.ResvAttr.serializer()),
  46. srcMsg = MsgComm.Msg(
  47. msgHead = MsgComm.MsgHead(
  48. fromUin = fromId, // qq
  49. toUin = targetId, // group
  50. msgType = 9, // 82?
  51. c2cCmd = 11,
  52. msgSeq = sequenceIds.first(),
  53. msgTime = time,
  54. msgUid = pdReserve.origUids!!.first(),
  55. // groupInfo = MsgComm.GroupInfo(groupCode = delegate.msgHead.groupInfo.groupCode),
  56. isSrcMsg = true
  57. ),
  58. msgBody = ImMsgBody.MsgBody(
  59. richText = ImMsgBody.RichText(
  60. elems = elements.toMutableList().also {
  61. if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
  62. }
  63. )
  64. )
  65. ).toByteArray(MsgComm.Msg.serializer())
  66. )
  67. }
  68. @Serializable(OnlineMessageSourceToFriendImpl.Serializer::class)
  69. internal class OnlineMessageSourceToFriendImpl(
  70. override val sequenceIds: IntArray,
  71. override val internalIds: IntArray,
  72. override val time: Int,
  73. override val originalMessage: MessageChain,
  74. override val sender: Bot,
  75. override val target: Friend
  76. ) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal {
  77. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToFriend")
  78. override val bot: Bot
  79. get() = sender
  80. override val ids: IntArray
  81. get() = sequenceIds
  82. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  83. private val jceData by lazy { toJceDataImpl(subject) }
  84. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  85. }
  86. @Serializable(OnlineMessageSourceToStrangerImpl.Serializer::class)
  87. internal class OnlineMessageSourceToStrangerImpl(
  88. override val sequenceIds: IntArray,
  89. override val internalIds: IntArray,
  90. override val time: Int,
  91. override val originalMessage: MessageChain,
  92. override val sender: Bot,
  93. override val target: Stranger
  94. ) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal {
  95. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToStranger")
  96. override val bot: Bot
  97. get() = sender
  98. override val ids: IntArray
  99. get() = sequenceIds
  100. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  101. private val jceData by lazy { toJceDataImpl(subject) }
  102. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  103. }
  104. @Serializable(OnlineMessageSourceToTempImpl.Serializer::class)
  105. internal class OnlineMessageSourceToTempImpl(
  106. override val sequenceIds: IntArray,
  107. override val internalIds: IntArray,
  108. override val time: Int,
  109. override val originalMessage: MessageChain,
  110. override val sender: Bot,
  111. override val target: Member
  112. ) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal {
  113. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToTemp")
  114. override val bot: Bot
  115. get() = sender
  116. override val ids: IntArray
  117. get() = sequenceIds
  118. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  119. private val jceData by lazy { toJceDataImpl(subject) }
  120. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  121. }
  122. @Serializable(OnlineMessageSourceToGroupImpl.Serializer::class)
  123. internal class OnlineMessageSourceToGroupImpl(
  124. coroutineScope: CoroutineScope,
  125. override val internalIds: IntArray, // aka random
  126. override val time: Int,
  127. override val originalMessage: MessageChain,
  128. override val sender: Bot,
  129. override val target: Group,
  130. providedSequenceIds: IntArray? = null,
  131. ) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
  132. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToGroup")
  133. override val ids: IntArray
  134. get() = sequenceIds
  135. override val bot: Bot
  136. get() = sender
  137. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  138. private val sequenceIdDeferred: Deferred<IntArray?> = providedSequenceIds?.let { CompletableDeferred(it) } ?: run {
  139. val multi = mutableMapOf<Int, Int>()
  140. coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, IntArray>(
  141. timeoutMillis = 3000L * [email protected]
  142. ) {
  143. if (it.messageRandom in [email protected]) {
  144. multi[it.messageRandom] = it.sequenceId
  145. if (multi.size == [email protected]) {
  146. IntArray(multi.size) { index ->
  147. multi[[email protected][index]]!!
  148. }
  149. } else null
  150. } else null
  151. }
  152. }
  153. @OptIn(ExperimentalCoroutinesApi::class)
  154. override val sequenceIds: IntArray
  155. get() = when {
  156. sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: intArrayOf()
  157. !sequenceIdDeferred.isActive -> intArrayOf()
  158. else -> error("sequenceIds not yet available")
  159. }
  160. suspend fun ensureSequenceIdAvailable() = kotlin.run { sequenceIdDeferred.await() }
  161. private val jceData by lazy {
  162. val elements = originalMessage.toRichTextElems(subject, withGeneralFlags = true)
  163. ImMsgBody.SourceMsg(
  164. origSeqs = sequenceIds,
  165. senderUin = fromId,
  166. toUin = Mirai.calculateGroupUinByGroupCode(targetId),
  167. flag = 1,
  168. elems = elements,
  169. type = 0,
  170. time = time,
  171. pbReserve = SourceMsg.ResvAttr(
  172. origUids = internalIds.map { it.toLongUnsigned() } // ids is actually messageRandom
  173. ).toByteArray(SourceMsg.ResvAttr.serializer()),
  174. srcMsg = MsgComm.Msg(
  175. msgHead = MsgComm.MsgHead(
  176. fromUin = fromId, // qq
  177. toUin = Mirai.calculateGroupUinByGroupCode(targetId), // group
  178. msgType = 82, // 82?
  179. c2cCmd = 1,
  180. msgSeq = sequenceIds.single(), // TODO !!
  181. msgTime = time,
  182. msgUid = internalIds.single().toLongUnsigned(), // TODO !!
  183. groupInfo = MsgComm.GroupInfo(groupCode = targetId),
  184. isSrcMsg = true
  185. ),
  186. msgBody = ImMsgBody.MsgBody(
  187. richText = ImMsgBody.RichText(
  188. elems = elements.toMutableList().also {
  189. if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
  190. }
  191. )
  192. )
  193. ).toByteArray(MsgComm.Msg.serializer())
  194. )
  195. }
  196. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  197. }