outgoingSourceImpl.kt 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  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.notice.group.GroupMessageProcessor.SendGroupMessageReceipt
  21. import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
  22. import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
  23. import net.mamoe.mirai.internal.network.protocol.data.proto.SourceMsg
  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. @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
  69. @Serializable(OnlineMessageSourceToFriendImpl.Serializer::class)
  70. internal class OnlineMessageSourceToFriendImpl(
  71. override val sequenceIds: IntArray,
  72. override val internalIds: IntArray,
  73. override val time: Int,
  74. override var originalMessage: MessageChain,
  75. override val sender: Bot,
  76. override val target: Friend,
  77. ) : OnlineMessageSource.Outgoing.ToFriend(), MessageSourceInternal, OutgoingMessageSourceInternal {
  78. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToFriend")
  79. override val bot: Bot
  80. get() = sender
  81. override val ids: IntArray
  82. get() = sequenceIds
  83. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  84. private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
  85. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  86. }
  87. @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
  88. @Serializable(OnlineMessageSourceToStrangerImpl.Serializer::class)
  89. internal class OnlineMessageSourceToStrangerImpl(
  90. override val sequenceIds: IntArray,
  91. override val internalIds: IntArray,
  92. override val time: Int,
  93. override var originalMessage: MessageChain,
  94. override val sender: Bot,
  95. override val target: Stranger,
  96. ) : OnlineMessageSource.Outgoing.ToStranger(), MessageSourceInternal, OutgoingMessageSourceInternal {
  97. constructor(
  98. delegate: Outgoing,
  99. target: Stranger,
  100. ) : this(delegate.ids, delegate.internalIds, delegate.time, delegate.originalMessage, delegate.sender, target)
  101. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToStranger")
  102. override val bot: Bot
  103. get() = sender
  104. override val ids: IntArray
  105. get() = sequenceIds
  106. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  107. private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
  108. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  109. }
  110. @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
  111. @Serializable(OnlineMessageSourceToTempImpl.Serializer::class)
  112. internal class OnlineMessageSourceToTempImpl(
  113. override val sequenceIds: IntArray,
  114. override val internalIds: IntArray,
  115. override val time: Int,
  116. override var originalMessage: MessageChain,
  117. override val sender: Bot,
  118. override val target: Member,
  119. ) : OnlineMessageSource.Outgoing.ToTemp(), MessageSourceInternal, OutgoingMessageSourceInternal {
  120. constructor(
  121. delegate: Outgoing,
  122. target: Member,
  123. ) : this(delegate.ids, delegate.internalIds, delegate.time, delegate.originalMessage, delegate.sender, target)
  124. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToTemp")
  125. override val bot: Bot
  126. get() = sender
  127. override val ids: IntArray
  128. get() = sequenceIds
  129. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  130. private val jceData: ImMsgBody.SourceMsg by lazy { toJceDataImpl(subject) }
  131. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  132. }
  133. @Suppress("SERIALIZER_TYPE_INCOMPATIBLE")
  134. @Serializable(OnlineMessageSourceToGroupImpl.Serializer::class)
  135. internal class OnlineMessageSourceToGroupImpl(
  136. coroutineScope: CoroutineScope,
  137. override val internalIds: IntArray, // aka random
  138. override val time: Int,
  139. override var originalMessage: MessageChain,
  140. override val sender: Bot,
  141. override val target: Group,
  142. providedSequenceIds: IntArray? = null,
  143. ) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal, OutgoingMessageSourceInternal {
  144. object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToGroup")
  145. override val ids: IntArray
  146. get() = sequenceIds
  147. override val bot: Bot
  148. get() = sender
  149. override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
  150. private val sequenceIdDeferred: Deferred<IntArray?> = providedSequenceIds?.let { CompletableDeferred(it) } ?: run {
  151. val multi = mutableMapOf<Int, Int>()
  152. coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, IntArray>(
  153. timeoutMillis = 3000L * this@OnlineMessageSourceToGroupImpl.internalIds.size
  154. ) {
  155. if (it.messageRandom in this@OnlineMessageSourceToGroupImpl.internalIds) {
  156. multi[it.messageRandom] = it.sequenceId
  157. if (multi.size == this@OnlineMessageSourceToGroupImpl.internalIds.size) {
  158. IntArray(multi.size) { index ->
  159. multi[this@OnlineMessageSourceToGroupImpl.internalIds[index]]!!
  160. }
  161. } else null
  162. } else null
  163. }
  164. }
  165. @OptIn(ExperimentalCoroutinesApi::class)
  166. override val sequenceIds: IntArray
  167. get() = when {
  168. sequenceIdDeferred.isCompleted -> sequenceIdDeferred.getCompleted() ?: intArrayOf()
  169. !sequenceIdDeferred.isActive -> intArrayOf()
  170. else -> error("sequenceIds not yet available")
  171. }
  172. suspend fun ensureSequenceIdAvailable() = kotlin.run { sequenceIdDeferred.await() }
  173. private val jceData: ImMsgBody.SourceMsg by lazy {
  174. val elements = originalMessage.toRichTextElems(subject, withGeneralFlags = true)
  175. ImMsgBody.SourceMsg(
  176. origSeqs = sequenceIds,
  177. senderUin = fromId,
  178. toUin = Mirai.calculateGroupUinByGroupCode(targetId),
  179. flag = 1,
  180. elems = elements,
  181. type = 0,
  182. time = time,
  183. pbReserve = SourceMsg.ResvAttr(
  184. origUids = internalIds.map { it.toLongUnsigned() } // ids is actually messageRandom
  185. ).toByteArray(SourceMsg.ResvAttr.serializer()),
  186. srcMsg = MsgComm.Msg(
  187. msgHead = MsgComm.MsgHead(
  188. fromUin = fromId, // qq
  189. toUin = Mirai.calculateGroupUinByGroupCode(targetId), // group
  190. msgType = 82, // 82?
  191. c2cCmd = 1,
  192. msgSeq = sequenceIds.single(),
  193. msgTime = time,
  194. msgUid = internalIds.single().toLongUnsigned(),
  195. groupInfo = MsgComm.GroupInfo(groupCode = targetId),
  196. isSrcMsg = true
  197. ),
  198. msgBody = ImMsgBody.MsgBody(
  199. richText = ImMsgBody.RichText(
  200. elems = elements.toMutableList().also {
  201. if (it.last().elemFlags2 == null) it.add(ImMsgBody.Elem(elemFlags2 = ImMsgBody.ElemFlags2()))
  202. }
  203. )
  204. )
  205. ).toByteArray(MsgComm.Msg.serializer())
  206. )
  207. }
  208. override fun toJceData(): ImMsgBody.SourceMsg = jceData
  209. }