mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-12 10:40:21 +08:00
Fix bugs
This commit is contained in:
parent
05dfeb7661
commit
6ef78118ad
@ -3,29 +3,29 @@ package net.mamoe.mirai.qqandroid.network
|
||||
import kotlinx.atomicfu.AtomicRef
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
import kotlinx.coroutines.sync.withLock
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.Input
|
||||
import kotlinx.io.core.buildPacket
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.event.Cancellable
|
||||
import net.mamoe.mirai.event.Subscribable
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.*
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
|
||||
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.getValue
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
|
||||
@ -41,14 +41,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
|
||||
private lateinit var channel: PlatformSocket
|
||||
|
||||
|
||||
override suspend fun login() {
|
||||
if (::channel.isInitialized) {
|
||||
channel.close()
|
||||
}
|
||||
channel = PlatformSocket()
|
||||
channel.connect("113.96.13.208", 8080)
|
||||
launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
|
||||
this.launch(CoroutineName("Incoming Packet Receiver")) { processReceive() }
|
||||
|
||||
// bot.logger.info("Trying login")
|
||||
var response: LoginPacket.LoginPacketResponse = LoginPacket.SubCommand9(bot.client).sendAndExpect()
|
||||
@ -104,27 +103,18 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
override suspend fun init() {
|
||||
//start updating friend/group list
|
||||
bot.logger.info("Start updating friend/group list")
|
||||
|
||||
/*
|
||||
val data = FriendList.GetFriendGroupList(
|
||||
bot.client,
|
||||
0,
|
||||
20,
|
||||
0,
|
||||
0
|
||||
).sendAndExpect<FriendList.GetFriendGroupList.Response>()
|
||||
|
||||
|
||||
println(data.contentToString())
|
||||
*/
|
||||
bot.logger.info("开始加载好友信息")
|
||||
|
||||
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
|
||||
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
|
||||
close()
|
||||
}
|
||||
}
|
||||
/*
|
||||
* 开始加载Contact表
|
||||
* */
|
||||
var currentFriendCount = 0
|
||||
var totalFriendCount: Short = 0
|
||||
var totalFriendCount: Short
|
||||
while (true) {
|
||||
val data = FriendList.GetFriendGroupList(
|
||||
bot.client,
|
||||
@ -134,14 +124,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
0
|
||||
).sendAndExpect<FriendList.GetFriendGroupList.Response>()
|
||||
totalFriendCount = data.totalFriendCount
|
||||
bot.qqs.delegate.addAll(
|
||||
data.friendList.map {
|
||||
QQImpl(this@QQAndroidBotNetworkHandler.bot, EmptyCoroutineContext, it.friendUin!!).also {
|
||||
currentFriendCount++
|
||||
}
|
||||
}
|
||||
)
|
||||
bot.logger.info("正在加载好友信息 ${currentFriendCount}/${totalFriendCount}")
|
||||
data.friendList.forEach {
|
||||
// atomic add
|
||||
bot.qqs.delegate.addLast(QQImpl(bot, EmptyCoroutineContext, it.friendUin).also {
|
||||
currentFriendCount++
|
||||
})
|
||||
}
|
||||
bot.logger.verbose("正在加载好友信息 ${currentFriendCount}/${totalFriendCount}")
|
||||
if (currentFriendCount >= totalFriendCount) {
|
||||
break
|
||||
}
|
||||
@ -155,22 +144,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
).sendAndExpect<FriendList.GetTroopList.Response>(100000)
|
||||
println(data.contentToString())
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 单线程处理包的接收, 分割和连接.
|
||||
*/
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val PacketReceiveDispatcher = newCoroutineDispatcher(1)
|
||||
|
||||
/**
|
||||
* 单线程处理包的解析 (协程挂起效率够)
|
||||
*/
|
||||
@Suppress("PrivatePropertyName")
|
||||
private val PacketProcessDispatcher = newCoroutineDispatcher(1)
|
||||
|
||||
/**
|
||||
* 缓存超时处理的 [Job]. 超时后将清空缓存, 以免阻碍后续包的处理
|
||||
*/
|
||||
@ -185,12 +160,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
private var expectingRemainingLength: Long = 0
|
||||
|
||||
/**
|
||||
* 在 [PacketProcessDispatcher] 调度器中解析包内容.
|
||||
* 解析包内容.
|
||||
*
|
||||
* @param input 一个完整的包的内容, 去掉开头的 int 包长度
|
||||
*/
|
||||
fun parsePacketAsync(input: Input): Job {
|
||||
return this.launch(PacketProcessDispatcher) {
|
||||
return this.launch {
|
||||
input.use { parsePacket(it) }
|
||||
}
|
||||
}
|
||||
@ -337,28 +312,32 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
val rawInput = try {
|
||||
channel.read()
|
||||
} catch (e: ClosedChannelException) {
|
||||
dispose()
|
||||
close()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: ReadPacketInternalException) {
|
||||
bot.logger.error("Socket channel read failed: ${e.message}")
|
||||
dispose()
|
||||
close()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
} catch (e: CancellationException) {
|
||||
return
|
||||
} catch (e: Throwable) {
|
||||
bot.logger.error("Caught unexpected exceptions", e)
|
||||
dispose()
|
||||
close()
|
||||
bot.tryReinitializeNetworkHandler(e)
|
||||
return
|
||||
}
|
||||
launch(context = PacketReceiveDispatcher + CoroutineName("Incoming Packet handler"), start = CoroutineStart.ATOMIC) {
|
||||
processPacket(rawInput)
|
||||
launch(CoroutineName("Incoming Packet handler"), start = CoroutineStart.ATOMIC) {
|
||||
packetReceiveLock.withLock {
|
||||
processPacket(rawInput)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val packetReceiveLock: Mutex = Mutex()
|
||||
|
||||
/**
|
||||
* 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms)
|
||||
*/
|
||||
@ -381,7 +360,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
}
|
||||
|
||||
private suspend inline fun <E : Packet> OutgoingPacket.doSendAndReceive(timeoutMillis: Long = 3000, handler: PacketListener): E {
|
||||
channel.send(delegate)
|
||||
withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) {
|
||||
channel.send(delegate)
|
||||
}
|
||||
bot.logger.info("Send: ${this.commandName}")
|
||||
return withTimeoutOrNull(timeoutMillis) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@ -403,11 +384,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
fun filter(commandName: String, sequenceId: Int) = this.commandName == commandName && this.sequenceId == sequenceId
|
||||
}
|
||||
|
||||
override fun dispose(cause: Throwable?) {
|
||||
override fun close(cause: Throwable?) {
|
||||
if (::channel.isInitialized) {
|
||||
channel.close()
|
||||
}
|
||||
super.dispose(cause)
|
||||
super.close(cause)
|
||||
}
|
||||
|
||||
override suspend fun awaitDisconnection() = supervisor.join()
|
||||
|
@ -67,7 +67,7 @@ internal class FriendListSubSrvRspCode(
|
||||
|
||||
@Serializable
|
||||
internal class FriendInfo(
|
||||
@SerialId(0) val friendUin: Long? = 0,
|
||||
@SerialId(0) val friendUin: Long,
|
||||
@SerialId(1) val groupId: Byte,
|
||||
@SerialId(2) val faceId: Short,
|
||||
@SerialId(3) val remark: String = "",
|
||||
|
@ -16,7 +16,6 @@ import net.mamoe.mirai.utils.io.writeQQ
|
||||
* 待发送给服务器的数据包. 它代表着一个 [ByteReadPacket].
|
||||
* 只有最终的包才会被包装为 [OutgoingPacket].
|
||||
*/
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
internal class OutgoingPacket constructor(
|
||||
name: String?,
|
||||
val commandName: String,
|
||||
|
@ -12,7 +12,6 @@ import net.mamoe.mirai.qqandroid.utils.GuidSource
|
||||
import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag
|
||||
import net.mamoe.mirai.qqandroid.utils.guidFlag
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.cryptor.decryptBy
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.io.discardExact
|
||||
@ -317,13 +316,13 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
|
||||
|
||||
|
||||
val subCommand = readUShort().toInt()
|
||||
println("subCommand=$subCommand")
|
||||
// println("subCommand=$subCommand")
|
||||
val type = readUByte()
|
||||
println("type=$type")
|
||||
// println("type=$type")
|
||||
|
||||
discardExact(2)
|
||||
val tlvMap: TlvMap = this.readTLVMap()
|
||||
tlvMap.printTLVMap()
|
||||
// tlvMap.printTLVMap()
|
||||
return when (type.toInt()) {
|
||||
0 -> onLoginSuccess(tlvMap, bot)
|
||||
1, 15 -> onErrorMessage(tlvMap)
|
||||
@ -340,7 +339,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
|
||||
bot: QQAndroidBot
|
||||
): LoginPacketResponse.DeviceLockLogin {
|
||||
bot.client.t104 = tlvMap.getOrFail(0x104)
|
||||
println("403: " + tlvMap[0x403]?.toUHexString())
|
||||
// println("403: " + tlvMap[0x403]?.toUHexString())
|
||||
return LoginPacketResponse.DeviceLockLogin(tlvMap[0x402]!!, tlvMap.getOrFail(0x403))
|
||||
}
|
||||
|
||||
@ -392,10 +391,10 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
|
||||
@UseExperimental(MiraiDebugAPI::class)
|
||||
private fun onLoginSuccess(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Success {
|
||||
val client = bot.client
|
||||
println("TLV KEYS: " + tlvMap.keys.joinToString { it.contentToString() })
|
||||
//println("TLV KEYS: " + tlvMap.keys.joinToString { it.contentToString() })
|
||||
|
||||
tlvMap[0x150]?.let { client.analysisTlv150(it) }
|
||||
tlvMap[0x305]?.let { println("TLV 0x305=${it.toUHexString()}") }
|
||||
// tlvMap[0x305]?.let { println("TLV 0x305=${it.toUHexString()}") }
|
||||
tlvMap[0x161]?.let { client.analysisTlv161(it) }
|
||||
tlvMap[0x119]?.let { t119Data ->
|
||||
t119Data.decryptBy(client.tgtgtKey).toReadPacket().debugPrint("0x119data").apply {
|
||||
|
@ -92,7 +92,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
|
||||
}
|
||||
|
||||
override fun dispose(cause: Throwable?) {
|
||||
super.dispose(cause)
|
||||
super.close(cause)
|
||||
|
||||
this.heartbeatJob?.cancel(CancellationException("handler closed"))
|
||||
this.heartbeatJob = null
|
||||
|
@ -22,7 +22,8 @@ data class BotAccount(
|
||||
/**
|
||||
* 标记直接访问 [BotAccount.id], 而不是访问 [Bot.uin]. 这可能会不兼容未来的 API 修改.
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
@Retention(AnnotationRetention.SOURCE)
|
||||
@Target(CLASS, TYPEALIAS, FUNCTION, PROPERTY, FIELD, CONSTRUCTOR)
|
||||
@Experimental(level = Experimental.Level.WARNING)
|
||||
internal annotation class RawAccountIdUse
|
||||
annotation class RawAccountIdUse
|
@ -92,20 +92,20 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
try {
|
||||
if (::_network.isInitialized) {
|
||||
BotOfflineEvent(this).broadcast()
|
||||
_network.dispose(cause)
|
||||
_network.close(cause)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error("Cannot close network handler", e)
|
||||
}
|
||||
_network = createNetworkHandler(this.coroutineContext)
|
||||
|
||||
loginLoop@ while (true) {
|
||||
_network = createNetworkHandler(this.coroutineContext)
|
||||
try {
|
||||
_network.login()
|
||||
break@loginLoop
|
||||
} catch (e: Exception) {
|
||||
e.logStacktrace()
|
||||
_network.dispose(e)
|
||||
_network.close(e)
|
||||
}
|
||||
logger.warning("Login failed. Retrying in 3s...")
|
||||
delay(3000)
|
||||
@ -116,7 +116,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
return _network.init()
|
||||
} catch (e: Exception) {
|
||||
e.logStacktrace()
|
||||
_network.dispose(e)
|
||||
_network.close(e)
|
||||
}
|
||||
logger.warning("Init failed. Retrying in 3s...")
|
||||
delay(3000)
|
||||
@ -130,12 +130,12 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
override fun dispose(throwable: Throwable?) {
|
||||
if (throwable == null) {
|
||||
network.dispose()
|
||||
network.close()
|
||||
this.botJob.complete()
|
||||
groups.delegate.clear()
|
||||
qqs.delegate.clear()
|
||||
} else {
|
||||
network.dispose(throwable)
|
||||
network.close(throwable)
|
||||
this.botJob.completeExceptionally(throwable)
|
||||
groups.delegate.clear()
|
||||
qqs.delegate.clear()
|
||||
|
@ -24,7 +24,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
|
||||
* - Key 刷新
|
||||
* - 所有数据包处理和发送
|
||||
*
|
||||
* [BotNetworkHandler.dispose] 时将会 [取消][Job.cancel] 所有此作用域下的协程
|
||||
* [BotNetworkHandler.close] 时将会 [取消][Job.cancel] 所有此作用域下的协程
|
||||
*/
|
||||
@Suppress("PropertyName")
|
||||
abstract class BotNetworkHandler : CoroutineScope {
|
||||
@ -64,12 +64,12 @@ abstract class BotNetworkHandler : CoroutineScope {
|
||||
/**
|
||||
* 关闭网络接口, 停止所有有关协程和任务
|
||||
*/
|
||||
open fun dispose(cause: Throwable? = null) {
|
||||
open fun close(cause: Throwable? = null) {
|
||||
if (supervisor.isActive) {
|
||||
if (cause != null) {
|
||||
supervisor.cancel(CancellationException("handler closed", cause))
|
||||
supervisor.cancel(CancellationException("NetworkHandler closed", cause))
|
||||
} else {
|
||||
supervisor.cancel()
|
||||
supervisor.cancel(CancellationException("NetworkHandler closed"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user