Commit 745cb748 authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

parents 7d1a6ef8 592d328e
...@@ -308,10 +308,10 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo ...@@ -308,10 +308,10 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
input: JceInput input: JceInput
) : JceDecoder(input) { ) : JceDecoder(input) {
override fun endStructure(desc: SerialDescriptor) { override fun endStructure(desc: SerialDescriptor) {
while (input.peakHead().type != STRUCT_END) { while (input.input.canRead() && input.peakHeadOrNull()?.type != STRUCT_END) {
input.readHead() input.readHeadOrNull() ?: return
} }
input.readHead() input.readHeadOrNull()
} }
} }
...@@ -513,6 +513,9 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo ...@@ -513,6 +513,9 @@ class Jce private constructor(private val charset: JceCharset, context: SerialMo
@PublishedApi @PublishedApi
internal fun peakHead(): JceHead = input.makeView().readHead() ?: error("no enough data to read head") internal fun peakHead(): JceHead = input.makeView().readHead() ?: error("no enough data to read head")
@PublishedApi
internal fun peakHeadOrNull(): JceHead? = input.makeView().readHead()
@Suppress("NOTHING_TO_INLINE") // 避免 stacktrace 出现两个 readHead @Suppress("NOTHING_TO_INLINE") // 避免 stacktrace 出现两个 readHead
private inline fun IoBuffer.readHead(): JceHead? { private inline fun IoBuffer.readHead(): JceHead? {
if (endOfInput) return null if (endOfInput) return null
......
...@@ -334,7 +334,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -334,7 +334,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
val handler = PacketListener(commandName = commandName, sequenceId = sequenceId) val handler = PacketListener(commandName = commandName, sequenceId = sequenceId)
packetListeners.addLast(handler) packetListeners.addLast(handler)
bot.logger.info("Send: ${this.commandName}")
var lastException: Exception? = null var lastException: Exception? = null
repeat(retry + 1) { repeat(retry + 1) {
try { try {
...@@ -343,18 +342,19 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -343,18 +342,19 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
lastException = e lastException = e
} }
} }
packetListeners.remove(handler)
throw lastException!! throw lastException!!
} }
private suspend inline fun <E : Packet> OutgoingPacket.doSendAndReceive(timeoutMillis: Long = 3000, handler: PacketListener): E { private suspend inline fun <E : Packet> OutgoingPacket.doSendAndReceive(timeoutMillis: Long = 3000, handler: PacketListener): E {
channel.send(delegate) channel.send(delegate)
bot.logger.info("Send: ${this.commandName}")
return withTimeoutOrNull(timeoutMillis) { return withTimeoutOrNull(timeoutMillis) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
handler.await() as E handler.await() as E
// 不要 `withTimeout`. timeout 的异常会不知道去哪了. // 不要 `withTimeout`. timeout 的异常会不知道去哪了.
} ?: net.mamoe.mirai.qqandroid.utils.inline { } ?: net.mamoe.mirai.qqandroid.utils.inline {
packetListeners.remove(handler) error("timeout when receiving response of $commandName")
error("timeout when sending $commandName")
} }
} }
......
...@@ -96,6 +96,8 @@ internal open class QQAndroidClient( ...@@ -96,6 +96,8 @@ internal open class QQAndroidClient(
val apkVersionName: ByteArray = "8.2.0".toByteArray() val apkVersionName: ByteArray = "8.2.0".toByteArray()
private val messageSequenceId: AtomicInt = atomic(0)
internal fun atomicNextMessageSequenceId(): Int = messageSequenceId.getAndIncrement()
val appClientVersion: Int = 0 val appClientVersion: Int = 0
......
...@@ -25,8 +25,9 @@ internal data class RequestPushNotify( ...@@ -25,8 +25,9 @@ internal data class RequestPushNotify(
@SerialId(13) val svrip: Int? @SerialId(13) val svrip: Int?
) : JceStruct, Packet ) : JceStruct, Packet
@Suppress("ArrayInDataClass")
@Serializable @Serializable
internal class MsgInfo( internal data class MsgInfo(
@SerialId(0) val lFromUin: Long = 0L, @SerialId(0) val lFromUin: Long = 0L,
@SerialId(1) val uMsgTime: Long = 0L, @SerialId(1) val uMsgTime: Long = 0L,
@SerialId(2) val shMsgType: Short, @SerialId(2) val shMsgType: Short,
...@@ -51,7 +52,7 @@ internal class MsgInfo( ...@@ -51,7 +52,7 @@ internal class MsgInfo(
@Serializable @Serializable
class ShareData( internal class ShareData(
@SerialId(0) val pkgname: String = "", @SerialId(0) val pkgname: String = "",
@SerialId(1) val msgtail: String = "", @SerialId(1) val msgtail: String = "",
@SerialId(2) val picurl: String = "", @SerialId(2) val picurl: String = "",
...@@ -59,13 +60,13 @@ class ShareData( ...@@ -59,13 +60,13 @@ class ShareData(
) : JceStruct ) : JceStruct
@Serializable @Serializable
class TempMsgHead( internal class TempMsgHead(
@SerialId(0) val c2c_type: Int? = 0, @SerialId(0) val c2c_type: Int? = 0,
@SerialId(1) val serviceType: Int? = 0 @SerialId(1) val serviceType: Int? = 0
) : JceStruct ) : JceStruct
@Serializable @Serializable
class CPicInfo( internal class CPicInfo(
@SerialId(0) val vPath: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(0) val vPath: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(1) val vHost: ByteArray? = EMPTY_BYTE_ARRAY @SerialId(1) val vHost: ByteArray? = EMPTY_BYTE_ARRAY
) : JceStruct ) : JceStruct
\ No newline at end of file
...@@ -8,7 +8,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY ...@@ -8,7 +8,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
private val EMPTY_MAP = mapOf<String, String>() private val EMPTY_MAP = mapOf<String, String>()
@Serializable @Serializable
class RequestPacket( internal class RequestPacket(
@SerialId(1) val iVersion: Short = 3, @SerialId(1) val iVersion: Short = 3,
@SerialId(2) val cPacketType: Byte = 0, @SerialId(2) val cPacketType: Byte = 0,
@SerialId(3) val iMessageType: Int = 0, @SerialId(3) val iMessageType: Int = 0,
...@@ -22,16 +22,16 @@ class RequestPacket( ...@@ -22,16 +22,16 @@ class RequestPacket(
) : JceStruct ) : JceStruct
@Serializable @Serializable
class RequestDataVersion3( internal class RequestDataVersion3(
@SerialId(0) val map: Map<String, ByteArray> // 注意: ByteArray 不能直接放序列化的 JceStruct!! 要放类似 RequestDataStructSvcReqRegister 的 @SerialId(0) val map: Map<String, ByteArray> // 注意: ByteArray 不能直接放序列化的 JceStruct!! 要放类似 RequestDataStructSvcReqRegister 的
) : JceStruct ) : JceStruct
@Serializable @Serializable
class RequestDataVersion2( internal class RequestDataVersion2(
@SerialId(0) val map: Map<String, Map<String, ByteArray>> @SerialId(0) val map: Map<String, Map<String, ByteArray>>
) : JceStruct ) : JceStruct
@Serializable @Serializable
class RequestDataStructSvcReqRegister( internal class RequestDataStructSvcReqRegister(
@SerialId(0) val struct: SvcReqRegister @SerialId(0) val struct: SvcReqRegister
) : JceStruct ) : JceStruct
\ No newline at end of file
package net.mamoe.mirai.qqandroid.network.protocol.data.jce package net.mamoe.mirai.qqandroid.network.protocol.data.jce
import kotlinx.serialization.Polymorphic
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.io.JceStruct import net.mamoe.mirai.qqandroid.io.JceStruct
@Serializable @Serializable
class SvcReqRegister( internal class SvcReqRegister(
@SerialId(0) val lUin: Long = 0L, @SerialId(0) val lUin: Long = 0L,
@SerialId(1) val lBid: Long = 0L, @SerialId(1) val lBid: Long = 0L,
@SerialId(2) val cConnType: Byte = 0, @SerialId(2) val cConnType: Byte = 0,
......
...@@ -6,9 +6,9 @@ import net.mamoe.mirai.qqandroid.io.ProtoBuf ...@@ -6,9 +6,9 @@ import net.mamoe.mirai.qqandroid.io.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
@Serializable @Serializable
class Vec0xd50 : ProtoBuf { internal class Vec0xd50 : ProtoBuf {
@Serializable @Serializable
class ExtSnsFrdData( internal class ExtSnsFrdData(
@SerialId(1) val frdUin: Long = 0L, @SerialId(1) val frdUin: Long = 0L,
@SerialId(91001) val musicSwitch: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(91001) val musicSwitch: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(101001) val mutualmarkAlienation: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(101001) val mutualmarkAlienation: ByteArray = EMPTY_BYTE_ARRAY,
...@@ -18,7 +18,7 @@ class Vec0xd50 : ProtoBuf { ...@@ -18,7 +18,7 @@ class Vec0xd50 : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class RspBody( internal class RspBody(
@SerialId(1) val msgUpdateData: List<Vec0xd50.ExtSnsFrdData>? = null, @SerialId(1) val msgUpdateData: List<Vec0xd50.ExtSnsFrdData>? = null,
@SerialId(11) val over: Int = 0, @SerialId(11) val over: Int = 0,
@SerialId(12) val nextStart: Int = 0, @SerialId(12) val nextStart: Int = 0,
...@@ -26,7 +26,7 @@ class Vec0xd50 : ProtoBuf { ...@@ -26,7 +26,7 @@ class Vec0xd50 : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class ReqBody( internal class ReqBody(
@SerialId(1) val appid: Long = 0L, @SerialId(1) val appid: Long = 0L,
@SerialId(2) val maxPkgSize: Int = 0, @SerialId(2) val maxPkgSize: Int = 0,
@SerialId(3) val startTime: Int = 0, @SerialId(3) val startTime: Int = 0,
...@@ -41,28 +41,28 @@ class Vec0xd50 : ProtoBuf { ...@@ -41,28 +41,28 @@ class Vec0xd50 : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class KSingRelationInfo( internal class KSingRelationInfo(
@SerialId(1) val flag: Int = 0 @SerialId(1) val flag: Int = 0
) : ProtoBuf ) : ProtoBuf
} }
@Serializable @Serializable
class Vec0xd6b : ProtoBuf { internal class Vec0xd6b : ProtoBuf {
@Serializable @Serializable
class ReqBody( internal class ReqBody(
@SerialId(1) val maxPkgSize: Int = 0, @SerialId(1) val maxPkgSize: Int = 0,
@SerialId(2) val startTime: Int = 0, @SerialId(2) val startTime: Int = 0,
@SerialId(11) val uinList: List<Long>? = null @SerialId(11) val uinList: List<Long>? = null
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class RspBody( internal class RspBody(
@SerialId(11) val msgMutualmarkData: List<Vec0xd6b.MutualMarkData>? = null, @SerialId(11) val msgMutualmarkData: List<Vec0xd6b.MutualMarkData>? = null,
@SerialId(12) val uint64UnfinishedUins: List<Long>? = null @SerialId(12) val uint64UnfinishedUins: List<Long>? = null
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class MutualMarkData( internal class MutualMarkData(
@SerialId(1) val frdUin: Long = 0L, @SerialId(1) val frdUin: Long = 0L,
@SerialId(2) val result: Int = 0 @SerialId(2) val result: Int = 0
// @SerialId(11) val mutualmarkInfo: List<Mutualmark.MutualMark>? = null // @SerialId(11) val mutualmarkInfo: List<Mutualmark.MutualMark>? = null
...@@ -70,9 +70,9 @@ class Vec0xd6b : ProtoBuf { ...@@ -70,9 +70,9 @@ class Vec0xd6b : ProtoBuf {
} }
@Serializable @Serializable
class Mutualmark : ProtoBuf { internal class Mutualmark : ProtoBuf {
@Serializable @Serializable
class MutualmarkInfo( internal class MutualmarkInfo(
@SerialId(1) val lastActionTime: Long = 0L, @SerialId(1) val lastActionTime: Long = 0L,
@SerialId(2) val level: Int = 0, @SerialId(2) val level: Int = 0,
@SerialId(3) val lastChangeTime: Long = 0L, @SerialId(3) val lastChangeTime: Long = 0L,
...@@ -86,7 +86,7 @@ class Mutualmark : ProtoBuf { ...@@ -86,7 +86,7 @@ class Mutualmark : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class ResourceInfo17( internal class ResourceInfo17(
@SerialId(1) val dynamicUrl: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(1) val dynamicUrl: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(2) val staticUrl: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(2) val staticUrl: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val cartoonUrl: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(3) val cartoonUrl: ByteArray = EMPTY_BYTE_ARRAY,
......
...@@ -2,8 +2,8 @@ package net.mamoe.mirai.qqandroid.network.protocol.data.proto ...@@ -2,8 +2,8 @@ package net.mamoe.mirai.qqandroid.network.protocol.data.proto
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.qqandroid.io.ProtoBuf import net.mamoe.mirai.qqandroid.io.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.utils.currentTimeSeconds import net.mamoe.mirai.utils.currentTimeSeconds
interface ImgReq : ProtoBuf interface ImgReq : ProtoBuf
......
...@@ -9,16 +9,16 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY ...@@ -9,16 +9,16 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
* msf.msgcomm.msg_comm * msf.msgcomm.msg_comm
*/ */
@Serializable @Serializable
class MsgComm : ProtoBuf { internal class MsgComm : ProtoBuf {
@Serializable @Serializable
class AppShareInfo( internal class AppShareInfo(
@SerialId(1) val appshareId: Int = 0, @SerialId(1) val appshareId: Int = 0,
@SerialId(2) val appshareCookie: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(2) val appshareCookie: ByteArray = EMPTY_BYTE_ARRAY,
@SerialId(3) val appshareResource: PluginInfo? = null @SerialId(3) val appshareResource: PluginInfo? = null
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class C2CTmpMsgHead( internal class C2CTmpMsgHead(
@SerialId(1) val c2cType: Int = 0, @SerialId(1) val c2cType: Int = 0,
@SerialId(2) val serviceType: Int = 0, @SerialId(2) val serviceType: Int = 0,
@SerialId(3) val groupUin: Long = 0L, @SerialId(3) val groupUin: Long = 0L,
...@@ -33,7 +33,7 @@ class MsgComm : ProtoBuf { ...@@ -33,7 +33,7 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class ContentHead( internal class ContentHead(
@SerialId(1) val pkgNum: Int = 0, @SerialId(1) val pkgNum: Int = 0,
@SerialId(2) val pkgIndex: Int = 0, @SerialId(2) val pkgIndex: Int = 0,
@SerialId(3) val divSeq: Int = 0, @SerialId(3) val divSeq: Int = 0,
...@@ -41,7 +41,7 @@ class MsgComm : ProtoBuf { ...@@ -41,7 +41,7 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class DiscussInfo( internal class DiscussInfo(
@SerialId(1) val discussUin: Long = 0L, @SerialId(1) val discussUin: Long = 0L,
@SerialId(2) val discussType: Int = 0, @SerialId(2) val discussType: Int = 0,
@SerialId(3) val discussInfoSeq: Long = 0L, @SerialId(3) val discussInfoSeq: Long = 0L,
...@@ -50,13 +50,13 @@ class MsgComm : ProtoBuf { ...@@ -50,13 +50,13 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class ExtGroupKeyInfo( internal class ExtGroupKeyInfo(
@SerialId(1) val curMaxSeq: Int = 0, @SerialId(1) val curMaxSeq: Int = 0,
@SerialId(2) val curTime: Long = 0L @SerialId(2) val curTime: Long = 0L
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class GroupInfo( internal class GroupInfo(
@SerialId(1) val groupCode: Long = 0L, @SerialId(1) val groupCode: Long = 0L,
@SerialId(2) val groupType: Int = 0, @SerialId(2) val groupType: Int = 0,
@SerialId(3) val groupInfoSeq: Long = 0L, @SerialId(3) val groupInfoSeq: Long = 0L,
...@@ -68,7 +68,7 @@ class MsgComm : ProtoBuf { ...@@ -68,7 +68,7 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class Msg( internal class Msg(
@SerialId(1) val msgHead: MsgHead, @SerialId(1) val msgHead: MsgHead,
@SerialId(2) val contentHead: ContentHead? = null, @SerialId(2) val contentHead: ContentHead? = null,
@SerialId(3) val msgBody: ImMsgBody.MsgBody, @SerialId(3) val msgBody: ImMsgBody.MsgBody,
...@@ -76,7 +76,7 @@ class MsgComm : ProtoBuf { ...@@ -76,7 +76,7 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class MsgHead( internal class MsgHead(
@SerialId(1) val fromUin: Long = 0L, @SerialId(1) val fromUin: Long = 0L,
@SerialId(2) val toUin: Long = 0L, @SerialId(2) val toUin: Long = 0L,
@SerialId(3) val msgType: Int = 0, @SerialId(3) val msgType: Int = 0,
...@@ -108,19 +108,19 @@ class MsgComm : ProtoBuf { ...@@ -108,19 +108,19 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class MsgType0x210( internal class MsgType0x210(
@SerialId(1) val subMsgType: Int = 0, @SerialId(1) val subMsgType: Int = 0,
@SerialId(2) val msgContent: ByteArray = EMPTY_BYTE_ARRAY @SerialId(2) val msgContent: ByteArray = EMPTY_BYTE_ARRAY
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class MutilTransHead( internal class MutilTransHead(
@SerialId(1) val status: Int = 0, @SerialId(1) val status: Int = 0,
@SerialId(2) val msgId: Int = 0 @SerialId(2) val msgId: Int = 0
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class PluginInfo( internal class PluginInfo(
@SerialId(1) val resId: Int = 0, @SerialId(1) val resId: Int = 0,
@SerialId(2) val pkgName: String = "", @SerialId(2) val pkgName: String = "",
@SerialId(3) val newVer: Int = 0, @SerialId(3) val newVer: Int = 0,
...@@ -135,13 +135,13 @@ class MsgComm : ProtoBuf { ...@@ -135,13 +135,13 @@ class MsgComm : ProtoBuf {
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class Uin2Nick( internal class Uin2Nick(
@SerialId(1) val uin: Long = 0L, @SerialId(1) val uin: Long = 0L,
@SerialId(2) val nick: String = "" @SerialId(2) val nick: String = ""
) : ProtoBuf ) : ProtoBuf
@Serializable @Serializable
class UinPairMsg( internal class UinPairMsg(
@SerialId(1) val lastReadTime: Int = 0, @SerialId(1) val lastReadTime: Int = 0,
@SerialId(2) val peerUin: Long = 0L, @SerialId(2) val peerUin: Long = 0L,
@SerialId(3) val msgCompleted: Int = 0, @SerialId(3) val msgCompleted: Int = 0,
......
...@@ -6,9 +6,9 @@ import net.mamoe.mirai.qqandroid.io.ProtoBuf ...@@ -6,9 +6,9 @@ import net.mamoe.mirai.qqandroid.io.ProtoBuf
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
@Serializable @Serializable
class MsgOnlinePush { internal class MsgOnlinePush {
@Serializable @Serializable
class PbPushMsg( internal class PbPushMsg(
@SerialId(1) val msg: MsgComm.Msg, @SerialId(1) val msg: MsgComm.Msg,
@SerialId(2) val svrip: Int = 0, @SerialId(2) val svrip: Int = 0,
@SerialId(3) val pushToken: ByteArray = EMPTY_BYTE_ARRAY, @SerialId(3) val pushToken: ByteArray = EMPTY_BYTE_ARRAY,
......
...@@ -48,6 +48,7 @@ internal val EMPTY_BYTE_ARRAY = ByteArray(0) ...@@ -48,6 +48,7 @@ internal val EMPTY_BYTE_ARRAY = ByteArray(0)
* *
* byte[] body encrypted by 16 zero * byte[] body encrypted by 16 zero
*/ */
@Deprecated("危险", level = DeprecationLevel.ERROR)
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
internal inline fun PacketFactory<*>.buildOutgoingPacket( internal inline fun PacketFactory<*>.buildOutgoingPacket(
client: QQAndroidClient, client: QQAndroidClient,
...@@ -102,7 +103,7 @@ internal inline fun PacketFactory<*>.buildOutgoingUniPacket( ...@@ -102,7 +103,7 @@ internal inline fun PacketFactory<*>.buildOutgoingUniPacket(
writeStringUtf8(it) writeStringUtf8(it)
} }
encryptAndWrite(key) { encryptAndWrite(key) {
writeUniPacket(commandName, extraData) { writeUniPacket(commandName, client.outgoingPacketUnknownValue, extraData) {
body(sequenceId) body(sequenceId)
} }
} }
...@@ -113,6 +114,7 @@ internal inline fun PacketFactory<*>.buildOutgoingUniPacket( ...@@ -113,6 +114,7 @@ internal inline fun PacketFactory<*>.buildOutgoingUniPacket(
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
internal inline fun BytePacketBuilder.writeUniPacket( internal inline fun BytePacketBuilder.writeUniPacket(
commandName: String, commandName: String,
unknownData: ByteArray,
extraData: ByteReadPacket = BRP_STUB, extraData: ByteReadPacket = BRP_STUB,
body: BytePacketBuilder.() -> Unit body: BytePacketBuilder.() -> Unit
) { ) {
...@@ -123,7 +125,7 @@ internal inline fun BytePacketBuilder.writeUniPacket( ...@@ -123,7 +125,7 @@ internal inline fun BytePacketBuilder.writeUniPacket(
} }
writeInt(4 + 4) writeInt(4 + 4)
writeInt(45112203) // 02 B0 5B 8B writeFully(unknownData) // 02 B0 5B 8B
if (extraData === BRP_STUB) { if (extraData === BRP_STUB) {
writeInt(0x04) writeInt(0x04)
...@@ -243,7 +245,7 @@ internal inline fun BytePacketBuilder.writeSsoPacket( ...@@ -243,7 +245,7 @@ internal inline fun BytePacketBuilder.writeSsoPacket(
} }
writeInt(4 + 4) writeInt(4 + 4)
writeInt(45112203) // 02 B0 5B 8B writeFully(client.outgoingPacketUnknownValue) // 02 B0 5B 8B
client.device.imei.let { client.device.imei.let {
writeInt(it.length + 4) writeInt(it.length + 4)
......
...@@ -25,8 +25,10 @@ import net.mamoe.mirai.qqandroid.utils.toRichTextElems ...@@ -25,8 +25,10 @@ import net.mamoe.mirai.qqandroid.utils.toRichTextElems
import net.mamoe.mirai.utils.cryptor.contentToString import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.hexToBytes
import net.mamoe.mirai.utils.io.toReadPacket import net.mamoe.mirai.utils.io.toReadPacket
import kotlin.math.absoluteValue
import kotlin.random.Random
class MessageSvc { internal class MessageSvc {
/** /**
* 告知要刷新好友消息 * 告知要刷新好友消息
*/ */
...@@ -119,8 +121,16 @@ class MessageSvc { ...@@ -119,8 +121,16 @@ class MessageSvc {
} }
} }
internal object PbSendMsg : PacketFactory<MsgSvc.PbSendMsgResp>("MessageSvc.PbSendMsg") { internal object PbSendMsg : PacketFactory<PbSendMsg.Response>("MessageSvc.PbSendMsg") {
object Response : Packet sealed class Response : Packet {
object SUCCESS : Response() {
override fun toString(): String = "MessageSvc.PbSendMsg.Response.SUCCESS"
}
data class Failed(val errorCode: Int, val errorMessage: String) : Response() {
override fun toString(): String = "MessageSvc.PbSendMsg.Response.FAILED(errorCode=$errorCode, errorMessage=$errorMessage"
}
}
/** /**
* 发送好友消息 * 发送好友消息
...@@ -142,18 +152,53 @@ class MessageSvc { ...@@ -142,18 +152,53 @@ class MessageSvc {
richText = ImMsgBody.RichText( richText = ImMsgBody.RichText(
elems = message.toRichTextElems() elems = message.toRichTextElems()
) )
) ),
// msgSeq = 17041, msgSeq = client.atomicNextMessageSequenceId(),
// msgRand = Random.nextInt().absoluteValue, msgRand = Random.nextInt().absoluteValue
// syncCookie = client.c2cMessageSync.syncCookie.takeIf { it.isNotEmpty() } ?: "08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00".hexToBytes(), // syncCookie = client.c2cMessageSync.syncCookie.takeIf { it.isNotEmpty() } ?: "08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00".hexToBytes(),
// msgVia = 1 // msgVia = 1
)
)
}
/**
* 发送群消息
*/
fun ToGroup(
client: QQAndroidClient,
groupId: Long,
message: MessageChain
): OutgoingPacket = buildOutgoingUniPacket(client) {
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
///return@buildOutgoingUniPacket
writeProtoBuf(
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupId)), // TODO: 2020/1/30 确认这里是 id 还是 internalId
contentHead = MsgComm.ContentHead(pkgNum = 1),
msgBody = ImMsgBody.MsgBody(
richText = ImMsgBody.RichText(
elems = message.toRichTextElems()
)
),
msgSeq = client.atomicNextMessageSequenceId(),
msgRand = Random.nextInt().absoluteValue
// syncCookie = client.c2cMessageSync.syncCookie.takeIf { it.isNotEmpty() } ?: "08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00".hexToBytes(),
// msgVia = 1
) )
) )
} }
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): MsgSvc.PbSendMsgResp { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
discardExact(4) discardExact(4)
return readRemainingAsProtoBuf(MsgSvc.PbSendMsgResp.serializer())
val response = readRemainingAsProtoBuf(MsgSvc.PbSendMsgResp.serializer())
return if (response.result == 0) {
Response.SUCCESS
} else {
Response.Failed(response.errtype, response.errmsg)
}
} }
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment