Make all packets internal

This commit is contained in:
Him188 2019-12-06 23:47:48 +08:00
parent 1ea8478584
commit e47143e872
37 changed files with 273 additions and 236 deletions

View File

@ -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

View File

@ -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

View File

@ -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)
/**
* 等待直到与服务器断开连接. 若未连接则立即返回
*/

View File

@ -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)

View File

@ -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) {

View File

@ -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()
}

View File

@ -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
}
}

View File

@ -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 版本

View File

@ -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>

View File

@ -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
)
}
}
}

View File

@ -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"
}

View File

@ -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)
}

View File

@ -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),

View File

@ -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"
}

View File

@ -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

View File

@ -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

View File

@ -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()
}
}

View File

@ -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;

View File

@ -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 {

View File

@ -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>() {
/**
* 查询好友的备注
*/

View File

@ -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

View File

@ -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"
}

View File

@ -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,

View File

@ -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()

View File

@ -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)
}

View File

@ -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)

View File

@ -18,7 +18,7 @@ import net.mamoe.mirai.qqAccount
/**
* 某群成员被禁言事件
*/
@Suppress("unused")
@Suppress("unused", "MemberVisibilityCanBePrivate")
class MemberMuteEvent(
val member: Member,
override val duration: TimeSpan,

View File

@ -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()}")

View File

@ -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() {

View File

@ -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!!
}

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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 {

View File

@ -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,

View File

@ -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)

View File

@ -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())