mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-13 03:16:05 +08:00
Make all packets internal
This commit is contained in:
parent
1ea8478584
commit
e47143e872
@ -7,6 +7,7 @@ package net.mamoe.mirai
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.requireSuccess
|
||||
@ -30,7 +31,9 @@ suspend inline fun Bot.getQQ(@PositiveNumbers number: Long): QQ = this.contacts.
|
||||
suspend inline fun Bot.getQQ(number: UInt): QQ = this.contacts.getQQ(number)
|
||||
|
||||
suspend inline fun Bot.getGroup(id: UInt): Group = this.contacts.getGroup(GroupId(id))
|
||||
suspend inline fun Bot.getGroup(@PositiveNumbers id: Long): Group = this.contacts.getGroup(GroupId(id.coerceAtLeastOrFail(0).toUInt()))
|
||||
suspend inline fun Bot.getGroup(@PositiveNumbers id: Long): Group =
|
||||
this.contacts.getGroup(GroupId(id.coerceAtLeastOrFail(0).toUInt()))
|
||||
|
||||
suspend inline fun Bot.getGroup(id: GroupId): Group = this.contacts.getGroup(id)
|
||||
suspend inline fun Bot.getGroup(internalId: GroupInternalId): Group = this.contacts.getGroup(internalId)
|
||||
|
||||
@ -60,7 +63,8 @@ inline fun <R> Bot.withSession(block: BotSession.() -> R): R {
|
||||
* 发送数据包
|
||||
* @throws IllegalStateException 当 [BotNetworkHandler.socket] 未开启时
|
||||
*/
|
||||
suspend inline fun Bot.sendPacket(packet: OutgoingPacket) = this.network.sendPacket(packet)
|
||||
internal suspend inline fun Bot.sendPacket(packet: OutgoingPacket) =
|
||||
(this.network as TIMBotNetworkHandler).socket.sendPacket(packet)
|
||||
|
||||
/**
|
||||
* 使用在默认配置基础上修改的配置进行登录
|
||||
@ -109,7 +113,8 @@ suspend inline fun Bot.alsoLogin(message: String): Bot {
|
||||
*/
|
||||
@UseExperimental(ExperimentalContracts::class)
|
||||
@JvmOverloads
|
||||
suspend inline fun Bot.addFriend(id: UInt, message: String? = null, remark: String? = null): AddFriendResult = contacts.addFriend(id, message, remark)
|
||||
suspend inline fun Bot.addFriend(id: UInt, message: String? = null, remark: String? = null): AddFriendResult =
|
||||
contacts.addFriend(id, message, remark)
|
||||
|
||||
/**
|
||||
* 取得机器人的 QQ 号
|
||||
|
@ -9,10 +9,8 @@ import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
||||
|
||||
/**
|
||||
* 数据包相关事件
|
||||
*
|
||||
* @param P 指代数据包的类型. 这个类型是 **invariant(不变的)**
|
||||
*/
|
||||
sealed class PacketEvent<P : Packet>(bot: Bot, open val packet: P) : BotEvent(bot)
|
||||
internal sealed class PacketEvent<P : Packet>(bot: Bot, open val packet: P) : BotEvent(bot)
|
||||
|
||||
|
||||
/* Client to Server */
|
||||
@ -20,21 +18,21 @@ sealed class PacketEvent<P : Packet>(bot: Bot, open val packet: P) : BotEvent(bo
|
||||
/**
|
||||
* 发送给服务器的数据包的相关事件
|
||||
*/
|
||||
sealed class OutgoingPacketEvent(bot: Bot, packet: OutgoingPacket) : PacketEvent<OutgoingPacket>(bot, packet)
|
||||
internal sealed class OutgoingPacketEvent(bot: Bot, packet: OutgoingPacket) : PacketEvent<OutgoingPacket>(bot, packet)
|
||||
|
||||
/**
|
||||
* 包已发送, 此时包数据已完全发送至服务器, 且包已被关闭.
|
||||
*
|
||||
* 不可被取消
|
||||
*/
|
||||
class PacketSentEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet)
|
||||
internal class PacketSentEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet)
|
||||
|
||||
/**
|
||||
* 包发送前, 此时包数据已经编码完成.
|
||||
*
|
||||
* 可被取消
|
||||
*/
|
||||
class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet), Cancellable
|
||||
internal class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEvent(bot, packet), Cancellable
|
||||
|
||||
|
||||
/* Server to Client */
|
||||
@ -42,9 +40,9 @@ class BeforePacketSendEvent(bot: Bot, packet: OutgoingPacket) : OutgoingPacketEv
|
||||
/**
|
||||
* 来自服务器的数据包的相关事件
|
||||
*/
|
||||
sealed class ServerPacketEvent<P : Packet>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
|
||||
internal sealed class ServerPacketEvent<P : Packet>(bot: Bot, packet: P) : PacketEvent<P>(bot, packet)
|
||||
|
||||
/**
|
||||
* 服务器数据包接收事件. 此时包已经解密完成.
|
||||
*/
|
||||
class ServerPacketReceivedEvent<P : Packet>(bot: Bot, packet: P) : ServerPacketEvent<P>(bot, packet), Cancellable
|
||||
internal class ServerPacketReceivedEvent<P : Packet>(bot: Bot, packet: P) : ServerPacketEvent<P>(bot, packet), Cancellable
|
@ -47,20 +47,6 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : CoroutineScope {
|
||||
*/
|
||||
suspend fun login(): LoginResult
|
||||
|
||||
/**
|
||||
* 添加一个临时包处理器, 并发送相应的包
|
||||
*
|
||||
* @see [BotSession.sendAndExpectAsync] 发送并期待一个包
|
||||
* @see [TemporaryPacketHandler] 临时包处理器
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>)
|
||||
|
||||
/**
|
||||
* 发送数据包
|
||||
*/
|
||||
suspend fun sendPacket(packet: OutgoingPacket)
|
||||
|
||||
/**
|
||||
* 等待直到与服务器断开连接. 若未连接则立即返回
|
||||
*/
|
||||
|
@ -46,7 +46,7 @@ internal inline fun TIMBotNetworkHandler.BotSession(
|
||||
* @author Him188moe
|
||||
*/
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
expect class BotSession(
|
||||
expect class BotSession internal constructor(
|
||||
bot: Bot,
|
||||
sessionKey: SessionKey,
|
||||
socket: DataPacketSocketAdapter,
|
||||
@ -58,9 +58,9 @@ expect class BotSession(
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
// cannot be internal because of `public BotSession`
|
||||
abstract class BotSessionBase(
|
||||
abstract class BotSessionBase internal constructor(
|
||||
val bot: Bot,
|
||||
val sessionKey: SessionKey,
|
||||
internal val sessionKey: SessionKey,
|
||||
val socket: DataPacketSocketAdapter,
|
||||
val NetworkScope: CoroutineScope
|
||||
) {
|
||||
@ -110,33 +110,36 @@ abstract class BotSessionBase(
|
||||
*
|
||||
* @see Bot.withSession 转换 receiver, 即 `this` 的指向, 为 [BotSession]
|
||||
*/
|
||||
suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpectAsync(
|
||||
internal suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpectAsync(
|
||||
checkSequence: Boolean = true,
|
||||
noinline handler: suspend (P) -> R
|
||||
): Deferred<R> {
|
||||
val deferred: CompletableDeferred<R> = CompletableDeferred(coroutineContext[Job])
|
||||
bot.network.addHandler(TemporaryPacketHandler(P::class, deferred, this@BotSessionBase as BotSession, checkSequence, coroutineContext + deferred).also {
|
||||
(bot.network as TIMBotNetworkHandler).addHandler(TemporaryPacketHandler(
|
||||
P::class, deferred, this@BotSessionBase as BotSession, checkSequence, coroutineContext + deferred
|
||||
).also {
|
||||
it.toSend(this)
|
||||
it.onExpect(handler)
|
||||
})
|
||||
return deferred
|
||||
}
|
||||
|
||||
suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpectAsync(checkSequence: Boolean = true): Deferred<P> =
|
||||
internal suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpectAsync(checkSequence: Boolean = true): Deferred<P> =
|
||||
sendAndExpectAsync<P, P>(checkSequence) { it }
|
||||
|
||||
suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpect(
|
||||
internal suspend inline fun <reified P : Packet, R> OutgoingPacket.sendAndExpect(
|
||||
checkSequence: Boolean = true,
|
||||
timeout: TimeSpan = 5.seconds,
|
||||
crossinline mapper: (P) -> R
|
||||
): R = withTimeout(timeout.millisecondsLong) { sendAndExpectAsync<P, R>(checkSequence) { mapper(it) }.await() }
|
||||
|
||||
suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpect(
|
||||
internal suspend inline fun <reified P : Packet> OutgoingPacket.sendAndExpect(
|
||||
checkSequence: Boolean = true,
|
||||
timeout: TimeSpan = 5.seconds
|
||||
): P = withTimeout(timeout.millisecondsLong) { sendAndExpectAsync<P, P>(checkSequence) { it }.await() }
|
||||
|
||||
suspend inline fun OutgoingPacket.send() = socket.sendPacket(this)
|
||||
internal suspend inline fun OutgoingPacket.send() =
|
||||
(socket as TIMBotNetworkHandler.BotSocketAdapter).sendPacket(this)
|
||||
|
||||
|
||||
suspend inline fun Int.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0).toUInt())
|
||||
@ -150,8 +153,16 @@ abstract class BotSessionBase(
|
||||
suspend inline fun GroupInternalId.group(): Group = bot.getGroup(this)
|
||||
|
||||
suspend fun Image.getLink(): ImageLink = when (this.id) {
|
||||
is ImageId0x06 -> FriendImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect<FriendImageLink>()
|
||||
is ImageId0x03 -> GroupImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect<ImageDownloadInfo>().requireSuccess()
|
||||
is ImageId0x06 -> FriendImagePacket.RequestImageLink(
|
||||
bot.qqAccount,
|
||||
bot.sessionKey,
|
||||
id
|
||||
).sendAndExpect<FriendImageLink>()
|
||||
is ImageId0x03 -> GroupImagePacket.RequestImageLink(
|
||||
bot.qqAccount,
|
||||
bot.sessionKey,
|
||||
id
|
||||
).sendAndExpect<GroupImageLink>().requireSuccess()
|
||||
else -> assertUnreachable()
|
||||
}
|
||||
|
||||
@ -167,7 +178,7 @@ inline val BotSession.qqAccount: UInt get() = bot.account.id // 为了与群和
|
||||
* 取得 [BotNetworkHandler] 的 sessionKey.
|
||||
* 实际上是一个捷径.
|
||||
*/
|
||||
inline val BotNetworkHandler<*>.sessionKey: SessionKey get() = this.session.sessionKey
|
||||
internal inline val BotNetworkHandler<*>.sessionKey: SessionKey get() = this.session.sessionKey
|
||||
|
||||
/**
|
||||
* 取得 [Bot] 的 [BotSession].
|
||||
@ -179,14 +190,14 @@ inline val Bot.session: BotSession get() = this.network.session
|
||||
* 取得 [Bot] 的 `sessionKey`.
|
||||
* 实际上是一个捷径.
|
||||
*/
|
||||
inline val Bot.sessionKey: SessionKey get() = this.session.sessionKey
|
||||
internal inline val Bot.sessionKey: SessionKey get() = this.session.sessionKey
|
||||
|
||||
|
||||
/**
|
||||
* 发送数据包
|
||||
* @throws IllegalStateException 当 [BotNetworkHandler.socket] 未开启时
|
||||
*/
|
||||
suspend inline fun BotSession.sendPacket(packet: OutgoingPacket) = this.bot.sendPacket(packet)
|
||||
internal suspend inline fun BotSession.sendPacket(packet: OutgoingPacket) = this.bot.sendPacket(packet)
|
||||
|
||||
|
||||
suspend inline fun BotSession.getQQ(@PositiveNumbers number: Long): QQ = this.bot.getQQ(number)
|
||||
|
@ -59,8 +59,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
||||
|
||||
private var heartbeatJob: Job? = null
|
||||
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) {
|
||||
suspend fun addHandler(temporaryPacketHandler: TemporaryPacketHandler<*, *>) {
|
||||
handlersLock.withLock {
|
||||
temporaryPacketHandlers.add(temporaryPacketHandler)
|
||||
}
|
||||
@ -116,8 +115,6 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
||||
this.socket.close()
|
||||
}
|
||||
|
||||
override suspend fun sendPacket(packet: OutgoingPacket) = socket.sendPacket(packet)
|
||||
|
||||
internal inner class BotSocketAdapter(override val serverIp: String) :
|
||||
DataPacketSocketAdapter {
|
||||
|
||||
@ -255,7 +252,7 @@ internal class TIMBotNetworkHandler internal constructor(coroutineContext: Corou
|
||||
loginHandler?.onPacketReceived(packet)
|
||||
}
|
||||
|
||||
override suspend fun sendPacket(packet: OutgoingPacket): Unit = withContext(coroutineContext + CoroutineName("sendPacket")) {
|
||||
internal suspend fun sendPacket(packet: OutgoingPacket): Unit = withContext(coroutineContext + CoroutineName("sendPacket")) {
|
||||
check(channel.isOpen) { "channel is not open" }
|
||||
|
||||
if (BeforePacketSendEvent(bot, packet).broadcast().cancelled) {
|
||||
|
@ -8,6 +8,7 @@ import net.mamoe.mirai.event.events.ServerPacketReceivedEvent
|
||||
import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
||||
|
||||
/**
|
||||
@ -36,14 +37,5 @@ interface DataPacketSocketAdapter : Closeable {
|
||||
*/
|
||||
val isOpen: Boolean
|
||||
|
||||
/**
|
||||
* 发送一个数据包(非异步).
|
||||
*
|
||||
* 可通过 hook 事件 [ServerPacketReceivedEvent] 来获取服务器返回.
|
||||
*
|
||||
* @see [BotSession.sendAndExpectAsync] kotlin DSL
|
||||
*/
|
||||
suspend fun sendPacket(packet: OutgoingPacket)
|
||||
|
||||
override fun close()
|
||||
}
|
@ -7,6 +7,7 @@ import kotlinx.coroutines.withContext
|
||||
import net.mamoe.mirai.network.BotSession
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.Packet
|
||||
import net.mamoe.mirai.network.sendPacket
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@ -23,7 +24,7 @@ import kotlin.reflect.KClass
|
||||
*
|
||||
* @see BotSession.sendAndExpectAsync
|
||||
*/
|
||||
class TemporaryPacketHandler<P : Packet, R>(
|
||||
internal class TemporaryPacketHandler<P : Packet, R>(
|
||||
private val expectationClass: KClass<P>,
|
||||
private val deferred: CompletableDeferred<R>,
|
||||
private val fromSession: BotSession,
|
||||
@ -40,24 +41,26 @@ class TemporaryPacketHandler<P : Packet, R>(
|
||||
lateinit var session: BotSession//无需覆盖
|
||||
|
||||
|
||||
fun toSend(packet: OutgoingPacket) {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun toSend(packet: OutgoingPacket) {
|
||||
this.toSend = packet
|
||||
}
|
||||
|
||||
fun onExpect(handler: suspend (P) -> R) {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
inline fun onExpect(noinline handler: suspend (P) -> R) {
|
||||
this.handler = handler
|
||||
}
|
||||
|
||||
internal suspend fun send(session: BotSession) {
|
||||
require(::handler.isInitialized) { "handler is not initialized" }
|
||||
internal suspend inline fun send(session: BotSession) {
|
||||
this.session = session
|
||||
session.socket.sendPacket(toSend)
|
||||
session.sendPacket(toSend)
|
||||
}
|
||||
|
||||
internal fun filter(session: BotSession, packet: Packet, sequenceId: UShort): Boolean =
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun filter(session: BotSession, packet: Packet, sequenceId: UShort): Boolean =
|
||||
expectationClass.isInstance(packet) && session === this.fromSession && if (checkSequence) sequenceId == toSend.sequenceId else true
|
||||
|
||||
internal suspend fun doReceiveWithoutExceptions(packet: Packet) {
|
||||
internal suspend inline fun doReceiveWithoutExceptions(packet: Packet) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val ret = try {
|
||||
withContext(callerContext) {
|
||||
@ -68,6 +71,5 @@ class TemporaryPacketHandler<P : Packet, R>(
|
||||
return
|
||||
}
|
||||
deferred.complete(ret)
|
||||
return
|
||||
}
|
||||
}
|
@ -9,11 +9,11 @@ package net.mamoe.mirai.network.protocol.tim.packet
|
||||
@MustBeDocumented
|
||||
@Retention(AnnotationRetention.RUNTIME)
|
||||
@Target(AnnotationTarget.CLASS)
|
||||
annotation class AnnotatedId( // 注解无法在 JS 平台使用, 但现在暂不需要考虑 JS
|
||||
internal annotation class AnnotatedId( // 注解无法在 JS 平台使用, 但现在暂不需要考虑 JS
|
||||
val id: KnownPacketId
|
||||
)
|
||||
|
||||
inline val AnnotatedId.value: UShort get() = id.value
|
||||
internal inline val AnnotatedId.value: UShort get() = id.value
|
||||
|
||||
/**
|
||||
* 包的最后一次修改时间, 和分析时使用的 TIM 版本
|
||||
|
@ -8,14 +8,14 @@ import net.mamoe.mirai.utils.decryptBy
|
||||
/**
|
||||
* 会话密匙
|
||||
*/
|
||||
inline class SessionKey(override val value: ByteArray) : DecrypterByteArray {
|
||||
internal inline class SessionKey(override val value: ByteArray) : DecrypterByteArray {
|
||||
companion object Type : DecrypterType<SessionKey>
|
||||
}
|
||||
|
||||
/**
|
||||
* [ByteArray] 解密器
|
||||
*/
|
||||
interface DecrypterByteArray : Decrypter {
|
||||
internal interface DecrypterByteArray : Decrypter {
|
||||
val value: ByteArray
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value)
|
||||
}
|
||||
@ -23,7 +23,7 @@ interface DecrypterByteArray : Decrypter {
|
||||
/**
|
||||
* [IoBuffer] 解密器
|
||||
*/
|
||||
interface DecrypterIoBuffer : Decrypter {
|
||||
internal interface DecrypterIoBuffer : Decrypter {
|
||||
val value: IoBuffer
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(value)
|
||||
}
|
||||
@ -31,18 +31,18 @@ interface DecrypterIoBuffer : Decrypter {
|
||||
/**
|
||||
* 连接在一起的解密器
|
||||
*/
|
||||
inline class LinkedDecrypter(inline val block: (ByteReadPacket) -> ByteReadPacket) : Decrypter {
|
||||
internal inline class LinkedDecrypter(inline val block: (ByteReadPacket) -> ByteReadPacket) : Decrypter {
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket = block(input)
|
||||
}
|
||||
|
||||
object NoDecrypter : Decrypter, DecrypterType<NoDecrypter> {
|
||||
internal object NoDecrypter : Decrypter, DecrypterType<NoDecrypter> {
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input
|
||||
}
|
||||
|
||||
/**
|
||||
* 解密器
|
||||
*/
|
||||
interface Decrypter {
|
||||
internal interface Decrypter {
|
||||
fun decrypt(input: ByteReadPacket): ByteReadPacket
|
||||
/**
|
||||
* 连接后将会先用 this 解密, 再用 [another] 解密
|
||||
@ -50,4 +50,4 @@ interface Decrypter {
|
||||
operator fun plus(another: Decrypter): Decrypter = LinkedDecrypter { another.decrypt(this.decrypt(it)) }
|
||||
}
|
||||
|
||||
interface DecrypterType<D : Decrypter>
|
||||
internal interface DecrypterType<D : Decrypter>
|
@ -18,7 +18,7 @@ import kotlin.jvm.JvmOverloads
|
||||
/**
|
||||
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket],
|
||||
*/
|
||||
class OutgoingPacket(
|
||||
internal class OutgoingPacket(
|
||||
name: String?,
|
||||
val packetId: PacketId,
|
||||
val sequenceId: UShort,
|
||||
@ -35,7 +35,7 @@ class OutgoingPacket(
|
||||
*
|
||||
* @param TPacket invariant
|
||||
*/
|
||||
abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<TPacket, SessionKey>(SessionKey) {
|
||||
internal abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<TPacket, SessionKey>(SessionKey) {
|
||||
/**
|
||||
* 在 [BotNetworkHandler] 下处理这个包. 广播事件等.
|
||||
*/
|
||||
@ -49,7 +49,7 @@ abstract class SessionPacketFactory<TPacket : Packet> : PacketFactory<TPacket, S
|
||||
*/
|
||||
@UseExperimental(ExperimentalContracts::class)
|
||||
@JvmOverloads
|
||||
inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
||||
internal inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
||||
name: String? = null,
|
||||
id: PacketId = this.id,
|
||||
sequenceId: UShort = PacketFactory.atomicNextSequenceId(),
|
||||
@ -81,7 +81,7 @@ inline fun PacketFactory<*, *>.buildOutgoingPacket(
|
||||
*/
|
||||
@UseExperimental(ExperimentalContracts::class)
|
||||
@JvmOverloads
|
||||
inline fun PacketFactory<*, *>.buildSessionPacket(
|
||||
internal inline fun PacketFactory<*, *>.buildSessionPacket(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
name: String? = null,
|
||||
@ -110,7 +110,7 @@ inline fun PacketFactory<*, *>.buildSessionPacket(
|
||||
*/
|
||||
@UseExperimental(ExperimentalContracts::class)
|
||||
@JvmOverloads
|
||||
fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
|
||||
internal fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
name: String? = null,
|
||||
@ -142,7 +142,18 @@ fun <T> PacketFactory<*, *>.buildSessionProtoPacket(
|
||||
writeFully(head)
|
||||
writeFully(proto)
|
||||
}
|
||||
is String -> buildSessionProtoPacket(bot, sessionKey, name, id, sequenceId, headerSizeHint, version, head.hexToBytes(), serializer, protoObj)
|
||||
is String -> buildSessionProtoPacket(
|
||||
bot,
|
||||
sessionKey,
|
||||
name,
|
||||
id,
|
||||
sequenceId,
|
||||
headerSizeHint,
|
||||
version,
|
||||
head.hexToBytes(),
|
||||
serializer,
|
||||
protoObj
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,18 +12,18 @@ interface Packet
|
||||
/**
|
||||
* 被忽略的数据包.
|
||||
*/
|
||||
inline class IgnoredPacket(val id: PacketId) : Packet
|
||||
internal inline class IgnoredPacket(internal val id: PacketId) : Packet
|
||||
|
||||
/**
|
||||
* 未知的包.
|
||||
*/
|
||||
class UnknownPacket(val id: PacketId, val body: ByteReadPacket) : Packet {
|
||||
internal class UnknownPacket(val id: PacketId, val body: ByteReadPacket) : Packet {
|
||||
override fun toString(): String = "UnknownPacket(${id.value.toUHexString()})\nbody=${body.readBytes().toUHexString()}"
|
||||
}
|
||||
|
||||
/**
|
||||
* 仅用于替换类型应为 [Unit] 的情况
|
||||
*/
|
||||
object NoPacket : Packet {
|
||||
internal object NoPacket : Packet {
|
||||
override fun toString(): String = "NoPacket"
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import kotlinx.io.pool.useInstance
|
||||
import kotlinx.serialization.DeserializationStrategy
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||
import net.mamoe.mirai.utils.io.debugPrint
|
||||
import net.mamoe.mirai.utils.io.read
|
||||
@ -23,7 +24,7 @@ import net.mamoe.mirai.utils.readProtoMap
|
||||
* @param TPacket 服务器回复包解析结果
|
||||
* @param TDecrypter 服务器回复包解密器
|
||||
*/
|
||||
abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
|
||||
internal abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val decrypterType: DecrypterType<TDecrypter>) {
|
||||
|
||||
/**
|
||||
* 2 Ubyte.
|
||||
@ -46,7 +47,10 @@ abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val d
|
||||
abstract suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): TPacket
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
fun <T> ByteReadPacket.decodeProtoPacket(deserializer: DeserializationStrategy<T>, debuggingTag: String? = null): T {
|
||||
fun <T> ByteReadPacket.decodeProtoPacket(
|
||||
deserializer: DeserializationStrategy<T>,
|
||||
debuggingTag: String? = null
|
||||
): T {
|
||||
val headLength = readInt()
|
||||
val protoLength = readInt()
|
||||
if (debuggingTag != null) {
|
||||
@ -72,7 +76,7 @@ abstract class PacketFactory<out TPacket : Packet, TDecrypter : Decrypter>(val d
|
||||
}
|
||||
}
|
||||
|
||||
object UnknownPacketFactory : SessionPacketFactory<UnknownPacket>() {
|
||||
internal object UnknownPacketFactory : SessionPacketFactory<UnknownPacket>() {
|
||||
override suspend fun BotNetworkHandler<*>.handlePacket(packet: UnknownPacket) {
|
||||
ByteArrayPool.useInstance {
|
||||
packet.body.readAvailable(it)
|
||||
@ -81,11 +85,19 @@ object UnknownPacketFactory : SessionPacketFactory<UnknownPacket>() {
|
||||
packet.body.close()
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): UnknownPacket {
|
||||
override suspend fun ByteReadPacket.decode(
|
||||
id: PacketId,
|
||||
sequenceId: UShort,
|
||||
handler: BotNetworkHandler<*>
|
||||
): UnknownPacket {
|
||||
return UnknownPacket(id, this)
|
||||
}
|
||||
}
|
||||
|
||||
object IgnoredPacketFactory : SessionPacketFactory<IgnoredPacket>() {
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): IgnoredPacket = IgnoredPacket(id)
|
||||
internal object IgnoredPacketFactory : SessionPacketFactory<IgnoredPacket>() {
|
||||
override suspend fun ByteReadPacket.decode(
|
||||
id: PacketId,
|
||||
sequenceId: UShort,
|
||||
handler: BotNetworkHandler<*>
|
||||
): IgnoredPacket = IgnoredPacket(id)
|
||||
}
|
@ -12,13 +12,13 @@ import net.mamoe.mirai.utils.io.toUHexString
|
||||
/**
|
||||
* 通过 [value] 匹配一个 [IgnoredPacketId] 或 [KnownPacketId], 无匹配则返回一个 [UnknownPacketId].
|
||||
*/
|
||||
fun matchPacketId(value: UShort): PacketId =
|
||||
internal fun matchPacketId(value: UShort): PacketId =
|
||||
IgnoredPacketIds.firstOrNull { it.value == value } ?: KnownPacketId.values().firstOrNull { it.value == value } ?: UnknownPacketId(value)
|
||||
|
||||
/**
|
||||
* 包 ID.
|
||||
*/
|
||||
interface PacketId {
|
||||
internal interface PacketId {
|
||||
val value: UShort
|
||||
val factory: PacketFactory<*, *>
|
||||
}
|
||||
@ -27,7 +27,7 @@ interface PacketId {
|
||||
* 用于代表 `null`. 调用任何属性时都将会得到一个 [error]
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object NullPacketId : PacketId {
|
||||
internal object NullPacketId : PacketId {
|
||||
override val factory: PacketFactory<*, *> get() = error("uninitialized")
|
||||
override val value: UShort get() = error("uninitialized")
|
||||
override fun toString(): String = "NullPacketId"
|
||||
@ -36,17 +36,17 @@ object NullPacketId : PacketId {
|
||||
/**
|
||||
* 未知的 [PacketId]
|
||||
*/
|
||||
inline class UnknownPacketId(override inline val value: UShort) : PacketId {
|
||||
internal inline class UnknownPacketId(override inline val value: UShort) : PacketId {
|
||||
override val factory: PacketFactory<*, *> get() = UnknownPacketFactory
|
||||
override fun toString(): String = "UnknownPacketId(${value.toUHexString()})"
|
||||
}
|
||||
|
||||
object IgnoredPacketIds : List<IgnoredPacketId> by {
|
||||
internal object IgnoredPacketIds : List<IgnoredPacketId> by {
|
||||
listOf<UShort>(
|
||||
).map { IgnoredPacketId(it.toUShort()) }
|
||||
}()
|
||||
|
||||
inline class IgnoredPacketId constructor(override val value: UShort) : PacketId {
|
||||
internal inline class IgnoredPacketId constructor(override val value: UShort) : PacketId {
|
||||
override val factory: PacketFactory<*, *> get() = IgnoredPacketFactory
|
||||
override fun toString(): String = "IgnoredPacketId(${value.toUHexString()})"
|
||||
}
|
||||
@ -55,7 +55,7 @@ inline class IgnoredPacketId constructor(override val value: UShort) : PacketId
|
||||
* 已知的 [matchPacketId]. 所有在 Mirai 中实现过的包都会使用这些 Id
|
||||
*/
|
||||
@Suppress("unused")
|
||||
enum class KnownPacketId(override inline val value: UShort, override inline val factory: PacketFactory<*, *>) :
|
||||
internal enum class KnownPacketId(override inline val value: UShort, override inline val factory: PacketFactory<*, *>) :
|
||||
PacketId {
|
||||
inline TOUCH(0x0825u, TouchPacket),
|
||||
inline SESSION_KEY(0x0828u, RequestSessionPacket),
|
||||
|
@ -21,7 +21,7 @@ import net.mamoe.mirai.withSession
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.QUERY_PREVIOUS_NAME)
|
||||
@PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
|
||||
object QueryPreviousNamePacket : SessionPacketFactory<PreviousNameList>() {
|
||||
internal object QueryPreviousNamePacket : SessionPacketFactory<PreviousNameList>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
@ -79,7 +79,7 @@ class PreviousNameList(
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.CAN_ADD_FRIEND)
|
||||
@PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
|
||||
object CanAddFriendPacket : SessionPacketFactory<CanAddFriendResponse>() {
|
||||
internal object CanAddFriendPacket : SessionPacketFactory<CanAddFriendResponse>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
qq: UInt,
|
||||
@ -112,7 +112,7 @@ object CanAddFriendPacket : SessionPacketFactory<CanAddFriendResponse>() {
|
||||
|
||||
}
|
||||
|
||||
sealed class CanAddFriendResponse : EventPacket {
|
||||
internal sealed class CanAddFriendResponse : EventPacket {
|
||||
abstract val qq: QQ
|
||||
|
||||
/**
|
||||
@ -157,7 +157,7 @@ inline class FriendAdditionKey(val value: IoBuffer)
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.REQUEST_FRIEND_ADDITION_KEY)
|
||||
@PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
|
||||
object RequestFriendAdditionKeyPacket : SessionPacketFactory<RequestFriendAdditionKeyPacket.Response>() {
|
||||
internal object RequestFriendAdditionKeyPacket : SessionPacketFactory<RequestFriendAdditionKeyPacket.Response>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
qq: UInt,
|
||||
@ -183,8 +183,9 @@ object RequestFriendAdditionKeyPacket : SessionPacketFactory<RequestFriendAdditi
|
||||
* 请求添加好友
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.ADD_FRIEND)
|
||||
object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
internal object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
@PacketVersion(date = "2019.11.11", timVersion = "2.3.2 (21173)")
|
||||
@Suppress("FunctionName")
|
||||
fun RequestAdd(
|
||||
bot: UInt,
|
||||
qq: UInt,
|
||||
@ -198,7 +199,7 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
*/
|
||||
remark: String?, //// TODO: 2019/11/15 无备注的情况
|
||||
key: FriendAdditionKey
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey) {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "AddFriendPacket.RequestAdd") {
|
||||
|
||||
//02 5D 12 93 30
|
||||
// 00
|
||||
@ -264,7 +265,7 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
* 备注. 不设置则需要为 `null` TODO 需要确认是否还需发送一个设置备注包. 因为测试时若有备注则会多发一个包并且包里面有所设置的备注
|
||||
*/
|
||||
remark: String?
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x02) {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x02, name = "AddFriendPacket.Approve") {
|
||||
writeByte(0x03)
|
||||
writeQQ(qq)
|
||||
writeZero(1)
|
||||
@ -282,7 +283,7 @@ object AddFriendPacket : SessionPacketFactory<AddFriendPacket.Response>() {
|
||||
writeHex("00 05 00 00 00 00 01")
|
||||
}
|
||||
|
||||
object Response : Packet {
|
||||
internal object Response : Packet {
|
||||
override fun toString(): String = "AddFriendPacket.Response"
|
||||
}
|
||||
|
||||
|
@ -29,31 +29,30 @@ import net.mamoe.mirai.withSession
|
||||
* @throws OverFileSizeMaxException 如果文件过大, 服务器拒绝接收时
|
||||
*/
|
||||
suspend fun QQ.uploadImage(image: ExternalImage): ImageId = bot.withSession {
|
||||
FriendImagePacket.RequestImageId(qqAccount, sessionKey, id, image)
|
||||
.sendAndExpectAsync<FriendImageResponse, ImageId> {
|
||||
return@sendAndExpectAsync when (it) {
|
||||
is FriendImageUKey -> {
|
||||
Http.postImage(
|
||||
htcmd = "0x6ff0070",
|
||||
uin = bot.qqAccount,
|
||||
groupId = null,
|
||||
uKeyHex = it.uKey.toUHexString(""),
|
||||
imageInput = image.input,
|
||||
inputSize = image.inputSize
|
||||
)
|
||||
it.imageId
|
||||
}
|
||||
is FriendImageAlreadyExists -> it.imageId
|
||||
is FriendImageOverFileSizeMax -> throw OverFileSizeMaxException()
|
||||
else -> error("This shouldn't happen")
|
||||
FriendImagePacket.RequestImageId(qqAccount, sessionKey, id, image).sendAndExpect<FriendImageResponse>().let {
|
||||
when (it) {
|
||||
is FriendImageUKey -> {
|
||||
Http.postImage(
|
||||
htcmd = "0x6ff0070",
|
||||
uin = bot.qqAccount,
|
||||
groupId = null,
|
||||
uKeyHex = it.uKey.toUHexString(""),
|
||||
imageInput = image.input,
|
||||
inputSize = image.inputSize
|
||||
)
|
||||
it.imageId
|
||||
}
|
||||
}.await()
|
||||
is FriendImageAlreadyExists -> it.imageId
|
||||
is FriendImageOverFileSizeMax -> throw OverFileSizeMaxException()
|
||||
else -> error("This shouldn't happen")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// region FriendImageResponse
|
||||
|
||||
interface FriendImageResponse : EventPacket
|
||||
internal interface FriendImageResponse : EventPacket
|
||||
|
||||
/**
|
||||
* 图片数据地址.
|
||||
@ -66,7 +65,7 @@ data class FriendImageLink(override inline val original: String) : FriendImageRe
|
||||
/**
|
||||
* 访问 HTTP API 时使用的 uKey
|
||||
*/
|
||||
class FriendImageUKey(inline val imageId: ImageId, inline val uKey: ByteArray) : FriendImageResponse {
|
||||
internal class FriendImageUKey(inline val imageId: ImageId, inline val uKey: ByteArray) : FriendImageResponse {
|
||||
override fun toString(): String = "FriendImageUKey(imageId=${imageId.value}, uKey=${uKey.toUHexString()})"
|
||||
}
|
||||
|
||||
@ -74,14 +73,14 @@ class FriendImageUKey(inline val imageId: ImageId, inline val uKey: ByteArray) :
|
||||
* 图片 ID 已存在
|
||||
* 发送消息时使用的 id
|
||||
*/
|
||||
inline class FriendImageAlreadyExists(inline val imageId: ImageId) : FriendImageResponse {
|
||||
internal inline class FriendImageAlreadyExists(inline val imageId: ImageId) : FriendImageResponse {
|
||||
override fun toString(): String = "FriendImageAlreadyExists(imageId=${imageId.value})"
|
||||
}
|
||||
|
||||
/**
|
||||
* 超过文件大小上限
|
||||
*/
|
||||
object FriendImageOverFileSizeMax : FriendImageResponse {
|
||||
internal object FriendImageOverFileSizeMax : FriendImageResponse {
|
||||
override fun toString(): String = "FriendImageOverFileSizeMax"
|
||||
}
|
||||
|
||||
@ -95,14 +94,19 @@ object FriendImageOverFileSizeMax : FriendImageResponse {
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.FRIEND_IMAGE_ID)
|
||||
@PacketVersion(date = "2019.11.16", timVersion = "2.3.2 (21173)")
|
||||
object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
internal object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
@Suppress("FunctionName")
|
||||
fun RequestImageId(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
target: UInt,
|
||||
image: ExternalImage
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x04) {
|
||||
): OutgoingPacket = buildSessionPacket(
|
||||
bot,
|
||||
sessionKey,
|
||||
version = TIMProtocol.version0x04,
|
||||
name = "FriendImagePacket.RequestPacketId"
|
||||
) {
|
||||
writeHex("00 00 00 07 00 00")
|
||||
|
||||
|
||||
@ -186,7 +190,12 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
|
||||
// TODO: 2019/11/22 should be ProtoBuf
|
||||
|
||||
return buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x04) {
|
||||
return buildSessionPacket(
|
||||
bot,
|
||||
sessionKey,
|
||||
version = TIMProtocol.version0x04,
|
||||
name = "FriendImagePacket.RequestImageLink"
|
||||
) {
|
||||
writeHex("00 00 00 07 00 00")
|
||||
|
||||
writeUShort(0x004Bu)
|
||||
@ -206,7 +215,11 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): FriendImageResponse {
|
||||
override suspend fun ByteReadPacket.decode(
|
||||
id: PacketId,
|
||||
sequenceId: UShort,
|
||||
handler: BotNetworkHandler<*>
|
||||
): FriendImageResponse {
|
||||
|
||||
// 上传图片, 成功获取ID
|
||||
//00 00 00 08 00 00
|
||||
@ -304,7 +317,6 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
// 3A 00 80 01 00
|
||||
|
||||
|
||||
|
||||
//00 00 00 08 00 00
|
||||
// [02 29]
|
||||
// 12 [06] 98 01 02 A0 01 00
|
||||
|
@ -17,7 +17,7 @@ import net.mamoe.mirai.utils.io.writeQQ
|
||||
* @author Him188moe
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.ACCOUNT_INFO)
|
||||
object RequestAccountInfoPacket : SessionPacketFactory<RequestAccountInfoPacket.Response>() {
|
||||
internal object RequestAccountInfoPacket : SessionPacketFactory<RequestAccountInfoPacket.Response>() {
|
||||
operator fun invoke(
|
||||
qq: UInt,
|
||||
sessionKey: SessionKey
|
||||
|
@ -21,7 +21,6 @@ import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.Http
|
||||
import net.mamoe.mirai.utils.assertUnreachable
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
|
||||
/**
|
||||
@ -58,13 +57,13 @@ suspend fun Group.uploadImage(image: ExternalImage): ImageId = withSession {
|
||||
return image.groupImageId
|
||||
}
|
||||
|
||||
interface GroupImageResponse : EventPacket
|
||||
internal interface GroupImageResponse : EventPacket
|
||||
|
||||
// endregion
|
||||
|
||||
@Suppress("unused")
|
||||
@Serializable
|
||||
class ImageDownloadInfo(
|
||||
class GroupImageLink(
|
||||
@SerialId(3) val errorCode: Int = 0, // 0 for success
|
||||
@SerialId(4) val errorMessage: String? = null, // 感动中国
|
||||
|
||||
@ -84,13 +83,14 @@ class ImageDownloadInfo(
|
||||
override fun toString(): String = "ImageDownloadInfo(${_original?.let { original } ?: errorMessage ?: "unknown"})"
|
||||
}
|
||||
|
||||
fun ImageDownloadInfo.requireSuccess(): ImageDownloadInfo {
|
||||
@Suppress("NOTHING_TO_INLINE")
|
||||
internal inline fun GroupImageLink.requireSuccess(): GroupImageLink {
|
||||
require(this.errorCode == 0) { this.errorMessage ?: "null" }
|
||||
return this
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ImageUploadInfo(
|
||||
internal class ImageUploadInfo(
|
||||
@SerialId(8) val uKey: ByteArray? = null
|
||||
) : GroupImageResponse {
|
||||
override fun toString(): String = "ImageUploadInfo(uKey=${uKey?.toUHexString()})"
|
||||
@ -101,7 +101,7 @@ class ImageUploadInfo(
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.GROUP_IMAGE_ID)
|
||||
@PacketVersion(date = "2019.11.22", timVersion = "2.3.2 (21173)")
|
||||
object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
internal object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
|
||||
private val constValue3 = byteArrayOf(
|
||||
0x28, 0x00, 0x5A, 0x00, 0x53, 0x00, 0x41, 0x00, 0x58, 0x00, 0x40, 0x00, 0x57,
|
||||
@ -115,7 +115,7 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
@SerialId(3) var body: Body
|
||||
) {
|
||||
@Serializable
|
||||
class Body(
|
||||
internal class Body(
|
||||
@SerialId(1) val group: Int,
|
||||
@SerialId(2) val bot: Int,
|
||||
@SerialId(3) val const1: Byte = 0,
|
||||
@ -142,7 +142,7 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
@SerialId(4) var body: Body
|
||||
) {
|
||||
@Serializable
|
||||
class Body(
|
||||
internal class Body(
|
||||
@SerialId(1) val group: Int,
|
||||
@SerialId(2) val bot: Int,
|
||||
@SerialId(3) val uniqueId: Int,
|
||||
@ -226,13 +226,13 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
@Serializable
|
||||
data class GroupImageResponseProto(
|
||||
@SerialId(3) val imageUploadInfoPacket: ImageUploadInfo? = null,
|
||||
@SerialId(4) val imageDownloadInfo: ImageDownloadInfo? = null
|
||||
@SerialId(4) val groupImageLink: GroupImageLink? = null
|
||||
)
|
||||
|
||||
val proto = decodeProtoPacket(GroupImageResponseProto.serializer())
|
||||
return when {
|
||||
proto.imageUploadInfoPacket != null -> proto.imageUploadInfoPacket
|
||||
proto.imageDownloadInfo != null -> proto.imageDownloadInfo
|
||||
proto.groupImageLink != null -> proto.groupImageLink
|
||||
else -> assertUnreachable()
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.contact.internal.MemberImpl
|
||||
import net.mamoe.mirai.contact.internal.Member
|
||||
import net.mamoe.mirai.message.MessageChain
|
||||
import net.mamoe.mirai.message.internal.toPacket
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
@ -32,10 +32,11 @@ class GroupInfo(
|
||||
val announcement: String get() = _announcement
|
||||
val members: ContactList<Member> get() = _members
|
||||
|
||||
override fun toString(): String = "GroupInfo(id=${group.id}, owner=$owner, name=$name, announcement=$announcement, members=${members.idContentString}"
|
||||
override fun toString(): String =
|
||||
"GroupInfo(id=${group.id}, owner=$owner, name=$name, announcement=$announcement, members=${members.idContentString}"
|
||||
}
|
||||
|
||||
data class RawGroupInfo(
|
||||
internal data class RawGroupInfo(
|
||||
val group: UInt,
|
||||
val owner: UInt,
|
||||
val name: String,
|
||||
@ -49,10 +50,12 @@ data class RawGroupInfo(
|
||||
suspend inline fun parseBy(group: Group): GroupInfo = group.bot.withSession {
|
||||
return GroupInfo(
|
||||
group,
|
||||
MemberImpl(this@RawGroupInfo.owner.qq(), group, MemberPermission.OWNER),
|
||||
this@RawGroupInfo.owner.qq().let { Member(it, group, MemberPermission.OWNER, it.coroutineContext) },
|
||||
this@RawGroupInfo.name,
|
||||
this@RawGroupInfo.announcement,
|
||||
ContactList(this@RawGroupInfo.members.mapValuesTo(MutableContactList()) { MemberImpl(it.key.qq(), group, it.value) })
|
||||
ContactList(this@RawGroupInfo.members.mapValuesTo(MutableContactList()) { entry: Map.Entry<UInt, MemberPermission> ->
|
||||
entry.key.qq().let { Member(it,group, entry.value, it.coroutineContext) }
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -69,14 +72,14 @@ inline class QuitGroupResponse(private val _group: GroupInternalId?) : Packet, G
|
||||
|
||||
@Suppress("FunctionName")
|
||||
@AnnotatedId(KnownPacketId.GROUP_PACKET)
|
||||
object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
internal object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
fun Message(
|
||||
bot: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
sessionKey: SessionKey,
|
||||
message: MessageChain
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupMessage") {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupPacket.GroupMessage") {
|
||||
writeUByte(0x2Au)
|
||||
writeGroup(groupInternalId)
|
||||
|
||||
@ -102,7 +105,7 @@ object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
group: GroupInternalId
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey) {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupPacket.QuitGroup") {
|
||||
writeUByte(0x09u)
|
||||
writeGroup(group)
|
||||
}
|
||||
@ -115,7 +118,7 @@ object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
bot: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
sessionKey: SessionKey
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "QueryGroupInfo", headerSizeHint = 9) {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupPacket.QueryGroupInfo", headerSizeHint = 9) {
|
||||
writeUByte(0x72u)
|
||||
writeGroup(groupInternalId)
|
||||
writeZero(4)
|
||||
@ -134,7 +137,7 @@ object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
* 0 为取消
|
||||
*/
|
||||
timeSeconds: UInt
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "MuteMember") {
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, name = "GroupPacket.Mute") {
|
||||
writeUByte(0x7Eu)
|
||||
writeGroup(groupInternalId)
|
||||
writeByte(0x20)
|
||||
@ -144,21 +147,25 @@ object GroupPacket : SessionPacketFactory<GroupPacket.GroupPacketResponse>() {
|
||||
writeUInt(timeSeconds)
|
||||
}
|
||||
|
||||
interface GroupPacketResponse : Packet
|
||||
internal interface GroupPacketResponse : Packet
|
||||
|
||||
@NoLog
|
||||
object MessageResponse : Packet, GroupPacketResponse {
|
||||
internal object MessageResponse : Packet, GroupPacketResponse {
|
||||
override fun toString(): String = "GroupPacket.MessageResponse"
|
||||
}
|
||||
|
||||
@NoLog
|
||||
object MuteResponse : Packet, GroupPacketResponse {
|
||||
internal object MuteResponse : Packet, GroupPacketResponse {
|
||||
override fun toString(): String = "GroupPacket.MuteResponse"
|
||||
}
|
||||
|
||||
@PacketVersion(date = "2019.11.27", timVersion = "2.3.2 (21173)")
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupPacketResponse {
|
||||
override suspend fun ByteReadPacket.decode(
|
||||
id: PacketId,
|
||||
sequenceId: UShort,
|
||||
handler: BotNetworkHandler<*>
|
||||
): GroupPacketResponse {
|
||||
return when (readUByte().toUInt()) {
|
||||
0x2Au -> MessageResponse
|
||||
0x7Eu -> MuteResponse // 成功: 7E 00 22 96 29 7B;
|
||||
|
@ -15,7 +15,7 @@ import net.mamoe.mirai.utils.io.*
|
||||
* 请求获取头像
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.REQUEST_PROFILE_AVATAR)
|
||||
object RequestProfileAvatarPacket : SessionPacketFactory<NoPacket>() {
|
||||
internal object RequestProfileAvatarPacket : SessionPacketFactory<NoPacket>() {
|
||||
//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(
|
||||
bot: UInt,
|
||||
@ -39,7 +39,7 @@ object RequestProfileAvatarPacket : SessionPacketFactory<NoPacket>() {
|
||||
* @see Profile
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.REQUEST_PROFILE_DETAILS)
|
||||
object RequestProfileDetailsPacket : SessionPacketFactory<RequestProfileDetailsResponse>() {
|
||||
internal object RequestProfileDetailsPacket : SessionPacketFactory<RequestProfileDetailsResponse>() {
|
||||
//00 01 3E F8 FB E3 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 B1 89 BE 09 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 87 73 86 9D 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
|
||||
@ -91,7 +91,7 @@ object RequestProfileDetailsPacket : SessionPacketFactory<RequestProfileDetailsR
|
||||
}
|
||||
|
||||
@AnnotatedId(KnownPacketId.REQUEST_PROFILE_DETAILS)
|
||||
data class RequestProfileDetailsResponse(
|
||||
internal data class RequestProfileDetailsResponse(
|
||||
val qq: UInt,
|
||||
val profile: Profile
|
||||
) : Packet {
|
||||
|
@ -16,7 +16,7 @@ import net.mamoe.mirai.utils.io.writeZero
|
||||
inline class FriendNameRemark(val value: String) : Packet
|
||||
|
||||
@AnnotatedId(KnownPacketId.QUERY_FRIEND_REMARK)
|
||||
object QueryFriendRemarkPacket : SessionPacketFactory<FriendNameRemark>() {
|
||||
internal object QueryFriendRemarkPacket : SessionPacketFactory<FriendNameRemark>() {
|
||||
/**
|
||||
* 查询好友的备注
|
||||
*/
|
||||
|
@ -11,7 +11,7 @@ import net.mamoe.mirai.utils.io.writeZero
|
||||
class FriendList : Packet
|
||||
|
||||
@PacketVersion(date = "2019.11.24", timVersion = "2.3.2 (21173)")
|
||||
object RequestFriendListPacket : SessionPacketFactory<FriendList>() {
|
||||
internal object RequestFriendListPacket : SessionPacketFactory<FriendList>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey
|
||||
|
@ -13,7 +13,7 @@ import net.mamoe.mirai.utils.md5
|
||||
|
||||
@AnnotatedId(KnownPacketId.SEND_FRIEND_MESSAGE)
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
object SendFriendMessagePacket : SessionPacketFactory<SendFriendMessagePacket.Response>() {
|
||||
internal object SendFriendMessagePacket : SessionPacketFactory<SendFriendMessagePacket.Response>() {
|
||||
operator fun invoke(
|
||||
botQQ: UInt,
|
||||
targetQQ: UInt,
|
||||
@ -65,7 +65,7 @@ object SendFriendMessagePacket : SessionPacketFactory<SendFriendMessagePacket.Re
|
||||
}
|
||||
|
||||
@NoLog
|
||||
object Response : Packet {
|
||||
internal object Response : Packet {
|
||||
override fun toString(): String = "SendFriendMessagePacket.Response"
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.network.sessionKey
|
||||
import net.mamoe.mirai.qqAccount
|
||||
@ -13,7 +14,7 @@ import net.mamoe.mirai.utils.io.readIoBuffer
|
||||
/**
|
||||
* 事件的识别 ID. 在 ACK 时使用
|
||||
*/
|
||||
class EventPacketIdentity(
|
||||
internal class EventPacketIdentity(
|
||||
val from: UInt,//对于好友消息, 这个是发送人
|
||||
val to: UInt,//对于好友消息, 这个是bot
|
||||
internal val uniqueId: IoBuffer//8
|
||||
@ -21,7 +22,7 @@ class EventPacketIdentity(
|
||||
override fun toString(): String = "($from->$to)"
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
|
||||
internal fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) = with(identity) {
|
||||
writeUInt(from)
|
||||
writeUInt(to)
|
||||
writeFully(uniqueId)
|
||||
@ -29,7 +30,7 @@ fun BytePacketBuilder.writeEventPacketIdentity(identity: EventPacketIdentity) =
|
||||
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun matchEventPacketFactory(value: UShort): EventParserAndHandler<*> =
|
||||
internal fun matchEventPacketFactory(value: UShort): EventParserAndHandler<*> =
|
||||
KnownEventParserAndHandler.firstOrNull { it.id == value } ?: IgnoredEventIds.firstOrNull { it.id == value } ?: UnknownEventParserAndHandler(value)
|
||||
|
||||
/**
|
||||
@ -37,14 +38,14 @@ fun matchEventPacketFactory(value: UShort): EventParserAndHandler<*> =
|
||||
*/
|
||||
@NoLog
|
||||
@Suppress("FunctionName")
|
||||
object EventPacketFactory : PacketFactory<Packet, SessionKey>(SessionKey) {
|
||||
internal object EventPacketFactory : PacketFactory<Packet, SessionKey>(SessionKey) {
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): Packet {
|
||||
val eventIdentity = EventPacketIdentity(
|
||||
from = readUInt(),
|
||||
to = readUInt(),
|
||||
uniqueId = readIoBuffer(8)
|
||||
)
|
||||
handler.sendPacket(EventPacketFactory(id, sequenceId, handler.bot.qqAccount, handler.sessionKey, eventIdentity))
|
||||
(handler as TIMBotNetworkHandler).socket.sendPacket(EventPacketFactory(id, sequenceId, handler.bot.qqAccount, handler.sessionKey, eventIdentity))
|
||||
discardExact(2) // 1F 40
|
||||
|
||||
return with(matchEventPacketFactory(readUShort())) { parse(handler.bot, eventIdentity) }.also {
|
||||
@ -75,7 +76,7 @@ object EventPacketFactory : PacketFactory<Packet, SessionKey>(SessionKey) {
|
||||
}
|
||||
}
|
||||
|
||||
interface EventParserAndHandler<TPacket : Packet> {
|
||||
internal interface EventParserAndHandler<TPacket : Packet> {
|
||||
val id: UShort
|
||||
|
||||
suspend fun ByteReadPacket.parse(bot: Bot, identity: EventPacketIdentity): TPacket
|
||||
@ -86,7 +87,7 @@ interface EventParserAndHandler<TPacket : Packet> {
|
||||
suspend fun BotNetworkHandler<*>.handlePacket(packet: TPacket) {}
|
||||
}
|
||||
|
||||
abstract class KnownEventParserAndHandler<TPacket : Packet>(override val id: UShort) : EventParserAndHandler<TPacket> {
|
||||
internal abstract class KnownEventParserAndHandler<TPacket : Packet>(override val id: UShort) : EventParserAndHandler<TPacket> {
|
||||
companion object FactoryList : MutableList<KnownEventParserAndHandler<*>> by mutableListOf(
|
||||
AndroidDeviceOnlineStatusChangedEventFactory,
|
||||
FriendConversationInitializedEventParserAndHandler,
|
||||
|
@ -24,7 +24,7 @@ data class FriendStatusChanged(
|
||||
* 好友在线状态改变
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.FRIEND_ONLINE_STATUS_CHANGE)
|
||||
object FriendOnlineStatusChangedPacket : SessionPacketFactory<FriendStatusChanged>() {
|
||||
internal object FriendOnlineStatusChangedPacket : SessionPacketFactory<FriendStatusChanged>() {
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): FriendStatusChanged {
|
||||
val qq = readUInt()
|
||||
|
@ -6,17 +6,17 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
|
||||
inline class IgnoredEventPacket(val id: UShort) : EventPacket {
|
||||
internal inline class IgnoredEventPacket(val id: UShort) : EventPacket {
|
||||
override fun toString(): String = "IgnoredEventPacket(id=0x${id.toUHexString("")})"
|
||||
}
|
||||
|
||||
object IgnoredEventIds : List<IgnoredEventParserAndHandler> by {
|
||||
internal object IgnoredEventIds : List<IgnoredEventParserAndHandler> by {
|
||||
listOf(
|
||||
//0x0021u, // 与群成员加入有关
|
||||
0x0210u // 新朋友等字符串通知
|
||||
).map { IgnoredEventParserAndHandler(it.toUShort()) }
|
||||
}()
|
||||
|
||||
inline class IgnoredEventParserAndHandler(override val id: UShort) : EventParserAndHandler<IgnoredEventPacket> {
|
||||
internal inline class IgnoredEventParserAndHandler(override val id: UShort) : EventParserAndHandler<IgnoredEventPacket> {
|
||||
override suspend fun ByteReadPacket.parse(bot: Bot, identity: EventPacketIdentity): IgnoredEventPacket = IgnoredEventPacket(id)
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.Member
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.internal.Member
|
||||
import net.mamoe.mirai.contact.internal.MemberImpl
|
||||
import net.mamoe.mirai.event.Subscribable
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
@ -74,7 +75,8 @@ internal object MemberJoinPacketHandler : KnownEventParserAndHandler<MemberJoinE
|
||||
val group = bot.getGroup(readUInt())
|
||||
|
||||
discardExact(1) // 01
|
||||
val member = MemberImpl(bot.getQQ(readUInt()), group, MemberPermission.MEMBER)
|
||||
val qq = bot.getQQ(readUInt())
|
||||
val member = Member(qq, group, MemberPermission.MEMBER, qq.coroutineContext)
|
||||
|
||||
return if (readByte().toInt() == 0x03) {
|
||||
MemberJoinEventPacket(member, null)
|
||||
|
@ -18,7 +18,7 @@ import net.mamoe.mirai.qqAccount
|
||||
/**
|
||||
* 某群成员被禁言事件
|
||||
*/
|
||||
@Suppress("unused")
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
class MemberMuteEvent(
|
||||
val member: Member,
|
||||
override val duration: TimeSpan,
|
||||
|
@ -10,7 +10,7 @@ import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
|
||||
data class UnknownEventPacket(
|
||||
internal data class UnknownEventPacket(
|
||||
val id: UShort,
|
||||
val identity: EventPacketIdentity,
|
||||
val body: ByteReadPacket
|
||||
@ -25,7 +25,7 @@ Mirai 21:54:15 : Packet received: UnknownEventPacket(id=00 57, identity=(9205034
|
||||
*/
|
||||
|
||||
//TODO This class should be declared with `inline`, but a CompilationException will be thrown
|
||||
class UnknownEventParserAndHandler(override val id: UShort) : EventParserAndHandler<UnknownEventPacket> {
|
||||
internal class UnknownEventParserAndHandler(override val id: UShort) : EventParserAndHandler<UnknownEventPacket> {
|
||||
|
||||
override suspend fun ByteReadPacket.parse(bot: Bot, identity: EventPacketIdentity): UnknownEventPacket {
|
||||
// MiraiLogger.debug("UnknownEventPacket(${id.toUHexString()}) = ${readBytes().toUHexString()}")
|
||||
|
@ -8,12 +8,12 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
object CaptchaKey : DecrypterByteArray, DecrypterType<CaptchaKey> {
|
||||
internal object CaptchaKey : DecrypterByteArray, DecrypterType<CaptchaKey> {
|
||||
override val value: ByteArray = TIMProtocol.key00BA
|
||||
}
|
||||
|
||||
@AnnotatedId(KnownPacketId.CAPTCHA)
|
||||
object CaptchaPacket : PacketFactory<CaptchaPacket.CaptchaResponse, CaptchaKey>(CaptchaKey) {
|
||||
internal object CaptchaPacket : PacketFactory<CaptchaPacket.CaptchaResponse, CaptchaKey>(CaptchaKey) {
|
||||
/**
|
||||
* 请求验证码传输
|
||||
*/
|
||||
@ -97,7 +97,7 @@ object CaptchaPacket : PacketFactory<CaptchaPacket.CaptchaResponse, CaptchaKey>(
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CaptchaResponse : Packet {
|
||||
internal sealed class CaptchaResponse : Packet {
|
||||
lateinit var token00BA: ByteArray//56 bytes
|
||||
|
||||
class Correct : CaptchaResponse() {
|
||||
|
@ -17,7 +17,7 @@ import net.mamoe.mirai.utils.io.writeQQ
|
||||
* 改变在线状态: "我在线上", "隐身" 等
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.CHANGE_ONLINE_STATUS)
|
||||
object ChangeOnlineStatusPacket : PacketFactory<ChangeOnlineStatusPacket.ChangeOnlineStatusResponse, NoDecrypter>(NoDecrypter) {
|
||||
internal object ChangeOnlineStatusPacket : PacketFactory<ChangeOnlineStatusPacket.ChangeOnlineStatusResponse, NoDecrypter>(NoDecrypter) {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
@ -32,7 +32,7 @@ object ChangeOnlineStatusPacket : PacketFactory<ChangeOnlineStatusPacket.ChangeO
|
||||
}
|
||||
}
|
||||
|
||||
object ChangeOnlineStatusResponse : Packet {
|
||||
internal object ChangeOnlineStatusResponse : Packet {
|
||||
override fun toString(): String = this::class.simpleName!!
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ import net.mamoe.mirai.utils.io.writeQQ
|
||||
|
||||
@NoLog
|
||||
@AnnotatedId(KnownPacketId.HEARTBEAT)
|
||||
object HeartbeatPacket : SessionPacketFactory<HeartbeatPacketResponse>() {
|
||||
internal object HeartbeatPacket : SessionPacketFactory<HeartbeatPacketResponse>() {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey
|
||||
@ -32,4 +32,4 @@ object HeartbeatPacket : SessionPacketFactory<HeartbeatPacketResponse>() {
|
||||
|
||||
@NoLog
|
||||
@AnnotatedId(KnownPacketId.HEARTBEAT)
|
||||
object HeartbeatPacketResponse : Packet, Subscribable
|
||||
internal object HeartbeatPacketResponse : Packet, Subscribable
|
@ -13,15 +13,15 @@ import net.mamoe.mirai.utils.encryptBy
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.writeCRC32
|
||||
|
||||
object ShareKey : DecrypterByteArray, DecrypterType<ShareKey> {
|
||||
internal object ShareKey : DecrypterByteArray, DecrypterType<ShareKey> {
|
||||
override val value: ByteArray = TIMProtocol.shareKey
|
||||
}
|
||||
|
||||
inline class PrivateKey(override val value: ByteArray) : DecrypterByteArray {
|
||||
internal inline class PrivateKey(override val value: ByteArray) : DecrypterByteArray {
|
||||
companion object Type : DecrypterType<PrivateKey>
|
||||
}
|
||||
|
||||
inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter {
|
||||
internal inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey) : Decrypter {
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket {
|
||||
var decrypted = ShareKey.decrypt(input)
|
||||
(decrypted.remaining).let {
|
||||
@ -45,7 +45,7 @@ inline class SubmitPasswordResponseDecrypter(private val privateKey: PrivateKey)
|
||||
* 提交密码
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.LOGIN)
|
||||
object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse, SubmitPasswordResponseDecrypter>(SubmitPasswordResponseDecrypter) {
|
||||
internal object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse, SubmitPasswordResponseDecrypter>(SubmitPasswordResponseDecrypter) {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
password: String,
|
||||
@ -76,7 +76,7 @@ object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse,
|
||||
}
|
||||
}
|
||||
|
||||
sealed class LoginResponse : Packet {
|
||||
internal sealed class LoginResponse : Packet {
|
||||
class KeyExchange(
|
||||
val tlv0006: IoBuffer,//120bytes
|
||||
val tokenUnknown: ByteArray?,
|
||||
@ -259,7 +259,7 @@ object SubmitPasswordPacket : PacketFactory<SubmitPasswordPacket.LoginResponse,
|
||||
}
|
||||
}
|
||||
|
||||
inline class SessionResponseDecryptionKey(private val delegate: IoBuffer) : Decrypter {
|
||||
internal inline class SessionResponseDecryptionKey(private val delegate: IoBuffer) : Decrypter {
|
||||
override fun decrypt(input: ByteReadPacket): ByteReadPacket = input.decryptBy(delegate)
|
||||
|
||||
override fun toString(): String = "SessionResponseDecryptionKey"
|
||||
|
@ -15,7 +15,7 @@ import net.mamoe.mirai.withSession
|
||||
|
||||
internal fun BotSession.RequestSKeyPacket(): OutgoingPacket = RequestSKeyPacket(qqAccount, sessionKey)
|
||||
|
||||
inline class SKey(
|
||||
internal inline class SKey(
|
||||
val value: String
|
||||
) : Packet
|
||||
|
||||
|
@ -10,7 +10,7 @@ import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.localIpAddress
|
||||
|
||||
@AnnotatedId(KnownPacketId.SESSION_KEY)
|
||||
object RequestSessionPacket : PacketFactory<RequestSessionPacket.SessionKeyResponse, SessionResponseDecryptionKey>(SessionResponseDecryptionKey) {
|
||||
internal object RequestSessionPacket : PacketFactory<RequestSessionPacket.SessionKeyResponse, SessionResponseDecryptionKey>(SessionResponseDecryptionKey) {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
serverIp: String,
|
||||
@ -59,7 +59,7 @@ object RequestSessionPacket : PacketFactory<RequestSessionPacket.SessionKeyRespo
|
||||
}
|
||||
}
|
||||
|
||||
class SessionKeyResponse(
|
||||
internal class SessionKeyResponse(
|
||||
val sessionKey: SessionKey,
|
||||
val tlv0105: ByteReadPacket? = null
|
||||
) : Packet {
|
||||
|
@ -11,7 +11,7 @@ import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
|
||||
object TouchKey : DecrypterByteArray, DecrypterType<TouchKey> {
|
||||
internal object TouchKey : DecrypterByteArray, DecrypterType<TouchKey> {
|
||||
override val value: ByteArray = TIMProtocol.touchKey
|
||||
}
|
||||
|
||||
@ -21,7 +21,7 @@ object TouchKey : DecrypterByteArray, DecrypterType<TouchKey> {
|
||||
* @author Him188moe
|
||||
*/
|
||||
@AnnotatedId(KnownPacketId.TOUCH)
|
||||
object TouchPacket : PacketFactory<TouchPacket.TouchResponse, TouchKey>(TouchKey) {
|
||||
internal object TouchPacket : PacketFactory<TouchPacket.TouchResponse, TouchKey>(TouchKey) {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
serverIp: String,
|
||||
@ -45,7 +45,7 @@ object TouchPacket : PacketFactory<TouchPacket.TouchResponse, TouchKey>(TouchKey
|
||||
}
|
||||
}
|
||||
|
||||
sealed class TouchResponse : Packet {
|
||||
internal sealed class TouchResponse : Packet {
|
||||
class OK(
|
||||
var loginTime: Int,
|
||||
val loginIP: String,
|
||||
|
@ -17,7 +17,7 @@ import kotlin.random.Random
|
||||
/**
|
||||
* 解密错误
|
||||
*/
|
||||
class DecryptionFailedException : Exception()
|
||||
internal class DecryptionFailedException : Exception()
|
||||
|
||||
|
||||
// region encrypt
|
||||
@ -28,9 +28,9 @@ class DecryptionFailedException : Exception()
|
||||
* @param key 长度至少为 16
|
||||
* @throws DecryptionFailedException 解密错误时
|
||||
*/
|
||||
fun ByteArray.encryptBy(key: ByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key, sourceLength = length)
|
||||
internal fun ByteArray.encryptBy(key: ByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key, sourceLength = length)
|
||||
|
||||
fun ByteArray.encryptBy(key: DecrypterByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key.value, sourceLength = length)
|
||||
internal fun ByteArray.encryptBy(key: DecrypterByteArray, length: Int = this.size): ByteArray = TEA.encrypt(this, key.value, sourceLength = length)
|
||||
|
||||
/**
|
||||
* 在 [ByteArrayPool] 缓存 [this], 然后使用 [key] 加密.
|
||||
@ -39,7 +39,7 @@ fun ByteArray.encryptBy(key: DecrypterByteArray, length: Int = this.size): ByteA
|
||||
* @consumer 由于缓存需要被回收, 需在方法内执行解密后明文的消耗过程
|
||||
* @throws DecryptionFailedException 解密错误时
|
||||
*/
|
||||
inline fun ByteReadPacket.encryptBy(key: ByteArray, offset: Int = 0, length: Int = remaining.toInt() - offset, consumer: (ByteArray) -> Unit) {
|
||||
internal inline fun ByteReadPacket.encryptBy(key: ByteArray, offset: Int = 0, length: Int = remaining.toInt() - offset, consumer: (ByteArray) -> Unit) {
|
||||
ByteArrayPool.useInstance {
|
||||
this.readFully(it, offset, length)
|
||||
consumer(it.encryptBy(key, length = length))
|
||||
@ -57,7 +57,7 @@ inline fun ByteReadPacket.encryptBy(key: ByteArray, offset: Int = 0, length: Int
|
||||
* @param key 固定长度 16
|
||||
* @throws DecryptionFailedException 解密错误时
|
||||
*/
|
||||
fun ByteArray.decryptBy(key: ByteArray, length: Int = this.size): ByteArray =
|
||||
internal fun ByteArray.decryptBy(key: ByteArray, length: Int = this.size): ByteArray =
|
||||
TEA.decrypt(checkDataLengthAndReturnSelf(length), key, sourceLength = length)
|
||||
|
||||
/**
|
||||
@ -68,7 +68,7 @@ fun ByteArray.decryptBy(key: ByteArray, length: Int = this.size): ByteArray =
|
||||
* @param key 长度至少为 16
|
||||
* @throws DecryptionFailedException 解密错误时
|
||||
*/
|
||||
fun ByteArray.decryptBy(key: IoBuffer, length: Int = this.size): ByteArray {
|
||||
internal fun ByteArray.decryptBy(key: IoBuffer, length: Int = this.size): ByteArray {
|
||||
checkDataLengthAndReturnSelf(length)
|
||||
return ByteArrayPool.useInstance { keyBuffer ->
|
||||
key.readFully(keyBuffer, 0, key.readRemaining)
|
||||
@ -82,7 +82,7 @@ fun ByteArray.decryptBy(key: IoBuffer, length: Int = this.size): ByteArray {
|
||||
* @param key 长度至少为 16
|
||||
* @throws DecryptionFailedException 解密错误时
|
||||
*/
|
||||
fun IoBuffer.decryptBy(key: ByteArray, offset: Int = 0, length: Int = readRemaining - offset): ByteArray {
|
||||
internal fun IoBuffer.decryptBy(key: ByteArray, offset: Int = 0, length: Int = readRemaining - offset): ByteArray {
|
||||
return ByteArrayPool.useInstance {
|
||||
this.readFully(it, offset, length)
|
||||
it.checkDataLengthAndReturnSelf(length)
|
||||
@ -94,20 +94,20 @@ fun IoBuffer.decryptBy(key: ByteArray, offset: Int = 0, length: Int = readRemain
|
||||
|
||||
// region ByteReadPacket extension
|
||||
|
||||
fun ByteReadPacket.decryptBy(key: ByteArray): ByteReadPacket = decryptAsByteArray(key) { data -> ByteReadPacket(data, 0) }
|
||||
internal fun ByteReadPacket.decryptBy(key: ByteArray): ByteReadPacket = decryptAsByteArray(key) { data -> ByteReadPacket(data, 0) }
|
||||
|
||||
fun ByteReadPacket.decryptBy(key: IoBuffer): ByteReadPacket = decryptAsByteArray(key) { data -> ByteReadPacket(data, 0) }
|
||||
internal fun ByteReadPacket.decryptBy(key: IoBuffer): ByteReadPacket = decryptAsByteArray(key) { data -> ByteReadPacket(data, 0) }
|
||||
|
||||
fun ByteReadPacket.decryptBy(key: Decrypter): ByteReadPacket = key.decrypt(this)
|
||||
internal fun ByteReadPacket.decryptBy(key: Decrypter): ByteReadPacket = key.decrypt(this)
|
||||
|
||||
inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R =
|
||||
internal inline fun <R> ByteReadPacket.decryptAsByteArray(key: ByteArray, consumer: (ByteArray) -> R): R =
|
||||
ByteArrayPool.useInstance {
|
||||
val length = remaining.toInt()
|
||||
readFully(it, 0, length)
|
||||
consumer(it.decryptBy(key, length))
|
||||
}.also { close() }
|
||||
|
||||
inline fun <R> ByteReadPacket.decryptAsByteArray(key: IoBuffer, consumer: (ByteArray) -> R): R =
|
||||
internal inline fun <R> ByteReadPacket.decryptAsByteArray(key: IoBuffer, consumer: (ByteArray) -> R): R =
|
||||
ByteArrayPool.useInstance {
|
||||
val length = remaining.toInt()
|
||||
readFully(it, 0, length)
|
||||
|
@ -16,46 +16,46 @@ import net.mamoe.mirai.utils.internal.coerceAtMostOrFail
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
fun BytePacketBuilder.writeZero(count: Int) {
|
||||
internal fun BytePacketBuilder.writeZero(count: Int) {
|
||||
require(count != 0) { "Trying to write zero with count 0, you made a mistake?" }
|
||||
require(count > 0) { "writeZero: count must > 0" }
|
||||
repeat(count) { this.writeByte(0) }
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeRandom(length: Int) = repeat(length) { this.writeByte(Random.Default.nextInt(255).toByte()) }
|
||||
internal fun BytePacketBuilder.writeRandom(length: Int) = repeat(length) { this.writeByte(Random.Default.nextInt(255).toByte()) }
|
||||
|
||||
fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt())
|
||||
fun BytePacketBuilder.writeQQ(qq: UInt) = this.writeUInt(qq)
|
||||
fun BytePacketBuilder.writeGroup(groupId: GroupId) = this.writeUInt(groupId.value)
|
||||
fun BytePacketBuilder.writeGroup(groupInternalId: GroupInternalId) = this.writeUInt(groupInternalId.value)
|
||||
fun BytePacketBuilder.writeFully(value: DecrypterByteArray) = this.writeFully(value.value)
|
||||
internal fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt())
|
||||
internal fun BytePacketBuilder.writeQQ(qq: UInt) = this.writeUInt(qq)
|
||||
internal fun BytePacketBuilder.writeGroup(groupId: GroupId) = this.writeUInt(groupId.value)
|
||||
internal fun BytePacketBuilder.writeGroup(groupInternalId: GroupInternalId) = this.writeUInt(groupInternalId.value)
|
||||
internal fun BytePacketBuilder.writeFully(value: DecrypterByteArray) = this.writeFully(value.value)
|
||||
|
||||
fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray) {
|
||||
internal fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray) {
|
||||
this.writeShort(byteArray.size.toShort())
|
||||
this.writeFully(byteArray)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||
internal fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||
BytePacketBuilder().apply(builder).build().use {
|
||||
if (tag != null) writeUByte(tag)
|
||||
writeUShort((lengthOffset?.invoke(it.remaining) ?: it.remaining).coerceAtMostOrFail(0xFFFFL).toUShort())
|
||||
writePacket(it)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeUVarIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||
internal fun BytePacketBuilder.writeUVarIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long)? = null, builder: BytePacketBuilder.() -> Unit) =
|
||||
BytePacketBuilder().apply(builder).build().use {
|
||||
if (tag != null) writeUByte(tag)
|
||||
writeUVarInt((lengthOffset?.invoke(it.remaining) ?: it.remaining).coerceAtMostOrFail(0xFFFFL))
|
||||
writePacket(it)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
|
||||
internal fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
|
||||
|
||||
fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray())
|
||||
internal fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray())
|
||||
|
||||
fun BytePacketBuilder.writeTime() = this.writeInt(currentTime.toInt())
|
||||
internal fun BytePacketBuilder.writeTime() = this.writeInt(currentTime.toInt())
|
||||
|
||||
fun BytePacketBuilder.writeHex(uHex: String) {
|
||||
internal fun BytePacketBuilder.writeHex(uHex: String) {
|
||||
uHex.split(" ").forEach {
|
||||
if (it.isNotBlank()) {
|
||||
writeUByte(it.toUByte(16))
|
||||
@ -63,49 +63,49 @@ fun BytePacketBuilder.writeHex(uHex: String) {
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> BytePacketBuilder.writeProto(serializer: SerializationStrategy<T>, obj: T) = writeFully(ProtoBuf.dump(serializer, obj))
|
||||
internal fun <T> BytePacketBuilder.writeProto(serializer: SerializationStrategy<T>, obj: T) = writeFully(ProtoBuf.dump(serializer, obj))
|
||||
|
||||
|
||||
fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) {
|
||||
internal fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) {
|
||||
writeUByte(tag)
|
||||
writeUVarInt(values.size.toUInt())
|
||||
writeFully(values)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTLV(tag: UByte, values: ByteArray) {
|
||||
internal fun BytePacketBuilder.writeTLV(tag: UByte, values: ByteArray) {
|
||||
writeUByte(tag)
|
||||
writeUVarInt(values.size.toUInt())
|
||||
writeFully(values)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTHex(tag: UByte, uHex: String) {
|
||||
internal fun BytePacketBuilder.writeTHex(tag: UByte, uHex: String) {
|
||||
this.writeUByte(tag)
|
||||
this.writeFully(uHex.hexToUBytes())
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue)
|
||||
internal fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue)
|
||||
|
||||
fun BytePacketBuilder.writeTV(tag: UByte, value: UByte) {
|
||||
internal fun BytePacketBuilder.writeTV(tag: UByte, value: UByte) {
|
||||
writeUByte(tag)
|
||||
writeUByte(value)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) {
|
||||
internal fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) {
|
||||
this.writeUByte(tag)
|
||||
this.writeUByte(value)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTUVarint(tag: UByte, value: UInt) {
|
||||
internal fun BytePacketBuilder.writeTUVarint(tag: UByte, value: UInt) {
|
||||
this.writeUByte(tag)
|
||||
this.writeUVarInt(value)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTByteArray(tag: UByte, value: ByteArray) {
|
||||
internal fun BytePacketBuilder.writeTByteArray(tag: UByte, value: ByteArray) {
|
||||
this.writeUByte(tag)
|
||||
this.writeFully(value)
|
||||
}
|
||||
|
||||
fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
|
||||
internal fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
|
||||
this.writeUByte(tag)
|
||||
this.writeFully(value)
|
||||
}
|
||||
@ -113,19 +113,19 @@ fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
|
||||
/**
|
||||
* 会使用 [ByteArrayPool] 缓存
|
||||
*/
|
||||
inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) =
|
||||
internal inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) =
|
||||
BytePacketBuilder().apply(encoder).build().encryptBy(key) { decrypted -> writeFully(decrypted) }
|
||||
|
||||
inline fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = ByteArrayPool.useInstance {
|
||||
internal inline fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = ByteArrayPool.useInstance {
|
||||
key.readFully(it, 0, key.readRemaining)
|
||||
encryptAndWrite(it, encoder)
|
||||
}
|
||||
|
||||
inline fun BytePacketBuilder.encryptAndWrite(key: DecrypterByteArray, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(key.value, encoder)
|
||||
internal inline fun BytePacketBuilder.encryptAndWrite(key: DecrypterByteArray, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(key.value, encoder)
|
||||
|
||||
inline fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder)
|
||||
internal inline fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder)
|
||||
|
||||
fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, loginIP: String, privateKey: PrivateKey) {
|
||||
internal fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, loginIP: String, privateKey: PrivateKey) {
|
||||
val firstMD5 = md5(password)
|
||||
val secondMD5 = md5(firstMD5 + byteArrayOf(0, 0, 0, 0) + qq.toUInt().toByteArray())
|
||||
|
||||
@ -149,7 +149,7 @@ fun BytePacketBuilder.writeTLV0006(qq: UInt, password: String, loginTime: Int, l
|
||||
}
|
||||
|
||||
@Tested
|
||||
fun BytePacketBuilder.writeDeviceName(random: Boolean) {
|
||||
internal fun BytePacketBuilder.writeDeviceName(random: Boolean) {
|
||||
val deviceName: String = if (random) {
|
||||
"DESKTOP-" + String(ByteArray(7) {
|
||||
(if (Random.nextBoolean()) Random.nextInt('A'.toInt()..'Z'.toInt())
|
||||
|
Loading…
Reference in New Issue
Block a user