Fix duplicated OnlinePush

This commit is contained in:
Him188 2020-04-10 22:24:46 +08:00
parent b0bc0ec62b
commit 458fe2ee94
7 changed files with 94 additions and 64 deletions

View File

@ -64,10 +64,7 @@ internal class GroupImpl(
groupInfo: GroupInfo,
members: Sequence<MemberInfo>
) : Group() {
companion object
val lastRecalledMessageRandoms: LockFreeCacheList<Int> = LockFreeCacheList(16) // events per 3 second
val lastMemberPermissionChangeSequences: LockFreeCacheList<Int> = LockFreeCacheList(16) // events per 3 second
companion object;
override val bot: QQAndroidBot by bot.unsafeWeakRef()

View File

@ -130,6 +130,8 @@ internal open class QQAndroidClient(
private val highwayDataTransSequenceIdForApplyUp: AtomicInt = atomic(77918)
internal fun nextHighwayDataTransSequenceIdForApplyUp(): Int = highwayDataTransSequenceIdForApplyUp.getAndAdd(2)
internal val onlinePushCacheList: LockFreeLinkedList<Short> = LockFreeLinkedList()
val appClientVersion: Int = 0
var networkType: NetworkType = NetworkType.WIFI

View File

@ -80,7 +80,7 @@ internal class OnlinePushPack {
internal class SvcRespPushMsg(
@JceId(0) val uin: Long,
@JceId(1) val vDelInfos: List<DelMsgInfo>,
@JceId(2) val svrip: Int,
@JceId(2) val svrip: Int = 0,
@JceId(3) val pushToken: ByteArray? = null,
@JceId(4) val serviceType: Int? = null,
@JceId(5) val deviceInfo: DeviceInfo? = null

View File

@ -36,8 +36,8 @@ internal class RequestPushNotify(
@Serializable
internal class MsgInfo(
@JceId(0) val lFromUin: Long? = 0L,
@JceId(1) val uMsgTime: Long? = 0L,
@JceId(0) val lFromUin: Long = 0L,
@JceId(1) val uMsgTime: Long = 0L,
@JceId(2) val shMsgType: Short,
@JceId(3) val shMsgSeq: Short,
@JceId(4) val strMsg: String?,

View File

@ -20,7 +20,7 @@ import net.mamoe.mirai.qqandroid.utils.io.ProtoBuf
class GroupOpenSysMsg : ProtoBuf {
@Serializable
internal class LightApp(
internal class LightApp(
@ProtoId(1) val app: String = "",
@ProtoId(2) val view: String = "",
@ProtoId(3) val desc: String = "",
@ -32,7 +32,7 @@ internal class LightApp(
) : ProtoBuf
@Serializable
internal class RichMsg(
internal class RichMsg(
@ProtoId(1) val title: String = "",
@ProtoId(2) val desc: String = "",
@ProtoId(3) val brief: String = "",
@ -42,7 +42,7 @@ internal class RichMsg(
) : ProtoBuf
@Serializable
internal class Sender(
internal class Sender(
@ProtoId(1) val uin: Long = 0L,
@ProtoId(2) val nick: String = "",
@ProtoId(3) val avatar: String = "",
@ -50,14 +50,14 @@ internal class Sender(
) : ProtoBuf
@Serializable
internal class Source(
internal class Source(
@ProtoId(1) val name: String = "",
@ProtoId(2) val icon: String = "",
@ProtoId(3) val url: String = ""
) : ProtoBuf
@Serializable
internal class SysMsgBody(
internal class SysMsgBody(
@ProtoId(1) val groupId: Long = 0L,
@ProtoId(2) val appid: Long = 0L,
@ProtoId(3) val sender: Sender? = null,
@ -71,7 +71,7 @@ internal class SysMsgBody(
@Serializable
internal class TroopTips0x857 : ProtoBuf {
@Serializable
internal class AIOGrayTipsInfo(
internal class AIOGrayTipsInfo(
@ProtoId(1) val optUint32ShowLastest: Int = 0,
@ProtoId(2) val optBytesContent: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val optUint32Remind: Int = 0,
@ -82,7 +82,7 @@ internal class AIOGrayTipsInfo(
) : ProtoBuf
@Serializable
internal class AIOTopTipsInfo(
internal class AIOTopTipsInfo(
@ProtoId(1) val optBytesContent: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(2) val optUint32Icon: Int = 0,
@ProtoId(3) val optEnumAction: Int /* enum */ = 1,
@ -94,12 +94,12 @@ internal class AIOTopTipsInfo(
) : ProtoBuf
@Serializable
internal class FloatedTipsInfo(
internal class FloatedTipsInfo(
@ProtoId(1) val optBytesContent: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class GeneralGrayTipInfo(
internal class GeneralGrayTipInfo(
@ProtoId(1) val busiType: Long = 0L,
@ProtoId(2) val busiId: Long = 0L,
@ProtoId(3) val ctrlFlag: Int = 0,
@ -113,7 +113,7 @@ internal class GeneralGrayTipInfo(
) : ProtoBuf
@Serializable
internal class GoldMsgTipsElem(
internal class GoldMsgTipsElem(
@ProtoId(1) val type: Int = 0,
@ProtoId(2) val billno: String = "",
@ProtoId(3) val result: Int = 0,
@ -126,25 +126,25 @@ internal class GoldMsgTipsElem(
) : ProtoBuf
@Serializable
internal class GroupInfoChange(
internal class GroupInfoChange(
@ProtoId(1) val groupHonorSwitch: Int = 0
) : ProtoBuf
@Serializable
internal class GroupNotifyInfo(
internal class GroupNotifyInfo(
@ProtoId(1) val optUint32AutoPullFlag: Int = 0,
@ProtoId(2) val optBytesFeedsId: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class InstCtrl(
internal class InstCtrl(
@ProtoId(1) val msgSendToInst: List<InstInfo>? = null,
@ProtoId(2) val msgExcludeInst: List<InstInfo>? = null,
@ProtoId(3) val msgFromInst: InstInfo? = null
) : ProtoBuf
@Serializable
internal class InstInfo(
internal class InstInfo(
@ProtoId(1) val apppid: Int = 0,
@ProtoId(2) val instid: Int = 0,
@ProtoId(3) val platform: Int = 0,
@ -157,7 +157,7 @@ internal class InstInfo(
) : ProtoBuf
@Serializable
internal class LbsShareChangePushInfo(
internal class LbsShareChangePushInfo(
@ProtoId(1) val msgType: Int = 0,
@ProtoId(2) val msgInfo: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val versionCtrl: ByteArray = EMPTY_BYTE_ARRAY,
@ -171,12 +171,12 @@ internal class LbsShareChangePushInfo(
) : ProtoBuf
@Serializable
internal class LuckyBagNotify(
internal class LuckyBagNotify(
@ProtoId(1) val msgTips: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class MediaChangePushInfo(
internal class MediaChangePushInfo(
@ProtoId(1) val msgType: Int = 0,
@ProtoId(2) val msgInfo: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val versionCtrl: ByteArray = EMPTY_BYTE_ARRAY,
@ -191,7 +191,7 @@ internal class MediaChangePushInfo(
@ProtoId(100) val extInfo: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf {
@Serializable
internal class PersonalSetting(
internal class PersonalSetting(
@ProtoId(1) val themeId: Int = 0,
@ProtoId(2) val playerId: Int = 0,
@ProtoId(3) val fontId: Int = 0
@ -199,14 +199,14 @@ internal class PersonalSetting(
}
@Serializable
internal class MessageBoxInfo(
internal class MessageBoxInfo(
@ProtoId(1) val optBytesContent: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(2) val optBytesTitle: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val optBytesButton: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class MessageRecallReminder(
internal class MessageRecallReminder(
@ProtoId(1) val uin: Long = 0L,
@ProtoId(2) val nickname: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val recalledMsgList: List<MessageMeta> = listOf(),
@ -216,7 +216,7 @@ internal class MessageRecallReminder(
@ProtoId(7) val opType: Int = 0
) : ProtoBuf {
@Serializable
internal class MessageMeta(
internal class MessageMeta(
@ProtoId(1) val seq: Int = 0,
@ProtoId(2) val time: Int = 0,
@ProtoId(3) val msgRandom: Int = 0,
@ -227,12 +227,12 @@ internal class MessageMeta(
}
@Serializable
internal class MiniAppNotify(
internal class MiniAppNotify(
@ProtoId(1) val msg: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class NotifyMsgBody(
internal class NotifyMsgBody(
@ProtoId(1) val optEnumType: Int /* enum */ = 1,
@ProtoId(2) val optUint64MsgTime: Long = 0L,
@ProtoId(3) val optUint64MsgExpires: Long = 0L,
@ -264,14 +264,14 @@ internal class NotifyMsgBody(
) : ProtoBuf
@Serializable
internal class NotifyObjmsgUpdate(
internal class NotifyObjmsgUpdate(
@ProtoId(1) val objmsgId: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(2) val updateType: Int = 0,
@ProtoId(3) val extMsg: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class RedGrayTipsInfo(
internal class RedGrayTipsInfo(
@ProtoId(1) val optUint32ShowLastest: Int = 0,
@ProtoId(2) val senderUin: Long = 0L,
@ProtoId(3) val receiverUin: Long = 0L,
@ -294,7 +294,7 @@ internal class RedGrayTipsInfo(
) : ProtoBuf
@Serializable
internal class ReqBody(
internal class ReqBody(
@ProtoId(1) val optUint64GroupCode: Long = 0L,
@ProtoId(2) val uint64Memberuins: List<Long>? = null,
@ProtoId(3) val optUint32Offline: Int = 0,
@ -304,12 +304,12 @@ internal class ReqBody(
) : ProtoBuf
@Serializable
internal class RspBody(
internal class RspBody(
@ProtoId(1) val optUint64GroupCode: Long = 0L
) : ProtoBuf
@Serializable
internal class SingChangePushInfo(
internal class SingChangePushInfo(
@ProtoId(1) val seq: Long = 0L,
@ProtoId(2) val actionType: Int = 0,
@ProtoId(3) val groupId: Long = 0L,
@ -319,13 +319,13 @@ internal class SingChangePushInfo(
) : ProtoBuf
@Serializable
internal class TemplParam(
internal class TemplParam(
@ProtoId(1) val name: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(2) val value: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf
@Serializable
internal class ThemeStateNotify(
internal class ThemeStateNotify(
@ProtoId(1) val state: Int = 0,
@ProtoId(2) val feedsId: ByteArray = EMPTY_BYTE_ARRAY,
@ProtoId(3) val themeName: ByteArray = EMPTY_BYTE_ARRAY,
@ -334,7 +334,7 @@ internal class ThemeStateNotify(
) : ProtoBuf
@Serializable
internal class TroopFormGrayTipsInfo(
internal class TroopFormGrayTipsInfo(
@ProtoId(1) val writerUin: Long = 0L,
@ProtoId(2) val creatorUin: Long = 0L,
@ProtoId(3) val richContent: ByteArray = EMPTY_BYTE_ARRAY,
@ -343,7 +343,7 @@ internal class TroopFormGrayTipsInfo(
) : ProtoBuf
@Serializable
internal class VideoChangePushInfo(
internal class VideoChangePushInfo(
@ProtoId(1) val seq: Long = 0L,
@ProtoId(2) val actionType: Int = 0,
@ProtoId(3) val groupId: Long = 0L,
@ -354,7 +354,7 @@ internal class VideoChangePushInfo(
) : ProtoBuf
@Serializable
internal class WereWolfPush(
internal class WereWolfPush(
@ProtoId(1) val pushType: Int = 0,
@ProtoId(2) val gameRoom: Long = 0L,
@ProtoId(3) val enumGameState: Int = 0,
@ -374,7 +374,7 @@ internal class WereWolfPush(
@ProtoId(17) val votedTieUsers: List<Long>? = null
) : ProtoBuf {
@Serializable
internal class GameRecord(
internal class GameRecord(
@ProtoId(1) val total: Int = 0,
@ProtoId(2) val win: Int = 0,
@ProtoId(3) val lose: Int = 0,
@ -382,7 +382,7 @@ internal class GameRecord(
) : ProtoBuf
@Serializable
internal class Role(
internal class Role(
@ProtoId(1) val uin: Long = 0L,
@ProtoId(2) val enumType: Int = 0,
@ProtoId(3) val enumState: Int = 0,

View File

@ -292,12 +292,6 @@ internal class MessageSvc {
}
return@mapNotNull null
}
732 -> { // ?
// 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58
bot.network.logger.debug { "unknown PbGetMsg type ${msg.msgHead.msgType}: ${msg._miraiContentToString()}" }
return@mapNotNull null
}
34 -> { // 主动入群
// 27 0B 60 E7 01 44 71 47 90 03 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 36 42 35 35 46 45 32 45 35 36 43 45 45 44 30 38 30 35 31 41 35 42 37 36 39 35 34 45 30 46 43 43 36 36 45 44 43 46 45 43 42 39 33 41 41 44 32 32
val group = bot.getGroupByUinOrNull(msg.msgHead.fromUin)
@ -309,8 +303,9 @@ internal class MessageSvc {
return@mapNotNull MemberJoinEvent.Active(group.newMember(msg.getNewMemberInfo())
.also { group.members.delegate.addLast(it) })
}
// 732: 27 0B 60 E7 0C 01 3E 03 3F A2 5E 90 60 E2 00 01 44 71 47 90 00 00 02 58
else -> {
bot.network.logger.debug { "unknown PbGetMsg type ${msg.msgHead.msgType}: ${msg._miraiContentToString()}" }
bot.network.logger.debug { "unknown PbGetMsg type ${msg.msgHead.msgType}" }
return@mapNotNull null
}
}

View File

@ -30,6 +30,7 @@ import net.mamoe.mirai.qqandroid.contact.checkIsMemberImpl
import net.mamoe.mirai.qqandroid.message.toMessageChain
import net.mamoe.mirai.qqandroid.network.MultiPacketBySequence
import net.mamoe.mirai.qqandroid.network.Packet
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.MsgInfo
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.MsgType0x210
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.OnlinePushPack
@ -47,6 +48,7 @@ import net.mamoe.mirai.qqandroid.utils.io.serialization.*
import net.mamoe.mirai.qqandroid.utils.io.serialization.jce.JceId
import net.mamoe.mirai.qqandroid.utils.read
import net.mamoe.mirai.qqandroid.utils.toUHexString
import net.mamoe.mirai.utils.LockFreeLinkedList
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.debug
@ -135,12 +137,8 @@ internal class OnlinePush {
}
val group = bot.getGroupByUin(content.fromUin) as GroupImpl
if (group.lastMemberPermissionChangeSequences.remove(content.msgSeq)) {
return null
}
if (var5 == 0L && this.remaining == 1L) {//管理员变更
group.lastMemberPermissionChangeSequences.addLast(content.msgSeq)
val newPermission =
if (this.readByte().toInt() == 1) MemberPermission.ADMINISTRATOR
else MemberPermission.MEMBER
@ -223,8 +221,31 @@ internal class OnlinePush {
"OnlinePush.RespPush"
) {
// to reduce nesting depth
private fun List<MsgInfo>.deco(mapper: ByteReadPacket.(msgInfo: MsgInfo) -> Sequence<Packet>): Sequence<Packet> {
return asSequence().flatMap { it.vMsg.read { mapper(it) } }
private fun List<MsgInfo>.deco(
client: QQAndroidClient,
mapper: ByteReadPacket.(msgInfo: MsgInfo) -> Sequence<Packet>
): Sequence<Packet> {
return asSequence().filter { msg ->
val cache = client.onlinePushCacheList.removeUntilFirst { it == msg.shMsgSeq }
if (cache == null) {
client.onlinePushCacheList.addLast(msg.shMsgSeq)
true
} else {
client.onlinePushCacheList.remove(cache)
false
}
}.flatMap { it.vMsg.read { mapper(it) } }
}
private inline fun LockFreeLinkedList<Short>.removeUntilFirst(block: (Short) -> Boolean): Short? {
this.forEach {
if (!block(it)) {
this.remove(it)
} else {
return it
}
}
return null
}
private fun lambda732(block: ByteReadPacket.(group: GroupImpl, bot: QQAndroidBot) -> Sequence<Packet>):
@ -362,9 +383,7 @@ internal class OnlinePush {
return@lambda732 recallReminder.recalledMsgList.asSequence().mapNotNull { pkg ->
when {
pkg.authorUin == bot.id && operator.id == bot.id -> null
group.lastRecalledMessageRandoms.remove(pkg.msgRandom) -> null
else -> {
group.lastRecalledMessageRandoms.addLast(pkg.msgRandom)
MessageRecallEvent.GroupRecall(bot, pkg.authorUin, pkg.msgRandom, pkg.time, operator, group)
}
}
@ -396,7 +415,7 @@ internal class OnlinePush {
bot.friends.delegate.addLast(new)
return@lambda528 sequenceOf(FriendAddEvent(new))
},
0xE2L to lambda528 { bot ->
0xE2L to lambda528 {
// TODO: unknown. maybe messages.
// 0A 35 08 00 10 A2 FF 8C F0 03 1A 1B E5 90 8C E6 84 8F E4 BD A0 E7 9A 84 E5 8A A0 E5 A5 BD E5 8F 8B E8 AF B7 E6 B1 82 22 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B 28 01
// vProtobuf.loadAs(Msgtype0x210.serializer())
@ -468,7 +487,7 @@ internal class OnlinePush {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Response {
val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req")
val packets: Sequence<Packet> = reqPushMsg.vMsgInfos.deco { msgInfo ->
val packets: Sequence<Packet> = reqPushMsg.vMsgInfos.deco(bot.client) { msgInfo ->
when (msgInfo.shMsgType.toInt()) {
732 -> {
val group = bot.getGroup(readUInt().toLong())
@ -478,7 +497,7 @@ internal class OnlinePush {
discardExact(1)
Transformers732[internalType]
?.let { it(this@deco, group, bot) }
?.let { it(this@deco, group as GroupImpl, bot) }
?: kotlin.run {
bot.network.logger.debug {
"unknown group 732 type $internalType, data: " + readBytes().toUHexString()
@ -507,11 +526,11 @@ internal class OnlinePush {
}
}
}
return Response(reqPushMsg.uin, reqPushMsg.svrip ?: 0, packets)
return Response(reqPushMsg, packets)
}
@Suppress("SpellCheckingInspection")
internal data class Response(val uin: Long, val svrip: Int, val sequence: Sequence<Packet>) :
internal data class Response(val request: OnlinePushPack.SvcReqPushMsg, val sequence: Sequence<Packet>) :
MultiPacketBySequence<Packet>(sequence) {
override fun toString(): String {
return "OnlinePush.ReqPush.Response"
@ -525,7 +544,7 @@ internal class OnlinePush {
) : JceStruct
override suspend fun QQAndroidBot.handle(packet: Response, sequenceId: Int): OutgoingPacket? {
return buildResponseUniPacket(client, sequenceId = sequenceId) {
return buildResponseUniPacket(client) {
writeJceStruct(
RequestPacket.serializer(),
RequestPacket(
@ -535,7 +554,24 @@ internal class OnlinePush {
sBuffer = jceRequestSBuffer(
"resp",
OnlinePushPack.SvcRespPushMsg.serializer(),
OnlinePushPack.SvcRespPushMsg(packet.uin, listOf(), packet.svrip)
OnlinePushPack.SvcRespPushMsg(
packet.request.uin,
packet.request.vMsgInfos.map { msg ->
OnlinePushPack.DelMsgInfo(
fromUin = msg.lFromUin,
shMsgSeq = msg.shMsgSeq,
vMsgCookies = msg.vMsgCookies,
uMsgTime = 0,
clientIp = 0,
sendTime = 0,
ssoIp = 0,
ssoSeq = 0,
uAppId = 0,
uMsgType = 0,
wCmd = 0
)
}
)
)
)
)