|
@@ -9,109 +9,54 @@
|
|
|
|
|
|
|
|
package net.mamoe.mirai.internal.contact.roaming
|
|
package net.mamoe.mirai.internal.contact.roaming
|
|
|
|
|
|
|
|
-import kotlinx.coroutines.flow.*
|
|
|
|
|
|
|
+import kotlinx.coroutines.flow.Flow
|
|
|
import net.mamoe.mirai.contact.roaming.RoamingMessageFilter
|
|
import net.mamoe.mirai.contact.roaming.RoamingMessageFilter
|
|
|
import net.mamoe.mirai.internal.contact.CommonGroupImpl
|
|
import net.mamoe.mirai.internal.contact.CommonGroupImpl
|
|
|
-import net.mamoe.mirai.internal.message.toMessageChainOnline
|
|
|
|
|
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
|
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
|
|
|
|
+import net.mamoe.mirai.internal.network.protocol.packet.chat.TroopManagement
|
|
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetGroupMsg
|
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbGetGroupMsg
|
|
|
import net.mamoe.mirai.message.data.MessageChain
|
|
import net.mamoe.mirai.message.data.MessageChain
|
|
|
-import net.mamoe.mirai.message.data.MessageSourceKind
|
|
|
|
|
|
|
|
|
|
internal class RoamingMessagesImplGroup(
|
|
internal class RoamingMessagesImplGroup(
|
|
|
override val contact: CommonGroupImpl
|
|
override val contact: CommonGroupImpl
|
|
|
) : SequenceBasedRoamingMessagesImpl() {
|
|
) : SequenceBasedRoamingMessagesImpl() {
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * time-based roaming without extending [TimeBasedRoamingMessagesImpl]
|
|
|
|
|
- * because protocol MessageSvc.PbGetGroupMsg doesn't support querying via time.
|
|
|
|
|
- * so this is actually sequence-based roaming.
|
|
|
|
|
- */
|
|
|
|
|
override suspend fun getMessagesIn(
|
|
override suspend fun getMessagesIn(
|
|
|
timeStart: Long,
|
|
timeStart: Long,
|
|
|
timeEnd: Long,
|
|
timeEnd: Long,
|
|
|
filter: RoamingMessageFilter?
|
|
filter: RoamingMessageFilter?
|
|
|
- ): Flow<MessageChain> {
|
|
|
|
|
- var currentSeq: Int = getLastMsgSeq() ?: return emptyFlow()
|
|
|
|
|
- var lastOfferedSeq = -1
|
|
|
|
|
-
|
|
|
|
|
- return flow {
|
|
|
|
|
- while (true) {
|
|
|
|
|
- val resp = getGroupMsg(currentSeq.toLong()) ?: break
|
|
|
|
|
-
|
|
|
|
|
- // the message may be sorted increasing by message time,
|
|
|
|
|
- // if so, additional sortBy will not take cost.
|
|
|
|
|
-
|
|
|
|
|
- val messageTimeSequence = resp.msgElem.asSequence().map { it.time }
|
|
|
|
|
-
|
|
|
|
|
- val maxTime = messageTimeSequence.max()
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- // we have fetched all messages
|
|
|
|
|
- // note: maxTime = 0 means all fetched messages were recalled
|
|
|
|
|
- if (maxTime < timeStart && maxTime != 0) break
|
|
|
|
|
-
|
|
|
|
|
- emitAll(
|
|
|
|
|
- resp.msgElem.asSequence()
|
|
|
|
|
- .filter { lastOfferedSeq == -1 || it.msgHead.msgSeq < lastOfferedSeq }
|
|
|
|
|
- .filter { it.time in timeStart..timeEnd }
|
|
|
|
|
- .sortedByDescending { it.msgHead.msgSeq } // Ensure caller receives newer messages first
|
|
|
|
|
- .filter { filter.apply(it) } // Call filter after sort
|
|
|
|
|
- .asFlow()
|
|
|
|
|
- .map { listOf(it).toMessageChainOnline(bot, contact.id, MessageSourceKind.GROUP) }
|
|
|
|
|
- )
|
|
|
|
|
-
|
|
|
|
|
-
|
|
|
|
|
- currentSeq = resp.msgElem.first().msgHead.msgSeq
|
|
|
|
|
- lastOfferedSeq = currentSeq
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- override suspend fun getMessagesBeforeFlow(
|
|
|
|
|
- messageId: Int?,
|
|
|
|
|
- filter: RoamingMessageFilter?
|
|
|
|
|
- ): Flow<MessageChain> {
|
|
|
|
|
- var currentSeq = messageId ?: (getLastMsgSeq() ?: return emptyFlow())
|
|
|
|
|
-
|
|
|
|
|
- return flow {
|
|
|
|
|
- while (true) {
|
|
|
|
|
- val resp = getGroupMsg(currentSeq.toLong()) ?: break
|
|
|
|
|
-
|
|
|
|
|
- emitAll(
|
|
|
|
|
- resp.msgElem.asSequence()
|
|
|
|
|
- .filter { getMessageSourceKindFromC2cCmdOrNull(it.msgHead.c2cCmd) != null } // ignore unsupported messages
|
|
|
|
|
- .sortedByDescending { it.time } // Ensure caller receiver newer messages first
|
|
|
|
|
- .filter { filter.apply(it) } // Call filter after sort
|
|
|
|
|
- .asFlow()
|
|
|
|
|
- .map { it.toMessageChainOnline(bot) }
|
|
|
|
|
- )
|
|
|
|
|
|
|
+ ): Flow<MessageChain> = getMessagesImpl(
|
|
|
|
|
+ preFilter = { maxTime -> maxTime >= timeStart || maxTime == 0 },
|
|
|
|
|
+ preSortFilter = { msg -> msg.msgHead.msgTime in timeStart..timeEnd },
|
|
|
|
|
+ filter = filter
|
|
|
|
|
+ )
|
|
|
|
|
+
|
|
|
|
|
+ override suspend fun getLastMsgSeq(): Int? {
|
|
|
|
|
+ // Iterate from the newest message to find messages within [timeStart] and [timeEnd]
|
|
|
|
|
+ val lastMsgSeqResp = bot.network.sendAndExpect(
|
|
|
|
|
+ TroopManagement.GetGroupLastMsgSeq(
|
|
|
|
|
+ client = bot.client,
|
|
|
|
|
+ groupUin = contact.uin
|
|
|
|
|
+ )
|
|
|
|
|
+ )
|
|
|
|
|
|
|
|
- currentSeq = resp.msgElem.minBy { it.time }.msgHead.msgSeq - 1
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return when (lastMsgSeqResp) {
|
|
|
|
|
+ TroopManagement.GetGroupLastMsgSeq.Response.Failed -> null
|
|
|
|
|
+ is TroopManagement.GetGroupLastMsgSeq.Response.Success -> lastMsgSeqResp.seq
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private suspend fun getGroupMsg(seq: Long): MessageSvcPbGetGroupMsg.Success? {
|
|
|
|
|
|
|
+ override suspend fun getMsg(seq: Int): List<MsgComm.Msg> {
|
|
|
val resp = contact.bot.network.sendAndExpect(
|
|
val resp = contact.bot.network.sendAndExpect(
|
|
|
MessageSvcPbGetGroupMsg(
|
|
MessageSvcPbGetGroupMsg(
|
|
|
client = contact.bot.client,
|
|
client = contact.bot.client,
|
|
|
groupUin = contact.uin,
|
|
groupUin = contact.uin,
|
|
|
- messageSequence = seq,
|
|
|
|
|
|
|
+ messageSequence = seq.toLong(),
|
|
|
count = 20 // maximum 20
|
|
count = 20 // maximum 20
|
|
|
)
|
|
)
|
|
|
)
|
|
)
|
|
|
|
|
|
|
|
- if (resp is MessageSvcPbGetGroupMsg.Failed) return null
|
|
|
|
|
- resp as MessageSvcPbGetGroupMsg.Success
|
|
|
|
|
- if (resp.msgElem.isEmpty()) return null
|
|
|
|
|
-
|
|
|
|
|
- return resp
|
|
|
|
|
|
|
+ if (resp is MessageSvcPbGetGroupMsg.Failed) return listOf()
|
|
|
|
|
+ resp as MessageSvcPbGetGroupMsg.Success // stupid smart cast
|
|
|
|
|
+ return resp.msgElem
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- private val MsgComm.Msg.time get() = msgHead.msgTime
|
|
|
|
|
-
|
|
|
|
|
- private fun RoamingMessageFilter?.apply(
|
|
|
|
|
- it: MsgComm.Msg
|
|
|
|
|
- ) = this?.invoke(createRoamingMessage(it, listOf())) != false
|
|
|
|
|
}
|
|
}
|