Fix StackOverflowError

This commit is contained in:
Him188 2019-12-08 21:00:04 +08:00
parent f402451812
commit 39204730eb
11 changed files with 215 additions and 33 deletions

View File

@ -2,14 +2,12 @@ package net.mamoe.mirai.network
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.io.core.use import kotlinx.io.core.use
import kotlinx.io.streams.inputStream import kotlinx.io.streams.inputStream
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.Image import net.mamoe.mirai.message.Image
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import net.mamoe.mirai.network.protocol.tim.packet.SessionKey import net.mamoe.mirai.network.protocol.tim.packet.SessionKey
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import java.io.InputStream import java.io.InputStream
@ -21,8 +19,9 @@ import java.io.InputStream
*/ */
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
actual class BotSession internal actual constructor( actual class BotSession internal actual constructor(
bot: Bot bot: Bot,
) : BotSessionBase(bot) { sessionKey: SessionKey
) : BotSessionBase(bot, sessionKey) {
suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream()
suspend inline fun Image.downloadAsBitmap(): Bitmap = withContext(Dispatchers.IO) { downloadAsStream().use { BitmapFactory.decodeStream(it) } } suspend inline fun Image.downloadAsBitmap(): Bitmap = withContext(Dispatchers.IO) { downloadAsStream().use { BitmapFactory.decodeStream(it) } }

View File

@ -41,10 +41,11 @@ fun GroupId.toInternalId(): GroupInternalId {//求你别出错
) )
} }
fun GroupInternalId.toId(): GroupId {//求你别出错 fun GroupInternalId.toId(): GroupId = with(value) {
//求你别出错
var left: UInt = this.toString().let { var left: UInt = this.toString().let {
if (it.length < 6) { if (it.length < 6) {
return GroupId(this.value) return GroupId(value)
} }
it.substring(0 until it.length - 6).toUInt() it.substring(0 until it.length - 6).toUInt()
} }
@ -96,6 +97,6 @@ fun GroupInternalId.toId(): GroupId {//求你别出错
left = left.toString().substring(0 until 3).toUInt() left = left.toString().substring(0 until 3).toUInt()
((left - 349u).toString() + right.toString()).toUInt() ((left - 349u).toString() + right.toString()).toUInt()
} }
else -> this.value else -> value
}) })
} }

View File

