Commit 8353a6ae authored by Him188's avatar Him188

Improve performance

parent 735b0934
...@@ -63,9 +63,13 @@ subscribe<FriendMessageEvent>{ ...@@ -63,9 +63,13 @@ subscribe<FriendMessageEvent>{
机器人可以转发图片消息.详情查看 [Image.kt](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt#L81) 机器人可以转发图片消息.详情查看 [Image.kt](mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/Message.kt#L81)
## 现已支持 ## 现已支持
- 发送好友/群消息(2019/10/14)
- 接收好友/群消息, 消息链解析(2019/10/14) - 发送好友/群消息(10/14)
- 好友在线状态改变(2019/10/14) - 接受解析好友消息(10/14)
- 接收解析群消息(10/14)
- 成员权限, 昵称(10/18)
- 好友在线状态改变(10/14)
- Android客户端上线/下线(10/18)
## 使用方法 ## 使用方法
### 要求 ### 要求
......
...@@ -175,7 +175,7 @@ object MiraiServer { ...@@ -175,7 +175,7 @@ object MiraiServer {
val bot = Bot(BotAccount(strings[0].toLong(), strings[1]), MiraiLogger) val bot = Bot(BotAccount(strings[0].toLong(), strings[1]), MiraiLogger)
if (runBlocking { bot.login() } === LoginResult.SUCCESS) { if (runBlocking { bot.login() } === LoginResult.SUCCESS) {
bot.green("Login succeed") bot.logGreen("Login succeed")
return bot return bot
} }
} }
......
...@@ -9,10 +9,8 @@ import net.mamoe.mirai.contact.groupIdToNumber ...@@ -9,10 +9,8 @@ import net.mamoe.mirai.contact.groupIdToNumber
import net.mamoe.mirai.network.BotNetworkHandler import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotAccount import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.ContactList import kotlin.jvm.JvmOverloads
import net.mamoe.mirai.utils.LoginConfiguration
import net.mamoe.mirai.utils.MiraiLogger
/** /**
* Mirai 的机器人. 一个机器人实例登录一个 QQ 账号. * Mirai 的机器人. 一个机器人实例登录一个 QQ 账号.
...@@ -61,9 +59,14 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) { ...@@ -61,9 +59,14 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
* [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程. * [关闭][BotNetworkHandler.close]网络处理器, 取消所有运行在 [BotNetworkHandler.NetworkScope] 下的协程.
* 然后重新启动并尝试登录 * 然后重新启动并尝试登录
*/ */
suspend fun reinitializeNetworkHandler(configuration: LoginConfiguration): LoginResult { @JvmOverloads
suspend fun reinitializeNetworkHandler(configuration: BotNetworkConfiguration, cause: Throwable? = null): LoginResult {
logger.logPurple("Reinitializing BotNetworkHandler") logger.logPurple("Reinitializing BotNetworkHandler")
network.close() try {
network.close(cause)
} catch (e: Exception) {
e.log()
}
network = TIMBotNetworkHandler(this) network = TIMBotNetworkHandler(this)
return network.login(configuration) return network.login(configuration)
} }
......
...@@ -8,8 +8,8 @@ import net.mamoe.mirai.contact.QQ ...@@ -8,8 +8,8 @@ import net.mamoe.mirai.contact.QQ
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.BotNetworkConfiguration
import net.mamoe.mirai.utils.ContactList import net.mamoe.mirai.utils.ContactList
import net.mamoe.mirai.utils.LoginConfiguration
import net.mamoe.mirai.utils.toUHexString import net.mamoe.mirai.utils.toUHexString
/** /**
...@@ -36,31 +36,31 @@ val Bot.qqs: ContactList<QQ> get() = this.contacts.qqs ...@@ -36,31 +36,31 @@ val Bot.qqs: ContactList<QQ> get() = this.contacts.qqs
//NetworkHandler //NetworkHandler
suspend fun Bot.sendPacket(packet: ClientPacket) = this.network.sendPacket(packet) suspend fun Bot.sendPacket(packet: ClientPacket) = this.network.sendPacket(packet)
suspend fun Bot.login(configuration: LoginConfiguration.() -> Unit): LoginResult = this.network.login(LoginConfiguration().apply(configuration)) suspend fun Bot.login(configuration: BotNetworkConfiguration.() -> Unit): LoginResult = this.network.login(BotNetworkConfiguration().apply(configuration))
suspend fun Bot.login(): LoginResult = this.network.login(LoginConfiguration.Default) suspend fun Bot.login(): LoginResult = this.network.login(BotNetworkConfiguration.Default)
//BotAccount //BotAccount
val Bot.qqAccount: Long get() = this.account.account val Bot.qqAccount: Long get() = this.account.account
//logging //logging
fun Bot.log(o: Any?) = info(o) fun Bot.log(o: Any?) = logInfo(o)
fun Bot.println(o: Any?) = info(o) fun Bot.println(o: Any?) = logInfo(o)
fun Bot.info(o: Any?) = this.logger.logInfo(o) fun Bot.logInfo(o: Any?) = this.logger.logInfo(o)
fun Bot.error(o: Any?) = this.logger.logError(o) fun Bot.logError(o: Any?) = this.logger.logError(o)
fun Bot.purple(o: Any?) = this.logger.logPurple(o) fun Bot.logPurple(o: Any?) = this.logger.logPurple(o)
fun Bot.cyan(o: Any?) = this.logger.logCyan(o) fun Bot.logCyan(o: Any?) = this.logger.logCyan(o)
fun Bot.green(o: Any?) = this.logger.logGreen(o) fun Bot.logGreen(o: Any?) = this.logger.logGreen(o)
fun Bot.debug(o: Any?) = this.logger.logDebug(o) fun Bot.logDebug(o: Any?) = this.logger.logDebug(o)
fun Bot.printPacketDebugging(packet: ServerPacket) { fun Bot.printPacketDebugging(packet: ServerPacket) {
debug("Packet=$packet") logDebug("Packet=$packet")
debug("Packet size=" + packet.input.readBytes().size) logDebug("Packet size=" + packet.input.readBytes().size)
debug("Packet data=" + packet.input.readBytes().toUHexString()) logDebug("Packet data=" + packet.input.readBytes().toUHexString())
} }
\ No newline at end of file
...@@ -51,16 +51,21 @@ interface Cancellable { ...@@ -51,16 +51,21 @@ interface Cancellable {
} }
/** /**
* 广播一个事件的唯一途径 * 广播一个事件的唯一途径.
* 若 [context] 不包含 [CoroutineExceptionHandler], 将会使用默认的异常捕获, 即 [log]
* 也就是说, 这个方法不会抛出异常, 只会把异常交由 [context] 捕获
*/ */
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@JvmOverloads @JvmOverloads
suspend fun <E : Event> E.broadcast(context: CoroutineContext? = null): E { suspend fun <E : Event> E.broadcast(context: CoroutineContext? = CoroutineExceptionHandler { _, e -> e.log() }): E {
var ctx = EventScope.coroutineContext var ctx = EventScope.coroutineContext
if (context != null) { if (context == null) {
if (context[CoroutineExceptionHandler] == null)
ctx += CoroutineExceptionHandler { _, e -> e.log() } ctx += CoroutineExceptionHandler { _, e -> e.log() }
} else {
ctx += context ctx += context
if (context[CoroutineExceptionHandler] == null) {
ctx += CoroutineExceptionHandler { _, e -> e.log() }
}
} }
return withContext(ctx) { this@broadcast.broadcastInternal() } return withContext(ctx) { this@broadcast.broadcastInternal() }
} }
......
...@@ -58,6 +58,7 @@ internal object EventListenerManger { ...@@ -58,6 +58,7 @@ internal object EventListenerManger {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
internal suspend fun <E : Event> E.broadcastInternal(): E { internal suspend fun <E : Event> E.broadcastInternal(): E {
suspend fun callListeners(listeners: EventListeners<in E>) = listeners.lock.withLock { suspend fun callListeners(listeners: EventListeners<in E>) = listeners.lock.withLock {
//fixme 这个锁会导致在事件处理时再监听这个事件死锁
listeners.removeIfInlined { it.onEvent(this) == ListeningStatus.STOPPED } listeners.removeIfInlined { it.onEvent(this) == ListeningStatus.STOPPED }
} }
......
...@@ -3,14 +3,16 @@ package net.mamoe.mirai.network ...@@ -3,14 +3,16 @@ package net.mamoe.mirai.network
import kotlinx.coroutines.CancellationException import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.cancelChildren import kotlinx.coroutines.cancelChildren
import kotlinx.io.core.Closeable
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.BotSocketAdapter
import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler import net.mamoe.mirai.network.protocol.tim.TIMBotNetworkHandler.LoginHandler
import net.mamoe.mirai.network.protocol.tim.handler.* import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.ClientHeartbeatPacket
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.Packet
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
import net.mamoe.mirai.utils.LoginConfiguration import net.mamoe.mirai.utils.BotNetworkConfiguration
import net.mamoe.mirai.utils.PlatformDatagramChannel import net.mamoe.mirai.utils.PlatformDatagramChannel
import kotlin.coroutines.ContinuationInterceptor import kotlin.coroutines.ContinuationInterceptor
...@@ -30,7 +32,7 @@ import kotlin.coroutines.ContinuationInterceptor ...@@ -30,7 +32,7 @@ import kotlin.coroutines.ContinuationInterceptor
* A BotNetworkHandler is used to connect with Tencent servers. * A BotNetworkHandler is used to connect with Tencent servers.
*/ */
@Suppress("PropertyName") @Suppress("PropertyName")
interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable { interface BotNetworkHandler<Socket : DataPacketSocketAdapter> {
/** /**
* [BotNetworkHandler] 的协程作用域. * [BotNetworkHandler] 的协程作用域.
* 所有 [BotNetworkHandler] 的协程均启动在此作用域下. * 所有 [BotNetworkHandler] 的协程均启动在此作用域下.
...@@ -47,17 +49,20 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable { ...@@ -47,17 +49,20 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable {
val socket: Socket val socket: Socket
/** /**
* 得到 [PacketHandler]. * 得到 [PacketHandler].
* `get(EventPacketHandler)` 返回 [EventPacketHandler] * `get(EventPacketHandler)` 返回 [EventPacketHandler]
* `get(ActionPacketHandler)` 返回 [ActionPacketHandler] * `get(ActionPacketHandler)` 返回 [ActionPacketHandler].
*
* 这个方法在 [PacketHandlerList] 中实现
*/ */
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T
/** /**
* 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果 * 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回登录结果
*/ */
suspend fun login(configuration: LoginConfiguration): LoginResult suspend fun login(configuration: BotNetworkConfiguration): LoginResult
/** /**
* 添加一个临时包处理器, 并发送相应的包 * 添加一个临时包处理器, 并发送相应的包
...@@ -72,13 +77,8 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable { ...@@ -72,13 +77,8 @@ interface BotNetworkHandler<Socket : DataPacketSocketAdapter> : Closeable {
*/ */
suspend fun sendPacket(packet: ClientPacket) suspend fun sendPacket(packet: ClientPacket)
override fun close() { fun close(cause: Throwable? = null) {
//todo check?? //todo check??
NetworkScope.coroutineContext[ContinuationInterceptor]!!.cancelChildren(HandlerClosedException()) NetworkScope.coroutineContext[ContinuationInterceptor]!!.cancelChildren(CancellationException("handler closed", cause))
} }
} }
\ No newline at end of file
/**
* [BotNetworkHandler] closed
*/
class HandlerClosedException : CancellationException("handler closed")
\ No newline at end of file
...@@ -6,6 +6,7 @@ import kotlinx.coroutines.CompletableJob ...@@ -6,6 +6,7 @@ import kotlinx.coroutines.CompletableJob
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.network.protocol.tim.handler.ActionPacketHandler
import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter import net.mamoe.mirai.network.protocol.tim.handler.DataPacketSocketAdapter
import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler import net.mamoe.mirai.network.protocol.tim.handler.TemporaryPacketHandler
import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
...@@ -101,3 +102,5 @@ class BotSession( ...@@ -101,3 +102,5 @@ class BotSession(
suspend fun BotSession.distributePacket(packet: ServerPacket) = this.socket.distributePacket(packet) suspend fun BotSession.distributePacket(packet: ServerPacket) = this.socket.distributePacket(packet)
val BotSession.isOpen: Boolean get() = socket.isOpen val BotSession.isOpen: Boolean get() = socket.isOpen
val BotSession.account: Long get() = bot.account.account val BotSession.account: Long get() = bot.account.account
val <T : BotNetworkHandler<*>> T.session get() = this[ActionPacketHandler].session
\ No newline at end of file
...@@ -17,10 +17,11 @@ import net.mamoe.mirai.network.BotNetworkHandler ...@@ -17,10 +17,11 @@ import net.mamoe.mirai.network.BotNetworkHandler
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.protocol.tim.handler.* import net.mamoe.mirai.network.protocol.tim.handler.*
import net.mamoe.mirai.network.protocol.tim.packet.* import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.* import net.mamoe.mirai.network.protocol.tim.packet.login.*
import net.mamoe.mirai.network.session
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
/** /**
* [BotNetworkHandler] 的 TIM PC 协议实现 * [BotNetworkHandler] 的 TIM PC 协议实现
* *
...@@ -45,7 +46,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -45,7 +46,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
temporaryPacketHandler.send(this[ActionPacketHandler].session) temporaryPacketHandler.send(this[ActionPacketHandler].session)
} }
override suspend fun login(configuration: LoginConfiguration): LoginResult { override suspend fun login(configuration: BotNetworkConfiguration): LoginResult {
TIMProtocol.SERVER_IP.forEach { TIMProtocol.SERVER_IP.forEach {
bot.logger.logInfo("Connecting server $it") bot.logger.logInfo("Connecting server $it")
this.socket = BotSocketAdapter(it, configuration) this.socket = BotSocketAdapter(it, configuration)
...@@ -79,8 +80,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -79,8 +80,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
private lateinit var sessionKey: ByteArray private lateinit var sessionKey: ByteArray
override fun close() { override fun close(cause: Throwable?) {
super.close() super.close(cause)
this.heartbeatJob?.cancel(CancellationException("handler closed")) this.heartbeatJob?.cancel(CancellationException("handler closed"))
this.heartbeatJob = null this.heartbeatJob = null
...@@ -98,7 +99,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -98,7 +99,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
override suspend fun sendPacket(packet: ClientPacket) = socket.sendPacket(packet) override suspend fun sendPacket(packet: ClientPacket) = socket.sendPacket(packet)
internal inner class BotSocketAdapter(override val serverIp: String, val configuration: LoginConfiguration) : DataPacketSocketAdapter { internal inner class BotSocketAdapter(override val serverIp: String, val configuration: BotNetworkConfiguration) : DataPacketSocketAdapter {
override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000) override val channel: PlatformDatagramChannel = PlatformDatagramChannel(serverIp, 8000)
override val isOpen: Boolean get() = channel.isOpen override val isOpen: Boolean get() = channel.isOpen
...@@ -140,7 +141,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -140,7 +141,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
internal suspend fun resendTouch(): LoginResult { internal suspend fun resendTouch(): LoginResult {
if (::loginHandler.isInitialized) loginHandler.close() if (::loginHandler.isInitialized) loginHandler.close()
loginHandler = LoginHandler() loginHandler = LoginHandler(configuration)
val expect = expectPacket<ServerTouchResponsePacket>() val expect = expectPacket<ServerTouchResponsePacket>()
...@@ -187,7 +188,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -187,7 +188,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
val name = packet::class.simpleName val name = packet::class.simpleName
if (name != null && !name.endsWith("Encrypted") && !name.endsWith("Raw")) { if (name != null && !name.endsWith("Encrypted") && !name.endsWith("Raw")) {
bot.cyan("Packet received: $packet") bot.logCyan("Packet received: $packet")
} }
if (packet is ServerEventPacket) { if (packet is ServerEventPacket) {
...@@ -240,14 +241,14 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -240,14 +241,14 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
channel.send(buffer)//JVM: withContext(IO) channel.send(buffer)//JVM: withContext(IO)
} catch (e: SendPacketInternalException) { } catch (e: SendPacketInternalException) {
bot.logger.logError("Caught SendPacketInternalException: ${e.cause?.message}") bot.logger.logError("Caught SendPacketInternalException: ${e.cause?.message}")
bot.reinitializeNetworkHandler(configuration) bot.reinitializeNetworkHandler(configuration, e)
return@withContext return@withContext
} finally { } finally {
buffer.release(IoBuffer.Pool) buffer.release(IoBuffer.Pool)
} }
} }
bot.green("Packet sent: $packet") bot.logGreen("Packet sent: $packet")
EventScope.launch { PacketSentEvent(bot, packet).broadcast() } EventScope.launch { PacketSentEvent(bot, packet).broadcast() }
} }
...@@ -264,7 +265,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -264,7 +265,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
/** /**
* 处理登录过程 * 处理登录过程
*/ */
inner class LoginHandler { inner class LoginHandler(private val configuration: BotNetworkConfiguration) {
private lateinit var token00BA: ByteArray private lateinit var token00BA: ByteArray
private lateinit var token0825: ByteArray//56 private lateinit var token0825: ByteArray//56
private var loginTime: Int = 0 private var loginTime: Int = 0
...@@ -350,7 +351,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -350,7 +351,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
is ServerCaptchaTransmissionPacket -> { is ServerCaptchaTransmissionPacket -> {
//packet is ServerCaptchaWrongPacket //packet is ServerCaptchaWrongPacket
if (this.captchaSectionId == 0) { if (this.captchaSectionId == 0) {
bot.error("验证码错误, 请重新输入") bot.logError("验证码错误, 请重新输入")
this.captchaSectionId = 1 this.captchaSectionId = 1
this.captchaCache = null this.captchaCache = null
} }
...@@ -402,8 +403,18 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -402,8 +403,18 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
heartbeatJob = NetworkScope.launch { heartbeatJob = NetworkScope.launch {
while (socket.isOpen) { while (socket.isOpen) {
delay(90000) delay(configuration.heartbeatPeriodMillis)
socket.sendPacket(ClientHeartbeatPacket(bot.qqAccount, sessionKey)) with(session) {
class HeartbeatTimeoutException : CancellationException("heartbeat timeout")
if (withTimeoutOrNull(configuration.heartbeatTimeoutMillis) {
ClientHeartbeatPacket(bot.qqAccount, sessionKey).sendAndExpect<ServerHeartbeatResponsePacket> {}
} == null) {
bot.logPurple("Heartbeat timed out")
bot.reinitializeNetworkHandler(configuration, HeartbeatTimeoutException())
return@launch
}
}
} }
} }
...@@ -447,7 +458,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) : ...@@ -447,7 +458,8 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
fun close() { fun close() {
this.captchaCache = null this.captchaCache = null
if (::sessionResponseDecryptionKey.isInitialized) this.sessionResponseDecryptionKey.release(IoBuffer.Pool) if (::sessionResponseDecryptionKey.isInitialized && sessionResponseDecryptionKey.readRemaining != 0)
this.sessionResponseDecryptionKey.release(IoBuffer.Pool)
} }
} }
} }
...@@ -13,6 +13,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendResult ...@@ -13,6 +13,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.action.AddFriendResult
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientAddFriendPacket import net.mamoe.mirai.network.protocol.tim.packet.action.ClientAddFriendPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientCanAddFriendPacket import net.mamoe.mirai.network.protocol.tim.packet.action.ClientCanAddFriendPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRefreshmentRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRequestPacket import net.mamoe.mirai.network.protocol.tim.packet.login.ClientSKeyRequestPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerSKeyResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.login.ServerSKeyResponsePacket
......
...@@ -10,7 +10,6 @@ import net.mamoe.mirai.getQQ ...@@ -10,7 +10,6 @@ import net.mamoe.mirai.getQQ
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.network.BotSession import net.mamoe.mirai.network.BotSession
import net.mamoe.mirai.network.distributePacket import net.mamoe.mirai.network.distributePacket
import net.mamoe.mirai.network.protocol.tim.packet.IgnoredServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerFriendOnlineStatusChangedPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerFriendOnlineStatusChangedPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ClientSendFriendMessagePacket
......
...@@ -33,15 +33,4 @@ fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T ...@@ -33,15 +33,4 @@ fun <T : PacketHandler> T.asNode(key: PacketHandler.Key<T>): PacketHandlerNode<T
open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() { open class PacketHandlerList : MutableList<PacketHandlerNode<*>> by mutableListOf() {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key === key }.instance as T operator fun <T : PacketHandler> get(key: PacketHandler.Key<T>): T = this.first { it.key === key }.instance as T
operator fun <T : PacketHandler> get(clazz: KClass<T>): T {
this.forEach {
if (it.clazz == clazz) {
@Suppress("UNCHECKED_CAST")
return@get it.instance as T
}
}
throw NoSuchElementException()
}
} }
...@@ -20,8 +20,6 @@ class ClientSendFriendMessagePacket( ...@@ -20,8 +20,6 @@ class ClientSendFriendMessagePacket(
private val message: MessageChain private val message: MessageChain
) : ClientPacket() { ) : ClientPacket() {
override fun encode(builder: BytePacketBuilder) = with(builder) { override fun encode(builder: BytePacketBuilder) = with(builder) {
writeRandom(2)
writeQQ(botQQ) writeQQ(botQQ)
writeHex(TIMProtocol.fixVer2) writeHex(TIMProtocol.fixVer2)
......
package net.mamoe.mirai.network.protocol.tim.packet.event package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
/** /**
......
...@@ -4,8 +4,6 @@ package net.mamoe.mirai.network.protocol.tim.packet.event ...@@ -4,8 +4,6 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.discardExact import kotlinx.io.core.discardExact
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
import net.mamoe.mirai.utils.readString import net.mamoe.mirai.utils.readString
......
...@@ -7,9 +7,7 @@ import kotlinx.io.core.discardExact ...@@ -7,9 +7,7 @@ import kotlinx.io.core.discardExact
import kotlinx.io.core.readUInt import kotlinx.io.core.readUInt
import net.mamoe.mirai.message.MessageChain import net.mamoe.mirai.message.MessageChain
import net.mamoe.mirai.message.internal.readMessageChain import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity import net.mamoe.mirai.utils.printStringFromHex
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
import net.mamoe.mirai.utils.printTLVMap
import net.mamoe.mirai.utils.read import net.mamoe.mirai.utils.read
import net.mamoe.mirai.utils.readLVByteArray import net.mamoe.mirai.utils.readLVByteArray
import net.mamoe.mirai.utils.readTLVMap import net.mamoe.mirai.utils.readTLVMap
...@@ -64,6 +62,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP ...@@ -64,6 +62,7 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
else -> error("Could not determine member permission, unknown tlv(key=0x04,value=$value0x04)") else -> error("Could not determine member permission, unknown tlv(key=0x04,value=$value0x04)")
} }
} }
0x01u -> SenderPermission.MEMBER
else -> error("Could not determine member permission, unknown tlv(key=0x03,value=$value0x03)") else -> error("Could not determine member permission, unknown tlv(key=0x03,value=$value0x03)")
} }
...@@ -78,6 +77,10 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP ...@@ -78,6 +77,10 @@ class ServerGroupMessageEventPacket(input: ByteReadPacket, eventIdentity: EventP
} }
} }
fun main() {
"00 00 00 08 00 0A 00 04 01 00 00 00 35 DB 60 A2 01 8D 62 3A B8 02 76 E4 B8 DD 06 B4 B4 BD A8 D5 DF 00 30 34 46 30 41 39 37 31 45 42 37 46 31 42 34 43 33 34 41 31 42 34 33 37 41 35 33 45 31 36 43 30 43 38 35 43 36 44 31 34 46 35 44 31 41 31 43 39 34".printStringFromHex()
}
// //
//以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 //以前的消息: 00 00 00 25 00 08 00 02 00 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 58 2C 60 86 35 3A 30 B3 C7 63 4A 80 E7 CD 5B 64 00 0B 78 16 5D A3 0A FD 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 0A FD AB 77 16 02 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 04 01 00 01 36 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
//刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 //刚刚的消息: 00 00 00 2D 00 05 00 02 00 01 00 06 00 04 00 01 2E 01 00 09 00 06 00 01 00 00 00 01 00 0A 00 04 01 00 00 00 00 01 00 04 00 00 00 00 00 03 00 01 01 38 03 3E 03 3F A2 76 E4 B8 DD 11 F4 B2 F2 1A E7 1F C4 F1 3F 23 FB 74 80 42 64 00 0B 78 1A 5D A3 26 C1 01 1D 00 00 00 00 01 00 00 00 01 4D 53 47 00 00 00 00 00 5D A3 26 C1 AA 34 08 42 00 00 00 00 0C 00 86 22 00 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 00 00 01 00 09 01 00 06 E4 BD A0 E5 A5 BD 0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00
...@@ -106,8 +109,8 @@ class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: Event ...@@ -106,8 +109,8 @@ class ServerFriendMessageEventPacket(input: ByteReadPacket, eventIdentity: Event
discardExact(2)//2个0x00 discardExact(2)//2个0x00
message = readMessageChain() message = readMessageChain()
val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() } //val map: Map<Int, ByteArray> = readTLVMap(true).withDefault { byteArrayOf() }
map.printTLVMap("readTLVMap") //map.printTLVMap("readTLVMap")
//println("map.getValue(18)=" + map.getValue(18).toUHexString()) //println("map.getValue(18)=" + map.getValue(18).toUHexString())
//19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01 //19 00 38 01 00 35 AA 02 32 50 03 60 00 68 00 9A 01 29 08 09 20 BF 02 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 B8 03 00 C0 03 00 D0 03 00 E8 03 00 12 00 25 01 00 09 48 69 6D 31 38 38 6D 6F 65 03 00 01 04 04 00 04 00 00 00 08 05 00 04 00 00 00 01 08 00 04 00 00 00 01
......
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS") @file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS")
package net.mamoe.mirai.network.protocol.tim.packet package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.* import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.event.* import net.mamoe.mirai.network.protocol.tim.packet.ClientPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.applySequence
import net.mamoe.mirai.network.protocol.tim.packet.decryptBy
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
/** /**
...@@ -60,27 +63,33 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -60,27 +63,33 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
0x0052u -> ServerGroupMessageEventPacket(input, eventIdentity) 0x0052u -> ServerGroupMessageEventPacket(input, eventIdentity)
0x00A6u -> ServerFriendMessageEventPacket(input.debugPrint("好友消息事件"), eventIdentity) 0x00A6u -> ServerFriendMessageEventPacket(input.debugColorizedPrint("好友消息事件", ignoreUntilFirstConst = true), eventIdentity)
//0210: 00 00 00 0E 00 08 00 02 00 01 00 0A 00 04 01 00 00 00 00 00 00 06 00 00 00 26 08 02 1A 02 08 49 0A 08 08 00 10 B2 DE 8C ED 05 0A 0C 08 A2 FF 8C F0 03 10 E4 A1 A7 ED 05 0A 0C 08 DD F1 92 B7 07 10 B1 DE 8C ED 05
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E // 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 16 00 00 00 37 08 02 1A 12 08 95 02 10 90 04 40 98 E1 8C ED 05 48 AF 96 C3 A4 03 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 1A 29 08 00 10 05 18 98 E1 8C ED 05 20 01 28 FF FF FF FF 0F 32 15 E5 AF B9 E6 96 B9 E6 AD A3 E5 9C A8 E8 BE 93 E5 85 A5 2E 2E 2E
//00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00 // 00 00 00 08 00 0A 00 04 01 00 00 00 00 00 00 07 00 00 00
0x0210u -> { /*{
discardExact(19) //todo 02 10 可能是发起会话? 在手机 QQ 打开一个公众号也有这个包; 取消关注公众号也会有这个包; 手机打开某人聊天界面也会有
println("type事件" + readUByte().toUInt()) 0x0210u -> discardExact(19)
println("type事件" + readUByte().toUInt().toByteArray().toUHexString())
//todo 错了. 可能是 00 79 才是. //todo 错了. 可能是 00 79 才是.
ServerFriendTypingCanceledPacket(input, eventIdentity) ServerFriendTypingCanceledPacket(input, eventIdentity)
/* /*
if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity) if (readUByte().toUInt() == 0x37u) ServerFriendTypingStartedPacket(input, eventIdentity)
else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)*/ else /*0x22*/ ServerFriendTypingCanceledPacket(input, eventIdentity)*/
} }*/
0x0079u -> IgnoredServerEventPacket(type, input, eventIdentity) 0x0210u -> IgnoredServerEventPacket(
eventId = type.toByteArray(),
showData = true,
input = input,
eventIdentity = eventIdentity
)
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity) //"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
else -> { else -> {//0x00 79u, 可能是正在输入的包
MiraiLogger.logDebug("UnknownEvent type = ${type.toInt().toByteArray().toUHexString()}") MiraiLogger.logDebug("UnknownEvent type = ${type.toByteArray().toUHexString()}")
UnknownServerEventPacket(input, eventIdentity) UnknownServerEventPacket(input, eventIdentity)
} }
}.applyId(id).applySequence(sequenceId) }.applyId(id).applySequence(sequenceId)
...@@ -114,7 +123,15 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event ...@@ -114,7 +123,15 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
* 如 00 79: 总是与 01 12 一起发生, 但 00 79 却没多大意义 * 如 00 79: 总是与 01 12 一起发生, 但 00 79 却没多大意义
*/ */
@Suppress("unused") @Suppress("unused")
class IgnoredServerEventPacket(val eventId: UShort, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) class IgnoredServerEventPacket(val eventId: ByteArray, private val showData: Boolean = false, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
override fun decode() {
if (showData) {
MiraiLogger.logDebug("IgnoredServerEventPacket data: " + this.input.readBytes().toUHexString())
} else {
this.input.discard()
}
}
}
/** /**
* Unknown event * Unknown event
......
package net.mamoe.mirai.network.protocol.tim.packet.event package net.mamoe.mirai.network.protocol.tim.packet.event
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import net.mamoe.mirai.network.protocol.tim.packet.EventPacketIdentity
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) { sealed class ServerFriendTypingPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
......
...@@ -78,10 +78,8 @@ private fun BytePacketBuilder.writePart1( ...@@ -78,10 +78,8 @@ private fun BytePacketBuilder.writePart1(
this.writeHex("00 06")//tag this.writeHex("00 06")//tag
this.writeHex("00 78")//length this.writeHex("00 78")//length
if (tlv0006 != null) { if (tlv0006 != null) {
MiraiLogger.logDebug("tlv0006!=null")
this.writeFully(tlv0006) this.writeFully(tlv0006)
} else { } else {
MiraiLogger.logDebug("tlv0006==null")
this.writeTLV0006(qq, password, loginTime, loginIP, privateKey) this.writeTLV0006(qq, password, loginTime, loginIP, privateKey)
} }
//fix //fix
......
package net.mamoe.mirai.utils
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket
/**
* 网络配置
*/
class BotNetworkConfiguration {
/**
* 等待 [ServerTouchResponsePacket] 的时间
*/
var touchTimeoutMillis: Long = 2000
/**
* 是否使用随机的设备名.
* 使用随机可以降低被封禁的风险, 但可能导致每次登录都需要输入验证码
* 当一台设备只登录少量账号时, 将此项设置为 `true` 可能更好.
*/
var randomDeviceName: Boolean = false
/**
* 心跳周期. 过长会导致被服务器断开连接.
*/
var heartbeatPeriodMillis: Long = 1 * 60 * 1000
/**
* 每次心跳时等待结果的时间.
* 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
*/
var heartbeatTimeoutMillis: Long = 2000
companion object {
val Default = BotNetworkConfiguration()
}
}
\ No newline at end of file
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import kotlinx.io.charsets.Charset
import kotlinx.io.charsets.Charsets
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.String import kotlinx.io.core.String
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
...@@ -18,7 +20,7 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s ...@@ -18,7 +20,7 @@ fun ByteArray.toHexString(separator: String = " "): String = this.joinToString(s
@JvmOverloads @JvmOverloads
fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator) fun ByteArray.toUHexString(separator: String = " "): String = this.toUByteArray().toUHexString(separator)
fun ByteArray.stringOf(): String = String(this) fun ByteArray.stringOfWitch(charset: Charset = Charsets.UTF_8): String = String(this, charset = charset)
//@JvmSynthetic TODO 等待 kotlin 修复 bug 后添加这个注解 //@JvmSynthetic TODO 等待 kotlin 修复 bug 后添加这个注解
@JvmOverloads @JvmOverloads
......
...@@ -8,6 +8,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.* ...@@ -8,6 +8,7 @@ import net.mamoe.mirai.network.protocol.tim.packet.*
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ServerCanAddFriendResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendFriendMessageResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendFriendMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendGroupMessageResponsePacket import net.mamoe.mirai.network.protocol.tim.packet.action.ServerSendGroupMessageResponsePacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.login.* import net.mamoe.mirai.network.protocol.tim.packet.login.*
......
...@@ -33,3 +33,25 @@ internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket { ...@@ -33,3 +33,25 @@ internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket {
DebugLogger.logPurple("ByteReadPacket $name=" + bytes.toUHexString()) DebugLogger.logPurple("ByteReadPacket $name=" + bytes.toUHexString())
return bytes.toReadPacket() return bytes.toReadPacket()
} }
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith(""))
internal fun ByteReadPacket.debugColorizedPrint(name: String = "", ignoreUntilFirstConst: Boolean = false): ByteReadPacket {
val bytes = this.readBytes()
bytes.printColorizedHex(name, ignoreUntilFirstConst)
return bytes.toReadPacket()
}
internal fun String.printStringFromHex() {
println(this.hexToBytes().stringOfWitch())
}
internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstConst: Boolean = false) {
println("Hex比较 `$name`")
println(toUHexString().colorize(ignoreUntilFirstConst))
println()
}
expect fun compareHex(hex1s: String, hex2s: String): String
expect fun String.colorize(ignoreUntilFirstConst: Boolean = false): String
\ No newline at end of file
package net.mamoe.mirai.utils
import net.mamoe.mirai.network.protocol.tim.packet.login.ServerTouchResponsePacket
class LoginConfiguration {
/**
* 等待 [ServerTouchResponsePacket] 的时间
*/
var touchTimeoutMillis: Long = 2000
var randomDeviceName: Boolean = false
companion object {
val Default = LoginConfiguration()
}
}
...@@ -4,7 +4,6 @@ package net.mamoe.mirai.utils ...@@ -4,7 +4,6 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.* import kotlinx.io.core.*
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.PacketId
import kotlin.random.Random import kotlin.random.Random
import kotlin.random.nextInt import kotlin.random.nextInt
...@@ -25,9 +24,10 @@ fun BytePacketBuilder.writeLVByteArray(byteArray: ByteArray) { ...@@ -25,9 +24,10 @@ fun BytePacketBuilder.writeLVByteArray(byteArray: ByteArray) {
fun BytePacketBuilder.writeLVPacket(packet: ByteReadPacket) { fun BytePacketBuilder.writeLVPacket(packet: ByteReadPacket) {
this.writeShort(packet.remaining.toShort()) this.writeShort(packet.remaining.toShort())
this.writePacket(packet) this.writePacket(packet)
packet.release()
} }
fun BytePacketBuilder.writeLVPacket(builder: BytePacketBuilder.() -> Unit) = this.writeLVPacket(BytePacketBuilder().apply(builder).use { it.build() }) fun BytePacketBuilder.writeLVPacket(builder: BytePacketBuilder.() -> Unit) = this.writeLVPacket(BytePacketBuilder().apply(builder).build())
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
fun BytePacketBuilder.writeLVString(str: String) = this.writeLVByteArray(str.toByteArray()) fun BytePacketBuilder.writeLVString(str: String) = this.writeLVByteArray(str.toByteArray())
......
...@@ -12,21 +12,30 @@ import kotlin.random.nextInt ...@@ -12,21 +12,30 @@ import kotlin.random.nextInt
* 255 -> 00 00 00 FF * 255 -> 00 00 00 FF
*/ */
fun Int.toByteArray(): ByteArray = byteArrayOf( fun Int.toByteArray(): ByteArray = byteArrayOf(
(this.ushr(24) and 0xFF).toByte(), (ushr(24) and 0xFF).toByte(),
(this.ushr(16) and 0xFF).toByte(), (ushr(16) and 0xFF).toByte(),
(this.ushr(8) and 0xFF).toByte(), (ushr(8) and 0xFF).toByte(),
(this.ushr(0) and 0xFF).toByte() (ushr(0) and 0xFF).toByte()
) )
/** /**
* 255u -> 00 00 00 FF * 255 -> 00 FF
*/ */
fun UShort.toByteArray(): ByteArray = with(toUInt()) {
byteArrayOf(
(shr(8) and 255u).toByte(),
(shr(0) and 255u).toByte()
)
}
/**
* 255u -> 00 00 00 FF
*/
fun UInt.toByteArray(): ByteArray = byteArrayOf( fun UInt.toByteArray(): ByteArray = byteArrayOf(
(this.shr(24) and 255u).toByte(), (shr(24) and 255u).toByte(),
(this.shr(16) and 255u).toByte(), (shr(16) and 255u).toByte(),
(this.shr(8) and 255u).toByte(), (shr(8) and 255u).toByte(),
(this.shr(0) and 255u).toByte() (shr(0) and 255u).toByte()
) )
fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator) fun Int.toUHexString(separator: String = " "): String = this.toByteArray().toUHexString(separator)
......
import net.mamoe.mirai.utils.hexToBytes
import net.mamoe.mirai.utils.stringOfWitch
import net.mamoe.mirai.utils.toUHexString
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
import java.util.*
import java.util.zip.GZIPInputStream
fun main() {
val short: Short = 0x8b1f.toShort()
// 7字节相同| |18字节向东
val bytes = "AA 02 56 30 01 3A 40 53 4B 4B 2F 6F 59 33 42 39 2F 68 56 54 45 4B 65 6A 5A 39 35 45 4D 7A 68 5A 2F 6F 4A 42 79 35 36 61 6F 50 59 32 6E 51 49 77 41 67 37 47 51 33 34 65 72 43 4C 41 72 50 4B 56 39 35 43 76 65 34 64 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00".hexToBytes()
println(bytes.stringOfWitch())
val string = bytes.stringOfWitch()
// println("53 4B 4B 2F 6F 59 33 42 39 2F 68 56 54 45 4B 65 6A 5A 39 35 45 4D 7A 68 5A 2F 6F 4A 42 79 35 36 61 6F 50 59 32 6E 51 49 77 41 67 37 47 51 33 34 65 72 43 4C 41 72 50 4B 56 39 35 43 76 65 34 64".hexToBytes().stringOfWitch())
println("53 4B 4B 2F 6F 59 33 42 39 2F 68 56 54 45 4B 65 6A 5A 39 35 45 4D 7A 68 5A 2F 6F 4A 42 79 35 36 61 6F 50 59 32 6E 51 49 77 41 67 37 47 51 33 34 65 72 43 4C 41 72 50 4B 56 39 35 43 76 65 34 64"
.hexToBytes().unbase64().stringOfWitch())
println("53 4B 4B 2F 6F 59 33 42 39 2F 68 56 54 45 4B 65 6A 5A 39 35 45 4D 7A 68 5A 2F 6F 4A 42 79 35 36 61 6F 50 59 32 6E 51 49 77 41 67 37 47 51 33 34 65 72 43 4C 41 72 50 4B 56 39 35 43 76 65 34 64"
.hexToBytes().unbase64().toUHexString())
//base64解密结果 48 A2 BF A1 8D C1 F7 F8 55 4C 42 9E 8D 9F 79 10 CC E1 67 FA 09 07 2E 7A 6A 83 D8 DA 74 08 C0 08 3B 19 0D F8 7A B0 8B 02 B3 CA 57 DE 42 BD EE 1D
println()
println()
println(Base64.getEncoder().encodeToString(".".repeat(1000).toByteArray()))
// 01 78
val data2 = "9C CD 92 BB 4E C3 30 14 86 77 9E C2 32 23 4A 73 69 D3 76 48 52 25 25 BD 48 84 56 54 15 97 05 85 C4 09 2E B9 A8 4E D2 92 6E DD 10 0C 88 81 0D 84 90 60 40 42 C0 C4 D6 C7 69 E8 63 E0 94 22 46 46 F8 2D 59 F2 B1 7F 9F E3 EF 58 AA 9D FA 1E 18 21 12 E1 30 90 21 5F E0 20 40 81 15 DA 38 70 65 98 C4 0E 53 85 35 65 0D 50 49 7E E4 82 23 82 91 23 C3 C2 3F 17 04 FE A1 83 3D B4 6D FA 48 86 42 45 2F F3 82 58 64 CA A2 2E 32 25 AD 51 66 54 AD 21 32 AA AA AB 1C 5F 15 04 AE 5E F9 76 F4 F0 84 3A 28 05 D3 8A 97 48 46 18 8D 8D C4 8B B1 11 B9 10 38 9E 49 B9 14 21 88 10 19 61 0B B5 37 E9 4A CC CD 04 45 D8 96 E1 38 ED B7 BA 9D 81 53 2F A5 7B A1 A8 B1 29 6E 69 EE C4 68 75 DB FE 46 C7 76 3B 27 BA 67 F4 93 DD 83 DE 7E 33 16 06 CD B2 C6 0F 35 42 D8 52 63 C7 DE 1A 0E 86 1A 04 0A 90 70 8C 7C E0 99 69 98 C4 B4 27 90 46 62 1C 7B 48 01 7F CD F5 37 01 89 5D 55 0A A4 63 A2 48 2C 9D 56 C5 03 2B F4 42 22 C3 F5 2A 97 0F FA A8 EC EE F1 E3 E6 82 CF 6E EF 17 B3 E7 F9 E5 55 F6 7E 96 4D 5F C1 CF 1D 12 9B 83 50 A4 28 4C 88 85 40 B0 6C E6 62 7A 3E 7F 78 5A BC BC CD 67 D7 90 66 F8 DA CC 0F D3 FF A9 7C 02 73 51 C1 65".replace(" ", " ").hexToBytes()
println(data2.size)
println(data2.unbase64().toUHexString())
}
fun ByteArray.unbase64() = Base64.getDecoder().decode(this)
fun ByteArray.ungzip(): ByteArray {
val out = ByteArrayOutputStream()
val `in` = ByteArrayInputStream(this)
val ungzip = GZIPInputStream(`in`)
val buffer = ByteArray(256)
var n: Int
while (ungzip.read(buffer).also { n = it } >= 0) {
out.write(buffer, 0, n)
}
return out.toByteArray()
}
\ No newline at end of file
This diff is collapsed.
...@@ -7,10 +7,10 @@ import kotlinx.io.core.discardExact ...@@ -7,10 +7,10 @@ import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes import kotlinx.io.core.readBytes
import net.mamoe.mirai.message.internal.readMessageChain import net.mamoe.mirai.message.internal.readMessageChain
import net.mamoe.mirai.network.protocol.tim.TIMProtocol import net.mamoe.mirai.network.protocol.tim.TIMProtocol
import net.mamoe.mirai.network.protocol.tim.packet.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket import net.mamoe.mirai.network.protocol.tim.packet.UnknownServerPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
import net.mamoe.mirai.network.protocol.tim.packet.event.UnknownServerEventPacket
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.*
/** /**
...@@ -177,6 +177,6 @@ object Main { ...@@ -177,6 +177,6 @@ object Main {
} }
fun main() { fun main() {
println("00 01 00 23 24 8B 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".hexToBytes().stringOf()) println("00 01 00 23 24 8B 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".hexToBytes().stringOfWitch())
} }
...@@ -7,7 +7,6 @@ import net.mamoe.mirai.event.events.FriendMessageEvent ...@@ -7,7 +7,6 @@ import net.mamoe.mirai.event.events.FriendMessageEvent
import net.mamoe.mirai.event.events.GroupMessageEvent import net.mamoe.mirai.event.events.GroupMessageEvent
import net.mamoe.mirai.event.subscribeAll import net.mamoe.mirai.event.subscribeAll
import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeAlways
import net.mamoe.mirai.event.subscribeOnce
import net.mamoe.mirai.event.subscribeUntilFalse import net.mamoe.mirai.event.subscribeUntilFalse
import net.mamoe.mirai.login import net.mamoe.mirai.login
import net.mamoe.mirai.message.Image import net.mamoe.mirai.message.Image
...@@ -20,8 +19,8 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -20,8 +19,8 @@ import net.mamoe.mirai.utils.MiraiLogger
@Suppress("UNUSED_VARIABLE") @Suppress("UNUSED_VARIABLE")
suspend fun main() { suspend fun main() {
val bot = Bot(BotAccount(//填写你的账号 val bot = Bot(BotAccount(//填写你的账号
account = 1994701021, account = 1994701121,
password = "asdhim188666" password = "123456"
), Console()) ), Console())
bot.login { bot.login {
...@@ -35,9 +34,10 @@ suspend fun main() { ...@@ -35,9 +34,10 @@ suspend fun main() {
} }
//提供泛型以监听事件 //提供泛型以监听事件
subscribeOnce<FriendMessageEvent> { subscribeAlways<FriendMessageEvent> {
//获取第一个纯文本消息, 获取不到会抛出 NoSuchElementException //获取第一个纯文本消息, 获取不到会抛出 NoSuchElementException
val firstText = it.message.first<PlainText>() //val firstText = it.message.first<PlainText>()
val firstText = it.message.firstOrNull<PlainText>()
//获取第一个图片 //获取第一个图片
val firstImage = it.message.firstOrNull<Image>() val firstImage = it.message.firstOrNull<Image>()
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment