StatSvc.Register: Provide SSO Ip and correct logic (#1240)

* StatSvc.Register: Provide SSO Ip and correct logic

* Remove unnessacy launch

Co-authored-by: Him188 <Him188@mamoe.net>

* Test for last polled ip

* Normal login test for last ip

* Fix test failed and remove debug code

* Fix unit test and build

* Optimize pollCurrent and pollAny method

* Use uOldSSOIp and uNewSSOIp only when protocol is PHONE

* Fix bug in toIpV4Long

* Fix new line in NettyBotNormalLoginTest.kt

* Using Inet4Address and toInt method for toIpV4Long

* Return Unsigned Long for toIpV4Long

* Remove unnessacy synchronized annotation

Co-authored-by: Him188 <Him188@mamoe.net>

* Using createAddress method instead of address

* Moving lastDisconnectedIp and lastConnectedIp to Server
List

* Fix build

* Fix build and remove empty line

* Keeping naming consistent

* Use bot.components instead of overrideComponents

Co-authored-by: Him188 <Him188@mamoe.net>

* Revert overrideComponents changes and add comment for overrideComponents

Co-authored-by: Him188 <Him188@mamoe.net>
This commit is contained in:
sandtechnology 2021-07-03 22:04:49 +08:00 committed by GitHub
parent 2713127466
commit b7869888f0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 131 additions and 15 deletions

View File

@ -102,6 +102,16 @@ internal open class QQAndroidBot constructor(
override fun toString(): String = "StateChangedObserver(BotOnlineEventBroadcaster)"
},
StateChangedObserver("LastConnectedAddressUpdater", State.OK) {
components[ServerList].run {
lastConnectedIP = getLastPolledIP()
}
},
StateChangedObserver("LastDisconnectedAddressUpdater", State.CLOSED) {
components[ServerList].run {
lastDisconnectedIP = lastConnectedIP
}
},
StateChangedObserver("BotOfflineEventBroadcaster", State.OK, State.CLOSED) { new ->
// logging performed by BotOfflineEventMonitor
val cause = new.getCause()

View File

@ -58,6 +58,22 @@ internal interface ServerList {
*/
fun refresh()
/**
* Last disconnected ip
*/
var lastDisconnectedIP: String
/**
* Last connected ip
*/
var lastConnectedIP: String
/**
* Get last poll ip
*/
fun getLastPolledIP(): String
/**
* [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty.
*/
@ -100,6 +116,9 @@ internal class ServerListImpl(
@Volatile
private var current: Queue<ServerAddress> = ArrayDeque(initial)
@Volatile
private var lastPolledAddress: ServerAddress? = null
@Synchronized
override fun setPreferred(list: Collection<ServerAddress>) {
logger.info { "Server list: ${list.joinToString()}." }
@ -121,12 +140,19 @@ internal class ServerListImpl(
}
}
override var lastDisconnectedIP: String = ""
override var lastConnectedIP: String = ""
override fun getLastPolledIP(): String = lastPolledAddress?.host ?: ""
/**
* [Poll][Queue.poll] from current address list. Returns `null` if current address list is empty.
*/
@Synchronized
override fun pollCurrent(): ServerAddress? {
return current.poll()
return current.poll()?.also { address ->
lastPolledAddress = address
}
}
/**
@ -135,10 +161,12 @@ internal class ServerListImpl(
@Synchronized
override fun pollAny(): ServerAddress {
if (current.isEmpty()) refresh()
return current.remove()
return current.remove().also { address ->
lastPolledAddress = address
}
}
override fun toString(): String {
return "ServerListImpl(current.size=${current.size})"
}
}
}

View File

@ -30,6 +30,7 @@ import net.mamoe.mirai.internal.message.contextualBugReportException
import net.mamoe.mirai.internal.network.*
import net.mamoe.mirai.internal.network.components.ContactCacheService
import net.mamoe.mirai.internal.network.components.ContactUpdater
import net.mamoe.mirai.internal.network.components.ServerList
import net.mamoe.mirai.internal.network.impl.netty.HeartbeatFailedException
import net.mamoe.mirai.internal.network.protocol.data.jce.*
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
@ -39,6 +40,8 @@ import net.mamoe.mirai.internal.network.protocol.packet.*
import net.mamoe.mirai.internal.utils.NetworkType
import net.mamoe.mirai.internal.utils._miraiContentToString
import net.mamoe.mirai.internal.utils.io.serialization.*
import net.mamoe.mirai.internal.utils.toIpV4Long
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.currentTimeMillis
import net.mamoe.mirai.utils.encodeToString
import net.mamoe.mirai.utils.toReadPacket
@ -158,16 +161,27 @@ internal class StatSvc {
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.appRegister
) = impl("online", client, 1L or 2 or 4, client.onlineStatus, regPushReason) {
client.bot.components[ContactCacheService].friendListCache?.let { friendListCache: FriendListCache ->
iLargeSeq = friendListCache.friendListSeq
// timeStamp = friendListCache.timeStamp
if (client.bot.configuration.protocol == BotConfiguration.MiraiProtocol.ANDROID_PHONE) {
client.bot.components[ServerList].run {
uOldSSOIp = lastDisconnectedIP.toIpV4Long()
uNewSSOIp = lastConnectedIP.toIpV4Long()
}
} else {
uOldSSOIp = 0
uNewSSOIp = 0
}
client.bot.components[ContactCacheService].friendListCache?.let { friendListCache ->
iLargeSeq = friendListCache.friendListSeq
}
// timeStamp = friendListCache.timeStamp
strVendorName = "MIUI"
strVendorOSName = "?ONEPLUS A5000_23_17"
}
fun offline(
client: QQAndroidClient,
regPushReason: RegPushReason = RegPushReason.appRegister
) = impl("offline", client, 0, OnlineStatus.OFFLINE, regPushReason)
) = impl("offline", client, 1L or 2 or 4, OnlineStatus.OFFLINE, regPushReason)
private fun impl(
name: String,
@ -221,10 +235,6 @@ internal class StatSvc {
strDevName = client.device.model.encodeToString(),
strDevType = client.device.model.encodeToString(),
strOSVer = client.device.version.release.encodeToString(),
uOldSSOIp = 0,
uNewSSOIp = 0,
strVendorName = "MIUI",
strVendorOSName = "?ONEPLUS A5000_23_17",
// register 时还需要
/*
var44.uNewSSOIp = field_127445;

View File

@ -11,6 +11,9 @@ package net.mamoe.mirai.internal.utils
import net.mamoe.mirai.contact.ContactOrBot
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.utils.toInt
import net.mamoe.mirai.utils.toLongUnsigned
import java.net.Inet4Address
internal fun Int.toIpV4AddressString(): String {
@ -27,6 +30,18 @@ internal fun Int.toIpV4AddressString(): String {
}
}
internal fun String.toIpV4Long(): Long {
return if (isEmpty()) {
0
} else {
try {
Inet4Address.getByName(this).address.toInt().toLongUnsigned()
} catch (e: UnknownHostException) {
-2
}
}
}
internal fun String.chineseLength(upTo: Int): Int {
return this.sumUpTo(upTo) {
when (it) {

View File

@ -27,6 +27,18 @@ internal class ServerListTest : AbstractTest() {
assertNotNull(ServerListImpl().pollCurrent())
}
@Test
fun `last poll ip is updated when polled`() {
val instance = ServerListImpl()
val old = instance.getLastPolledIP()
assertNotNull(old)
assert(old.isEmpty())
assertNotNull(instance.pollCurrent())
val new = instance.getLastPolledIP()
assertNotNull(new)
assertNotEquals(old, new)
}
@Test
fun `not empty for initial`() {
assertNotNull(ServerListImpl().pollAny())

View File

@ -34,7 +34,7 @@ internal abstract class AbstractNettyNHTestWithSelector : AbstractRealNetworkHan
val channel = AbstractNettyNHTest.NettyNHTestChannel()
val selector = TestSelector<TestNettyNH> {
object : TestNettyNH(bot, createContext(), address) {
object : TestNettyNH(bot, createContext(), createAddress()) {
override suspend fun createConnection(decodePipeline: PacketDecodePipeline): Channel = channel
}
}

View File

@ -132,11 +132,13 @@ internal sealed class AbstractRealNetworkHandlerTest<H : NetworkHandler> : Abstr
return instance
}
open fun createHandler(): NetworkHandler = factory.create(createContext(), address)
open fun createHandler(): NetworkHandler = factory.create(createContext(), createAddress())
open fun createContext(): NetworkHandlerContextImpl =
NetworkHandlerContextImpl(bot, networkLogger, bot.createNetworkLevelComponents())
val address: InetSocketAddress = InetSocketAddress.createUnresolved("localhost", 123)
//Use overrideComponents to avoid StackOverflowError when applying components
open fun createAddress(): InetSocketAddress =
overrideComponents[ServerList].pollAny().let { InetSocketAddress.createUnresolved(it.host, it.port) }
///////////////////////////////////////////////////////////////////////////
// Assertions

View File

@ -0,0 +1,39 @@
package net.mamoe.mirai.internal.network.impl.netty
import net.mamoe.mirai.internal.network.components.ServerList
import net.mamoe.mirai.internal.network.framework.AbstractNettyNHTest
import net.mamoe.mirai.internal.network.framework.TestNettyNH
import net.mamoe.mirai.internal.network.handler.NetworkHandler
import net.mamoe.mirai.internal.test.runBlockingUnit
import org.junit.jupiter.api.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals
internal class NettyAddressChangedTest : AbstractNettyNHTest() {
@Test
fun `test login ip changes`() = runBlockingUnit {
networkLogger.debug("before login, Assuming both ip is empty")
val lastConnectedIpOld = bot.components[ServerList].lastConnectedIP
val lastDisconnectedIpOld = bot.components[ServerList].lastDisconnectedIP
assert(lastConnectedIpOld.isEmpty()) { "Assuming lastConnectedIp is empty" }
assert(lastDisconnectedIpOld.isEmpty()) { "Assuming lastDisconnectedIp is empty" }
networkLogger.debug("Do login, Assuming lastConnectedIp is NOT empty")
bot.login()
assertState(NetworkHandler.State.OK)
assertNotEquals(
lastConnectedIpOld,
bot.components[ServerList].lastConnectedIP,
"Assuming lastConnectedIp is NOT empty"
)
networkLogger.debug("Offline the bot, Assuming lastConnectedIp is equals lastDisconnectedIp")
(bot.network as TestNettyNH).setStateClosed()
assertState(NetworkHandler.State.CLOSED)
assertEquals(
bot.components[ServerList].lastConnectedIP,
bot.components[ServerList].lastDisconnectedIP,
"Assuming lastConnectedIp is equals lastDisconnectedIp"
)
}
}

View File

@ -26,7 +26,7 @@ import kotlin.test.assertFalse
internal class NettyBotNormalLoginTest : AbstractNettyNHTest() {
val selector = KeepAliveNetworkHandlerSelector(selectorLogger) {
super.factory.create(createContext(), address)
super.factory.create(createContext(), createAddress())
}
override fun createHandler(): NetworkHandler {