mirror of
https://github.com/mamoe/mirai.git
synced 2025-03-23 22:00:10 +08:00
Fix wrong decoding on ConfigPushSvc and update default server list (#1015)
* Fix wrong decoding on ConfigPushSvc and update default server list * Fix a bug which won't update server list * Improve wording * Fix an encoding error * Fix wording * Naming consistently * Improve ServerListPush message Co-authored-by: Him188 <Him188@mamoe.net> Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
parent
4ac7d3fa9a
commit
9699218601
@ -14,7 +14,6 @@ package net.mamoe.mirai.internal.network
|
||||
import kotlinx.atomicfu.AtomicBoolean
|
||||
import kotlinx.atomicfu.AtomicInt
|
||||
import kotlinx.atomicfu.atomic
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.io.core.BytePacketBuilder
|
||||
import kotlinx.io.core.String
|
||||
import kotlinx.io.core.toByteArray
|
||||
@ -46,7 +45,7 @@ internal fun getRandomByteArray(length: Int): ByteArray = ByteArray(length) { Ra
|
||||
// [114.221.148.179:14000, 113.96.13.125:8080, 14.22.3.51:8080, 42.81.172.207:443, 114.221.144.89:80, 125.94.60.148:14000, 42.81.192.226:443, 114.221.148.233:8080, msfwifi.3g.qq.com:8080, 42.81.172.22:80]
|
||||
|
||||
internal val DefaultServerList: MutableSet<Pair<String, Int>> =
|
||||
"114.221.148.179:14000, 113.96.13.125:8080, 14.22.3.51:8080, 42.81.172.207:443, 114.221.144.89:80, 125.94.60.148:14000, 42.81.192.226:443, 114.221.148.233:8080, msfwifi.3g.qq.com:8080, 42.81.172.22:80"
|
||||
"msfwifi.3g.qq.com:8080, 14.215.138.110:8080, 113.96.12.224:8080, 157.255.13.77:14000, 120.232.18.27:443, 183.3.235.162:14000, 163.177.89.195:443, 183.232.94.44:80, 203.205.255.224:8080, 203.205.255.221:8080"
|
||||
.split(", ")
|
||||
.map {
|
||||
val host = it.substringBefore(':')
|
||||
|
@ -368,14 +368,14 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
||||
logger.warning { "Missing ConfigPushSvc.PushReq. Switching server..." }
|
||||
bot.launch { BotOfflineEvent.RequireReconnect(bot).broadcast() }
|
||||
} else {
|
||||
logger.warning { "Missing ConfigPushSvc.PushReq. Using latest response. File uploading may be affected." }
|
||||
logger.warning { "Missing ConfigPushSvc.PushReq. Using the latest response. File uploading may be affected." }
|
||||
}
|
||||
}
|
||||
is ConfigPushSvc.PushReq.PushReqResponse.Success -> {
|
||||
logger.info { "ConfigPushSvc.PushReq: Success." }
|
||||
is ConfigPushSvc.PushReq.PushReqResponse.ConfigPush -> {
|
||||
logger.info { "ConfigPushSvc.PushReq: Config updated." }
|
||||
}
|
||||
is ConfigPushSvc.PushReq.PushReqResponse.ChangeServer -> {
|
||||
logger.info { "ConfigPushSvc.PushReq: Require reconnect" }
|
||||
is ConfigPushSvc.PushReq.PushReqResponse.ServerListPush -> {
|
||||
logger.info { "ConfigPushSvc.PushReq: Server updated." }
|
||||
// handled in ConfigPushSvc
|
||||
return@launch
|
||||
}
|
||||
|
@ -147,6 +147,55 @@ internal class PushReq(
|
||||
@TarsId(3) @JvmField val seq: Long
|
||||
) : JceStruct, Packet
|
||||
|
||||
@Serializable
|
||||
internal data class ServerListPush(
|
||||
@TarsId(1) val mobileSSOServerList: List<ServerInfo>,
|
||||
@TarsId(3) val wifiSSOServerList: List<ServerInfo>,
|
||||
@TarsId(4) val reconnectNeeded: Int = 0,
|
||||
//@JvmField @TarsId(5) val skipped:Byte? = 0,
|
||||
//@JvmField @TarsId(6) val skipped:Byte? = 0,
|
||||
//@JvmField @TarsId(7) val skipped:Int? = 1,
|
||||
@TarsId(8) val mobileHttpServerList: List<ServerInfo>,
|
||||
@TarsId(9) val wifiHttpServerList: List<ServerInfo>,
|
||||
@TarsId(10) val quicServerList: List<ServerInfo>,
|
||||
@TarsId(11) val ssoServerListIpv6: List<ServerInfo>,
|
||||
@TarsId(12) val httpServerListIpv6: List<ServerInfo>,
|
||||
@TarsId(13) val quicServerListIpv6: List<ServerInfo>,
|
||||
/**
|
||||
* wifi下&1==1则启用
|
||||
* 移动数据(mobile)下&2==2则启用
|
||||
*/
|
||||
@TarsId(14) val ipv6ConfigVal: Byte? = 0,
|
||||
//@JvmField @TarsId(15) val netTestDelay:Int? = 0,
|
||||
@TarsId(16) val configDesc: String? = ""
|
||||
) : JceStruct {
|
||||
|
||||
@Serializable
|
||||
data class ServerInfo(
|
||||
@TarsId(1) val host: String,
|
||||
@TarsId(2) val port: Int,
|
||||
//@JvmField @TarsId(3) val skipped: Byte = 0,
|
||||
//@JvmField @TarsId(4) val skipped: Byte = 0,
|
||||
/**
|
||||
* 2,3->http
|
||||
* 0,1->socket
|
||||
*/
|
||||
//@JvmField @TarsId(5) val protocolType: Byte? = 0,
|
||||
//@JvmField @TarsId(6) val skipped: Int? = 8,
|
||||
//@JvmField @TarsId(7) val skipped: Byte? = 0,
|
||||
@TarsId(8) val location: String = "",
|
||||
/**
|
||||
* cm->China mobile 中国移动
|
||||
* uni->China unicom 中国联通
|
||||
* others->其他
|
||||
*/
|
||||
@TarsId(9) val ispName: String = ""
|
||||
) : JceStruct {
|
||||
override fun toString(): String {
|
||||
return "$host:$port"
|
||||
}
|
||||
}
|
||||
}
|
||||
@Serializable
|
||||
internal class PushResp(
|
||||
@TarsId(1) @JvmField val type: Int,
|
||||
|
@ -12,7 +12,6 @@ package net.mamoe.mirai.internal.network.protocol.packet.login
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.event.AbstractEvent
|
||||
import net.mamoe.mirai.event.Event
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
@ -24,15 +23,15 @@ import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.FileStoragePushFSSvcList
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.PushResp
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.ServerListPush
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Subcmd0x501
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.IncomingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildResponseUniPacket
|
||||
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||
import net.mamoe.mirai.internal.utils.NetworkType
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.jceRequestSBuffer
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readUniPacket
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeJceStruct
|
||||
import net.mamoe.mirai.utils.info
|
||||
import net.mamoe.mirai.utils.toUHexString
|
||||
@ -46,66 +45,46 @@ internal class ConfigPushSvc {
|
||||
) {
|
||||
override val canBeCached: Boolean get() = false
|
||||
|
||||
sealed class PushReqResponse : Packet, Event, AbstractEvent(), Packet.NoEventLog {
|
||||
class Success(
|
||||
val struct: PushReqJceStruct
|
||||
) : PushReqResponse() {
|
||||
sealed class PushReqResponse(val struct: PushReqJceStruct) : Packet, Event, AbstractEvent(), Packet.NoEventLog {
|
||||
class Unknown(struct: PushReqJceStruct) : PushReqResponse(struct) {
|
||||
override fun toString(): String {
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.Success"
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ChangeServer(
|
||||
@TarsId(1) val serverList: List<ServerInfo>,
|
||||
// @TarsId(3) val serverList2: List<ServerInfo>,
|
||||
// @TarsId(8) val serverList3: List<ServerInfo>,
|
||||
) : JceStruct, PushReqResponse() {
|
||||
class LogAction(struct: PushReqJceStruct) : PushReqResponse(struct) {
|
||||
override fun toString(): String {
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.ChangeServer"
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ServerInfo(
|
||||
/*
|
||||
skipping String1
|
||||
skipping Short
|
||||
skipping Byte
|
||||
skipping Zero
|
||||
skipping Zero
|
||||
skipping Byte
|
||||
skipping Byte
|
||||
skipping String1
|
||||
skipping String1
|
||||
*/
|
||||
@TarsId(1) val host: String,
|
||||
@TarsId(2) val port: Int,
|
||||
@TarsId(8) val location: String
|
||||
) : JceStruct {
|
||||
override fun toString(): String {
|
||||
return "$host:$port"
|
||||
}
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.LogAction"
|
||||
}
|
||||
}
|
||||
|
||||
class ServerListPush(struct: PushReqJceStruct) : PushReqResponse(struct) {
|
||||
override fun toString(): String {
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.ServerListPush"
|
||||
}
|
||||
}
|
||||
|
||||
class ConfigPush(struct: PushReqJceStruct) : PushReqResponse(struct) {
|
||||
override fun toString(): String {
|
||||
return "ConfigPushSvc.PushReq.PushReqResponse.ConfigPush"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): PushReqResponse {
|
||||
val pushReq = readUniPacket(PushReqJceStruct.serializer(), "PushReq")
|
||||
return when (pushReq.type) {
|
||||
1 -> kotlin.runCatching {
|
||||
pushReq.jcebuf.loadAs(PushReqResponse.ChangeServer.serializer())
|
||||
}.getOrElse {
|
||||
throw contextualBugReportException(
|
||||
"ConfigPush.ReqPush type=1",
|
||||
forDebug = pushReq.jcebuf.toUHexString(),
|
||||
)
|
||||
}
|
||||
else -> PushReqResponse.Success(pushReq)
|
||||
1 -> PushReqResponse.ServerListPush(pushReq)
|
||||
2 -> PushReqResponse.ConfigPush(pushReq)
|
||||
3 -> PushReqResponse.LogAction(pushReq)
|
||||
else -> PushReqResponse.Unknown(pushReq)
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun QQAndroidBot.handle(packet: PushReqResponse, sequenceId: Int): OutgoingPacket? {
|
||||
fun handleSuccess(packet: PushReqResponse.Success) {
|
||||
fun handleConfigPush(packet: PushReqResponse.ConfigPush) {
|
||||
val pushReq = packet.struct
|
||||
|
||||
// FS server
|
||||
@ -148,64 +127,79 @@ internal class ConfigPushSvc {
|
||||
)
|
||||
}
|
||||
|
||||
fun handleRequireReconnect(resp: PushReqResponse.ChangeServer) {
|
||||
bot.logger.info { "Server requires reconnect." }
|
||||
bot.logger.info { "Server list: ${resp.serverList.joinToString()}." }
|
||||
fun handleServerListPush(resp: PushReqResponse.ServerListPush) {
|
||||
bot.network.logger.info { "Server list updated." }
|
||||
val serverListPush = kotlin.runCatching {
|
||||
resp.struct.jcebuf.loadAs(ServerListPush.serializer())
|
||||
}.getOrElse {
|
||||
throw contextualBugReportException(
|
||||
"ConfigPush.ReqPush type=1",
|
||||
forDebug = resp.struct.jcebuf.toUHexString(),
|
||||
)
|
||||
}
|
||||
val pushServerList = if (client.networkType == NetworkType.WIFI) {
|
||||
serverListPush.wifiSSOServerList
|
||||
} else {
|
||||
serverListPush.mobileSSOServerList
|
||||
}
|
||||
|
||||
if (resp.serverList.isNotEmpty()) {
|
||||
bot.logger.info { "Server list: ${pushServerList.joinToString()}." }
|
||||
|
||||
if (pushServerList.isNotEmpty()) {
|
||||
bot.serverList.clear()
|
||||
resp.serverList.shuffled().forEach {
|
||||
pushServerList.shuffled().forEach {
|
||||
bot.serverList.add(it.host to it.port)
|
||||
}
|
||||
}
|
||||
bot.bdhSyncer.saveToCache()
|
||||
bot.bdhSyncer.saveServerListToCache()
|
||||
|
||||
bot.launch {
|
||||
delay(1000)
|
||||
BotOfflineEvent.RequireReconnect(bot).broadcast()
|
||||
if (serverListPush.reconnectNeeded == 1) {
|
||||
bot.logger.info { "Server request to change server." }
|
||||
bot.launch {
|
||||
delay(1000)
|
||||
BotOfflineEvent.RequireReconnect(bot).broadcast()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when (packet) {
|
||||
is PushReqResponse.Success -> {
|
||||
handleSuccess(packet)
|
||||
if (!client.wLoginSigInfoInitialized) return null // concurrently doing reconnection
|
||||
return buildResponseUniPacket(
|
||||
client,
|
||||
sequenceId = sequenceId,
|
||||
key = client.wLoginSigInfo.d2Key
|
||||
) {
|
||||
writeJceStruct(
|
||||
RequestPacket.serializer(),
|
||||
RequestPacket(
|
||||
requestId = 0,
|
||||
version = 3,
|
||||
servantName = "QQService.ConfigPushSvc.MainServant",
|
||||
funcName = "PushResp",
|
||||
sBuffer = jceRequestSBuffer(
|
||||
"PushResp",
|
||||
PushResp.serializer(),
|
||||
PushResp(
|
||||
type = packet.struct.type,
|
||||
seq = packet.struct.seq,
|
||||
jcebuf = if (packet.struct.type == 3) packet.struct.jcebuf else null
|
||||
)
|
||||
)
|
||||
is PushReqResponse.ConfigPush -> {
|
||||
handleConfigPush(packet)
|
||||
}
|
||||
is PushReqResponse.ServerListPush -> {
|
||||
handleServerListPush(packet)
|
||||
}
|
||||
is PushReqResponse.LogAction, is PushReqResponse.Unknown -> {
|
||||
//ignore
|
||||
}
|
||||
}
|
||||
//Always send resp
|
||||
if (!client.wLoginSigInfoInitialized) return null // concurrently doing reconnection
|
||||
return buildResponseUniPacket(
|
||||
client,
|
||||
sequenceId = sequenceId,
|
||||
key = client.wLoginSigInfo.d2Key
|
||||
) {
|
||||
writeJceStruct(
|
||||
RequestPacket.serializer(),
|
||||
RequestPacket(
|
||||
requestId = client.nextRequestPacketRequestId(),
|
||||
version = 3,
|
||||
servantName = "QQService.ConfigPushSvc.MainServant",
|
||||
funcName = "PushResp",
|
||||
sBuffer = jceRequestSBuffer(
|
||||
"PushResp",
|
||||
PushResp.serializer(),
|
||||
PushResp(
|
||||
type = packet.struct.type,
|
||||
seq = packet.struct.seq,
|
||||
jcebuf = if (packet.struct.type == 3) packet.struct.jcebuf else null
|
||||
)
|
||||
)
|
||||
// writePacket(this.build().debugPrintThis())
|
||||
}
|
||||
}
|
||||
is PushReqResponse.ChangeServer -> {
|
||||
handleRequireReconnect(packet)
|
||||
return null
|
||||
}
|
||||
else -> {
|
||||
// handled in QQABot
|
||||
return null
|
||||
}
|
||||
)
|
||||
)
|
||||
// writePacket(this.build().debugPrintThis())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user