@ -6,8 +6,10 @@ import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.contact.data.Profile import net.mamoe.mirai.contact.data.Profile
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.packet.action.AvatarLink
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendNameRemark import net.mamoe.mirai.network.protocol.tim.packet.action.FriendNameRemark
import net.mamoe.mirai.network.protocol.tim.packet.action.PreviousNameList import net.mamoe.mirai.network.protocol.tim.packet.action.PreviousNameList
import net.mamoe.mirai.utils.MiraiExperimentalAPI
/** /**
* QQ 对象. * QQ 对象.
@ -22,6 +24,12 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.PreviousNameList
* @author Him188moe * @author Him188moe
*/ */
interface QQ : Contact, CoroutineScope { interface QQ : Contact, CoroutineScope {
/**
* 请求头像下载链接
*/
// @MiraiExperimentalAPI
//suspend fun queryAvatar(): AvatarLink
/** /**
* 查询用户资料 * 查询用户资料
*/ */

View File

@ -31,7 +31,7 @@ import kotlin.coroutines.coroutineContext
* 构造 [BotSession] 的捷径 * 构造 [BotSession] 的捷径
*/ */
@Suppress("FunctionName", "NOTHING_TO_INLINE") @Suppress("FunctionName", "NOTHING_TO_INLINE")
internal inline fun TIMBotNetworkHandler.BotSession(): BotSession = BotSession(bot) internal inline fun TIMBotNetworkHandler.BotSession(sessionKey: SessionKey): BotSession = BotSession(bot, sessionKey)
/** /**
* 登录会话. 当登录完成后, 客户端会拿到 sessionKey. * 登录会话. 当登录完成后, 客户端会拿到 sessionKey.
@ -43,7 +43,8 @@ internal inline fun TIMBotNetworkHandler.BotSession(): BotSession = BotSession(b
*/ */
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
expect class BotSession internal constructor( expect class BotSession internal constructor(
bot: Bot bot: Bot,
sessionKey: SessionKey
) : BotSessionBase ) : BotSessionBase
/** /**
@ -52,9 +53,9 @@ expect class BotSession internal constructor(
@MiraiInternalAPI @MiraiInternalAPI
// cannot be internal because of `public BotSession` // cannot be internal because of `public BotSession`
abstract class BotSessionBase internal constructor( abstract class BotSessionBase internal constructor(
val bot: Bot val bot: Bot,
internal val sessionKey: SessionKey
) { ) {
internal val sessionKey: SessionKey get() = bot.sessionKey
val socket: DataPacketSocketAdapter get() = bot.network.socket val socket: DataPacketSocketAdapter get() = bot.network.socket
val NetworkScope: CoroutineScope get() = bot.network val NetworkScope: CoroutineScope get() = bot.network

View File

@ -474,7 +474,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
BotLoginSucceedEvent(bot).broadcast() BotLoginSucceedEvent(bot).broadcast()
session = BotSession() session = BotSession(sessionKey)
val configuration = currentBotConfiguration() val configuration = currentBotConfiguration()
heartbeatJob = this@TIMBotNetworkHandler.launch { heartbeatJob = this@TIMBotNetworkHandler.launch {

View File

@ -79,6 +79,7 @@ internal enum class KnownPacketId(override inline val value: UShort, override in
inline REQUEST_PROFILE_AVATAR(0x0031u, RequestProfileAvatarPacket), inline REQUEST_PROFILE_AVATAR(0x0031u, RequestProfileAvatarPacket),
inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket), inline REQUEST_PROFILE_DETAILS(0x003Cu, RequestProfileDetailsPacket),
inline QUERY_NICKNAME(0x0126u, QueryNicknamePacket),
inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket), inline QUERY_PREVIOUS_NAME(0x01BCu, QueryPreviousNamePacket),

View File

@ -0,0 +1,29 @@
package net.mamoe.mirai.network.protocol.tim.packet.action
// 0001
// 已确认 查好友列表的列表
// send
// 20 01 00 00 00 00 01 00 00
// receive
// 20 00 01 03 00 00 00 15 01 01 03
// 00 0C 01 02 [09] E4 BF A1 E7 94 A8 E5 8D A1
// 00 0F 02 03 [0C] E8 BD AF E4 BB B6 E6 B3 A8 E5 86 8C
// 00 09 03 04 [06] E6 BA 90 E7 A0 81
// 00 00
// 0134
// 这里有好友也有群(为 internal id) 97208217
// 不太确定. 可能是查好友与群列表??
// send
// 00 00 01 5B 5D EB 58 AD 00 00 03 E8 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
// receive
// 00 00 19 00 00 01 5D 5D EB 5D C6 00 00 00 00 01 00 00 00 19 00 54 E5 06 01 00 00 00 00 00 01 00 00 00 64 B2 1D 01 00 00 00 00 00 01 00 00 00 66 7C C5 01 00 00 00 00 00 01 00 00 01 60 31 EC 01 00 00 00 00 00 01 00 00 01 B3 E6 AC 01 00 00 00 00 00 01 00 00 02 45 16 DF 01 00 00 00 00 00 01 00 00 03 37 67 20 01 00 00 00 00 00 01 00 00 05 B0 F4 6F 01 00 00 00 00 00 01 00 00 0C D9 1F 45 01 00 00 00 00 00 01 00 00 0F 0D 35 E1 01 00 00 00 00 00 01 00 00 10 18 86 83 01 00 00 00 00 00 01 00 00 11 A9 8B F7 01 00 00 00 00 00 01 00 00 31 05 12 1C 01 00 00 00 00 00 01 00 00 37 99 77 D7 01 00 00 00 00 00 01 00 00 37 C8 4D C7 04 00 00 00 00 00 00 37 E9 68 46 01 00 00 00 00 00 01 00 00 37 E9 94 CF 01 00 00 00 00 00 01 00 00 3E 03 3F A2 01 00 00 00 00 00 01 00 00 50 BA 4A 8F 01 00 00 00 00 00 01 00 00 55 7A D6 86 01 00 00 00 00 00 01 00 00 6C 78 B1 E0 01 00 00 00 00 00 01 00 00 78 59 79 87 01 00 00 00 00 00 01 00 00 79 9B 1B 59 04 00 00 00 00 00 00 A6 81 A4 9D 01 00 00 00 00 00 01 00 00 A6 A0 EE EF 01 00 00 00 00 00 01 00 00 00 00

View File

@ -10,12 +10,133 @@ import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
inline class AvatarLink(val value: String) : Packet
inline class NicknameMap(val delegate: Map<UInt, String>) : Packet
/**
* 批量查询昵称.
*/
@AnnotatedId(KnownPacketId.QUERY_NICKNAME)
internal object QueryNicknamePacket : SessionPacketFactory<NicknameMap>() {
/**
* 单个查询.
*/
@PacketVersion(date = "2019.12.7", timVersion = "2.3.2 (21173)")
operator fun invoke(
bot: UInt,
sessionKey: SessionKey,
qq: UInt
): OutgoingPacket = buildSessionPacket(bot, sessionKey) {
writeHex("03 00 00 00 00 00 00 00 00 00 00")
writeByte(1)
writeUInt(qq)
}
/**
* 批量查询.
* 注意!! 服务器不一定全都返回... 需要重复查没返回的
*/
@PacketVersion(date = "2019.12.7", timVersion = "2.3.2 (21173)")
operator fun invoke(
bot: UInt,
sessionKey: SessionKey,
qq: Array<UInt>
): OutgoingPacket = buildSessionPacket(bot, sessionKey) {
writeHex("03 00 00 00 00 00 00 00 00 00 00")
writeUByte(qq.size.toUByte())
qq.forEach {
writeUInt(it)
}
}
/*
批量查询昵称
发出包ID = UnknownPacketId(01 26)
sequence = 44 57
fixVer2=02 00 00 00 01 2E 01 00 00 69 35
解密body=03 00 00 00 00 00 00 00 00 00 00 [24]
(02 45 16 DF) (6C 78 B1 E0) (11 73 69 76) (36 79 19 E1) (49 28 A4 F4) (81 66 8B BC) (2D 6B 19 EC) (28 3D 91 25) (00 54 E5 06) (37 E9 94 CF) (55 7A D6 86)
(01 60 31 EC) (2F B1 5E EF) (05 B0 F4 6F) (0F 0D 35 E1) (00 66 7C C5) A6 81 A4 9D 31 05 12 1C A6 A0 EE EF 10 18 86 83 37 99 77 D7 50 BA 4A 8F 10 CE 72 4C 32 71 EE 30 79 63 C6 98 (3E C2 FA 6E) 02 27 13 93 01 2E E5 D7 37 E9 68 46 00 64 B2 1D 03 37 67 20 0A 9C 58 FB 05 94 75 87
(0B 9F C6 B6)
(18 BE 4B 0E)
接收包id=UnknownPacketId(01 26),
sequence=44 57
解析body=UnknownPacket(01 26)
body= 03 00 00 00 00 00 00 00 00 00 00 12 04 14 37
(02 45 16 DF) 00 36 FF 00
[0F] E6 94 BE E7 9D 9B E3 81 AE E5 A4 A9 E7 A9 BA
11 88 02 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 80 08 80 00 41
(6C 78 B1 E0) 00 2D 1C 01
[19] 61 2E E8 B4 A2 E7 A5 9E 7C 20 E6 8E A5 E5 90 84 E7 A7 8D E4 B8 9A E5 8A A1
11 C0 02 40 07 C7 08 1C 00 4D 59 53 00 00 4B 4C 00 4B 55 4C 00 00 00 00 00 00 04 00 00 E2 10 34
(11 73 69 76) 01 DD 19 00
[0C] E5 BC 80 E5 BF 83 E5 B0 B1 E5 A5 BD
11 08 82 46 07 CA 00 00 00 00 00 31 00 00 33 32 00 00 00 35 08 04 08 04 08 04 04 01 17 E3 10 32
(36 79 19 E1) 00 00 1F 00
[0A] 45 70 69 6D 65 74 68 65 75 73
00 08 02 00 07 C4 02 08 00 41 42 57 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 10 49
(49 28 A4 F4) 02 B5 17 01
[21] E9 A1 B9 E7 9B AE 6B 61 6B 61 6F 74 61 6C 6B EF BC 88 E6 9C 89 E4 BA 8B E6 8A 96 E6 88 91 EF BC 89
11 80 02 00 07 CC 06 0B 00 00 00 31 00 00 34 34 00 00 00 31 00 00 00 00 00 00 04 00 00 80 10 2E
(81 66 8B BC) 02 64 77 00
[06] E4 B8 87 E7 A0 81
00 80 02 00 07 6C 0A 03 00 00 00 31 00 00 33 31 00 00 00 35 00 00 00 00 00 00 04 00 00 00 00 37
(2D 6B 19 EC) 02 58 16 01
[0F] E5 93 A5 E5 8F AA E6 98 AF E4 BC A0 E9 80 81
11 00 02 00 07 CC 0C 0F 00 00 00 31 00 00 35 33 00 00 00 33 00 00 00 00 00 00 04 00 00 00 00 31
28 3D 91 25 02 D9 FF FF 09 E5 B0 8F E8 A1 A8 E5 BC 9F 11 C8 02 46 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 08 04 08 04 08 04 04 20 06 E2 00 3B 00 54 E5 06 02 5B 78 00 13 61 E5 85 A8 E6 96 B0 E5 9F 9F E5 90 8D E6 89 B9 E5 8F 91 00 08 82 46 07 6B 08 16 00 00 00 31 00 00 34 33 00 00 00 31 00 00 00 00 00 00 04 00 08 02 00 4C 37 E9 94 CF 00 00 00 FF 24 E6 B3 89 E5 B7 9E E5 B8 82 E6 86 A8 E9 BC A0 E7 BD 91 E7 BB 9C E7 A7 91 E6 8A 80 E6 9C 89 E9 99 90 E5 85 AC 01 00 00 00 00 00 00 00 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 40 02 30 55 7A D6 86 02 49 1B 01 08 E5 AE A2 E6 9C 8D 56 36 11 00 02 00 07 C8 01 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 12 00 4A 01 60 31 EC 02 58 FF 00 22 E5 BC 80 E5 BD A9 E7 BD 91 2D E5 B0 8F E8 B1 86 28 31 32 E5 88 B0 32 32 E7 82 B9 E5 9C A8 E7 BA BF 29 00 40 00 00 00 00 05 1E 00 00 00 31 00 00 35 31 00 00 00 31 08 04 04 09 0C 04 04 00 00 02 00 38 2F B1 5E EF 00 00 00 FF 10 E4 B8 8A E6 96 B9 65 E6 8E A8 E8 BD AF E4 BB B6 01 80 00 00 00 00 00 00 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 00 00 39 05 B0 F4 6F 00 78 23 01 11 E2 99 A1 20 E2 9C BF E2 80 BF E2 9C BF 20 52 4F 4E 11 88 82 42 07 C0 09 0C 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 80 00 2E 0F 0D 35 E1 00 00 23 00 06 E5 9C B0 E8 A1 A3 00 40 02 46 07 C0 02 08 00 00 00 31 00 00 34 35 00 00 00 33 00 00 00 00 00 00 04 10 00 02 00 31 00 66 7C C5 00 00 0A 00 09 E8 B5 9A E5 B0 8F E5 AE A2 00 C8 02 42 07 D8 0C 0C 00 00 00 31 00 00 34 31 00 00 00 31 00 00 00 00 00 00 04 24 02 00 00 3A
(A6 81 A4 9D) 02 25 29 00 12 E6 96 B0 E6 98 93 E9 80 9A E5 AE A2 E6 9C 8D E4 B8 89 11 80 02 01 07 BA 0A 10 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 00 00 3A 31 05 12 1C 01 86 1C 00 12 E5 BF A7 E4 BC A4 E8 BF 98 E6 98 AF E5 BF AB E4 B9 90 00 88 02 02 07 C7 04 13 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 08 20 00 00 04 5D EC AF 48
---------------------------
发出包ID = UnknownPacketId(01 26)
sequence = 44 58
fixVer2=02 00 00 00 01 2E 01 00 00 69 35
解密body=03 00 00 00 00 00 00 00 00 00 00 12 A6 A0 EE EF 10 18 86 83 37 99 77 D7 50 BA 4A 8F 10 CE 72 4C 32 71 EE 30 79 63 C6 98
(3E C2 FA 6E) 02 27 13 93 01 2E E5 D7 37 E9 68 46 (00 64 B2 1D) (03 37 67 20) 0A 9C 58 FB 05 94 75 87 (11 48 2B 1A) 0B 9F C6 B6 18 BE 4B 0E
接收包id=UnknownPacketId(01 26),
sequence=44 58
解析body=UnknownPacket(01 26)
body=03 00 00 00 00 00 00 00 00 00 00 00 03 8E 3C A6 A0 EE EF 02 07 6C 01 14 E8 8B B9 E6 9E 9C 49 44 E4 B8 93 E4 B8 9A E8 A7 A3 E9 94 81 11 00 02 01 07 77 01 01 00 00 00 31 00 00 31 31 00 00 00 31 00 00 00 00 00 00 04 00 00 02 00 31 10 18 86 83 00 C3 22 00 09 35 35 38 E7 94 B5 E8 AE AF 00 08 02 40 07 C1 0C 01 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 04 00 10 35 37 99 77 D7 02 5B 2A 00 0D E8 BF 9C E6 8B 93 E7 94 B5 E8 AE AF 33 00 C0 00 02 07 B9 09 0E 00 00 00 31 00 00 33 35 00 00 00 35 00 00 00 00 00 00 04 00 00 40 00 2E 50 BA 4A 8F 02 1C 09 00 06 E6 96 B9 E5 80 8D 11 40 02 00 07 DA 01 01 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 82 00 2C 10 CE 72 4C 00 00 23 00 04 4C 6F 73 74 11 08 02 00 07 C0 02 12 00 00 00 31 00 00 31 31 00 00 00 38 08 04 00 00 00 00 04 00 08 72 00 30 32 71 EE 30 00 93 21 00 08 69 57 65 62 53 68 6F 70 00 00 02 00 07 C2 01 01 00 00 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 12 00 2B 79 63 C6 98 02 A6 12 00 03 5E 4F 5E 11 80 02 00 07 D1 08 12 00 00 00 31 00 00 33 37 00 00 00 32 00 00 00 00 00 00 04 00 00 60 00 3D 3E C2 FA 6E 02 2B 1D 01 15 E9 A3 8E E9 93 83 E8 8D 89 E6 95 99 E8 82 B2 E6 9C 8D E5 8A A1 00 80 00 00 07 C6 06 10 00 00 00 31 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 2E 02 27 13 93 02 0D FF FF 06 E7 83 82 E8 8F 9C 00 08 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 04 A2 00 33 01 2E E5 D7 00 D8 22 00 0B 4F 28 E2 88 A9 5F E2 88 A9 29 4F 11 48 82 46 07 C1 08 1A 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 0C 80 08 30 37 E9 68 46 00 00 00 FF 08 33 35 E4 BA 92 E8 81 94 01 00 00 00 00 00 00 00 00 00 00 31 00 00 33 35 00 00 00 32 00 00 00 00 00 00 04 00 00 40 02 37 00 64 B2 1D 00 00 FF FF 0F E5 98 89 E4 BC A6 E8 99 8E E8 99 8E E8 99 8E 01 48 06 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 01 40 8C 00 34 03 37 67 20 00 93 24 00 0C E8 93 9D E6 98 9F E7 A7 91 E6 8A 80 00 08 02 46 07 BF 0A 1A 00 00 00 31 00 00 33 35 00 00 00 35 08 04 08 04 08 04 04 00 00 00 10 2C 0A 9C 58 FB 01 53 00 00 04 4B E3 80 81 00 48 02 02 07 E3 00 00 00 00 00 31 00 00 00 00 00 00 00 00 0C 04 08 04 04 09 04 FD 03 02 00 2E 05 94 75 87 02 25 1F 00 06 54 4E 54 50 52 4F 00 40 02 00 07 C4 01 01 00 00 00 31 00 00 34 33 00 00 00 31 00 00 00 00 00 00 04 00 00 02 00 2E 11 48 2B 1A 02 0A 0B 00 06 E6 9D 8E E9 98 B3 11 08 02 02 07 D8 03 1C 00 00 00 31 00 00 34 34 00 00 00 33 00 00 00 00 00 00 04 00 00 6C 00 30 0B 9F C6 B6 00 AE 14 00 08 F0 9F 91 BC F0 9F 91 BF 11 00 02 42 07 CF 01 18 00 00 00 00 00 00 00 00 00 00 00 00 08 04 08 04 04 07 04 00 04 A0 00 34
(18 BE 4B 0E) 00 00 36 00
[0C] E5 B3 B0 E5 9B 9E E8 B7 AF E8 BD AC
00 08 02 00 07 AD 02 03 00 00 00 31 00 00 31 35 00 00 32 32 00 00 00 00 00 00 04 00 00 00 00 00
04 5D EC AF 48
*/
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): NicknameMap {
//03 00 00 00 00 00 00 00 00 00 00 12 04 14 37
val type = readUByte().toInt()
if (type == 15) {
discardExact(14)
val map = linkedMapOf<UInt, String>()
while (remaining != 5L) { // 最后总是会剩余 04 5D EC AF 48
val qq = readUInt()
discardExact(4) // 4 个状态信息, 未知
val nickname = readString(readUByte().toInt())
discardExact(32) // 未知
map[qq] = nickname
}
return NicknameMap(map)
} else {
error("Unsupported type $type")
}
}
}
// 用户资料的头像 // 用户资料的头像
/** /**
* 请求获取头像 * 请求获取头像
*/ */ // ? 这个包的数据跟下面那个包一样
@AnnotatedId(KnownPacketId.REQUEST_PROFILE_AVATAR) @AnnotatedId(KnownPacketId.REQUEST_PROFILE_AVATAR)
internal object RequestProfileAvatarPacket : SessionPacketFactory<NoPacket>() { internal object RequestProfileAvatarPacket : SessionPacketFactory<AvatarLink>() {
//00 01 00 17 D4 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5 //00 01 00 17 D4 54 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5
operator fun invoke( operator fun invoke(
bot: UInt, bot: UInt,
@ -27,9 +148,9 @@ internal object RequestProfileAvatarPacket : SessionPacketFactory<NoPacket>() {
writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5") writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 4E 22 4E 25 4E 26 4E 27 4E 29 4E 2A 4E 2B 4E 2D 4E 2E 4E 2F 4E 30 4E 31 4E 33 4E 35 4E 36 4E 37 4E 38 4E 3F 4E 40 4E 41 4E 42 4E 43 4E 45 4E 49 4E 4B 4E 4F 4E 54 4E 5B 52 0B 52 0F 5D C2 5D C8 65 97 69 9D 69 A9 9D A5 A4 91 A4 93 A4 94 A4 9C A4 B5")
} }
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): NoPacket { override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): AvatarLink {
println(" RequestProfileAvatarPacket body=${this.readBytes().toUHexString()}") println(" RequestProfileAvatarPacket body=${this.readBytes().toUHexString()}")
return NoPacket TODO()
} }
} }

