mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-31 11:30:16 +08:00
Support OtherClient list sync after login, support deviceName
This commit is contained in:
parent
ad8ffa6cd4
commit
3ce6f092a1
@ -14,9 +14,7 @@
|
|||||||
package net.mamoe.mirai
|
package net.mamoe.mirai
|
||||||
|
|
||||||
import net.mamoe.kjbb.JvmBlockingBridge
|
import net.mamoe.kjbb.JvmBlockingBridge
|
||||||
import net.mamoe.mirai.contact.Contact
|
import net.mamoe.mirai.contact.*
|
||||||
import net.mamoe.mirai.contact.Friend
|
|
||||||
import net.mamoe.mirai.contact.PermissionDeniedException
|
|
||||||
import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
|
import net.mamoe.mirai.event.events.BotInvitedJoinGroupRequestEvent
|
||||||
import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
import net.mamoe.mirai.event.events.MemberJoinRequestEvent
|
||||||
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
import net.mamoe.mirai.event.events.NewFriendRequestEvent
|
||||||
@ -179,6 +177,14 @@ public interface IMirai : LowLevelApiAccessor {
|
|||||||
message: String = ""
|
message: String = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取在线的 [OtherClient] 列表
|
||||||
|
*/
|
||||||
|
@JvmBlockingBridge
|
||||||
|
public suspend fun getOnlineOtherClientsList(
|
||||||
|
bot: Bot,
|
||||||
|
): List<OtherClientInfo>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 忽略加群验证(需管理员权限)
|
* 忽略加群验证(需管理员权限)
|
||||||
*
|
*
|
||||||
|
@ -12,21 +12,21 @@
|
|||||||
package net.mamoe.mirai.contact
|
package net.mamoe.mirai.contact
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.event.events.OtherClientOnlineEvent
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
import net.mamoe.mirai.message.data.Image
|
import net.mamoe.mirai.message.data.Image
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol.ANDROID_PAD
|
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol.ANDROID_PAD
|
||||||
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol.ANDROID_PHONE
|
import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol.ANDROID_PHONE
|
||||||
import net.mamoe.mirai.utils.ExternalImage
|
import net.mamoe.mirai.utils.ExternalImage
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||||
|
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 其他设备. 如当 [Bot] 以 [ANDROID_PHONE] 登录时, 还可以有其他设备以 [ANDROID_PAD], iOS, PC 或其他设备登录.
|
* 其他设备. 如当 [Bot] 以 [ANDROID_PHONE] 登录时, 还可以有其他设备以 [ANDROID_PAD], iOS, PC 或其他设备登录.
|
||||||
*/
|
*/
|
||||||
public interface OtherClient : Contact {
|
public interface OtherClient : Contact {
|
||||||
/**
|
public val info: OtherClientInfo
|
||||||
* 设备类型
|
|
||||||
*/
|
|
||||||
public val kind: ClientKind
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 此设备属于的 [Bot]
|
* 此设备属于的 [Bot]
|
||||||
@ -47,11 +47,72 @@ public interface OtherClient : Contact {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MiraiInternalApi
|
||||||
|
public inline val OtherClient.appId: Int
|
||||||
|
get() = info.appId
|
||||||
|
public inline val OtherClient.platform: Platform get() = info.platform
|
||||||
|
public inline val OtherClient.deviceName: String get() = info.deviceName
|
||||||
|
public inline val OtherClient.deviceKind: String get() = info.deviceKind
|
||||||
|
|
||||||
|
@MiraiExperimentalApi
|
||||||
|
public data class OtherClientInfo @MiraiInternalApi constructor(
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 仅运行时识别. 随着客户端更新此 ID 可能有变化.
|
||||||
|
*
|
||||||
|
* 不可能有 [appId] 相同的两个客户端t在线.
|
||||||
|
*/
|
||||||
|
public val appId: Int,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 登录平台
|
||||||
|
*/
|
||||||
|
public val platform: Platform,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:
|
||||||
|
* - Mi 10 Pro
|
||||||
|
* - 电脑
|
||||||
|
* - xxx 的 iPad
|
||||||
|
* - mirai
|
||||||
|
*/
|
||||||
|
public val deviceName: String,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:
|
||||||
|
* - Mi 10 Pro
|
||||||
|
* - DESKTOP-ABCDEFG
|
||||||
|
* - iPad
|
||||||
|
* - mirai
|
||||||
|
*/
|
||||||
|
public val deviceKind: String,
|
||||||
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备类型
|
* @see OtherClientInfo.platform
|
||||||
|
*/
|
||||||
|
public enum class Platform(
|
||||||
|
@MiraiInternalApi public val terminalId: Int,
|
||||||
|
@MiraiInternalApi public val platformId: Int,
|
||||||
|
) {
|
||||||
|
IOS(3, 1),
|
||||||
|
MOBILE(2, 2), // android
|
||||||
|
WINDOWS(1, 3),
|
||||||
|
|
||||||
|
UNKNOWN(0, 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
public companion object {
|
||||||
|
@MiraiInternalApi
|
||||||
|
public fun getByTerminalId(terminalId: Int): Platform? = values().find { it.terminalId == terminalId }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 详细设备类型. 在登录时查询到的设备列表中无此信息. 只在 [OtherClientOnlineEvent] 才有.
|
||||||
*/
|
*/
|
||||||
public enum class ClientKind(
|
public enum class ClientKind(
|
||||||
public val id: Int,
|
@MiraiInternalApi public val id: Int,
|
||||||
) {
|
) {
|
||||||
ANDROID_PAD(68104),
|
ANDROID_PAD(68104),
|
||||||
AOL_CHAOJIHUIYUAN(73730),
|
AOL_CHAOJIHUIYUAN(73730),
|
||||||
@ -76,9 +137,7 @@ public enum class ClientKind(
|
|||||||
QQ_SERVICE(71170),
|
QQ_SERVICE(71170),
|
||||||
TV_QQ(69130),
|
TV_QQ(69130),
|
||||||
WIN8(69899),
|
WIN8(69899),
|
||||||
WINPHONE(65804),
|
WINPHONE(65804);
|
||||||
|
|
||||||
UNKNOWN(-1);
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
public operator fun get(id: Int): ClientKind? = values().find { it.id == id }
|
public operator fun get(id: Int): ClientKind? = values().find { it.id == id }
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
package net.mamoe.mirai.contact
|
package net.mamoe.mirai.contact
|
||||||
|
|
||||||
|
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||||
import java.util.concurrent.ConcurrentLinkedQueue
|
import java.util.concurrent.ConcurrentLinkedQueue
|
||||||
|
|
||||||
@ -16,8 +17,9 @@ public class OtherClientList internal constructor(
|
|||||||
@MiraiInternalApi @JvmField
|
@MiraiInternalApi @JvmField
|
||||||
public val delegate: MutableCollection<OtherClient> = ConcurrentLinkedQueue()
|
public val delegate: MutableCollection<OtherClient> = ConcurrentLinkedQueue()
|
||||||
) : Collection<OtherClient> by delegate {
|
) : Collection<OtherClient> by delegate {
|
||||||
public operator fun get(kind: ClientKind): OtherClient? = this.find { it.kind == kind }
|
@MiraiExperimentalApi
|
||||||
|
public operator fun get(appId: Int): OtherClient? = this.find { it.appId == appId }
|
||||||
|
|
||||||
public fun getOrFail(kind: ClientKind): OtherClient =
|
public fun getOrFail(appId: Int): OtherClient =
|
||||||
get(kind) ?: throw NoSuchElementException("OtherClient with kind=$kind not found.")
|
get(appId) ?: throw NoSuchElementException("OtherClient with appId=$appId not found.")
|
||||||
}
|
}
|
@ -502,7 +502,7 @@ public class OtherClientMessageEvent constructor(
|
|||||||
public override val senderName: String get() = sender.nick
|
public override val senderName: String get() = sender.nick
|
||||||
public override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend
|
public override val source: OnlineMessageSource.Incoming.FromFriend get() = message.source as OnlineMessageSource.Incoming.FromFriend
|
||||||
|
|
||||||
public override fun toString(): String = "OtherClientMessageEvent(client=${client.kind}, message=$message)"
|
public override fun toString(): String = "OtherClientMessageEvent(client=${client.platform}, message=$message)"
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,9 +10,11 @@
|
|||||||
package net.mamoe.mirai.event.events
|
package net.mamoe.mirai.event.events
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
|
import net.mamoe.mirai.contact.ClientKind
|
||||||
import net.mamoe.mirai.contact.OtherClient
|
import net.mamoe.mirai.contact.OtherClient
|
||||||
import net.mamoe.mirai.event.AbstractEvent
|
import net.mamoe.mirai.event.AbstractEvent
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
|
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||||
|
|
||||||
public interface OtherClientEvent : BotEvent, Packet {
|
public interface OtherClientEvent : BotEvent, Packet {
|
||||||
public val client: OtherClient
|
public val client: OtherClient
|
||||||
@ -23,13 +25,17 @@ public interface OtherClientEvent : BotEvent, Packet {
|
|||||||
/**
|
/**
|
||||||
* 其他设备上线
|
* 其他设备上线
|
||||||
*/
|
*/
|
||||||
public data class OtherClientOnlineEvent(
|
public data class OtherClientOnlineEvent @MiraiInternalApi constructor(
|
||||||
override val client: OtherClient
|
override val client: OtherClient,
|
||||||
|
/**
|
||||||
|
* 详细设备类型,通常非 `null`.
|
||||||
|
*/
|
||||||
|
val kind: ClientKind?
|
||||||
) : OtherClientEvent, AbstractEvent()
|
) : OtherClientEvent, AbstractEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 其他设备离线
|
* 其他设备离线
|
||||||
*/
|
*/
|
||||||
public data class OtherClientOfflineEvent(
|
public data class OtherClientOfflineEvent(
|
||||||
override val client: OtherClient
|
override val client: OtherClient,
|
||||||
) : OtherClientEvent, AbstractEvent()
|
) : OtherClientEvent, AbstractEvent()
|
@ -28,6 +28,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.LongMsg
|
|||||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
|
||||||
|
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
|
||||||
import net.mamoe.mirai.internal.utils.MiraiPlatformUtils
|
import net.mamoe.mirai.internal.utils.MiraiPlatformUtils
|
||||||
import net.mamoe.mirai.internal.utils.encodeToString
|
import net.mamoe.mirai.internal.utils.encodeToString
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||||
@ -156,6 +157,15 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
|
|||||||
group.checkBotPermission(MemberPermission.ADMINISTRATOR)
|
group.checkBotPermission(MemberPermission.ADMINISTRATOR)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun getOnlineOtherClientsList(bot: Bot): List<OtherClientInfo> {
|
||||||
|
bot.asQQAndroidBot()
|
||||||
|
val response = bot.network.run {
|
||||||
|
StatSvc.GetDevLoginInfo(bot.client).sendAndExpect<StatSvc.GetDevLoginInfo.Response>()
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.deviceList.map { it.toOtherClientInfo() }
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
|
override suspend fun ignoreMemberJoinRequest(event: MemberJoinRequestEvent, blackList: Boolean) {
|
||||||
checkGroupPermission(event.bot, event.groupId) { event::class.simpleName ?: "<anonymous class>" }
|
checkGroupPermission(event.bot, event.groupId) { event::class.simpleName ?: "<anonymous class>" }
|
||||||
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
@Suppress("INVISIBLE_REFERENCE", "INVISIBLE_MEMBER")
|
||||||
|
@ -23,7 +23,6 @@ import net.mamoe.mirai.internal.contact.checkIsGroupImpl
|
|||||||
import net.mamoe.mirai.internal.message.*
|
import net.mamoe.mirai.internal.message.*
|
||||||
import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler
|
import net.mamoe.mirai.internal.network.QQAndroidBotNetworkHandler
|
||||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.InstanceInfo
|
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
|
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
|
||||||
import net.mamoe.mirai.message.data.*
|
import net.mamoe.mirai.message.data.*
|
||||||
import net.mamoe.mirai.network.LoginFailedException
|
import net.mamoe.mirai.network.LoginFailedException
|
||||||
@ -41,10 +40,9 @@ internal fun Bot.asQQAndroidBot(): QQAndroidBot {
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun QQAndroidBot.createOtherClient(
|
internal fun QQAndroidBot.createOtherClient(
|
||||||
kind: ClientKind,
|
info: OtherClientInfo,
|
||||||
instanceInfo: InstanceInfo,
|
|
||||||
): OtherClientImpl {
|
): OtherClientImpl {
|
||||||
return OtherClientImpl(this, coroutineContext, kind, instanceInfo)
|
return OtherClientImpl(this, coroutineContext, info)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("INVISIBLE_MEMBER", "BooleanLiteralArgument", "OverridingDeprecatedMember")
|
@Suppress("INVISIBLE_MEMBER", "BooleanLiteralArgument", "OverridingDeprecatedMember")
|
||||||
|
@ -10,23 +10,18 @@
|
|||||||
package net.mamoe.mirai.internal.contact
|
package net.mamoe.mirai.internal.contact
|
||||||
|
|
||||||
import net.mamoe.mirai.Bot
|
import net.mamoe.mirai.Bot
|
||||||
import net.mamoe.mirai.contact.ClientKind
|
|
||||||
import net.mamoe.mirai.contact.OtherClient
|
import net.mamoe.mirai.contact.OtherClient
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.InstanceInfo
|
import net.mamoe.mirai.contact.OtherClientInfo
|
||||||
import net.mamoe.mirai.message.MessageReceipt
|
import net.mamoe.mirai.message.MessageReceipt
|
||||||
import net.mamoe.mirai.message.data.Image
|
import net.mamoe.mirai.message.data.Image
|
||||||
import net.mamoe.mirai.message.data.Message
|
import net.mamoe.mirai.message.data.Message
|
||||||
import net.mamoe.mirai.utils.ExternalImage
|
import net.mamoe.mirai.utils.ExternalImage
|
||||||
import net.mamoe.mirai.utils.cast
|
|
||||||
import kotlin.coroutines.CoroutineContext
|
import kotlin.coroutines.CoroutineContext
|
||||||
|
|
||||||
internal val OtherClient.instanceInfo: InstanceInfo get() = this.cast<OtherClientImpl>().instanceInfo
|
|
||||||
|
|
||||||
internal class OtherClientImpl(
|
internal class OtherClientImpl(
|
||||||
bot: Bot,
|
bot: Bot,
|
||||||
coroutineContext: CoroutineContext,
|
coroutineContext: CoroutineContext,
|
||||||
override val kind: ClientKind,
|
override val info: OtherClientInfo,
|
||||||
val instanceInfo: InstanceInfo
|
|
||||||
) : OtherClient, AbstractContact(bot, coroutineContext) {
|
) : OtherClient, AbstractContact(bot, coroutineContext) {
|
||||||
override suspend fun sendMessage(message: Message): MessageReceipt<OtherClient> {
|
override suspend fun sendMessage(message: Message): MessageReceipt<OtherClient> {
|
||||||
throw UnsupportedOperationException("OtherClientImpl.sendMessage is not yet supported.")
|
throw UnsupportedOperationException("OtherClientImpl.sendMessage is not yet supported.")
|
||||||
@ -37,7 +32,7 @@ internal class OtherClientImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return "OtherClient(bot=${bot.id},kind=$kind)"
|
return "OtherClient(bot=${bot.id},deviceName=${info.deviceName},platform=${info.platform})"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,7 +107,7 @@ internal fun net.mamoe.mirai.event.events.MessageEvent.logMessageReceived() {
|
|||||||
"${sender.nick}(${sender.id}) -> $message".replaceMagicCodes()
|
"${sender.nick}(${sender.id}) -> $message".replaceMagicCodes()
|
||||||
}
|
}
|
||||||
is net.mamoe.mirai.event.events.OtherClientMessageEvent -> bot.logger.verbose {
|
is net.mamoe.mirai.event.events.OtherClientMessageEvent -> bot.logger.verbose {
|
||||||
"${client.kind} -> $message".replaceMagicCodes()
|
"${client.platform} -> $message".replaceMagicCodes()
|
||||||
}
|
}
|
||||||
is GroupMessageSyncEvent -> bot.logger.verbose {
|
is GroupMessageSyncEvent -> bot.logger.verbose {
|
||||||
renderGroupMessage(group, senderName, sender, message)
|
renderGroupMessage(group, senderName, sender, message)
|
||||||
|
@ -20,6 +20,8 @@ import kotlinx.io.core.ByteReadPacket
|
|||||||
import kotlinx.io.core.buildPacket
|
import kotlinx.io.core.buildPacket
|
||||||
import kotlinx.io.core.readBytes
|
import kotlinx.io.core.readBytes
|
||||||
import net.mamoe.mirai.Mirai
|
import net.mamoe.mirai.Mirai
|
||||||
|
import net.mamoe.mirai.contact.deviceName
|
||||||
|
import net.mamoe.mirai.contact.platform
|
||||||
import net.mamoe.mirai.event.*
|
import net.mamoe.mirai.event.*
|
||||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||||
import net.mamoe.mirai.event.events.BotOnlineEvent
|
import net.mamoe.mirai.event.events.BotOnlineEvent
|
||||||
@ -27,6 +29,7 @@ import net.mamoe.mirai.event.events.BotReloginEvent
|
|||||||
import net.mamoe.mirai.event.events.MessageEvent
|
import net.mamoe.mirai.event.events.MessageEvent
|
||||||
import net.mamoe.mirai.internal.QQAndroidBot
|
import net.mamoe.mirai.internal.QQAndroidBot
|
||||||
import net.mamoe.mirai.internal.contact.*
|
import net.mamoe.mirai.internal.contact.*
|
||||||
|
import net.mamoe.mirai.internal.createOtherClient
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum
|
import net.mamoe.mirai.internal.network.protocol.data.jce.StTroopNum
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
|
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgSvc
|
||||||
import net.mamoe.mirai.internal.network.protocol.packet.*
|
import net.mamoe.mirai.internal.network.protocol.packet.*
|
||||||
@ -247,11 +250,24 @@ internal class QQAndroidBotNetworkHandler(coroutineContext: CoroutineContext, bo
|
|||||||
|
|
||||||
// println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
|
// println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}")
|
||||||
registerClientOnline()
|
registerClientOnline()
|
||||||
|
|
||||||
startHeartbeatJobOrKill()
|
startHeartbeatJobOrKill()
|
||||||
|
|
||||||
|
bot.otherClientsLock.withLock {
|
||||||
|
updateOtherClientsList()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun registerClientOnline(timeoutMillis: Long = 3000) {
|
private suspend fun registerClientOnline() {
|
||||||
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(timeoutMillis)
|
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>()
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun updateOtherClientsList() {
|
||||||
|
val list = Mirai.getOnlineOtherClientsList(bot)
|
||||||
|
bot.otherClients.delegate.clear()
|
||||||
|
bot.otherClients.delegate.addAll(list.map { bot.createOtherClient(it) })
|
||||||
|
|
||||||
|
bot.logger.info { "Online OtherClients: " + bot.otherClients.joinToString { "${it.deviceName}(${it.platform.name})" } }
|
||||||
}
|
}
|
||||||
|
|
||||||
// caches
|
// caches
|
||||||
|
@ -6,18 +6,13 @@
|
|||||||
*
|
*
|
||||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
*/
|
*/
|
||||||
|
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||||
package net.mamoe.mirai.internal.network.protocol.data.jce
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
import kotlinx.serialization.Serializable
|
||||||
import net.mamoe.mirai.internal.utils.io.JceStruct
|
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||||
|
|
||||||
@Suppress("ClassName", "SpellCheckingInspection")
|
|
||||||
@Serializable
|
@Serializable
|
||||||
internal class shareData(
|
internal class DeviceItemDes(
|
||||||
@JvmField @TarsId(0) val pkgname: String = "",
|
@JvmField @TarsId(0) val vecItemDes: ByteArray
|
||||||
@JvmField @TarsId(1) val msgtail: String = "",
|
|
||||||
@JvmField @TarsId(2) val picurl: String = "",
|
|
||||||
@JvmField @TarsId(3) val url: String = ""
|
|
||||||
) : JceStruct
|
) : JceStruct
|
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.mamoe.mirai.contact.OtherClientInfo
|
||||||
|
import net.mamoe.mirai.contact.Platform
|
||||||
|
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||||
|
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal data class SvcDevLoginInfo(
|
||||||
|
@JvmField @TarsId(0) val iAppId: Long,
|
||||||
|
// @JvmField @TarsId(1) val vecGuid: ByteArray? = null,
|
||||||
|
@JvmField @TarsId(2) val iLoginTime: Long,
|
||||||
|
@JvmField @TarsId(3) val iLoginPlatform: Long? = null, // 1: ios, 2: android, 3: windows, 4: symbian, 5: feature
|
||||||
|
@JvmField @TarsId(4) val loginLocation: String? = "",
|
||||||
|
@JvmField @TarsId(5) val deviceName: String? = "",
|
||||||
|
@JvmField @TarsId(6) val deviceTypeInfo: String? = "",
|
||||||
|
// @JvmField @TarsId(7) val stDeviceItemDes: DeviceItemDes? = null,
|
||||||
|
@JvmField @TarsId(8) val iTerType: Long? = null, // 1:windows, 2: mobile, 3: ios
|
||||||
|
@JvmField @TarsId(9) val iProductType: Long? = null, // always 0
|
||||||
|
@JvmField @TarsId(10) val iCanBeKicked: Long? = null // isOnline
|
||||||
|
) : JceStruct
|
||||||
|
|
||||||
|
internal fun SvcDevLoginInfo.toOtherClientInfo() = OtherClientInfo(
|
||||||
|
iAppId.toInt(),
|
||||||
|
Platform.getByTerminalId(iTerType?.toInt() ?: 0) ?: Platform.UNKNOWN,
|
||||||
|
deviceName.orEmpty(),
|
||||||
|
deviceTypeInfo.orEmpty()
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
vecCurrentLoginDevInfo=[SvcDevLoginInfo#1676411955 {
|
||||||
|
deviceName=mirai
|
||||||
|
deviceTypeInfo=mirai
|
||||||
|
iAppId=0x000000002002E738(537061176)
|
||||||
|
iCanBeKicked=0x0000000000000001(1)
|
||||||
|
iLoginPlatform=0x0000000000000002(2)
|
||||||
|
iLoginTime=0x000000005FE4A45C(1608819804)
|
||||||
|
iProductType=0x0000000000000000(0)
|
||||||
|
iTerType=0x0000000000000002(2)
|
||||||
|
}, SvcDevLoginInfo#1676411955 {
|
||||||
|
deviceName=xxx的iPad
|
||||||
|
deviceTypeInfo=iPad
|
||||||
|
iAppId=0x000000002002FB7C(537066364)
|
||||||
|
iCanBeKicked=0x0000000000000001(1)
|
||||||
|
iLoginPlatform=0x0000000000000001(1)
|
||||||
|
iLoginTime=0x000000005FE4A418(1608819736)
|
||||||
|
iProductType=0x0000000000000000(0)
|
||||||
|
iTerType=0x0000000000000003(3)
|
||||||
|
}, SvcDevLoginInfo#1676411955 {
|
||||||
|
deviceName=Mi 10 Pro
|
||||||
|
deviceTypeInfo=Mi 10 Pro
|
||||||
|
iAppId=0x000000002002FBB7(537066423)
|
||||||
|
iCanBeKicked=0x0000000000000001(1)
|
||||||
|
iLoginPlatform=0x0000000000000002(2)
|
||||||
|
iLoginTime=0x000000005FE4A628(1608820264)
|
||||||
|
iProductType=0x0000000000000000(0)
|
||||||
|
iTerType=0x0000000000000002(2)
|
||||||
|
}, SvcDevLoginInfo#1676411955 {
|
||||||
|
deviceName=DESKTOP-KMQEB7V
|
||||||
|
deviceTypeInfo=电脑
|
||||||
|
iAppId=0x0000000000000001(1)
|
||||||
|
iCanBeKicked=0x0000000000000001(1)
|
||||||
|
iLoginPlatform=0x0000000000000003(3)
|
||||||
|
iLoginTime=0x000000005FE4A5C1(1608820161)
|
||||||
|
iProductType=0x0000000000000000(0)
|
||||||
|
iTerType=0x0000000000000001(1)
|
||||||
|
loginLocation=中国湖北省武汉市
|
||||||
|
}]
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
internal class SvcReqGetDevLoginInfo(
|
||||||
|
@JvmField @TarsId(0) val vecGuid: ByteArray,
|
||||||
|
@JvmField @TarsId(1) val appName: String = "",
|
||||||
|
@JvmField @TarsId(2) val iLoginType: Long = 1L,
|
||||||
|
@JvmField @TarsId(3) val iTimeStamp: Long,
|
||||||
|
@JvmField @TarsId(4) val iNextItemIndex: Long,
|
||||||
|
@JvmField @TarsId(5) val iRequireMax: Long,
|
||||||
|
@JvmField @TarsId(6) val iGetDevListType: Long? = 7L // 1: online list 2: recent list? 4: getAuthLoginDevList?
|
||||||
|
) : JceStruct
|
||||||
|
|
@ -84,7 +84,7 @@ internal class RequestPushGroupMsg(
|
|||||||
@JvmField @TarsId(13) val uAppShareID: Long? = null,
|
@JvmField @TarsId(13) val uAppShareID: Long? = null,
|
||||||
@JvmField @TarsId(14) val vGPicInfo: List<GPicInfo>? = null,
|
@JvmField @TarsId(14) val vGPicInfo: List<GPicInfo>? = null,
|
||||||
@JvmField @TarsId(15) val vAppShareCookie: ByteArray? = null,
|
@JvmField @TarsId(15) val vAppShareCookie: ByteArray? = null,
|
||||||
@JvmField @TarsId(16) val stShareData: shareData? = null,
|
@JvmField @TarsId(16) val stShareData: ShareData? = null,
|
||||||
@JvmField @TarsId(17) val fromInstId: Long? = null,
|
@JvmField @TarsId(17) val fromInstId: Long? = null,
|
||||||
@JvmField @TarsId(18) val stGroupMsgHead: GroupMsgHead? = null,
|
@JvmField @TarsId(18) val stGroupMsgHead: GroupMsgHead? = null,
|
||||||
@JvmField @TarsId(19) val wUserActive: Int? = null,
|
@JvmField @TarsId(19) val wUserActive: Int? = null,
|
||||||
|
@ -0,0 +1,26 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||||
|
*
|
||||||
|
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||||
|
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||||
|
*
|
||||||
|
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.mamoe.mirai.internal.network.protocol.data.jce
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||||
|
import net.mamoe.mirai.internal.utils.io.serialization.tars.TarsId
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
internal class SvcRspGetDevLoginInfo(
|
||||||
|
@JvmField @TarsId(0) val iResult: Int,
|
||||||
|
@JvmField @TarsId(1) val result: String? = "",
|
||||||
|
@JvmField @TarsId(2) val iNextItemIndex: Long,
|
||||||
|
@JvmField @TarsId(3) val iTotalItemCount: Long,
|
||||||
|
@JvmField @TarsId(4) val vecCurrentLoginDevInfo: List<SvcDevLoginInfo>? = null,
|
||||||
|
@JvmField @TarsId(5) val vecHistoryLoginDevInfo: List<SvcDevLoginInfo>? = null,
|
||||||
|
@JvmField @TarsId(6) val vecAuthLoginDevInfo: List<SvcDevLoginInfo>? = null
|
||||||
|
) : JceStruct
|
||||||
|
|
@ -23,6 +23,7 @@ import net.mamoe.mirai.Mirai
|
|||||||
import net.mamoe.mirai.contact.Group
|
import net.mamoe.mirai.contact.Group
|
||||||
import net.mamoe.mirai.contact.MemberPermission
|
import net.mamoe.mirai.contact.MemberPermission
|
||||||
import net.mamoe.mirai.contact.NormalMember
|
import net.mamoe.mirai.contact.NormalMember
|
||||||
|
import net.mamoe.mirai.contact.appId
|
||||||
import net.mamoe.mirai.data.MemberInfo
|
import net.mamoe.mirai.data.MemberInfo
|
||||||
import net.mamoe.mirai.event.AbstractEvent
|
import net.mamoe.mirai.event.AbstractEvent
|
||||||
import net.mamoe.mirai.event.Event
|
import net.mamoe.mirai.event.Event
|
||||||
@ -409,7 +410,7 @@ private suspend fun MsgComm.Msg.transform(bot: QQAndroidBot): Packet? {
|
|||||||
|
|
||||||
with(data.msgHeader ?: return null) {
|
with(data.msgHeader ?: return null) {
|
||||||
if (srcUin != dstUin || dstUin != bot.id) return null
|
if (srcUin != dstUin || dstUin != bot.id) return null
|
||||||
val client = bot.otherClients.find { it.instanceInfo.iAppId == srcInstId }
|
val client = bot.otherClients.find { it.appId == srcInstId }
|
||||||
?: return null// don't compare with dstAppId. diff.
|
?: return null// don't compare with dstAppId. diff.
|
||||||
|
|
||||||
val chain = buildMessageChain {
|
val chain = buildMessageChain {
|
||||||
|
@ -13,7 +13,9 @@ import kotlinx.coroutines.cancel
|
|||||||
import kotlinx.coroutines.sync.withLock
|
import kotlinx.coroutines.sync.withLock
|
||||||
import kotlinx.io.core.ByteReadPacket
|
import kotlinx.io.core.ByteReadPacket
|
||||||
import kotlinx.serialization.protobuf.ProtoBuf
|
import kotlinx.serialization.protobuf.ProtoBuf
|
||||||
|
import net.mamoe.mirai.Mirai
|
||||||
import net.mamoe.mirai.contact.ClientKind
|
import net.mamoe.mirai.contact.ClientKind
|
||||||
|
import net.mamoe.mirai.contact.appId
|
||||||
import net.mamoe.mirai.event.events.BotOfflineEvent
|
import net.mamoe.mirai.event.events.BotOfflineEvent
|
||||||
import net.mamoe.mirai.event.events.OtherClientOfflineEvent
|
import net.mamoe.mirai.event.events.OtherClientOfflineEvent
|
||||||
import net.mamoe.mirai.event.events.OtherClientOnlineEvent
|
import net.mamoe.mirai.event.events.OtherClientOnlineEvent
|
||||||
@ -22,6 +24,7 @@ import net.mamoe.mirai.internal.createOtherClient
|
|||||||
import net.mamoe.mirai.internal.message.contextualBugReportException
|
import net.mamoe.mirai.internal.message.contextualBugReportException
|
||||||
import net.mamoe.mirai.internal.network.Packet
|
import net.mamoe.mirai.internal.network.Packet
|
||||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||||
|
import net.mamoe.mirai.internal.network.getRandomByteArray
|
||||||
import net.mamoe.mirai.internal.network.guid
|
import net.mamoe.mirai.internal.network.guid
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.jce.*
|
import net.mamoe.mirai.internal.network.protocol.data.jce.*
|
||||||
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
|
import net.mamoe.mirai.internal.network.protocol.data.proto.Oidb0x769
|
||||||
@ -29,6 +32,7 @@ import net.mamoe.mirai.internal.network.protocol.data.proto.StatSvcGetOnline
|
|||||||
import net.mamoe.mirai.internal.network.protocol.packet.*
|
import net.mamoe.mirai.internal.network.protocol.packet.*
|
||||||
import net.mamoe.mirai.internal.utils.*
|
import net.mamoe.mirai.internal.utils.*
|
||||||
import net.mamoe.mirai.internal.utils.io.serialization.*
|
import net.mamoe.mirai.internal.utils.io.serialization.*
|
||||||
|
import net.mamoe.mirai.utils.currentTimeMillis
|
||||||
import java.util.concurrent.CancellationException
|
import java.util.concurrent.CancellationException
|
||||||
|
|
||||||
@Suppress("EnumEntryName", "unused")
|
@Suppress("EnumEntryName", "unused")
|
||||||
@ -107,9 +111,9 @@ internal class StatSvc {
|
|||||||
writeJceStruct(
|
writeJceStruct(
|
||||||
RequestPacket.serializer(),
|
RequestPacket.serializer(),
|
||||||
RequestPacket(
|
RequestPacket(
|
||||||
sServantName = "PushService",
|
servantName = "PushService",
|
||||||
sFuncName = "SvcReqRegister",
|
funcName = "SvcReqRegister",
|
||||||
iRequestId = 0,
|
requestId = 0,
|
||||||
sBuffer = jceRequestSBuffer(
|
sBuffer = jceRequestSBuffer(
|
||||||
"SvcReqRegister",
|
"SvcReqRegister",
|
||||||
SvcReqRegister.serializer(),
|
SvcReqRegister.serializer(),
|
||||||
@ -205,9 +209,9 @@ internal class StatSvc {
|
|||||||
writeJceStruct(
|
writeJceStruct(
|
||||||
RequestPacket.serializer(),
|
RequestPacket.serializer(),
|
||||||
RequestPacket(
|
RequestPacket(
|
||||||
sServantName = "StatSvc",
|
servantName = "StatSvc",
|
||||||
sFuncName = "RspMSFForceOffline",
|
funcName = "RspMSFForceOffline",
|
||||||
iRequestId = 0,
|
requestId = 0,
|
||||||
sBuffer = jceRequestSBuffer(
|
sBuffer = jceRequestSBuffer(
|
||||||
"RspMSFForceOffline",
|
"RspMSFForceOffline",
|
||||||
RspMSFForceOffline.serializer(),
|
RspMSFForceOffline.serializer(),
|
||||||
@ -230,25 +234,29 @@ internal class StatSvc {
|
|||||||
bot.otherClientsLock.withLock {
|
bot.otherClientsLock.withLock {
|
||||||
val notify = readUniPacket(SvcReqMSFLoginNotifyData.serializer())
|
val notify = readUniPacket(SvcReqMSFLoginNotifyData.serializer())
|
||||||
|
|
||||||
val kind = notify.iClientType?.toInt()?.let(ClientKind::get) ?: return null
|
val appId = notify.iAppId.toInt()
|
||||||
|
|
||||||
when (notify.status.toInt()) {
|
when (notify.status.toInt()) {
|
||||||
1 -> {
|
1 -> { // online
|
||||||
if (bot.otherClients.any { it.kind == kind }) return null
|
if (bot.otherClients.any { it.appId == appId }) return null
|
||||||
val client = bot.createOtherClient(
|
|
||||||
kind,
|
val info = Mirai.getOnlineOtherClientsList(bot).find { it.appId == appId }
|
||||||
notify.vecInstanceList?.find { it.iClientType == notify.iClientType }
|
?: throw contextualBugReportException(
|
||||||
?: throw contextualBugReportException(
|
"SvcReqMSFLoginNotify (OtherClient online)",
|
||||||
"decode SvcReqMSFLoginNotify (OtherClient online)",
|
notify._miraiContentToString(),
|
||||||
notify._miraiContentToString(),
|
additional = "Failed to find corresponding instanceInfo."
|
||||||
additional = "Failed to find corresponding instanceInfo."
|
)
|
||||||
))
|
|
||||||
|
val client = bot.createOtherClient(info)
|
||||||
bot.otherClients.delegate.add(client)
|
bot.otherClients.delegate.add(client)
|
||||||
OtherClientOnlineEvent(client)
|
OtherClientOnlineEvent(
|
||||||
|
client,
|
||||||
|
ClientKind[notify.iClientType?.toInt() ?: 0]
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
2 -> {
|
2 -> { // off
|
||||||
val client = bot.otherClients.find { it.kind == kind } ?: return null
|
val client = bot.otherClients.find { it.appId == appId } ?: return null
|
||||||
client.cancel(CancellationException("Offline"))
|
client.cancel(CancellationException("Offline"))
|
||||||
bot.otherClients.delegate.remove(client)
|
bot.otherClients.delegate.remove(client)
|
||||||
OtherClientOfflineEvent(client)
|
OtherClientOfflineEvent(client)
|
||||||
@ -262,4 +270,46 @@ internal class StatSvc {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal object GetDevLoginInfo : OutgoingPacketFactory<GetDevLoginInfo.Response>("StatSvc.GetDevLoginInfo") {
|
||||||
|
|
||||||
|
@Suppress("unused") // false positive
|
||||||
|
data class Response(
|
||||||
|
val deviceList: List<SvcDevLoginInfo>,
|
||||||
|
) : Packet {
|
||||||
|
override fun toString(): String {
|
||||||
|
return "StatSvc.GetDevLoginInfo.Response(deviceList.size=${deviceList.size})"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun invoke(
|
||||||
|
client: QQAndroidClient,
|
||||||
|
) = buildOutgoingUniPacket(client) {
|
||||||
|
writeJceRequestPacket(
|
||||||
|
servantName = "StatSvc",
|
||||||
|
funcName = "SvcReqGetDevLoginInfo",
|
||||||
|
serializer = SvcReqGetDevLoginInfo.serializer(),
|
||||||
|
body = SvcReqGetDevLoginInfo(
|
||||||
|
iLoginType = 2,
|
||||||
|
iRequireMax = 20,
|
||||||
|
iTimeStamp = currentTimeMillis(),
|
||||||
|
iGetDevListType = 1,
|
||||||
|
vecGuid = getRandomByteArray(16), // 服务器防止频繁查询
|
||||||
|
iNextItemIndex = 0,
|
||||||
|
appName = client.protocol.apkId //"com.tencent.mobileqq"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||||
|
val resp = readUniPacket(SvcRspGetDevLoginInfo.serializer())
|
||||||
|
|
||||||
|
// result 62 maybe too frequent
|
||||||
|
return Response(
|
||||||
|
resp.vecCurrentLoginDevInfo?.takeIf { it.isNotEmpty() }
|
||||||
|
?: resp.vecAuthLoginDevInfo?.takeIf { it.isNotEmpty() }
|
||||||
|
?: resp.vecHistoryLoginDevInfo.orEmpty()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -191,7 +191,7 @@ internal class TarsInput(
|
|||||||
Tars.BYTE -> input.readByte().toInt()
|
Tars.BYTE -> input.readByte().toInt()
|
||||||
Tars.SHORT -> input.readShort().toInt()
|
Tars.SHORT -> input.readShort().toInt()
|
||||||
Tars.INT -> input.readInt()
|
Tars.INT -> input.readInt()
|
||||||
else -> error("type mismatch: $head")
|
else -> error("type mismatch: $head, expecting int.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,7 +200,7 @@ internal class TarsInput(
|
|||||||
Tars.ZERO_TYPE -> 0
|
Tars.ZERO_TYPE -> 0
|
||||||
Tars.BYTE -> input.readByte().toShort()
|
Tars.BYTE -> input.readByte().toShort()
|
||||||
Tars.SHORT -> input.readShort()
|
Tars.SHORT -> input.readShort()
|
||||||
else -> error("type mismatch: $head")
|
else -> error("type mismatch: $head, expecting short.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ internal class TarsInput(
|
|||||||
Tars.SHORT -> input.readShort().toLong()
|
Tars.SHORT -> input.readShort().toLong()
|
||||||
Tars.INT -> input.readInt().toLong()
|
Tars.INT -> input.readInt().toLong()
|
||||||
Tars.LONG -> input.readLong()
|
Tars.LONG -> input.readLong()
|
||||||
else -> error("type mismatch ${head.type}")
|
else -> error("type mismatch ${head}, expecting long.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,7 +220,7 @@ internal class TarsInput(
|
|||||||
return when (head.type) {
|
return when (head.type) {
|
||||||
Tars.ZERO_TYPE -> 0
|
Tars.ZERO_TYPE -> 0
|
||||||
Tars.BYTE -> input.readByte()
|
Tars.BYTE -> input.readByte()
|
||||||
else -> error("type mismatch: $head")
|
else -> error("type mismatch: $head, expecting byte.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ internal class TarsInput(
|
|||||||
return when (head.type) {
|
return when (head.type) {
|
||||||
Tars.ZERO_TYPE -> 0f
|
Tars.ZERO_TYPE -> 0f
|
||||||
Tars.FLOAT -> input.readFloat()
|
Tars.FLOAT -> input.readFloat()
|
||||||
else -> error("type mismatch: $head")
|
else -> error("type mismatch: $head, expecting float.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,18 +96,18 @@ internal fun <T : ProtoBuf> ByteReadPacket.readUniPacket(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value
|
private fun <K, V> Map<K, V>.singleValue(): V = this.entries.single().value
|
||||||
|
|
||||||
private fun <R> ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R {
|
internal fun <R> ByteReadPacket.decodeUniRequestPacketAndDeserialize(name: String? = null, block: (ByteArray) -> R): R {
|
||||||
val request = this.readJceStruct(RequestPacket.serializer())
|
val request = this.readJceStruct(RequestPacket.serializer())
|
||||||
|
|
||||||
return block(if (name == null) when (request.version?.toInt() ?: 3) {
|
return block(if (name == null) when (request.version?.toInt() ?: 3) {
|
||||||
2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.firstValue().firstValue()
|
2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.singleValue().singleValue()
|
||||||
3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.firstValue()
|
3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.singleValue()
|
||||||
else -> error("unsupported version ${request.version}")
|
else -> error("unsupported version ${request.version}")
|
||||||
} else when (request.version?.toInt() ?: 3) {
|
} else when (request.version?.toInt() ?: 3) {
|
||||||
2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.getOrElse(name) { error("cannot find $name") }
|
2 -> request.sBuffer.loadAs(RequestDataVersion2.serializer()).map.getOrElse(name) { error("cannot find $name") }
|
||||||
.firstValue()
|
.singleValue()
|
||||||
3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.getOrElse(name) { error("cannot find $name") }
|
3 -> request.sBuffer.loadAs(RequestDataVersion3.serializer()).map.getOrElse(name) { error("cannot find $name") }
|
||||||
else -> error("unsupported version ${request.version}")
|
else -> error("unsupported version ${request.version}")
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user