mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 23:50:08 +08:00
Redesign notice handling and introduce NoticeProcessorPipeline
part 2
Do not broadcast StrangerAddedEvent if added twice, fix stranger scope not closed Do not add new instance if there is already one Close and remove corresponding stranger instance if there is new friend.
This commit is contained in:
parent
e1ffaa5410
commit
56cbe2d8a2
@ -28,34 +28,34 @@ import java.util.concurrent.atomic.AtomicBoolean
|
||||
/**
|
||||
* 好友昵称改变事件. 目前仅支持解析 (来自 PC 端的修改).
|
||||
*/
|
||||
public data class FriendRemarkChangeEvent internal constructor(
|
||||
public data class FriendRemarkChangeEvent @MiraiInternalApi public constructor(
|
||||
public override val friend: Friend,
|
||||
public val oldRemark: String,
|
||||
public val newRemark: String
|
||||
public val newRemark: String,
|
||||
) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 成功添加了一个新好友的事件
|
||||
*/
|
||||
public data class FriendAddEvent @MiraiInternalApi constructor(
|
||||
public data class FriendAddEvent @MiraiInternalApi public constructor(
|
||||
/**
|
||||
* 新好友. 已经添加到 [Bot.friends]
|
||||
*/
|
||||
public override val friend: Friend
|
||||
public override val friend: Friend,
|
||||
) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 好友已被删除或主动删除的事件.
|
||||
*/
|
||||
public data class FriendDeleteEvent internal constructor(
|
||||
public override val friend: Friend
|
||||
public data class FriendDeleteEvent @MiraiInternalApi public constructor(
|
||||
public override val friend: Friend,
|
||||
) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 一个账号请求添加机器人为好友的事件
|
||||
*/
|
||||
@Suppress("DEPRECATION")
|
||||
public data class NewFriendRequestEvent internal constructor(
|
||||
public data class NewFriendRequestEvent @MiraiInternalApi public constructor(
|
||||
public override val bot: Bot,
|
||||
/**
|
||||
* 事件唯一识别号
|
||||
@ -76,7 +76,7 @@ public data class NewFriendRequestEvent internal constructor(
|
||||
/**
|
||||
* 群名片或好友昵称
|
||||
*/
|
||||
public val fromNick: String
|
||||
public val fromNick: String,
|
||||
) : BotEvent, Packet, AbstractEvent(), FriendInfoChangeEvent {
|
||||
@JvmField
|
||||
internal val responded: AtomicBoolean = AtomicBoolean(false)
|
||||
@ -97,25 +97,25 @@ public data class NewFriendRequestEvent internal constructor(
|
||||
/**
|
||||
* [Friend] 头像被修改. 在此事件广播前就已经修改完毕.
|
||||
*/
|
||||
public data class FriendAvatarChangedEvent internal constructor(
|
||||
public override val friend: Friend
|
||||
public data class FriendAvatarChangedEvent @MiraiInternalApi public constructor(
|
||||
public override val friend: Friend,
|
||||
) : FriendEvent, Packet, AbstractEvent()
|
||||
|
||||
/**
|
||||
* [Friend] 昵称改变事件, 在此事件广播时好友已经完成改名
|
||||
* @see BotNickChangedEvent
|
||||
*/
|
||||
public data class FriendNickChangedEvent internal constructor(
|
||||
public data class FriendNickChangedEvent @MiraiInternalApi public constructor(
|
||||
public override val friend: Friend,
|
||||
public val from: String,
|
||||
public val to: String
|
||||
public val to: String,
|
||||
) : FriendEvent, Packet, AbstractEvent(), FriendInfoChangeEvent
|
||||
|
||||
/**
|
||||
* 好友输入状态改变的事件,当开始输入文字、退出聊天窗口或清空输入框时会触发此事件
|
||||
*/
|
||||
public data class FriendInputStatusChangedEvent internal constructor(
|
||||
public data class FriendInputStatusChangedEvent @MiraiInternalApi public constructor(
|
||||
public override val friend: Friend,
|
||||
public val inputting: Boolean
|
||||
public val inputting: Boolean,
|
||||
|
||||
) : FriendEvent, Packet, AbstractEvent()
|
||||
) : FriendEvent, Packet, AbstractEvent()
|
@ -24,7 +24,7 @@ public data class StrangerAddEvent @MiraiInternalApi public constructor(
|
||||
/**
|
||||
* 新的陌生人. 已经添加到 [Bot.strangers]
|
||||
*/
|
||||
public override val stranger: Stranger
|
||||
public override val stranger: Stranger,
|
||||
) : StrangerEvent, Packet, AbstractEvent()
|
||||
|
||||
|
||||
@ -33,19 +33,16 @@ public data class StrangerAddEvent @MiraiInternalApi public constructor(
|
||||
*
|
||||
*/
|
||||
public sealed class StrangerRelationChangeEvent(
|
||||
public override val stranger: Stranger
|
||||
public override val stranger: Stranger,
|
||||
) : StrangerEvent, Packet, AbstractEvent() {
|
||||
/**
|
||||
* 主动删除陌生人或陌生人被删除的事件
|
||||
*
|
||||
* 除主动删除外,此事件为惰性广播,无法确保实时性
|
||||
* 目前被动删除仅会在陌生人二次添加时才会进行广播
|
||||
* 主动删除陌生人或陌生人被删除的事件, 不一定能接收到被动删除的事件
|
||||
*/
|
||||
public class Deleted(
|
||||
/**
|
||||
* 被删除的陌生人
|
||||
*/
|
||||
stranger: Stranger
|
||||
stranger: Stranger,
|
||||
) : StrangerRelationChangeEvent(stranger)
|
||||
|
||||
/**
|
||||
@ -63,7 +60,7 @@ public sealed class StrangerRelationChangeEvent(
|
||||
*
|
||||
* 已经添加到Bot的好友列表中
|
||||
*/
|
||||
public val friend: Friend
|
||||
public val friend: Friend,
|
||||
) : StrangerRelationChangeEvent(stranger)
|
||||
|
||||
}
|
@ -95,10 +95,13 @@ internal abstract class AbstractBot constructor(
|
||||
final override val groups: ContactList<GroupImpl> = ContactList()
|
||||
final override val strangers: ContactList<StrangerImpl> = ContactList()
|
||||
|
||||
final override val asFriend: FriendImpl by lazy { Mirai.newFriend(this, FriendInfoImpl(uin, nick, "")).cast() }
|
||||
final override val asFriend: FriendImpl by lazy {
|
||||
Mirai.newFriend(this, FriendInfoImpl(uin, "", "")).cast()
|
||||
} // nick is initialized later on login
|
||||
final override val asStranger: StrangerImpl by lazy {
|
||||
Mirai.newStranger(this, StrangerInfoImpl(bot.id, bot.nick)).cast()
|
||||
}
|
||||
final override var nick: String by asFriend.info::nick
|
||||
|
||||
override fun close(cause: Throwable?) {
|
||||
if (!this.isActive) return
|
||||
|
@ -14,6 +14,8 @@ import io.ktor.client.engine.okhttp.*
|
||||
import io.ktor.client.features.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.*
|
||||
import io.ktor.http.*
|
||||
import io.ktor.utils.io.core.*
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.currentCoroutineContext
|
||||
import kotlinx.io.core.discardExact
|
||||
@ -30,7 +32,9 @@ import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl.Companion.impl
|
||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl.Companion.impl
|
||||
import net.mamoe.mirai.internal.message.*
|
||||
import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
|
||||
import net.mamoe.mirai.internal.network.components.EventDispatcher
|
||||
|
@ -230,12 +230,6 @@ internal open class QQAndroidBot constructor(
|
||||
get() = client.wLoginSigInfo.sKey.data
|
||||
.fold(5381) { acc: Int, b: Byte -> acc + acc.shl(5) + b.toInt() }
|
||||
.and(Int.MAX_VALUE)
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// contacts
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
override lateinit var nick: String
|
||||
}
|
||||
|
||||
internal fun QQAndroidBot.getGroupByUinOrFail(uin: Long) =
|
||||
|
@ -10,6 +10,9 @@
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.data.UserInfo
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
@ -28,17 +31,32 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.Cmd0x352
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils.AtomicIntSeq
|
||||
import net.mamoe.mirai.internal.utils.C2CPkgMsgParsingCache
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.Message
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.isContentEmpty
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
import kotlin.contracts.contract
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
internal val User.info: UserInfo? get() = this.castOrNull<AbstractUser>()?.info
|
||||
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun User.impl(): AbstractUser {
|
||||
contract { returns() implies (this@impl is AbstractUser) }
|
||||
check(this is AbstractUser)
|
||||
return this
|
||||
}
|
||||
|
||||
internal val User.correspondingMessageSourceKind
|
||||
get() = when (this) {
|
||||
is Friend -> MessageSourceKind.FRIEND
|
||||
is Member -> MessageSourceKind.TEMP
|
||||
is Stranger -> MessageSourceKind.STRANGER
|
||||
else -> error("Unknown user: ${this::class.qualifiedName}")
|
||||
}
|
||||
|
||||
internal abstract class AbstractUser(
|
||||
bot: QQAndroidBot,
|
||||
parentCoroutineContext: CoroutineContext,
|
||||
@ -49,6 +67,9 @@ internal abstract class AbstractUser(
|
||||
final override var nick: String = userInfo.nick
|
||||
final override val remark: String = userInfo.remark
|
||||
|
||||
val messageSeq = AtomicIntSeq.forMessageSeq()
|
||||
val fragmentedMessageMerger = C2CPkgMsgParsingCache()
|
||||
|
||||
open val info: UserInfo = userInfo
|
||||
|
||||
@Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
|
||||
@ -58,7 +79,8 @@ internal abstract class AbstractUser(
|
||||
}
|
||||
val resp = bot.network.run {
|
||||
LongConn.OffPicUp(
|
||||
bot.client, Cmd0x352.TryUpImgReq(
|
||||
bot.client,
|
||||
Cmd0x352.TryUpImgReq(
|
||||
buType = 1,
|
||||
srcUin = bot.id,
|
||||
dstUin = this@AbstractUser.id,
|
||||
@ -66,8 +88,8 @@ internal abstract class AbstractUser(
|
||||
fileSize = resource.size,
|
||||
fileName = resource.md5.toUHexString("") + "." + resource.formatName,
|
||||
imgOriginal = true,
|
||||
buildVer = bot.client.buildVer
|
||||
)
|
||||
buildVer = bot.client.buildVer,
|
||||
),
|
||||
).sendAndExpect<LongConn.OffPicUp.Response>()
|
||||
}
|
||||
|
||||
|
@ -14,12 +14,9 @@
|
||||
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Friend
|
||||
import net.mamoe.mirai.data.FriendInfo
|
||||
import net.mamoe.mirai.event.events.FriendMessagePostSendEvent
|
||||
import net.mamoe.mirai.event.events.FriendMessagePreSendEvent
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
@ -31,7 +28,6 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.audioCodec
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.internal.utils.C2CPkgMsgParsingCache
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
@ -53,9 +49,9 @@ internal fun net.mamoe.mirai.internal.network.protocol.data.jce.FriendInfo.toMir
|
||||
)
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal inline fun Friend.checkIsFriendImpl(): FriendImpl {
|
||||
internal inline fun Friend.impl(): FriendImpl {
|
||||
contract {
|
||||
returns() implies (this@checkIsFriendImpl is FriendImpl)
|
||||
returns() implies (this@impl is FriendImpl)
|
||||
}
|
||||
check(this is FriendImpl) { "A Friend instance is not instance of FriendImpl. Your instance: ${this::class.qualifiedName}" }
|
||||
return this
|
||||
@ -64,11 +60,8 @@ internal inline fun Friend.checkIsFriendImpl(): FriendImpl {
|
||||
internal class FriendImpl(
|
||||
bot: QQAndroidBot,
|
||||
parentCoroutineContext: CoroutineContext,
|
||||
internal val friendInfo: FriendInfo,
|
||||
) : Friend, AbstractUser(bot, parentCoroutineContext, friendInfo) {
|
||||
@Suppress("unused") // bug
|
||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||
val friendPkgMsgParsingCache = C2CPkgMsgParsingCache()
|
||||
override val info: FriendInfoImpl,
|
||||
) : Friend, AbstractUser(bot, parentCoroutineContext, info) {
|
||||
override suspend fun delete() {
|
||||
check(bot.friends[this.id] != null) {
|
||||
"Friend ${this.id} had already been deleted"
|
||||
|
@ -303,7 +303,8 @@ internal fun Group.newMember(memberInfo: MemberInfo): Member {
|
||||
)
|
||||
}
|
||||
|
||||
internal fun Group.addNewNormalMember(memberInfo: MemberInfo): NormalMemberImpl {
|
||||
internal fun Group.addNewNormalMember(memberInfo: MemberInfo): NormalMemberImpl? {
|
||||
if (members.contains(memberInfo.uin)) return null
|
||||
return newNormalMember(memberInfo).also {
|
||||
members.delegate.add(it)
|
||||
}
|
||||
|
@ -11,8 +11,6 @@
|
||||
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.launch
|
||||
@ -36,12 +34,9 @@ import kotlin.coroutines.CoroutineContext
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
internal class NormalMemberImpl constructor(
|
||||
group: GroupImpl,
|
||||
coroutineContext: CoroutineContext,
|
||||
parentCoroutineContext: CoroutineContext,
|
||||
memberInfo: MemberInfo,
|
||||
) : NormalMember, AbstractMember(group, coroutineContext, memberInfo) {
|
||||
|
||||
@Suppress("unused") // false positive
|
||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||
) : NormalMember, AbstractMember(group, parentCoroutineContext, memberInfo) {
|
||||
|
||||
override val joinTimestamp: Int get() = info.joinTimestamp
|
||||
override val lastSpeakTimestamp: Int get() = info.lastSpeakTimestamp
|
||||
@ -57,7 +52,7 @@ internal class NormalMemberImpl constructor(
|
||||
?: handler.sendMessageImpl<NormalMember>(
|
||||
message = message,
|
||||
preSendEventConstructor = ::GroupTempMessagePreSendEvent,
|
||||
postSendEventConstructor = ::GroupTempMessagePostSendEvent.cast()
|
||||
postSendEventConstructor = ::GroupTempMessagePostSendEvent.cast(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -102,7 +97,7 @@ internal class NormalMemberImpl constructor(
|
||||
TroopManagement.EditGroupNametag(
|
||||
bot.client,
|
||||
this@NormalMemberImpl,
|
||||
newValue
|
||||
newValue,
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberCardChangeEvent(oldValue, newValue, this@NormalMemberImpl).broadcast()
|
||||
@ -122,7 +117,7 @@ internal class NormalMemberImpl constructor(
|
||||
TroopManagement.EditSpecialTitle(
|
||||
bot.client,
|
||||
this@NormalMemberImpl,
|
||||
newValue
|
||||
newValue,
|
||||
).sendWithoutExpect()
|
||||
}
|
||||
MemberSpecialTitleChangeEvent(oldValue, newValue, this@NormalMemberImpl, null).broadcast()
|
||||
@ -143,7 +138,7 @@ internal class NormalMemberImpl constructor(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@NormalMemberImpl.id,
|
||||
timeInSecond = durationSeconds
|
||||
timeInSecond = durationSeconds,
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@ -159,7 +154,7 @@ internal class NormalMemberImpl constructor(
|
||||
client = bot.client,
|
||||
groupCode = group.id,
|
||||
memberUin = this@NormalMemberImpl.id,
|
||||
timeInSecond = 0
|
||||
timeInSecond = 0,
|
||||
).sendAndExpect<TroopManagement.Mute.Response>()
|
||||
}
|
||||
|
||||
@ -210,7 +205,7 @@ internal class NormalMemberImpl constructor(
|
||||
val resp: TroopManagement.ModifyAdmin.Response = TroopManagement.ModifyAdmin(
|
||||
client = bot.client,
|
||||
member = this@NormalMemberImpl,
|
||||
operation = operation
|
||||
operation = operation,
|
||||
).sendAndExpect()
|
||||
|
||||
check(resp.success) {
|
||||
@ -227,7 +222,7 @@ internal class NormalMemberImpl constructor(
|
||||
internal fun Member.checkBotPermissionHighest(operationName: String) {
|
||||
check(group.botPermission == MemberPermission.OWNER) {
|
||||
throw PermissionDeniedException(
|
||||
"`$operationName` operation requires the OWNER permission, while bot has ${group.botPermission}"
|
||||
"`$operationName` operation requires the OWNER permission, while bot has ${group.botPermission}",
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -236,7 +231,7 @@ internal fun Member.checkBotPermissionHigherThanThis(operationName: String) {
|
||||
check(group.botPermission > this.permission) {
|
||||
throw PermissionDeniedException(
|
||||
"`$operationName` operation requires a higher permission, while " +
|
||||
"${group.botPermission} < ${this.permission}"
|
||||
"${group.botPermission} < ${this.permission}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -17,8 +17,6 @@
|
||||
|
||||
package net.mamoe.mirai.internal.contact
|
||||
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import net.mamoe.mirai.LowLevelApi
|
||||
import net.mamoe.mirai.contact.Stranger
|
||||
import net.mamoe.mirai.contact.User
|
||||
@ -39,10 +37,8 @@ import kotlin.coroutines.CoroutineContext
|
||||
|
||||
|
||||
@OptIn(ExperimentalContracts::class)
|
||||
internal inline fun Stranger.checkIsImpl(): StrangerImpl {
|
||||
contract {
|
||||
returns() implies (this@checkIsImpl is StrangerImpl)
|
||||
}
|
||||
internal inline fun Stranger.impl(): StrangerImpl {
|
||||
contract { returns() implies (this@impl is StrangerImpl) }
|
||||
check(this is StrangerImpl) { "A Stranger instance is not instance of StrangerImpl. Your instance: ${this::class.qualifiedName}" }
|
||||
return this
|
||||
}
|
||||
@ -50,10 +46,8 @@ internal inline fun Stranger.checkIsImpl(): StrangerImpl {
|
||||
internal class StrangerImpl(
|
||||
bot: QQAndroidBot,
|
||||
parentCoroutineContext: CoroutineContext,
|
||||
internal val strangerInfo: StrangerInfo,
|
||||
) : Stranger, AbstractUser(bot, parentCoroutineContext, strangerInfo) {
|
||||
@Suppress("unused") // bug
|
||||
val lastMessageSequence: AtomicInt = atomic(-1)
|
||||
override val info: StrangerInfo,
|
||||
) : Stranger, AbstractUser(bot, parentCoroutineContext, info) {
|
||||
override suspend fun delete() {
|
||||
check(bot.strangers[this.id] != null) {
|
||||
"Stranger ${this.id} had already been deleted"
|
||||
@ -66,7 +60,7 @@ internal class StrangerImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private val handler by lazy { StrangerSendMessageHandler(this) }
|
||||
private val handler: StrangerSendMessageHandler by lazy { StrangerSendMessageHandler(this) }
|
||||
|
||||
@Suppress("DuplicatedCode")
|
||||
override suspend fun sendMessage(message: Message): MessageReceipt<Stranger> {
|
||||
|
@ -18,4 +18,8 @@ internal data class FriendInfoImpl(
|
||||
override val uin: Long,
|
||||
override var nick: String,
|
||||
override var remark: String,
|
||||
) : FriendInfo
|
||||
) : FriendInfo {
|
||||
companion object {
|
||||
fun FriendInfo.impl() = if (this is FriendInfoImpl) this else FriendInfoImpl(uin, nick, remark)
|
||||
}
|
||||
}
|
@ -20,4 +20,8 @@ internal class StrangerInfoImpl(
|
||||
override val nick: String,
|
||||
override val fromGroup: Long = 0,
|
||||
override val remark: String = "",
|
||||
) : StrangerInfo
|
||||
) : StrangerInfo {
|
||||
companion object {
|
||||
fun StrangerInfo.impl() = if (this is StrangerInfoImpl) this else StrangerInfoImpl(uin, nick, fromGroup, remark)
|
||||
}
|
||||
}
|
@ -24,6 +24,7 @@ import net.mamoe.mirai.internal.network.components.SsoSession
|
||||
import net.mamoe.mirai.internal.network.protocol.SyncingCacheList
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.FileStoragePushFSSvcList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.Tlv
|
||||
import net.mamoe.mirai.internal.utils.AtomicIntSeq
|
||||
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal
|
||||
import net.mamoe.mirai.internal.utils.NetworkType
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -124,13 +125,10 @@ internal open class QQAndroidClient(
|
||||
|
||||
internal var strangerSeq: Int = 0
|
||||
|
||||
// TODO: 2021/4/14 investigate whether they can be minimized
|
||||
private val friendSeq: AtomicInt = atomic(getRandomUnsignedInt())
|
||||
internal fun getFriendSeq(): Int = friendSeq.value
|
||||
|
||||
internal fun nextFriendSeq(): Int = friendSeq.incrementAndGet()
|
||||
|
||||
internal fun setFriendSeq(compare: Int, id: Int): Boolean = friendSeq.compareAndSet(compare, id % 65535)
|
||||
/**
|
||||
* for send
|
||||
*/
|
||||
val sendFriendMessageSeq = AtomicIntSeq.forPrivateSync()
|
||||
|
||||
internal val groupConfig: GroupConfig = GroupConfig()
|
||||
|
||||
|
@ -19,10 +19,8 @@ import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.coroutines.sync.withPermit
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.data.FriendInfo
|
||||
import net.mamoe.mirai.data.MemberInfo
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.FriendImpl
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.StrangerImpl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
@ -34,6 +32,7 @@ import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.component.ComponentKey
|
||||
import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||
import net.mamoe.mirai.internal.network.isValid
|
||||
import net.mamoe.mirai.internal.network.notice.NewContactSupport
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.SvcRespRegister
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.isValid
|
||||
@ -76,7 +75,7 @@ internal class ContactUpdaterImpl(
|
||||
val bot: QQAndroidBot, // not good
|
||||
val components: ComponentStorage,
|
||||
private val logger: MiraiLogger,
|
||||
) : ContactUpdater {
|
||||
) : ContactUpdater, NewContactSupport {
|
||||
override val otherClientsLock: Mutex = Mutex()
|
||||
override val groupListModifyLock: Mutex = Mutex()
|
||||
private val cacheService get() = components[ContactCacheService]
|
||||
@ -176,16 +175,13 @@ internal class ContactUpdaterImpl(
|
||||
}
|
||||
|
||||
for (friendInfoImpl in list) {
|
||||
addFriendToBot(friendInfoImpl)
|
||||
bot.addNewFriendAndRemoveStranger(friendInfoImpl)
|
||||
}
|
||||
|
||||
|
||||
initFriendOk = true
|
||||
}
|
||||
|
||||
private fun addFriendToBot(it: FriendInfo) =
|
||||
bot.friends.delegate.add(FriendImpl(bot, bot.coroutineContext, it))
|
||||
|
||||
private suspend fun addGroupToBot(stTroopNum: StTroopNum) = stTroopNum.run {
|
||||
suspend fun refreshGroupMemberList(): Sequence<MemberInfo> {
|
||||
return Mirai.getRawGroupMemberList(
|
||||
@ -214,11 +210,11 @@ internal class ContactUpdaterImpl(
|
||||
bot.groups.delegate.add(
|
||||
GroupImpl(
|
||||
bot = bot,
|
||||
coroutineContext = bot.coroutineContext,
|
||||
parentCoroutineContext = bot.coroutineContext,
|
||||
id = groupCode,
|
||||
groupInfo = GroupInfoImpl(stTroopNum),
|
||||
members = members
|
||||
)
|
||||
members = members,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,7 @@ import net.mamoe.mirai.internal.network.component.ComponentStorage
|
||||
import net.mamoe.mirai.internal.network.notice.decoders.MsgType0x2DC
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgOnlinePush
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans.PbMsgInfo
|
||||
@ -32,6 +33,19 @@ import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
/**
|
||||
* Centralized processor pipeline for [MessageSvcPbGetMsg] and [OnlinePushPbPushTransMsg]
|
||||
*/
|
||||
internal interface NoticeProcessorPipeline {
|
||||
fun registerProcessor(processor: NoticeProcessor)
|
||||
|
||||
suspend fun process(bot: QQAndroidBot, data: Any?, attributes: TypeSafeMap = TypeSafeMap()): Collection<Packet>
|
||||
|
||||
companion object : ComponentKey<NoticeProcessorPipeline> {
|
||||
val ComponentStorage.noticeProcessorPipeline get() = get(NoticeProcessorPipeline)
|
||||
}
|
||||
}
|
||||
|
||||
internal interface PipelineContext {
|
||||
val bot: QQAndroidBot
|
||||
val attributes: TypeSafeMap
|
||||
@ -40,7 +54,7 @@ internal interface PipelineContext {
|
||||
val isConsumed: Boolean
|
||||
|
||||
/**
|
||||
* Mark the input as consumed so that there will not be warnings like 'Unknown type xxx'
|
||||
* Mark the input as consumed so that there will not be warnings like 'Unknown type xxx'. This will not stop the pipeline.
|
||||
*
|
||||
* If this is executed, make sure you provided all information important for debugging.
|
||||
*
|
||||
@ -79,19 +93,6 @@ internal interface PipelineContext {
|
||||
|
||||
internal inline val PipelineContext.context get() = this
|
||||
|
||||
/**
|
||||
* Centralized processor pipeline for [MessageSvcPbGetMsg] and [OnlinePushPbPushTransMsg]
|
||||
*/
|
||||
internal interface NoticeProcessorPipeline {
|
||||
fun registerProcessor(processor: NoticeProcessor)
|
||||
|
||||
suspend fun process(bot: QQAndroidBot, data: Any?, attributes: TypeSafeMap = TypeSafeMap()): Collection<Packet>
|
||||
|
||||
companion object : ComponentKey<NoticeProcessorPipeline> {
|
||||
val ComponentStorage.noticeProcessorPipeline get() = get(NoticeProcessorPipeline)
|
||||
}
|
||||
}
|
||||
|
||||
internal class NoticeProcessorPipelineImpl(
|
||||
private val logger: MiraiLogger,
|
||||
) : NoticeProcessorPipeline {
|
||||
@ -142,6 +143,10 @@ internal class NoticeProcessorPipelineImpl(
|
||||
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// NoticeProcessor
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* A processor handling some specific type of message.
|
||||
*/
|
||||
@ -157,11 +162,11 @@ internal abstract class SimpleNoticeProcessor<T : Any>(
|
||||
|
||||
final override suspend fun process(context: PipelineContext, data: Any?) {
|
||||
if (type.isInstance(data)) {
|
||||
context.process0(data.uncheckedCast())
|
||||
context.processImpl(data.uncheckedCast())
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract suspend fun PipelineContext.process0(data: T)
|
||||
protected abstract suspend fun PipelineContext.processImpl(data: T)
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
@ -170,11 +175,11 @@ internal abstract class SimpleNoticeProcessor<T : Any>(
|
||||
}
|
||||
|
||||
internal abstract class MsgCommonMsgProcessor : SimpleNoticeProcessor<MsgComm.Msg>(type()) {
|
||||
abstract override suspend fun PipelineContext.process0(data: MsgComm.Msg)
|
||||
abstract override suspend fun PipelineContext.processImpl(data: MsgComm.Msg)
|
||||
}
|
||||
|
||||
internal abstract class MixedNoticeProcessor : AnyNoticeProcessor() {
|
||||
final override suspend fun PipelineContext.process0(data: Any) {
|
||||
final override suspend fun PipelineContext.processImpl(data: Any) {
|
||||
when (data) {
|
||||
is MsgInfo -> processImpl(data)
|
||||
is PbMsgInfo -> processImpl(data)
|
||||
@ -183,14 +188,16 @@ internal abstract class MixedNoticeProcessor : AnyNoticeProcessor() {
|
||||
is MsgType0x210 -> processImpl(data)
|
||||
is MsgType0x2DC -> processImpl(data)
|
||||
is Structmsg.StructMsg -> processImpl(data)
|
||||
is RequestPushStatus -> processImpl(data)
|
||||
}
|
||||
}
|
||||
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgInfo) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgType0x210) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgType0x2DC) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgType0x210) {} // 528
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgType0x2DC) {} // 732
|
||||
protected open suspend fun PipelineContext.processImpl(data: PbMsgInfo) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgOnlinePush.PbPushMsg) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: MsgComm.Msg) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: Structmsg.StructMsg) {}
|
||||
protected open suspend fun PipelineContext.processImpl(data: RequestPushStatus) {}
|
||||
}
|
@ -9,8 +9,6 @@
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUByte
|
||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||
import net.mamoe.mirai.internal.network.components.PipelineContext
|
||||
import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
|
||||
@ -18,27 +16,12 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.OnlinePushTrans.PbMs
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.utils.read
|
||||
|
||||
internal class BinaryMessageProcessor : SimpleNoticeProcessor<PbMsgInfo>(type()), GroupEventProcessorContext {
|
||||
override suspend fun PipelineContext.process0(data: PbMsgInfo) {
|
||||
internal class BinaryMessageProcessor : SimpleNoticeProcessor<PbMsgInfo>(type()), NewContactSupport {
|
||||
override suspend fun PipelineContext.processImpl(data: PbMsgInfo) {
|
||||
data.msgData.read<Unit> {
|
||||
when (data.msgType) {
|
||||
44 -> {
|
||||
// 3D C4 33 DD 01 FF CD 76 F4 03 C3 7E 2E 34
|
||||
// 群转让
|
||||
// start with 3D C4 33 DD 01 FF
|
||||
// 3D C4 33 DD 01 FF C3 7E 2E 34 CD 76 F4 03
|
||||
// 权限变更
|
||||
// 3D C4 33 DD 01 00/01 .....
|
||||
// 3D C4 33 DD 01 01 C3 7E 2E 34 01
|
||||
this.discardExact(5)
|
||||
when (val mode = readUByte().toInt()) {
|
||||
0xFF -> {
|
||||
TODO("removed")
|
||||
}
|
||||
else -> {
|
||||
TODO("removed")
|
||||
}
|
||||
}
|
||||
TODO("removed")
|
||||
}
|
||||
34 -> {
|
||||
TODO("removed")
|
||||
@ -46,50 +29,7 @@ internal class BinaryMessageProcessor : SimpleNoticeProcessor<PbMsgInfo>(type())
|
||||
else -> {
|
||||
when {
|
||||
data.msgType == 529 && data.msgSubtype == 9 -> {
|
||||
/*
|
||||
PbMsgInfo#1773430973 {
|
||||
fromUin=0x0000000026BA1173(649728371)
|
||||
generalFlag=0x00000001(1)
|
||||
msgData=0A 07 70 72 69 6E 74 65 72 10 02 1A CD 02 0A 1F 53 61 6D 73 75 6E 67 20 4D 4C 2D 31 38 36 30 20 53 65 72 69 65 73 20 28 55 53 42 30 30 31 29 0A 16 4F 6E 65 4E 6F 74 65 20 66 6F 72 20 57 69 6E 64 6F 77 73 20 31 30 0A 19 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 20 74 6F 20 45 76 65 72 6E 6F 74 65 0A 11 4F 6E 65 4E 6F 74 65 20 28 44 65 73 6B 74 6F 70 29 0A 1D 4D 69 63 72 6F 73 6F 66 74 20 58 50 53 20 44 6F 63 75 6D 65 6E 74 20 57 72 69 74 65 72 0A 16 4D 69 63 72 6F 73 6F 66 74 20 50 72 69 6E 74 20 74 6F 20 50 44 46 0A 15 46 6F 78 69 74 20 50 68 61 6E 74 6F 6D 20 50 72 69 6E 74 65 72 0A 03 46 61 78 32 09 0A 03 6A 70 67 10 01 18 00 32 0A 0A 04 6A 70 65 67 10 01 18 00 32 09 0A 03 70 6E 67 10 01 18 00 32 09 0A 03 67 69 66 10 01 18 00 32 09 0A 03 62 6D 70 10 01 18 00 32 09 0A 03 64 6F 63 10 01 18 01 32 0A 0A 04 64 6F 63 78 10 01 18 01 32 09 0A 03 74 78 74 10 00 18 00 32 09 0A 03 70 64 66 10 01 18 01 32 09 0A 03 70 70 74 10 01 18 01 32 0A 0A 04 70 70 74 78 10 01 18 01 32 09 0A 03 78 6C 73 10 01 18 01 32 0A 0A 04 78 6C 73 78 10 01 18 01
|
||||
msgSeq=0x00001AFF(6911)
|
||||
msgSubtype=0x00000009(9)
|
||||
msgTime=0x5FDF21A3(1608458659)
|
||||
msgType=0x00000211(529)
|
||||
msgUid=0x010000005FDEE04C(72057595646369868)
|
||||
realMsgTime=0x5FDF21A3(1608458659)
|
||||
svrIp=0x3E689409(1047041033)
|
||||
toUin=0x0000000026BA1173(649728371)
|
||||
}
|
||||
*/
|
||||
/*
|
||||
*
|
||||
printer
|
||||
Samsung ML-1860 Series (USB001)
|
||||
OneNote for Windows 10
|
||||
Phantom Print to Evernote
|
||||
OneNote (Desktop)
|
||||
Microsoft XPS Document Writer
|
||||
Microsoft Print to PDF
|
||||
Foxit Phantom Printer
|
||||
Fax2
|
||||
jpg2
|
||||
|
||||
jpeg2
|
||||
png2
|
||||
gif2
|
||||
bmp2
|
||||
doc2
|
||||
|
||||
docx2
|
||||
txt2
|
||||
pdf2
|
||||
ppt2
|
||||
|
||||
pptx2
|
||||
xls2
|
||||
|
||||
xlsx*/
|
||||
return
|
||||
TODO("removed")
|
||||
}
|
||||
}
|
||||
throw contextualBugReportException(
|
||||
|
@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUByte
|
||||
import kotlinx.io.core.readUShort
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.contact.impl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.toMiraiFriendInfo
|
||||
import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.components.PipelineContext
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.FrdSysMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x115.SubMsgType0x115
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x44.Submsgtype0x44
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0xb3.SubMsgType0xb3
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList.GetFriendGroupList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
/**
|
||||
* All [FriendEvent] except [FriendMessageEvent]
|
||||
*
|
||||
* @see FriendInputStatusChangedEvent
|
||||
* @see FriendAddEvent
|
||||
* @see StrangerRelationChangeEvent.Friended
|
||||
*/
|
||||
internal class FriendNoticeProcessor(
|
||||
private val logger: MiraiLogger,
|
||||
) : MixedNoticeProcessor(), NewContactSupport {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
|
||||
if (msgHead.msgType != 191) return
|
||||
|
||||
var fromGroup = 0L
|
||||
var pbNick = ""
|
||||
msgBody.msgContent.read {
|
||||
readUByte() // version
|
||||
discardExact(readUByte().toInt()) //skip
|
||||
readUShort() //source id
|
||||
readUShort() //SourceSubID
|
||||
discardExact(readUShort().toLong()) //skip size
|
||||
if (readUShort().toInt() != 0) { //hasExtraInfo
|
||||
discardExact(readUShort().toInt()) //mail address info, skip
|
||||
}
|
||||
discardExact(4 + readUShort().toInt()) //skip
|
||||
for (i in 1..readUByte().toInt()) { //pb size
|
||||
val type = readUShort().toInt()
|
||||
val pbArray = ByteArray(readUShort().toInt() and 0xFF)
|
||||
readAvailable(pbArray)
|
||||
when (type) {
|
||||
1000 -> pbArray.loadAs(FrdSysMsg.GroupInfo.serializer()).let { fromGroup = it.groupUin }
|
||||
1002 -> pbArray.loadAs(FrdSysMsg.FriendMiscInfo.serializer())
|
||||
.let { pbNick = it.fromuinNick }
|
||||
else -> {
|
||||
} //ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
msgHead.context {
|
||||
if (fromUin == authUin) {
|
||||
logger.error { "Could not determine uin since `fromUin` = `authUin` = $fromUin" }
|
||||
return
|
||||
}
|
||||
val id = fromUin or authUin // 对方 qq
|
||||
if (bot.getStranger(id) != null) return
|
||||
|
||||
val nick = fromNick.ifEmpty { authNick }.ifEmpty { pbNick }
|
||||
collect(StrangerAddEvent(bot.addNewStranger(StrangerInfoImpl(id, nick, fromGroup)) ?: return))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override suspend fun PipelineContext.processImpl(data: MsgType0x210) = data.context {
|
||||
when (data.uSubMsgType) {
|
||||
0xB3L -> {
|
||||
// 08 01 12 52 08 A2 FF 8C F0 03 10 00 1D 15 3D 90 5E 22 2E E6 88 91 E4 BB AC E5 B7 B2 E7 BB 8F E6 98 AF E5 A5 BD E5 8F 8B E5 95 A6 EF BC 8C E4 B8 80 E8 B5 B7 E6 9D A5 E8 81 8A E5 A4 A9 E5 90 A7 21 2A 09 48 69 6D 31 38 38 6D 6F 65 30 07 38 03 48 DD F1 92 B7 07
|
||||
val body: SubMsgType0xb3.MsgBody = vProtobuf.loadAs(SubMsgType0xb3.MsgBody.serializer())
|
||||
handleFriendAddedB(data, body)
|
||||
}
|
||||
0x44L -> {
|
||||
val body = vProtobuf.loadAs(Submsgtype0x44.MsgBody.serializer())
|
||||
handleFriendAddedA(body)
|
||||
}
|
||||
0x27L -> {
|
||||
val body = vProtobuf.loadAs(SubMsgType0x27MsgBody.serializer())
|
||||
for (msgModInfo in body.msgModInfos) {
|
||||
when {
|
||||
msgModInfo.msgModFriendRemark != null -> handleRemarkChanged(msgModInfo.msgModFriendRemark)
|
||||
msgModInfo.msgDelFriend != null -> handleFriendDeleted(msgModInfo.msgDelFriend)
|
||||
msgModInfo.msgModCustomFace != null -> handleAvatarChanged(msgModInfo.msgModCustomFace)
|
||||
msgModInfo.msgModProfile != null -> handleProfileChanged(msgModInfo.msgModProfile)
|
||||
}
|
||||
}
|
||||
}
|
||||
0x115L -> {
|
||||
val body = vProtobuf.loadAs(SubMsgType0x115.MsgBody.serializer())
|
||||
handleInputStatusChanged(body)
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
markAsConsumed()
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleInputStatusChanged(body: SubMsgType0x115.MsgBody) {
|
||||
val friend = bot.getFriend(body.fromUin) ?: return
|
||||
val item = body.msgNotifyItem ?: return
|
||||
collect(FriendInputStatusChangedEvent(friend, item.eventType == 1))
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleProfileChanged(body: ModProfile) {
|
||||
var containsUnknown = false
|
||||
for (profileInfo in body.msgProfileInfos) {
|
||||
when (profileInfo.field) {
|
||||
20002 -> { // 昵称修改
|
||||
val to = profileInfo.value
|
||||
if (body.uin == bot.id) {
|
||||
val from = bot.nick
|
||||
if (from == to) continue
|
||||
collect(BotNickChangedEvent(bot, from, to))
|
||||
bot.nick = to
|
||||
} else {
|
||||
val friend = bot.getFriend(body.uin)?.impl() ?: continue
|
||||
val from = bot.nick
|
||||
if (from == to) continue
|
||||
collect(FriendNickChangedEvent(friend, from, to))
|
||||
friend.info.nick = to
|
||||
}
|
||||
}
|
||||
else -> containsUnknown = true
|
||||
}
|
||||
}
|
||||
if (body.msgProfileInfos.isEmpty() || containsUnknown) {
|
||||
logger.debug { "Transformers528 0x27L: ProfileChanged new data: ${body._miraiContentToString()}" }
|
||||
}
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleRemarkChanged(body: ModFriendRemark) {
|
||||
for (new in body.msgFrdRmk) {
|
||||
val friend = bot.getFriend(new.fuin)?.impl() ?: continue
|
||||
|
||||
// TODO: 2020/4/10 ADD REMARK QUERY
|
||||
collect(FriendRemarkChangeEvent(friend, friend.remark, new.rmkName))
|
||||
friend.info.remark = new.rmkName
|
||||
}
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleAvatarChanged(body: ModCustomFace) {
|
||||
if (body.uin == bot.id) {
|
||||
collect(BotAvatarChangedEvent(bot))
|
||||
}
|
||||
collect(FriendAvatarChangedEvent(bot.getFriend(body.uin) ?: return))
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleFriendDeleted(body: DelFriend) {
|
||||
for (id in body.uint64Uins) {
|
||||
collect(FriendDeleteEvent(bot.removeFriend(id) ?: continue))
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun PipelineContext.handleFriendAddedA(
|
||||
body: Submsgtype0x44.MsgBody,
|
||||
) = body.msgFriendMsgSync.context {
|
||||
if (this == null) return
|
||||
|
||||
when (processtype) {
|
||||
3, 9, 10 -> {
|
||||
if (bot.getFriend(fuin) != null) return
|
||||
|
||||
val response = GetFriendGroupList.forSingleFriend(bot.client, fuin).sendAndExpect(bot)
|
||||
val info = response.friendList.firstOrNull() ?: return
|
||||
collect(
|
||||
FriendAddEvent(bot.addNewFriendAndRemoveStranger(info.toMiraiFriendInfo()) ?: return),
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun PipelineContext.handleFriendAddedB(data: MsgType0x210, body: SubMsgType0xb3.MsgBody) = data.context {
|
||||
val info = FriendInfoImpl(
|
||||
uin = body.msgAddFrdNotify.fuin,
|
||||
nick = body.msgAddFrdNotify.fuinNick,
|
||||
remark = "",
|
||||
)
|
||||
|
||||
val removed = bot.removeStranger(info.uin)
|
||||
val added = bot.addNewFriendAndRemoveStranger(info) ?: return
|
||||
collect(FriendAddEvent(added))
|
||||
if (removed != null) collect(StrangerRelationChangeEvent.Friended(removed, added))
|
||||
}
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
||||
import net.mamoe.mirai.internal.getGroupByUin
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
|
||||
internal interface GroupEventProcessorContext {
|
||||
|
||||
fun MsgComm.Msg.getNewMemberInfo(): MemberInfoImpl {
|
||||
return MemberInfoImpl(
|
||||
nameCard = msgHead.authNick.ifEmpty { msgHead.fromNick },
|
||||
permission = MemberPermission.MEMBER,
|
||||
specialTitle = "",
|
||||
muteTimestamp = 0,
|
||||
uin = msgHead.authUin,
|
||||
nick = msgHead.authNick.ifEmpty { msgHead.fromNick },
|
||||
remark = "",
|
||||
anonymousId = null
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun QQAndroidBot.createGroupForBot(groupUin: Long): GroupImpl? {
|
||||
val group = getGroupByUin(groupUin)
|
||||
if (group != null) {
|
||||
return null
|
||||
}
|
||||
|
||||
return getNewGroup(Mirai.calculateGroupCodeByGroupUin(groupUin))?.apply { groups.delegate.add(this) }
|
||||
}
|
||||
|
||||
suspend fun QQAndroidBot.getNewGroup(groupCode: Long): GroupImpl? {
|
||||
val troopNum = FriendList.GetTroopListSimplify(client)
|
||||
.sendAndExpect(network, timeoutMillis = 10_000, retry = 5)
|
||||
.groups.firstOrNull { it.groupCode == groupCode } ?: return null
|
||||
|
||||
return GroupImpl(
|
||||
bot = this,
|
||||
coroutineContext = coroutineContext,
|
||||
id = groupCode,
|
||||
groupInfo = GroupInfoImpl(troopNum),
|
||||
members = Mirai.getRawGroupMemberList(
|
||||
this,
|
||||
troopNum.groupUin,
|
||||
troopNum.groupCode,
|
||||
troopNum.dwGroupOwnerUin
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -39,6 +39,9 @@ import net.mamoe.mirai.utils.read
|
||||
|
||||
|
||||
/**
|
||||
* Member/Bot invited/active join // force/active leave
|
||||
* Member/Bot permission change
|
||||
*
|
||||
* @see BotJoinGroupEvent
|
||||
* @see MemberJoinEvent
|
||||
*
|
||||
@ -47,10 +50,13 @@ import net.mamoe.mirai.utils.read
|
||||
*
|
||||
* @see MemberPermissionChangeEvent
|
||||
* @see BotGroupPermissionChangeEvent
|
||||
*
|
||||
* @see BotInvitedJoinGroupRequestEvent
|
||||
* @see MemberJoinRequestEvent
|
||||
*/
|
||||
internal class GroupListNoticeProcessor(
|
||||
private val logger: MiraiLogger
|
||||
) : MixedNoticeProcessor(), GroupEventProcessorContext {
|
||||
private val logger: MiraiLogger,
|
||||
) : MixedNoticeProcessor(), NewContactSupport {
|
||||
|
||||
override suspend fun PipelineContext.processImpl(data: MsgType0x210) {
|
||||
if (data.uSubMsgType != 0x44L) return
|
||||
@ -60,7 +66,7 @@ internal class GroupListNoticeProcessor(
|
||||
when (msg.msgGroupMsgSync.msgType) {
|
||||
1, 2 -> {
|
||||
bot.components[ContactUpdater].groupListModifyLock.withLock {
|
||||
bot.createGroupForBot(Mirai.calculateGroupUinByGroupCode(msg.msgGroupMsgSync.grpCode))?.let {
|
||||
bot.addNewGroupByCode(msg.msgGroupMsgSync.grpCode)?.let {
|
||||
collect(BotJoinGroupEvent.Active(it))
|
||||
}
|
||||
}
|
||||
@ -85,10 +91,10 @@ internal class GroupListNoticeProcessor(
|
||||
1 -> {
|
||||
val dataList = message.parseToMessageDataList()
|
||||
val invitor = dataList.first().let { messageData ->
|
||||
group.getOrFail(messageData.data.toLong())
|
||||
group[messageData.data.toLong()] ?: return
|
||||
}
|
||||
val member = dataList.last().let { messageData ->
|
||||
group.addNewNormalMember(messageData.toMemberInfo())
|
||||
group.addNewNormalMember(messageData.toMemberInfo()) ?: return
|
||||
}
|
||||
collect(MemberJoinEvent.Invite(member, invitor))
|
||||
}
|
||||
@ -116,50 +122,73 @@ internal class GroupListNoticeProcessor(
|
||||
* @see BotJoinGroupEvent.Active
|
||||
*/
|
||||
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
|
||||
if (data.msgHead.msgType != 33) return
|
||||
bot.components[ContactUpdater].groupListModifyLock.withLock {
|
||||
msgBody.msgContent.read {
|
||||
val groupUin = Mirai.calculateGroupUinByGroupCode(readUInt().toLong())
|
||||
val group =
|
||||
bot.getGroupByUin(groupUin) ?: bot.createGroupForBot(groupUin) ?: return markAsConsumed()
|
||||
discardExact(1)
|
||||
val joinedMemberUin = readUInt().toLong()
|
||||
val joinType = readByte().toInt()
|
||||
val invitorUin = readUInt().toLong()
|
||||
when (joinType) {
|
||||
// 邀请加入
|
||||
-125, 3 -> {
|
||||
val invitor = group[invitorUin] ?: return markAsConsumed()
|
||||
collected += if (joinedMemberUin == bot.id) {
|
||||
BotJoinGroupEvent.Invite(invitor)
|
||||
} else {
|
||||
MemberJoinEvent.Invite(group.addNewNormalMember(getNewMemberInfo()), invitor)
|
||||
}
|
||||
}
|
||||
// 通过群员分享的二维码/直接加入
|
||||
-126, 2 -> {
|
||||
collected += if (joinedMemberUin == bot.id) {
|
||||
BotJoinGroupEvent.Active(group)
|
||||
} else {
|
||||
MemberJoinEvent.Active(group.addNewNormalMember(getNewMemberInfo()))
|
||||
}
|
||||
}
|
||||
// 忽略
|
||||
else -> {
|
||||
when (data.msgHead.msgType) {
|
||||
33 -> processGroupJoin33(data)
|
||||
34 -> Unit // 34 与 33 重复, 忽略 34
|
||||
38 -> processGroupJoin38(data)
|
||||
85 -> processGroupJoin85(data)
|
||||
else -> return
|
||||
}
|
||||
markAsConsumed()
|
||||
}
|
||||
}
|
||||
|
||||
// 33
|
||||
private suspend fun PipelineContext.processGroupJoin33(data: MsgComm.Msg) = data.context {
|
||||
msgBody.msgContent.read {
|
||||
val groupUin = Mirai.calculateGroupUinByGroupCode(readUInt().toLong())
|
||||
val group = bot.getGroupByUin(groupUin) ?: bot.addNewGroupByUin(groupUin) ?: return
|
||||
discardExact(1)
|
||||
val joinedMemberUin = readUInt().toLong()
|
||||
val joinType = readByte().toInt()
|
||||
val invitorUin = readUInt().toLong()
|
||||
when (joinType) {
|
||||
// 邀请加入
|
||||
-125, 3 -> {
|
||||
val invitor = group[invitorUin] ?: return
|
||||
collected += if (joinedMemberUin == bot.id) {
|
||||
BotJoinGroupEvent.Invite(invitor)
|
||||
} else {
|
||||
MemberJoinEvent.Invite(group.addNewNormalMember(getNewMemberInfo()) ?: return, invitor)
|
||||
}
|
||||
}
|
||||
// 通过群员分享的二维码/直接加入
|
||||
-126, 2 -> {
|
||||
collected += if (joinedMemberUin == bot.id) {
|
||||
BotJoinGroupEvent.Active(group)
|
||||
} else {
|
||||
MemberJoinEvent.Active(group.addNewNormalMember(getNewMemberInfo()) ?: return)
|
||||
}
|
||||
}
|
||||
// 忽略
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
// 邀请入群
|
||||
// package: 27 0B 60 E7 01 CA CC 69 8B 83 44 71 47 90 06 B9 DC C0 ED D4 B1 00 30 33 44 30 42 38 46 30 39 37 32 38 35 43 34 31 38 30 33 36 41 34 36 31 36 31 35 32 37 38 46 46 43 30 41 38 30 36 30 36 45 38 31 43 39 41 34 38 37
|
||||
// package: groupUin + 01 CA CC 69 8B 83 + invitorUin + length(06) + string + magicKey
|
||||
|
||||
|
||||
// 主动入群, 直接加入: msgContent=27 0B 60 E7 01 76 E4 B8 DD 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 42 39 41 30 33 45 38 34 30 39 34 42 46 30 45 32 45 38 42 31 43 43 41 34 32 42 38 42 44 42 35 34 44 42 31 44 32 32 30 46 30 38 39 46 46 35 41 38
|
||||
// 主动直接加入 27 0B 60 E7 01 76 E4 B8 DD 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 33 30 45 38 42 31 33 46 41 41 31 33 46 38 31 35 34 41 38 33 32 37 31 43 34 34 38 35 33 35 46 45 31 38 32 43 39 42 43 46 46 32 44 39 39 46 41 37
|
||||
|
||||
// 有人被邀请(经过同意后)加入 27 0B 60 E7 01 76 E4 B8 DD 83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 34 30 34 38 32 33 38 35 37 41 37 38 46 33 45 37 35 38 42 39 38 46 43 45 44 43 32 41 30 31 36 36 30 34 31 36 39 35 39 30 38 39 30 39 45 31 34 34
|
||||
// 搜索到群, 直接加入 27 0B 60 E7 01 07 6E 47 BA 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 32 30 39 39 42 39 41 46 32 39 41 35 42 33 46 34 32 30 44 36 44 36 39 35 44 38 45 34 35 30 46 30 45 30 38 45 31 41 39 42 46 46 45 32 30 32 34 35
|
||||
}
|
||||
// 邀请入群
|
||||
// package: 27 0B 60 E7 01 CA CC 69 8B 83 44 71 47 90 06 B9 DC C0 ED D4 B1 00 30 33 44 30 42 38 46 30 39 37 32 38 35 43 34 31 38 30 33 36 41 34 36 31 36 31 35 32 37 38 46 46 43 30 41 38 30 36 30 36 45 38 31 43 39 41 34 38 37
|
||||
// package: groupUin + 01 CA CC 69 8B 83 + invitorUin + length(06) + string + magicKey
|
||||
|
||||
|
||||
// 主动入群, 直接加入: msgContent=27 0B 60 E7 01 76 E4 B8 DD 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 42 39 41 30 33 45 38 34 30 39 34 42 46 30 45 32 45 38 42 31 43 43 41 34 32 42 38 42 44 42 35 34 44 42 31 44 32 32 30 46 30 38 39 46 46 35 41 38
|
||||
// 主动直接加入 27 0B 60 E7 01 76 E4 B8 DD 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 33 30 45 38 42 31 33 46 41 41 31 33 46 38 31 35 34 41 38 33 32 37 31 43 34 34 38 35 33 35 46 45 31 38 32 43 39 42 43 46 46 32 44 39 39 46 41 37
|
||||
|
||||
// 有人被邀请(经过同意后)加入 27 0B 60 E7 01 76 E4 B8 DD 83 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 34 30 34 38 32 33 38 35 37 41 37 38 46 33 45 37 35 38 42 39 38 46 43 45 44 43 32 41 30 31 36 36 30 34 31 36 39 35 39 30 38 39 30 39 45 31 34 34
|
||||
// 搜索到群, 直接加入 27 0B 60 E7 01 07 6E 47 BA 82 3E 03 3F A2 06 B4 B4 BD A8 D5 DF 00 30 32 30 39 39 42 39 41 46 32 39 41 35 42 33 46 34 32 30 44 36 44 36 39 35 44 38 45 34 35 30 46 30 45 30 38 45 31 41 39 42 46 46 45 32 30 32 34 35
|
||||
}
|
||||
|
||||
// 38
|
||||
private suspend fun PipelineContext.processGroupJoin38(data: MsgComm.Msg) = data.context {
|
||||
if (bot.getGroupByUin(msgHead.fromUin) != null) return
|
||||
bot.addNewGroupByUin(msgHead.fromUin)?.let { collect(BotJoinGroupEvent.Active(it)) }
|
||||
}
|
||||
|
||||
// 85
|
||||
private suspend fun PipelineContext.processGroupJoin85(data: MsgComm.Msg) = data.context {
|
||||
// msgHead.authUin: 处理人
|
||||
if (msgHead.toUin != bot.id) return
|
||||
processGroupJoin38(data)
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -201,10 +230,10 @@ internal class GroupListNoticeProcessor(
|
||||
}
|
||||
2 -> { // 被邀请入群, 自动同意, 不需处理
|
||||
|
||||
// val group = bot.getNewGroup(groupCode) ?: return null
|
||||
// val invitor = group[actionUin]
|
||||
//
|
||||
// BotJoinGroupEvent.Invite(invitor)
|
||||
// val group = bot.getNewGroup(groupCode) ?: return null
|
||||
// val invitor = group[actionUin]
|
||||
//
|
||||
// BotJoinGroupEvent.Invite(invitor)
|
||||
}
|
||||
3 -> { // 已被请他管理员处理
|
||||
}
|
||||
@ -250,6 +279,13 @@ internal class GroupListNoticeProcessor(
|
||||
markAsConsumed()
|
||||
when (data.msgType) {
|
||||
44 -> data.msgData.read {
|
||||
// 3D C4 33 DD 01 FF CD 76 F4 03 C3 7E 2E 34
|
||||
// 群转让
|
||||
// start with 3D C4 33 DD 01 FF
|
||||
// 3D C4 33 DD 01 FF C3 7E 2E 34 CD 76 F4 03
|
||||
// 权限变更
|
||||
// 3D C4 33 DD 01 00/01 .....
|
||||
// 3D C4 33 DD 01 01 C3 7E 2E 34 01
|
||||
discardExact(5)
|
||||
val kind = readUByte().toInt()
|
||||
if (kind == 0xFF) {
|
||||
@ -327,7 +363,7 @@ toUin=0x0000000026BA1173(649728371)
|
||||
target: Long,
|
||||
kind: Int,
|
||||
operator: Long,
|
||||
groupUin: Long
|
||||
groupUin: Long,
|
||||
) {
|
||||
when (kind) {
|
||||
2, 0x82 -> bot.getGroupByUin(groupUin)?.let { group ->
|
||||
@ -367,7 +403,7 @@ toUin=0x0000000026BA1173(649728371)
|
||||
private fun PipelineContext.handlePermissionChange(
|
||||
data: OnlinePushTrans.PbMsgInfo,
|
||||
target: Long,
|
||||
newPermissionByte: Int
|
||||
newPermissionByte: Int,
|
||||
) {
|
||||
val group = bot.getGroupByUin(data.fromUin) ?: return
|
||||
|
||||
@ -410,7 +446,7 @@ toUin=0x0000000026BA1173(649728371)
|
||||
// member Retrieve or permission changed to OWNER
|
||||
var newOwner = group[to]
|
||||
if (newOwner == null) {
|
||||
newOwner = group.addNewNormalMember(MemberInfoImpl(uin = to, nick = "", permission = OWNER))
|
||||
newOwner = group.addNewNormalMember(MemberInfoImpl(uin = to, nick = "", permission = OWNER)) ?: return
|
||||
collect(MemberJoinEvent.Retrieve(newOwner))
|
||||
} else if (newOwner.permission != OWNER) {
|
||||
collect(MemberPermissionChangeEvent(newOwner, newOwner.permission, OWNER))
|
||||
@ -421,7 +457,7 @@ toUin=0x0000000026BA1173(649728371)
|
||||
|
||||
// bot Retrieve or permission changed to OWNER
|
||||
if (group == null) {
|
||||
collect(BotJoinGroupEvent.Retrieve(bot.createGroupForBot(data.fromUin)!!))
|
||||
collect(BotJoinGroupEvent.Retrieve(bot.addNewGroupByUin(data.fromUin) ?: return))
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -35,6 +35,9 @@ import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.utils.*
|
||||
|
||||
/**
|
||||
* Handles [GroupMessageEvent]. For private message events, see [PrivateMessageNoticeProcessor]
|
||||
*/
|
||||
internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPushMsg>(type()) {
|
||||
internal data class SendGroupMessageReceipt(
|
||||
val messageRandom: Int,
|
||||
@ -61,7 +64,7 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
}
|
||||
|
||||
|
||||
override suspend fun PipelineContext.process0(data: MsgOnlinePush.PbPushMsg) {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgOnlinePush.PbPushMsg) {
|
||||
val msgHead = data.msg.msgHead
|
||||
|
||||
val isFromSelfAccount = msgHead.fromUin == bot.id
|
||||
@ -73,13 +76,7 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
// 3116=group music share
|
||||
// 2021=group file
|
||||
// message sent by bot
|
||||
collect(
|
||||
SendGroupMessageReceipt(
|
||||
messageRandom,
|
||||
msgHead.msgSeq,
|
||||
msgHead.fromAppid
|
||||
)
|
||||
)
|
||||
collect(SendGroupMessageReceipt(messageRandom, msgHead.msgSeq, msgHead.fromAppid))
|
||||
return
|
||||
}
|
||||
// else: sync form other device
|
||||
@ -132,7 +129,7 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
group = group,
|
||||
sender = sender,
|
||||
senderName = nameCard.nick,
|
||||
)
|
||||
),
|
||||
)
|
||||
return
|
||||
} else {
|
||||
@ -145,8 +142,8 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
sender = sender,
|
||||
message = msgs.map { it.msg }.toMessageChainOnline(bot, group.id, MessageSourceKind.GROUP),
|
||||
permission = sender.permission,
|
||||
time = msgHead.msgTime
|
||||
)
|
||||
time = msgHead.msgTime,
|
||||
),
|
||||
)
|
||||
return
|
||||
}
|
||||
@ -154,7 +151,7 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
|
||||
private suspend inline fun broadcastNameCardChangedEventIfNecessary(
|
||||
sender: Member,
|
||||
new: MemberNick
|
||||
new: MemberNick,
|
||||
) {
|
||||
if (sender is NormalMemberImpl) {
|
||||
val currentNameCard = sender.nameCard
|
||||
@ -177,7 +174,7 @@ internal class GroupMessageProcessor : SimpleNoticeProcessor<MsgOnlinePush.PbPus
|
||||
|
||||
private fun findSenderName(
|
||||
extraInfo: ImMsgBody.ExtraInfo?,
|
||||
groupInfo: MsgComm.GroupInfo
|
||||
groupInfo: MsgComm.GroupInfo,
|
||||
): MemberNick? =
|
||||
extraInfo?.groupCard?.takeIf { it.isNotEmpty() }?.decodeCommCardNameBuf()?.let {
|
||||
MemberNick(it, true)
|
||||
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import kotlinx.coroutines.cancel
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.FriendImpl
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.StrangerImpl
|
||||
import net.mamoe.mirai.internal.contact.impl
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.GroupInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.MemberInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
||||
import net.mamoe.mirai.internal.getGroupByUin
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
|
||||
internal interface NewContactSupport {
|
||||
|
||||
fun MsgComm.Msg.getNewMemberInfo(): MemberInfoImpl {
|
||||
return MemberInfoImpl(
|
||||
nameCard = msgHead.authNick.ifEmpty { msgHead.fromNick },
|
||||
permission = MemberPermission.MEMBER,
|
||||
specialTitle = "",
|
||||
muteTimestamp = 0,
|
||||
uin = msgHead.authUin,
|
||||
nick = msgHead.authNick.ifEmpty { msgHead.fromNick },
|
||||
remark = "",
|
||||
anonymousId = null,
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun QQAndroidBot.addNewGroupByCode(code: Long): GroupImpl? {
|
||||
if (getGroup(code) != null) return null
|
||||
return getNewGroup(code)?.apply { groups.delegate.add(this) }
|
||||
}
|
||||
|
||||
suspend fun QQAndroidBot.addNewGroupByUin(groupUin: Long): GroupImpl? {
|
||||
if (getGroupByUin(groupUin) != null) return null
|
||||
return getNewGroup(Mirai.calculateGroupCodeByGroupUin(groupUin))?.apply { groups.delegate.add(this) }
|
||||
}
|
||||
|
||||
suspend fun QQAndroidBot.addNewGroup(stTroopNum: StTroopNum): GroupImpl? {
|
||||
if (getGroup(stTroopNum.groupCode) != null) return null
|
||||
return getNewGroup(stTroopNum)?.apply { groups.delegate.add(this) }
|
||||
}
|
||||
|
||||
fun QQAndroidBot.removeStranger(id: Long): StrangerImpl? {
|
||||
val instance = strangers[id] ?: return null
|
||||
strangers.remove(instance.id)
|
||||
instance.cancel()
|
||||
return instance
|
||||
}
|
||||
|
||||
fun QQAndroidBot.removeFriend(id: Long): FriendImpl? {
|
||||
val instance = friends[id] ?: return null
|
||||
friends.remove(instance.id)
|
||||
instance.cancel()
|
||||
return instance
|
||||
}
|
||||
|
||||
fun QQAndroidBot.addNewFriendAndRemoveStranger(info: FriendInfoImpl): FriendImpl? {
|
||||
if (friends.contains(info.uin)) return null
|
||||
strangers[info.uin]?.let { removeStranger(it.id) }
|
||||
val friend = Mirai.newFriend(bot, info).impl()
|
||||
friends.delegate.add(friend)
|
||||
return friend
|
||||
}
|
||||
|
||||
fun QQAndroidBot.addNewStranger(info: StrangerInfoImpl): StrangerImpl? {
|
||||
if (friends.contains(info.uin)) return null // cannot have both stranger and friend
|
||||
if (strangers.contains(info.uin)) return null
|
||||
val stranger = Mirai.newStranger(bot, info).impl()
|
||||
strangers.delegate.add(stranger)
|
||||
return stranger
|
||||
}
|
||||
|
||||
private suspend fun QQAndroidBot.getNewGroup(groupCode: Long): GroupImpl? {
|
||||
val troopNum = FriendList.GetTroopListSimplify(client)
|
||||
.sendAndExpect(network, timeoutMillis = 10_000, retry = 5)
|
||||
.groups.firstOrNull { it.groupCode == groupCode } ?: return null
|
||||
|
||||
return getNewGroup(troopNum)
|
||||
}
|
||||
|
||||
private suspend fun QQAndroidBot.getNewGroup(troopNum: StTroopNum): GroupImpl? {
|
||||
return GroupImpl(
|
||||
bot = this,
|
||||
parentCoroutineContext = coroutineContext,
|
||||
id = troopNum.groupCode,
|
||||
groupInfo = GroupInfoImpl(troopNum),
|
||||
members = Mirai.getRawGroupMemberList(
|
||||
this,
|
||||
troopNum.groupUin,
|
||||
troopNum.groupCode,
|
||||
troopNum.dwGroupOwnerUin,
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.ClientKind
|
||||
import net.mamoe.mirai.contact.OtherClientInfo
|
||||
import net.mamoe.mirai.contact.Platform
|
||||
import net.mamoe.mirai.event.events.OtherClientMessageEvent
|
||||
import net.mamoe.mirai.event.events.OtherClientOfflineEvent
|
||||
import net.mamoe.mirai.event.events.OtherClientOnlineEvent
|
||||
import net.mamoe.mirai.internal.contact.appId
|
||||
import net.mamoe.mirai.internal.contact.createOtherClient
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceFromFriendImpl
|
||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||
import net.mamoe.mirai.internal.network.components.ContactUpdater
|
||||
import net.mamoe.mirai.internal.network.components.MixedNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.components.PipelineContext
|
||||
import net.mamoe.mirai.internal.network.handler.logger
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.buildMessageChain
|
||||
import net.mamoe.mirai.utils.context
|
||||
|
||||
/**
|
||||
* @see OtherClientOnlineEvent
|
||||
* @see OtherClientOfflineEvent
|
||||
*
|
||||
* @see OtherClientMessageEvent
|
||||
*/
|
||||
internal class OtherClientNoticeProcessor : MixedNoticeProcessor() {
|
||||
/**
|
||||
* @see OtherClientOnlineEvent
|
||||
* @see OtherClientOfflineEvent
|
||||
*/
|
||||
override suspend fun PipelineContext.processImpl(data: RequestPushStatus) {
|
||||
markAsConsumed()
|
||||
bot.components[ContactUpdater].otherClientsLock.withLock {
|
||||
val instanceInfo = data.vecInstanceList?.firstOrNull()
|
||||
val appId = instanceInfo?.iAppId ?: 1
|
||||
when (data.status.toInt()) {
|
||||
1 -> { // online
|
||||
if (bot.otherClients.any { appId == it.appId }) return
|
||||
|
||||
suspend fun tryFindInQuery(): OtherClientInfo? {
|
||||
return Mirai.getOnlineOtherClientsList(bot).find { it.appId == appId }
|
||||
?: kotlin.run {
|
||||
delay(2000) // sometimes server sync slow
|
||||
Mirai.getOnlineOtherClientsList(bot).find { it.appId == appId }
|
||||
}
|
||||
}
|
||||
|
||||
val info =
|
||||
tryFindInQuery() ?: kotlin.run {
|
||||
bot.network.logger.warning(
|
||||
contextualBugReportException(
|
||||
"SvcRequestPushStatus (OtherClient online)",
|
||||
"packet: \n" + data._miraiContentToString() +
|
||||
"\n\nquery: \n" +
|
||||
Mirai.getOnlineOtherClientsList(bot)._miraiContentToString(),
|
||||
additional = "Failed to find corresponding instanceInfo.",
|
||||
),
|
||||
)
|
||||
OtherClientInfo(appId, Platform.WINDOWS, "", "电脑")
|
||||
}
|
||||
|
||||
val client = bot.createOtherClient(info)
|
||||
bot.otherClients.delegate.add(client)
|
||||
collected += OtherClientOnlineEvent(
|
||||
client,
|
||||
ClientKind[data.nClientType?.toInt() ?: 0],
|
||||
)
|
||||
}
|
||||
|
||||
2 -> { // off
|
||||
val client = bot.otherClients.find { it.appId == appId } ?: return
|
||||
client.cancel(CancellationException("Offline"))
|
||||
bot.otherClients.delegate.remove(client)
|
||||
collected += OtherClientOfflineEvent(client)
|
||||
}
|
||||
|
||||
else -> throw contextualBugReportException(
|
||||
"decode SvcRequestPushStatus (PC Client status change)",
|
||||
data._miraiContentToString(),
|
||||
additional = "unknown status=${data.status}",
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see OtherClientMessageEvent
|
||||
*/
|
||||
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
|
||||
if (msgHead.msgType != 529) return
|
||||
markAsConsumed() // todo check
|
||||
if (msgHead.c2cCmd != 7) return
|
||||
val body = msgBody.msgContent.loadAs(SubMsgType0x7.MsgBody.serializer())
|
||||
|
||||
val textMsg =
|
||||
body.msgSubcmd0x4Generic?.buf?.loadAs(SubMsgType0x7.MsgBody.QQDataTextMsg.serializer())
|
||||
?: return
|
||||
|
||||
with(body.msgHeader ?: return) {
|
||||
if (dstUin != bot.id) return
|
||||
val client = bot.otherClients.find { it.appId == srcInstId }
|
||||
?: return // don't compare with dstAppId. diff.
|
||||
|
||||
val chain = buildMessageChain {
|
||||
+OnlineMessageSourceFromFriendImpl(bot, listOf(data))
|
||||
for (msgItem in textMsg.msgItems) {
|
||||
when (msgItem.type) {
|
||||
1 -> +PlainText(msgItem.text)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collect(OtherClientMessageEvent(client, chain, msgHead.msgTime))
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
import net.mamoe.mirai.internal.getGroupByUin
|
||||
import net.mamoe.mirai.internal.message.toMessageChainOnline
|
||||
import net.mamoe.mirai.internal.network.components.PipelineContext
|
||||
import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
||||
import net.mamoe.mirai.internal.network.notice.SystemMessageProcessor.Companion.fromSync
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.utils.context
|
||||
|
||||
/**
|
||||
* Handles [UserMessageEvent] and their sync events. For [GroupMessageEvent], see [GroupMessageProcessor]
|
||||
*
|
||||
* @see StrangerMessageEvent
|
||||
* @see StrangerMessageSyncEvent
|
||||
*
|
||||
* @see FriendMessageEvent
|
||||
* @see FriendMessageSyncEvent
|
||||
*
|
||||
* @see GroupTempMessageEvent
|
||||
* @see GroupTempMessageSyncEvent
|
||||
*/
|
||||
internal class PrivateMessageNoticeProcessor : SimpleNoticeProcessor<MsgComm.Msg>(type()) {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg) = data.context {
|
||||
if (msgHead.fromUin == bot.id && fromSync) {
|
||||
// Bot send message to himself? or from other client? I am not the implementer.
|
||||
bot.client.sendFriendMessageSeq.updateIfSmallerThan(msgHead.msgSeq)
|
||||
return
|
||||
}
|
||||
if (!bot.components[SsoProcessor].firstLoginSucceed) return
|
||||
val senderUin = if (fromSync) msgHead.toUin else msgHead.fromUin
|
||||
when (msgHead.msgType) {
|
||||
166, 167, // 单向好友
|
||||
208, // friend ptt, maybe also support stranger
|
||||
-> {
|
||||
handlePrivateMessage(data, bot.getFriend(senderUin) ?: bot.getStranger(senderUin) ?: return)
|
||||
markAsConsumed()
|
||||
}
|
||||
|
||||
141, // group temp
|
||||
-> {
|
||||
val tmpHead = msgHead.c2cTmpMsgHead ?: return
|
||||
val group = bot.getGroupByUin(tmpHead.groupUin) ?: return
|
||||
handlePrivateMessage(data, group[senderUin] ?: return)
|
||||
markAsConsumed()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private suspend fun PipelineContext.handlePrivateMessage(
|
||||
data: MsgComm.Msg,
|
||||
user: User,
|
||||
) = data.context {
|
||||
user.impl()
|
||||
if (!user.messageSeq.updateIfDifferentWith(msgHead.msgSeq)) return
|
||||
if (contentHead?.autoReply == 1) return
|
||||
|
||||
val msgs = user.fragmentedMessageMerger.tryMerge(this)
|
||||
if (msgs.isEmpty()) return
|
||||
|
||||
val chain = msgs.toMessageChainOnline(bot, 0, user.correspondingMessageSourceKind)
|
||||
val time = msgHead.msgTime
|
||||
|
||||
collected += if (fromSync) {
|
||||
when (user) {
|
||||
is FriendImpl -> FriendMessageSyncEvent(user, chain, time)
|
||||
is StrangerImpl -> StrangerMessageSyncEvent(user, chain, time)
|
||||
is NormalMemberImpl -> GroupTempMessageSyncEvent(user, chain, time)
|
||||
else -> null
|
||||
}
|
||||
} else {
|
||||
when (user) {
|
||||
is FriendImpl -> FriendMessageEvent(user, chain, time)
|
||||
is StrangerImpl -> StrangerMessageEvent(user, chain, time)
|
||||
is NormalMemberImpl -> GroupTempMessageEvent(user, chain, time)
|
||||
else -> null
|
||||
}
|
||||
} ?: error("unreachable")
|
||||
}
|
||||
}
|
@ -10,39 +10,24 @@
|
||||
package net.mamoe.mirai.internal.network.notice
|
||||
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUByte
|
||||
import kotlinx.io.core.readUShort
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
import net.mamoe.mirai.internal.contact.info.StrangerInfoImpl
|
||||
import net.mamoe.mirai.internal.getGroupByUin
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceFromFriendImpl
|
||||
import net.mamoe.mirai.internal.message.toMessageChainOnline
|
||||
import net.mamoe.mirai.internal.network.components.ContactUpdater
|
||||
import net.mamoe.mirai.internal.network.components.MsgCommonMsgProcessor
|
||||
import net.mamoe.mirai.internal.network.components.PipelineContext
|
||||
import net.mamoe.mirai.internal.network.components.SsoProcessor
|
||||
import net.mamoe.mirai.internal.network.handler.logger
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.FrdSysMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.SubMsgType0x7
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.PlainText
|
||||
import net.mamoe.mirai.message.data.buildMessageChain
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.TypeKey
|
||||
import net.mamoe.mirai.utils.debug
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
|
||||
internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProcessorContext {
|
||||
internal class SystemMessageProcessor : MsgCommonMsgProcessor(), NewContactSupport {
|
||||
companion object {
|
||||
val KEY_FROM_SYNC = TypeKey<Boolean>("fromSync")
|
||||
val PipelineContext.fromSync get() = attributes[KEY_FROM_SYNC]
|
||||
}
|
||||
|
||||
override suspend fun PipelineContext.process0(data: MsgComm.Msg): Unit = data.run {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgComm.Msg): Unit = data.run {
|
||||
// TODO: 2021/6/26 extract logic into multiple processors
|
||||
when (msgHead.msgType) {
|
||||
33 -> bot.components[ContactUpdater].groupListModifyLock.withLock {
|
||||
@ -53,19 +38,11 @@ internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProce
|
||||
}
|
||||
|
||||
38 -> bot.components[ContactUpdater].groupListModifyLock.withLock { // 建群
|
||||
bot.createGroupForBot(msgHead.fromUin)
|
||||
?.let { collect(BotJoinGroupEvent.Active(it)) }
|
||||
return
|
||||
TODO("removed")
|
||||
}
|
||||
|
||||
85 -> bot.components[ContactUpdater].groupListModifyLock.withLock { // 其他客户端入群
|
||||
// msgHead.authUin: 处理人
|
||||
|
||||
if (msgHead.toUin == bot.id) {
|
||||
bot.createGroupForBot(msgHead.fromUin)
|
||||
?.let { collect(BotJoinGroupEvent.Active(it)) }
|
||||
}
|
||||
return
|
||||
TODO("removed")
|
||||
}
|
||||
|
||||
/*
|
||||
@ -116,92 +93,11 @@ internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProce
|
||||
|
||||
//167 单向好友
|
||||
166, 167 -> {
|
||||
//我也不知道为什么要这样写,但它就是能跑
|
||||
if (msgHead.fromUin == bot.id && fromSync) {
|
||||
loop@ while (true) {
|
||||
val instance = bot.client.getFriendSeq()
|
||||
if (instance < msgHead.msgSeq) {
|
||||
if (bot.client.setFriendSeq(instance, msgHead.msgSeq)) {
|
||||
break@loop
|
||||
}
|
||||
} else break@loop
|
||||
}
|
||||
return
|
||||
}
|
||||
if (!bot.components[SsoProcessor].firstLoginSucceed) {
|
||||
return
|
||||
}
|
||||
val fromUin = if (fromSync) {
|
||||
msgHead.toUin
|
||||
} else {
|
||||
msgHead.fromUin
|
||||
}
|
||||
bot.getFriend(fromUin)?.let { friend ->
|
||||
friend.checkIsFriendImpl()
|
||||
friend.lastMessageSequence.loop {
|
||||
//我也不知道为什么要这样写,但它就是能跑
|
||||
if (friend.lastMessageSequence.value != msgHead.msgSeq
|
||||
&& friend.lastMessageSequence.compareAndSet(it, msgHead.msgSeq)
|
||||
&& contentHead?.autoReply != 1
|
||||
) {
|
||||
val msgs = friend.friendPkgMsgParsingCache.tryMerge(this)
|
||||
if (msgs.isNotEmpty()) {
|
||||
collect(
|
||||
if (fromSync) {
|
||||
FriendMessageSyncEvent(
|
||||
friend,
|
||||
msgs.toMessageChainOnline(bot, 0, MessageSourceKind.FRIEND),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else {
|
||||
FriendMessageEvent(
|
||||
friend,
|
||||
msgs.toMessageChainOnline(bot, 0, MessageSourceKind.FRIEND),
|
||||
msgHead.msgTime
|
||||
)
|
||||
}
|
||||
)
|
||||
} else return
|
||||
}
|
||||
return
|
||||
}
|
||||
} ?: bot.getStranger(fromUin)?.let { stranger ->
|
||||
stranger.checkIsImpl()
|
||||
stranger.lastMessageSequence.loop {
|
||||
//我也不知道为什么要这样写,但它就是能跑
|
||||
if (stranger.lastMessageSequence.value != msgHead.msgSeq && stranger.lastMessageSequence.compareAndSet(
|
||||
it,
|
||||
msgHead.msgSeq
|
||||
) && contentHead?.autoReply != 1
|
||||
) {
|
||||
collect(
|
||||
if (fromSync) {
|
||||
StrangerMessageSyncEvent(
|
||||
stranger,
|
||||
listOf(this).toMessageChainOnline(bot, 0, MessageSourceKind.STRANGER),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else {
|
||||
StrangerMessageEvent(
|
||||
stranger,
|
||||
listOf(this).toMessageChainOnline(bot, 0, MessageSourceKind.STRANGER),
|
||||
msgHead.msgTime
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
TODO("removed")
|
||||
}
|
||||
208 -> {
|
||||
// friend ptt
|
||||
val target = bot.getFriend(msgHead.fromUin) ?: return
|
||||
val lsc = listOf(this).toMessageChainOnline(bot, 0, MessageSourceKind.FRIEND)
|
||||
|
||||
collect(FriendMessageEvent(target, lsc, msgHead.msgTime))
|
||||
return
|
||||
TODO("removed")
|
||||
}
|
||||
529 -> {
|
||||
|
||||
@ -210,30 +106,7 @@ internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProce
|
||||
when (msgHead.c2cCmd) {
|
||||
// other client sync
|
||||
7 -> {
|
||||
val body = msgBody.msgContent.loadAs(SubMsgType0x7.MsgBody.serializer())
|
||||
|
||||
val textMsg =
|
||||
body.msgSubcmd0x4Generic?.buf?.loadAs(SubMsgType0x7.MsgBody.QQDataTextMsg.serializer())
|
||||
?: return
|
||||
|
||||
with(body.msgHeader ?: return) {
|
||||
if (dstUin != bot.id) return
|
||||
val client = bot.otherClients.find { it.appId == srcInstId }
|
||||
?: return// don't compare with dstAppId. diff.
|
||||
|
||||
val chain = buildMessageChain {
|
||||
+OnlineMessageSourceFromFriendImpl(bot, listOf(data))
|
||||
for (msgItem in textMsg.msgItems) {
|
||||
when (msgItem.type) {
|
||||
1 -> +PlainText(msgItem.text)
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collect(OtherClientMessageEvent(client, chain, msgHead.msgTime))
|
||||
}
|
||||
TODO("removed")
|
||||
}
|
||||
}
|
||||
|
||||
@ -245,39 +118,7 @@ internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProce
|
||||
if (!bot.components[SsoProcessor].firstLoginSucceed || msgHead.fromUin == bot.id && !fromSync) {
|
||||
return
|
||||
}
|
||||
val tmpHead = msgHead.c2cTmpMsgHead ?: return
|
||||
val member = bot.getGroupByUin(tmpHead.groupUin)?.get(
|
||||
if (fromSync) {
|
||||
msgHead.toUin
|
||||
} else {
|
||||
msgHead.fromUin
|
||||
}
|
||||
)
|
||||
?: return
|
||||
|
||||
member.checkIsMemberImpl()
|
||||
|
||||
member.lastMessageSequence.loop { instant ->
|
||||
if (member.lastMessageSequence.value != msgHead.msgSeq && contentHead?.autoReply != 1) {
|
||||
if (member.lastMessageSequence.compareAndSet(instant, msgHead.msgSeq)) {
|
||||
collect(
|
||||
if (fromSync) {
|
||||
GroupTempMessageSyncEvent(
|
||||
member,
|
||||
listOf(this).toMessageChainOnline(bot, 0, MessageSourceKind.TEMP),
|
||||
msgHead.msgTime
|
||||
)
|
||||
} else {
|
||||
GroupTempMessageEvent(
|
||||
member,
|
||||
listOf(this).toMessageChainOnline(bot, 0, MessageSourceKind.TEMP),
|
||||
msgHead.msgTime
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
} else return
|
||||
}
|
||||
TODO("removed")
|
||||
}
|
||||
84, 87 -> { // 请求入群验证 和 被要求入群
|
||||
bot.network.run {
|
||||
@ -298,45 +139,7 @@ internal class SystemMessageProcessor : MsgCommonMsgProcessor(), GroupEventProce
|
||||
}
|
||||
//陌生人添加信息
|
||||
191 -> {
|
||||
var fromGroup = 0L
|
||||
var pbNick = ""
|
||||
msgBody.msgContent.read {
|
||||
readUByte()// version
|
||||
discardExact(readUByte().toInt())//skip
|
||||
readUShort()//source id
|
||||
readUShort()//SourceSubID
|
||||
discardExact(readUShort().toLong())//skip size
|
||||
if (readUShort().toInt() != 0) {//hasExtraInfo
|
||||
discardExact(readUShort().toInt())//mail address info, skip
|
||||
}
|
||||
discardExact(4 + readUShort().toInt())//skip
|
||||
for (i in 1..readUByte().toInt()) {//pb size
|
||||
val type = readUShort().toInt()
|
||||
val pbArray = ByteArray(readUShort().toInt() and 0xFF)
|
||||
readAvailable(pbArray)
|
||||
when (type) {
|
||||
1000 -> pbArray.loadAs(FrdSysMsg.GroupInfo.serializer()).let { fromGroup = it.groupUin }
|
||||
1002 -> pbArray.loadAs(FrdSysMsg.FriendMiscInfo.serializer())
|
||||
.let { pbNick = it.fromuinNick }
|
||||
else -> {
|
||||
}//ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
val nick =
|
||||
sequenceOf(msgHead.fromNick, msgHead.authNick, pbNick).filter { it.isNotEmpty() }.firstOrNull()
|
||||
?: return
|
||||
val id =
|
||||
sequenceOf(msgHead.fromUin, msgHead.authUin).filter { it != 0L }.firstOrNull() ?: return//对方QQ
|
||||
Mirai.newStranger(bot, StrangerInfoImpl(id, nick, fromGroup)).checkIsImpl().let {
|
||||
bot.getStranger(id)?.let { previous ->
|
||||
bot.strangers.remove(id)
|
||||
StrangerRelationChangeEvent.Deleted(previous).broadcast()
|
||||
}
|
||||
bot.strangers.delegate.add(it)
|
||||
|
||||
collect(StrangerAddEvent(it))
|
||||
}
|
||||
TODO("removed")
|
||||
}
|
||||
// 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
|
||||
// 732: 27 0B 60 E7 11 00 40 08 07 20 E7 C1 AD B8 02 5A 36 08 B4 E7 E0 F0 09 1A 1A 08 9C D4 16 10 F7 D2 D8 F5 05 18 D0 E2 85 F4 06 20 00 28 00 30 B4 E7 E0 F0 09 2A 0E 08 00 12 0A 08 9C D4 16 10 00 18 01 20 00 30 00 38 00
|
||||
|
@ -30,7 +30,7 @@ import net.mamoe.mirai.utils.toUHexString
|
||||
internal class MsgInfoDecoder(
|
||||
private val logger: MiraiLogger,
|
||||
) : SimpleNoticeProcessor<MsgInfo>(type()) {
|
||||
override suspend fun PipelineContext.process0(data: MsgInfo) {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgInfo) {
|
||||
when (data.shMsgType.toUShort().toInt()) {
|
||||
// 528
|
||||
0x210 -> fire(data.vMsg.loadAs(MsgType0x210.serializer()))
|
||||
|
@ -14,7 +14,7 @@ import net.mamoe.mirai.internal.network.components.SimpleNoticeProcessor
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
|
||||
internal class MsgType0x210Decoder : SimpleNoticeProcessor<MsgType0x210>(type()) {
|
||||
override suspend fun PipelineContext.process0(data: MsgType0x210) {
|
||||
override suspend fun PipelineContext.processImpl(data: MsgType0x210) {
|
||||
when (data.uSubMsgType) {
|
||||
0x8AL -> {
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||
|
||||
@ -25,6 +26,5 @@ internal class RequestPushStatus(
|
||||
@JvmField @TarsId(6) val nClientType: Long? = null,
|
||||
@JvmField @TarsId(7) val nInstanceId: Long? = null,
|
||||
@JvmField @TarsId(8) val vecInstanceList: List<InstanceInfo>? = null,
|
||||
) : JceStruct
|
||||
|
||||
) : JceStruct, Packet
|
||||
|
||||
|
@ -952,7 +952,7 @@ internal class Submsgtype0x27 {
|
||||
@Serializable
|
||||
internal class ProfileInfo(
|
||||
@ProtoNumber(1) @JvmField val field: Int = 0,
|
||||
@ProtoNumber(2) @JvmField val value: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(2) @JvmField val value: String = "",
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
|
@ -13,6 +13,7 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.components.NoticeProcessorPipeline.Companion.noticeProcessorPipeline
|
||||
import net.mamoe.mirai.internal.network.components.PacketCodec
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
@ -27,7 +28,9 @@ import net.mamoe.mirai.internal.network.protocol.packet.login.Heartbeat
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.login.WtLogin
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.summarycard.SummaryCard
|
||||
import net.mamoe.mirai.internal.network.toPacket
|
||||
import net.mamoe.mirai.utils.MiraiLoggerWithSwitch
|
||||
import net.mamoe.mirai.utils.TypeSafeMap
|
||||
|
||||
internal sealed class PacketFactory<TPacket : Packet?> {
|
||||
/**
|
||||
@ -36,6 +39,17 @@ internal sealed class PacketFactory<TPacket : Packet?> {
|
||||
abstract val receivingCommandName: String
|
||||
|
||||
open val canBeCached: Boolean get() = true
|
||||
|
||||
protected companion object {
|
||||
|
||||
@JvmStatic
|
||||
suspend fun QQAndroidBot.processPacketThroughPipeline(
|
||||
data: Any?,
|
||||
attributes: TypeSafeMap = TypeSafeMap(),
|
||||
): Packet {
|
||||
return components.noticeProcessorPipeline.process(this, data, attributes).toPacket()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -264,7 +264,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
sequenceIds = sequenceIds,
|
||||
randIds = randIds,
|
||||
sequenceIdsInitializer = { size ->
|
||||
IntArray(size) { client.nextFriendSeq() }
|
||||
IntArray(size) { client.sendFriendMessageSeq.next() }
|
||||
},
|
||||
postInit = {
|
||||
sourceCallback(
|
||||
@ -278,7 +278,7 @@ internal object MessageSvcPbSendMsg : OutgoingPacketFactory<MessageSvcPbSendMsg.
|
||||
)
|
||||
)
|
||||
},
|
||||
doFragmented = fragmented
|
||||
doFragmented = fragmented,
|
||||
)
|
||||
}
|
||||
/*= buildOutgoingUniPacket(client) {
|
||||
|
@ -9,84 +9,18 @@
|
||||
|
||||
package net.mamoe.mirai.internal.network.protocol.packet.chat.receive
|
||||
|
||||
import kotlinx.coroutines.CancellationException
|
||||
import kotlinx.coroutines.cancel
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.ClientKind
|
||||
import net.mamoe.mirai.contact.OtherClientInfo
|
||||
import net.mamoe.mirai.contact.Platform
|
||||
import net.mamoe.mirai.event.events.OtherClientOfflineEvent
|
||||
import net.mamoe.mirai.event.events.OtherClientOnlineEvent
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.appId
|
||||
import net.mamoe.mirai.internal.contact.createOtherClient
|
||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.components.ContactUpdater
|
||||
import net.mamoe.mirai.internal.network.handler.logger
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPushStatus
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
|
||||
|
||||
internal object MessageSvcRequestPushStatus : IncomingPacketFactory<Packet?>(
|
||||
"MessageSvc.RequestPushStatus", ""
|
||||
internal object MessageSvcRequestPushStatus : IncomingPacketFactory<Packet>(
|
||||
"MessageSvc.RequestPushStatus", "",
|
||||
) {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet? {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet {
|
||||
val packet = readUniPacket(RequestPushStatus.serializer())
|
||||
bot.components[ContactUpdater].otherClientsLock.withLock {
|
||||
val instanceInfo = packet.vecInstanceList?.firstOrNull()
|
||||
val appId = instanceInfo?.iAppId ?: 1
|
||||
return when (packet.status.toInt()) {
|
||||
1 -> { // online
|
||||
if (bot.otherClients.any { appId == it.appId }) return null
|
||||
|
||||
suspend fun tryFindInQuery(): OtherClientInfo? {
|
||||
return Mirai.getOnlineOtherClientsList(bot).find { it.appId == appId }
|
||||
?: kotlin.run {
|
||||
delay(2000) // sometimes server sync slow
|
||||
Mirai.getOnlineOtherClientsList(bot).find { it.appId == appId }
|
||||
}
|
||||
}
|
||||
|
||||
val info =
|
||||
tryFindInQuery() ?: kotlin.run {
|
||||
bot.network.logger.warning(
|
||||
contextualBugReportException(
|
||||
"SvcRequestPushStatus (OtherClient online)",
|
||||
"packet: \n" + packet._miraiContentToString() +
|
||||
"\n\nquery: \n" +
|
||||
Mirai.getOnlineOtherClientsList(bot)._miraiContentToString(),
|
||||
additional = "Failed to find corresponding instanceInfo."
|
||||
)
|
||||
)
|
||||
OtherClientInfo(appId, Platform.WINDOWS, "", "电脑")
|
||||
}
|
||||
|
||||
val client = bot.createOtherClient(info)
|
||||
bot.otherClients.delegate.add(client)
|
||||
OtherClientOnlineEvent(
|
||||
client,
|
||||
ClientKind[packet.nClientType?.toInt() ?: 0]
|
||||
)
|
||||
}
|
||||
|
||||
2 -> { // off
|
||||
val client = bot.otherClients.find { it.appId == appId } ?: return null
|
||||
client.cancel(CancellationException("Offline"))
|
||||
bot.otherClients.delegate.remove(client)
|
||||
OtherClientOfflineEvent(client)
|
||||
}
|
||||
|
||||
else -> throw contextualBugReportException(
|
||||
"decode SvcRequestPushStatus (PC Client status change)",
|
||||
packet._miraiContentToString(),
|
||||
additional = "unknown status=${packet.status}"
|
||||
)
|
||||
}
|
||||
}
|
||||
return bot.processPacketThroughPipeline(packet)
|
||||
}
|
||||
}
|
@ -17,15 +17,15 @@ package net.mamoe.mirai.internal.network.protocol.packet.chat.receive
|
||||
import kotlinx.io.core.*
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.Mirai
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.NormalMember
|
||||
import net.mamoe.mirai.contact.User
|
||||
import net.mamoe.mirai.data.GroupHonorType
|
||||
import net.mamoe.mirai.event.events.*
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.contact.*
|
||||
import net.mamoe.mirai.internal.contact.info.FriendInfoImpl
|
||||
import net.mamoe.mirai.internal.contact.GroupImpl
|
||||
import net.mamoe.mirai.internal.contact.checkIsGroupImpl
|
||||
import net.mamoe.mirai.internal.contact.checkIsMemberImpl
|
||||
import net.mamoe.mirai.internal.network.MultiPacketImpl
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
@ -34,17 +34,12 @@ import net.mamoe.mirai.internal.network.protocol.data.jce.MsgInfo
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.MsgType0x210
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.OnlinePushPack
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x115
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x122
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x27.SubMsgType0x27.*
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0x44.Submsgtype0x44
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Submsgtype0xb3
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.TroopTips0x857
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildResponseUniPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.sendAndExpect
|
||||
import net.mamoe.mirai.internal.utils._miraiContentToString
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.*
|
||||
@ -538,20 +533,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
0x111L to ignoredLambda528,
|
||||
// 新好友
|
||||
0xB3L to lambda528 { bot ->
|
||||
// 08 01 12 52 08 A2 FF 8C F0 03 10 00 1D 15 3D 90 5E 22 2E E6 88 91 E4 BB AC E5 B7 B2 E7 BB 8F E6 98 AF E5 A5 BD E5 8F 8B E5 95 A6 EF BC 8C E4 B8 80 E8 B5 B7 E6 9D A5 E8 81 8A E5 A4 A9 E5 90 A7 21 2A 09 48 69 6D 31 38 38 6D 6F 65 30 07 38 03 48 DD F1 92 B7 07
|
||||
val body = vProtobuf.loadAs(Submsgtype0xb3.SubMsgType0xb3.MsgBody.serializer())
|
||||
val new = Mirai.newFriend(
|
||||
bot, FriendInfoImpl(
|
||||
uin = body.msgAddFrdNotify.fuin,
|
||||
nick = body.msgAddFrdNotify.fuinNick,
|
||||
remark = "",
|
||||
)
|
||||
).checkIsFriendImpl()
|
||||
bot.friends.delegate.add(new)
|
||||
return@lambda528 bot.getStranger(new.id)?.let {
|
||||
bot.strangers.remove(new.id)
|
||||
sequenceOf(StrangerRelationChangeEvent.Friended(it, new), FriendAddEvent(new))
|
||||
} ?: sequenceOf(FriendAddEvent(new))
|
||||
TODO("removed")
|
||||
},
|
||||
0xE2L to lambda528 { _ ->
|
||||
// TODO: unknown. maybe messages.
|
||||
@ -561,35 +543,7 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
return@lambda528 emptySequence()
|
||||
},
|
||||
0x44L to lambda528 { bot ->
|
||||
val msg = vProtobuf.loadAs(Submsgtype0x44.MsgBody.serializer())
|
||||
|
||||
val packetList = mutableListOf<Packet>()
|
||||
if (msg.msgFriendMsgSync != null) {
|
||||
when (msg.msgFriendMsgSync.processtype) {
|
||||
3, 9, 10 -> {
|
||||
if (bot.getFriend(msg.msgFriendMsgSync.fuin) == null) {
|
||||
val response: FriendList.GetFriendGroupList.Response =
|
||||
FriendList.GetFriendGroupList.forSingleFriend(
|
||||
bot.client,
|
||||
msg.msgFriendMsgSync.fuin
|
||||
).sendAndExpect(bot)
|
||||
response.friendList.firstOrNull()?.let {
|
||||
val friend = Mirai.newFriend(bot, it.toMiraiFriendInfo()).checkIsFriendImpl()
|
||||
bot.friends.delegate.add(friend)
|
||||
packetList.add(FriendAddEvent(friend))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msg.msgGroupMsgSync != null) {
|
||||
when (msg.msgGroupMsgSync.msgType) {
|
||||
1, 2 -> {
|
||||
TODO("removed")
|
||||
}
|
||||
}
|
||||
}
|
||||
return@lambda528 packetList.asSequence()
|
||||
TODO("removed")
|
||||
},
|
||||
// bot 在其他客户端被踢或主动退出而同步情况
|
||||
0xD4L to lambda528 { _ ->
|
||||
@ -666,39 +620,10 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
},
|
||||
//好友输入状态
|
||||
0x115L to lambda528 { bot ->
|
||||
val body = vProtobuf.loadAs(Submsgtype0x115.SubMsgType0x115.MsgBody.serializer())
|
||||
val friend = bot.getFriend(body.fromUin)
|
||||
val item = body.msgNotifyItem
|
||||
return@lambda528 if (friend != null && item != null) {
|
||||
sequenceOf(FriendInputStatusChangedEvent(friend, item.eventType == 1))
|
||||
} else {
|
||||
emptySequence()
|
||||
}
|
||||
TODO("removed")
|
||||
},
|
||||
// 群相关, ModFriendRemark, DelFriend, ModGroupProfile
|
||||
0x27L to lambda528 { bot ->
|
||||
fun ModFriendRemark.transform(bot: QQAndroidBot): Sequence<Packet> {
|
||||
return this.msgFrdRmk.asSequence().mapNotNull {
|
||||
val friend = bot.getFriend(it.fuin) ?: return@mapNotNull null
|
||||
val old: String
|
||||
friend.checkIsFriendImpl().friendInfo
|
||||
.also { info -> old = info.remark }
|
||||
.remark = it.rmkName
|
||||
// TODO: 2020/4/10 ADD REMARK QUERY
|
||||
FriendRemarkChangeEvent(friend, old, it.rmkName)
|
||||
}
|
||||
}
|
||||
|
||||
fun DelFriend.transform(bot: QQAndroidBot): Sequence<Packet> {
|
||||
return this.uint64Uins.asSequence().mapNotNull {
|
||||
|
||||
val friend = bot.getFriend(it) ?: return@mapNotNull null
|
||||
if (bot.friends.delegate.remove(friend)) {
|
||||
FriendDeleteEvent(friend)
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
fun ModGroupProfile.transform(bot: QQAndroidBot): Sequence<Packet> {
|
||||
return this.msgGroupProfileInfos.asSequence().mapNotNull { info ->
|
||||
when (info.field) {
|
||||
@ -729,23 +654,23 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
var85.troopface = var3;
|
||||
var85.hasSetNewTroopHead = true;
|
||||
*/
|
||||
// bot.logger.debug(
|
||||
// contextualBugReportException(
|
||||
// "解析 Transformers528 0x27L ModGroupProfile 群头像修改",
|
||||
// forDebug = "this=${this._miraiContentToString()}"
|
||||
// )
|
||||
// )
|
||||
// bot.logger.debug(
|
||||
// contextualBugReportException(
|
||||
// "解析 Transformers528 0x27L ModGroupProfile 群头像修改",
|
||||
// forDebug = "this=${this._miraiContentToString()}"
|
||||
// )
|
||||
// )
|
||||
null
|
||||
}
|
||||
3 -> { // troop.credit.data
|
||||
// top_package/akkz.java:3475
|
||||
// top_package/akkz.java:3498
|
||||
// bot.logger.debug(
|
||||
// contextualBugReportException(
|
||||
// "解析 Transformers528 0x27L ModGroupProfile 群 troop.credit.data",
|
||||
// forDebug = "this=${this._miraiContentToString()}"
|
||||
// )
|
||||
// )
|
||||
// bot.logger.debug(
|
||||
// contextualBugReportException(
|
||||
// "解析 Transformers528 0x27L ModGroupProfile 群 troop.credit.data",
|
||||
// forDebug = "this=${this._miraiContentToString()}"
|
||||
// )
|
||||
// )
|
||||
null
|
||||
}
|
||||
|
||||
@ -789,64 +714,15 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
}
|
||||
}
|
||||
|
||||
fun ModCustomFace.transform(bot: QQAndroidBot): Sequence<Packet> {
|
||||
if (uin == bot.id) {
|
||||
return sequenceOf(BotAvatarChangedEvent(bot))
|
||||
}
|
||||
val friend = bot.getFriend(uin) ?: return emptySequence()
|
||||
return sequenceOf(FriendAvatarChangedEvent(friend))
|
||||
}
|
||||
|
||||
fun ModProfile.transform(bot: QQAndroidBot): Sequence<Packet> = buildList<Packet> {
|
||||
var containsUnknown = false
|
||||
msgProfileInfos.forEach { modified ->
|
||||
when (modified.field) {
|
||||
20002 -> { // 昵称修改
|
||||
val value = modified.value
|
||||
val to = value.encodeToString()
|
||||
if (uin == bot.id) {
|
||||
val from = bot.nick
|
||||
if (from != to) {
|
||||
bot.nick = to
|
||||
bot.asFriend.checkIsFriendImpl().nick = to
|
||||
add(BotNickChangedEvent(bot, from, to))
|
||||
}
|
||||
} else {
|
||||
val friend = (bot.getFriend(uin) ?: return@forEach) as FriendImpl
|
||||
val info = friend.friendInfo
|
||||
val from = info.nick
|
||||
when (info) {
|
||||
is FriendInfoImpl -> info.nick = to
|
||||
else -> {
|
||||
bot.network.logger.debug {
|
||||
"Unknown how to update nick for $info"
|
||||
}
|
||||
}
|
||||
}
|
||||
add(FriendNickChangedEvent(friend, from, to))
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
containsUnknown = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if (msgProfileInfos.isEmpty() || containsUnknown) {
|
||||
bot.network.logger.debug {
|
||||
"Transformers528 0x27L: new data: ${_miraiContentToString()}"
|
||||
}
|
||||
}
|
||||
}.asSequence()
|
||||
|
||||
return@lambda528 vProtobuf.loadAs(SubMsgType0x27MsgBody.serializer()).msgModInfos.asSequence()
|
||||
.flatMap {
|
||||
when {
|
||||
it.msgModFriendRemark != null -> it.msgModFriendRemark.transform(bot)
|
||||
it.msgDelFriend != null -> it.msgDelFriend.transform(bot)
|
||||
it.msgModFriendRemark != null -> TODO("removed")
|
||||
it.msgDelFriend != null -> TODO("removed")
|
||||
it.msgModGroupProfile != null -> it.msgModGroupProfile.transform(bot)
|
||||
it.msgModGroupMemberProfile != null -> it.msgModGroupMemberProfile.transform(bot)
|
||||
it.msgModCustomFace != null -> it.msgModCustomFace.transform(bot)
|
||||
it.msgModProfile != null -> it.msgModProfile.transform(bot)
|
||||
it.msgModCustomFace != null -> TODO("removed")
|
||||
it.msgModProfile != null -> TODO("removed")
|
||||
else -> {
|
||||
bot.network.logger.debug {
|
||||
"Transformers528 0x27L: new data: ${it._miraiContentToString()}"
|
||||
@ -856,5 +732,5 @@ internal object Transformers528 : Map<Long, Lambda528> by mapOf(
|
||||
}
|
||||
}
|
||||
// 0A 1C 10 28 4A 18 0A 16 08 00 10 A2 FF 8C F0 03 1A 0C E6 BD 9C E6 B1 9F E7 BE A4 E5 8F 8B
|
||||
}
|
||||
},
|
||||
)
|
||||
|
78
mirai-core/src/commonMain/kotlin/utils/AtomicIntSeq.kt
Normal file
78
mirai-core/src/commonMain/kotlin/utils/AtomicIntSeq.kt
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2019-2021 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.internal.utils
|
||||
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.atomicfu.update
|
||||
import net.mamoe.mirai.utils.getRandomUnsignedInt
|
||||
import net.mamoe.mirai.utils.toLongUnsigned
|
||||
|
||||
// We probably can reduce duplicates by using value classes, but atomicFU compiler might not be able to compile it.
|
||||
|
||||
// TODO: 2021/6/27 tests
|
||||
internal class AtomicIntSeq private constructor(
|
||||
initial: Int,
|
||||
private val maxExclusive: Int,
|
||||
) {
|
||||
private val value = atomic(initial)
|
||||
|
||||
/**
|
||||
* Increment [value] within the range from 0 (inclusive) to [maxExclusive] (exclusive).
|
||||
*/
|
||||
fun next(): Int = value.incrementAndGet().mod(maxExclusive) // positive
|
||||
|
||||
/**
|
||||
* Atomically update [value] if it is smaller than [new].
|
||||
*/
|
||||
fun updateIfSmallerThan(new: Int): Boolean {
|
||||
value.update { instant ->
|
||||
if (instant < new) new else return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun updateIfDifferentWith(new: Int): Boolean {
|
||||
value.update { instant ->
|
||||
if (instant == new) return false
|
||||
new
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun forMessageSeq() = AtomicIntSeq(0, Int.MAX_VALUE)
|
||||
|
||||
@JvmStatic
|
||||
fun forPrivateSync() = AtomicIntSeq(getRandomUnsignedInt(), 65535)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: 2021/6/27 tests
|
||||
internal class AtomicLongSeq(
|
||||
initial: Long = getRandomUnsignedInt().toLongUnsigned(),
|
||||
private val maxExclusive: Long = 65535,
|
||||
) {
|
||||
private val value = atomic(initial)
|
||||
|
||||
/**
|
||||
* Increment [value] within the range from 0 (inclusive) to [maxExclusive] (exclusive).
|
||||
*/
|
||||
fun next(): Long = value.incrementAndGet().mod(maxExclusive) // positive
|
||||
|
||||
/**
|
||||
* Atomically update [value] if it is smaller than [new].
|
||||
*/
|
||||
fun updateIfSmallerThan(new: Long) {
|
||||
value.update { instant ->
|
||||
if (instant < new) new else return
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user