View File

@ -2,7 +2,26 @@
package net.mamoe.mirai package net.mamoe.mirai
import kotlinx.io.core.buildPacket
import kotlinx.io.core.readBytes
import net.mamoe.mirai.contact.GroupInternalId
import net.mamoe.mirai.contact.toId
import net.mamoe.mirai.utils.io.toByteArray
import net.mamoe.mirai.utils.io.toUHexString
actual object MiraiEnvironment { actual object MiraiEnvironment {
@JvmStatic @JvmStatic
actual val platform: Platform get() = Platform.JVM actual val platform: Platform
get() = Platform.JVM
}
@ExperimentalUnsignedTypes
fun main() {
println(GroupInternalId(2793514141u).toId().value.toLong())
println(GroupInternalId(2040208217u).toId().value.toLong())
println(289942298u.toByteArray().toUHexString())
println(1040400290u.toByteArray().toUHexString())
println(buildPacket {
writeStringUtf8("信用卡")
}.readBytes().toUByteArray().toUHexString())
} }

View File

@ -1,13 +1,11 @@
package net.mamoe.mirai.network package net.mamoe.mirai.network
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.io.core.use import kotlinx.io.core.use
import kotlinx.io.streams.inputStream import kotlinx.io.streams.inputStream
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.message.Image import net.mamoe.mirai.message.Image
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import net.mamoe.mirai.network.protocol.tim.packet.SessionKey import net.mamoe.mirai.network.protocol.tim.packet.SessionKey
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
@ -24,8 +22,9 @@ import javax.imageio.ImageIO
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
@Suppress("unused") @Suppress("unused")
actual class BotSession internal actual constructor( actual class BotSession internal actual constructor(
bot: Bot bot: Bot,
) : BotSessionBase(bot) { sessionKey: SessionKey
) : BotSessionBase(bot, sessionKey) {
suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream()
suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } } suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } }

View File

@ -134,27 +134,29 @@ suspend fun main() {
println("Ready perfectly") println("Ready perfectly")
} }
suspend fun decryptRecordedPackets(filename: String) { suspend fun decryptRecordedPackets(filename: String?) {
File(filename).toRecorder() (if (filename == null) File(".").listFiles()?.maxBy { it.lastModified() }!!
.list.forEach { else File(filename)).toRecorder().also {
println("total count = " + it.list.size)
println()
}.list.forEach {
if (it.isSend) { if (it.isSend) {
try { try {
dataSent(it.data) dataSent(it.data)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() //e.printStackTrace()
} }
} else { } else {
try { try {
dataReceived(it.data) dataReceived(it.data)
} catch (e: Exception) { } catch (e: Exception) {
e.printStackTrace() // e.printStackTrace()
} }
} }
} }
} }
decryptRecordedPackets("GMTDate(seconds=3, minutes=46, hours=7, dayOfWeek=SATURDAY, dayOfMonth=7, dayOfYear=341, month=DECEMBER, year=2019, timestamp=1575704763731).record") decryptRecordedPackets(null)
//startPacketListening() //startPacketListening()
} }
@ -180,13 +182,13 @@ internal object PacketDebugger {
* 7. 运行完 `mov eax,dword ptr ss:[ebp+10]` * 7. 运行完 `mov eax,dword ptr ss:[ebp+10]`
* 8. 查看内存, `eax` `eax+10` 16 字节就是 `sessionKey` * 8. 查看内存, `eax` `eax+10` 16 字节就是 `sessionKey`
*/ */
val sessionKey: SessionKey = SessionKey("98 4C 42 37 0F 87 BB A2 97 57 A1 77 A9 A9 74 37".hexToBytes()) val sessionKey: SessionKey = SessionKey("F3 4A 4E F4 79 C4 92 62 EF 0F D8 6E D3 AB E3 80".hexToBytes())
// TODO: 2019/12/7 无法访问 internal 是 kotlin bug, KT-34849 // TODO: 2019/12/7 无法访问 internal 是 kotlin bug, KT-34849
/** /**
* null 则不筛选 * null 则不筛选
*/ */
val qq: UInt? = null val qq: UInt? = 215555909u
/** /**
* 打开后则记录每一个包到文件. * 打开后则记录每一个包到文件.
*/ */
@ -229,7 +231,7 @@ internal object PacketDebugger {
} }
.runCatching { .runCatching {
decode(id, sequenceId, DebugNetworkHandler) decode(id, sequenceId, DebugNetworkHandler)
}.getOrElse { it.printStackTrace(); null } }.getOrElse { /*it.printStackTrace();*/ null }
} }
} }
@ -237,7 +239,9 @@ internal object PacketDebugger {
if (packet !is IgnoredEventPacket) { if (packet !is IgnoredEventPacket) {
println("--------------") println("--------------")
println("接收包id=$id, \nsequence=${sequenceId.toUHexString()}") println("接收包id=$id, \nsequence=${sequenceId.toUHexString()}")
println(" 解密body=${decodedBody.toUHexString()}") if (packet !is UnknownPacket) {
println(" 解密body=${decodedBody.toUHexString()}")
}
println(" 解析body=$packet") println(" 解析body=$packet")
} }
@ -390,7 +394,7 @@ internal object DebugNetworkHandler : BotNetworkHandler<DataPacketSocketAdapter>
} }
override val bot: Bot = Bot(qq ?: 0u, "", coroutineContext) override val bot: Bot = Bot(qq ?: 0u, "", coroutineContext)
override val session = BotSession(bot) override val session = BotSession(bot, SessionKey(byteArrayOf()))
override suspend fun login(): LoginResult = LoginResult.SUCCESS override suspend fun login(): LoginResult = LoginResult.SUCCESS