mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-05 07:10:11 +08:00
支持使用QQ互联通道发送音乐分享 (#889)
* Add new MessageContent MusicShare and its protocol internals. #690, #682 * MusicShare sending * MusicShare: MessageSource integration fundamentals * - MessageReceipt integration for MusicShare - Support MusicShare in QuoteReply: transform as PlainText - Support LightApp refining, support decoding MusicShare * Dump api for MusicShare * Remove debugging code * 2.1.0-dev-3 * Remove confusing providedSequenceIds in OnlineMessageSourceToGroupImpl * fix build Co-authored-by: wdvxdr <wdvxdr@foxmail.com>
This commit is contained in:
parent
705153c7d6
commit
2e5b223b6a
binary-compatibility-validator/api
buildSrc/src/main/kotlin
mirai-core-api/src/commonMain/kotlin/message/data
mirai-core/src/commonMain/kotlin
@ -4661,6 +4661,41 @@ public final class net/mamoe/mirai/message/data/MessageUtils {
|
||||
public static final synthetic fun toPlainText (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/PlainText;
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/message/data/MusicShare : net/mamoe/mirai/message/data/ConstrainSingle, net/mamoe/mirai/message/data/MessageContent {
|
||||
public static final field Key Lnet/mamoe/mirai/message/data/MusicShare$Key;
|
||||
public fun <init> (Lnet/mamoe/mirai/message/data/MusicType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public fun <init> (Lnet/mamoe/mirai/message/data/MusicType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V
|
||||
public synthetic fun <init> (Lnet/mamoe/mirai/message/data/MusicType;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
|
||||
public fun contentToString ()Ljava/lang/String;
|
||||
public fun equals (Ljava/lang/Object;)Z
|
||||
public final fun getBrief ()Ljava/lang/String;
|
||||
public final fun getJumpUrl ()Ljava/lang/String;
|
||||
public fun getKey ()Lnet/mamoe/mirai/message/data/MessageKey;
|
||||
public final fun getMusicUrl ()Ljava/lang/String;
|
||||
public final fun getPictureUrl ()Ljava/lang/String;
|
||||
public final fun getSummary ()Ljava/lang/String;
|
||||
public final fun getTitle ()Ljava/lang/String;
|
||||
public final fun getType ()Lnet/mamoe/mirai/message/data/MusicType;
|
||||
public fun hashCode ()I
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/message/data/MusicShare$Key : net/mamoe/mirai/message/data/AbstractPolymorphicMessageKey {
|
||||
}
|
||||
|
||||
public final class net/mamoe/mirai/message/data/MusicType : java/lang/Enum {
|
||||
public static final field MiguMusic Lnet/mamoe/mirai/message/data/MusicType;
|
||||
public static final field NeteaseCloudMusic Lnet/mamoe/mirai/message/data/MusicType;
|
||||
public static final field QQMusic Lnet/mamoe/mirai/message/data/MusicType;
|
||||
public final fun getAppId ()J
|
||||
public final fun getPackageName ()Ljava/lang/String;
|
||||
public final fun getPlatform ()I
|
||||
public final fun getSdkVersion ()Ljava/lang/String;
|
||||
public final fun getSignature ()Ljava/lang/String;
|
||||
public static fun valueOf (Ljava/lang/String;)Lnet/mamoe/mirai/message/data/MusicType;
|
||||
public static fun values ()[Lnet/mamoe/mirai/message/data/MusicType;
|
||||
}
|
||||
|
||||
public abstract class net/mamoe/mirai/message/data/OfflineMessageSource : net/mamoe/mirai/message/data/MessageSource {
|
||||
public static final field Key Lnet/mamoe/mirai/message/data/OfflineMessageSource$Key;
|
||||
public fun <init> ()V
|
||||
|
@ -12,7 +12,7 @@
|
||||
import org.gradle.api.attributes.Attribute
|
||||
|
||||
object Versions {
|
||||
const val project = "2.1.0-dev-2"
|
||||
const val project = "2.1.0-dev-3"
|
||||
|
||||
const val kotlinCompiler = "1.4.21"
|
||||
const val kotlinStdlib = "1.4.21"
|
||||
|
132
mirai-core-api/src/commonMain/kotlin/message/data/MusicShare.kt
Normal file
132
mirai-core-api/src/commonMain/kotlin/message/data/MusicShare.kt
Normal file
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright 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
|
||||
*/
|
||||
|
||||
@file:Suppress("unused")
|
||||
|
||||
package net.mamoe.mirai.message.data
|
||||
|
||||
import net.mamoe.mirai.utils.MiraiExperimentalApi
|
||||
import net.mamoe.mirai.utils.MiraiInternalApi
|
||||
import net.mamoe.mirai.utils.safeCast
|
||||
|
||||
/**
|
||||
* QQ 互联通道音乐分享
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
@MiraiExperimentalApi
|
||||
public class MusicShare @JvmOverloads constructor(
|
||||
/**
|
||||
* 音乐应用类型
|
||||
*/
|
||||
public val type: MusicType,
|
||||
/**
|
||||
* 消息卡片标题
|
||||
*/
|
||||
public val title: String,
|
||||
/**
|
||||
* 消息卡片内容
|
||||
*/
|
||||
public val summary: String,
|
||||
/**
|
||||
* 点击卡片跳转网页 URL
|
||||
*/
|
||||
public val jumpUrl: String,
|
||||
/**
|
||||
* 消息卡片图片 URL
|
||||
*/
|
||||
public val pictureUrl: String,
|
||||
/**
|
||||
* 音乐文件 URL
|
||||
*/
|
||||
public val musicUrl: String,
|
||||
/**
|
||||
* 在消息列表显示
|
||||
*/
|
||||
public val brief: String = "[分享]$title",
|
||||
) : MessageContent, ConstrainSingle {
|
||||
|
||||
override val key: MessageKey<*> get() = Key
|
||||
|
||||
override fun contentToString(): String =
|
||||
brief.takeIf { it.isNotBlank() } ?: "[分享]$title" // empty content is not accepted by `sendMessage`
|
||||
|
||||
// MusicShare(type=NeteaseCloudMusic, title='ファッション', summary='rinahamu/Yunomi', brief='', url='http://music.163.com/song/1338728297/?userid=324076307', pictureUrl='http://p2.music.126.net/y19E5SadGUmSR8SZxkrNtw==/109951163785855539.jpg', musicUrl='http://music.163.com/song/media/outer/url?id=1338728297&userid=324076307')
|
||||
override fun toString(): String {
|
||||
return "MusicShare(type=$type, title='$title', summary='$summary', brief='$brief', url='$jumpUrl', pictureUrl='$pictureUrl', musicUrl='$musicUrl')"
|
||||
}
|
||||
|
||||
|
||||
// don't make this class 'data' unless we made it stable.
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as MusicShare
|
||||
|
||||
if (type != other.type) return false
|
||||
if (title != other.title) return false
|
||||
if (summary != other.summary) return false
|
||||
if (brief != other.brief) return false
|
||||
if (jumpUrl != other.jumpUrl) return false
|
||||
if (pictureUrl != other.pictureUrl) return false
|
||||
if (musicUrl != other.musicUrl) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = type.hashCode()
|
||||
result = 31 * result + title.hashCode()
|
||||
result = 31 * result + summary.hashCode()
|
||||
result = 31 * result + brief.hashCode()
|
||||
result = 31 * result + jumpUrl.hashCode()
|
||||
result = 31 * result + pictureUrl.hashCode()
|
||||
result = 31 * result + musicUrl.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
public companion object Key :
|
||||
AbstractPolymorphicMessageKey<MessageContent, MusicShare>(MessageContent, { it.safeCast() })
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.1
|
||||
*/
|
||||
public enum class MusicType constructor(
|
||||
@MiraiInternalApi public val appId: Long,
|
||||
@MiraiInternalApi public val platform: Int,
|
||||
@MiraiInternalApi public val sdkVersion: String,
|
||||
@MiraiInternalApi public val packageName: String,
|
||||
@MiraiInternalApi public val signature: String
|
||||
) {
|
||||
NeteaseCloudMusic(
|
||||
100495085,
|
||||
1,
|
||||
"0.0.0",
|
||||
"com.netease.cloudmusic",
|
||||
"da6b069da1e2982db3e386233f68d76d"
|
||||
),
|
||||
QQMusic(
|
||||
100497308,
|
||||
1,
|
||||
"0.0.0",
|
||||
"com.tencent.qqmusic",
|
||||
"cbd27cd7c861227d013a25b2d10f0799"
|
||||
),
|
||||
MiguMusic(
|
||||
1101053067,
|
||||
1,
|
||||
"0.0.0",
|
||||
"cmccwm.mobilemusic",
|
||||
"6cdc72a439cef99a3418d2a78aa28c73"
|
||||
)
|
||||
}
|
@ -17,13 +17,17 @@ import net.mamoe.mirai.contact.MessageTooLargeException
|
||||
import net.mamoe.mirai.event.broadcast
|
||||
import net.mamoe.mirai.event.events.EventCancelledException
|
||||
import net.mamoe.mirai.event.events.GroupMessagePreSendEvent
|
||||
import net.mamoe.mirai.event.nextEventOrNull
|
||||
import net.mamoe.mirai.internal.MiraiImpl
|
||||
import net.mamoe.mirai.internal.forwardMessage
|
||||
import net.mamoe.mirai.internal.longMessage
|
||||
import net.mamoe.mirai.internal.message.*
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.MusicSharePacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.SendMessageMultiProtocol
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToGroup
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.OnlinePushPbPushGroupMsg
|
||||
import net.mamoe.mirai.message.MessageReceipt
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||
@ -111,61 +115,83 @@ private suspend fun GroupImpl.sendMessagePacket(
|
||||
|
||||
val group = this
|
||||
|
||||
val source: OnlineMessageSourceToGroupImpl
|
||||
var source: OnlineMessageSourceToGroupImpl? = null
|
||||
|
||||
bot.network.run {
|
||||
MessageSvcPbSendMsg.createToGroup(
|
||||
bot.client,
|
||||
group,
|
||||
finalMessage,
|
||||
SendMessageMultiProtocol.createToGroup(
|
||||
bot.client, group, finalMessage,
|
||||
step == GroupMessageSendingStep.FRAGMENTED
|
||||
) { source = it }.forEach { packet ->
|
||||
packet.sendAndExpect<MessageSvcPbSendMsg.Response>().let { resp ->
|
||||
if (resp is MessageSvcPbSendMsg.Response.MessageTooLarge) {
|
||||
return when (step) {
|
||||
GroupMessageSendingStep.FIRST -> {
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
GroupMessageSendingStep.LONG_MESSAGE
|
||||
)
|
||||
}
|
||||
GroupMessageSendingStep.LONG_MESSAGE -> {
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
GroupMessageSendingStep.FRAGMENTED
|
||||
)
|
||||
|
||||
}
|
||||
else -> {
|
||||
throw MessageTooLargeException(
|
||||
group,
|
||||
originalMessage,
|
||||
finalMessage,
|
||||
"Message '${finalMessage.content.take(10)}' is too large."
|
||||
)
|
||||
}
|
||||
}.getOrThrow()
|
||||
when (val resp = packet.sendAndExpect<Packet>()) {
|
||||
is MessageSvcPbSendMsg.Response -> {
|
||||
if (resp is MessageSvcPbSendMsg.Response.MessageTooLarge) {
|
||||
return when (step) {
|
||||
GroupMessageSendingStep.FIRST -> {
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
GroupMessageSendingStep.LONG_MESSAGE
|
||||
)
|
||||
}
|
||||
GroupMessageSendingStep.LONG_MESSAGE -> {
|
||||
sendMessageImpl(
|
||||
originalMessage,
|
||||
transformedMessage,
|
||||
GroupMessageSendingStep.FRAGMENTED
|
||||
)
|
||||
|
||||
}
|
||||
else -> {
|
||||
throw MessageTooLargeException(
|
||||
group,
|
||||
originalMessage,
|
||||
finalMessage,
|
||||
"Message '${finalMessage.content.take(10)}' is too large."
|
||||
)
|
||||
}
|
||||
}.getOrThrow()
|
||||
}
|
||||
check(resp is MessageSvcPbSendMsg.Response.SUCCESS) {
|
||||
"Send group message failed: $resp"
|
||||
}
|
||||
}
|
||||
check(resp is MessageSvcPbSendMsg.Response.SUCCESS) {
|
||||
"Send group message failed: $resp"
|
||||
is MusicSharePacket.Response -> {
|
||||
resp.pkg.checkSuccess("send group music share")
|
||||
|
||||
val receipt: OnlinePushPbPushGroupMsg.SendGroupMessageReceipt =
|
||||
nextEventOrNull(3000) { it.fromAppId == 3116 }
|
||||
?: OnlinePushPbPushGroupMsg.SendGroupMessageReceipt.EMPTY
|
||||
|
||||
source = OnlineMessageSourceToGroupImpl(
|
||||
group,
|
||||
internalIds = intArrayOf(receipt.messageRandom),
|
||||
providedSequenceIds = intArrayOf(receipt.sequenceId),
|
||||
sender = bot,
|
||||
target = group,
|
||||
time = currentTimeSeconds().toInt(),
|
||||
originalMessage = finalMessage
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
check(source != null) {
|
||||
"Internal error: source is not initialized"
|
||||
}
|
||||
|
||||
try {
|
||||
source!!.ensureSequenceIdAvailable()
|
||||
} catch (e: Exception) {
|
||||
bot.network.logger.warning(
|
||||
"Timeout awaiting sequenceId for group message(${finalMessage.content.take(10)}). Some features may not work properly",
|
||||
e
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
return MessageReceipt(source!!, group)
|
||||
}
|
||||
|
||||
try {
|
||||
source.ensureSequenceIdAvailable()
|
||||
} catch (e: Exception) {
|
||||
bot.network.logger.warning(
|
||||
"Timeout awaiting sequenceId for group message(${finalMessage.content.take(10)}). Some features may not work properly",
|
||||
e
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
return MessageReceipt(source, group)
|
||||
}
|
||||
|
||||
private suspend fun GroupImpl.uploadGroupLongMessageHighway(
|
||||
|
@ -232,6 +232,12 @@ internal fun MessageChain.toRichTextElems(
|
||||
)
|
||||
)
|
||||
}
|
||||
is MusicShare -> {
|
||||
// 只有在 QuoteReply 的 source 里才会进行 MusicShare 转换, 因此可以转 PT.
|
||||
// 发送消息时会被特殊处理
|
||||
transformOneMessage(PlainText(currentMessage.content))
|
||||
}
|
||||
|
||||
is ForwardMessage,
|
||||
is MessageSource, // mirai metadata only
|
||||
is RichMessage // already transformed above
|
||||
@ -510,7 +516,8 @@ internal fun List<ImMsgBody.Elem>.joinToMessageChain(
|
||||
else -> error("unknown compression flag=${element.lightApp.data[0]}")
|
||||
}
|
||||
}
|
||||
list.add(LightApp(content))
|
||||
|
||||
list.add(LightApp(content).refine())
|
||||
}
|
||||
element.richMsg != null -> {
|
||||
val content = runWithBugReport("解析 richMsg", { element.richMsg.template1.toUHexString() }) {
|
||||
|
172
mirai-core/src/commonMain/kotlin/message/lightApp.kt
Normal file
172
mirai-core/src/commonMain/kotlin/message/lightApp.kt
Normal file
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 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.message
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import net.mamoe.mirai.message.data.LightApp
|
||||
import net.mamoe.mirai.message.data.MusicShare
|
||||
import net.mamoe.mirai.message.data.MusicType
|
||||
import net.mamoe.mirai.message.data.SingleMessage
|
||||
|
||||
private val json = Json {
|
||||
ignoreUnknownKeys = true
|
||||
}
|
||||
|
||||
internal fun LightApp.tryDeserialize(): LightAppStruct? {
|
||||
return kotlin.runCatching {
|
||||
json.decodeFromString(LightAppStruct.serializer(), this.content)
|
||||
}.getOrNull()
|
||||
}
|
||||
|
||||
/**
|
||||
* 识别 app 内容, 如果有必要
|
||||
*/
|
||||
internal fun LightApp.refine(): SingleMessage {
|
||||
val struct = tryDeserialize() ?: return this
|
||||
struct.run {
|
||||
if (meta.music != null) {
|
||||
MusicType.values().find { it.appId.toInt() == meta.music.appid }?.let { musicType ->
|
||||
meta.music.run {
|
||||
return MusicShare(
|
||||
type = musicType, title = title, summary = desc,
|
||||
jumpUrl = jumpUrl, pictureUrl = preview, musicUrl = musicUrl, brief = prompt
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
/*
|
||||
EXAMPLE LightAppStruct for MusicShare
|
||||
|
||||
{
|
||||
"app": "com.tencent.structmsg",
|
||||
"config": {
|
||||
"autosize": true,
|
||||
"ctime": 1611339208,
|
||||
"forward": true,
|
||||
"token": "1f27c2b5687e0320549992a4652c8465",
|
||||
"type": "normal"
|
||||
},
|
||||
"desc": "音乐",
|
||||
"extra": {
|
||||
"app_type": 1,
|
||||
"appid": 100495085, // NeteaseCloudMusic
|
||||
"uin": 123456789 // qq uin
|
||||
},
|
||||
"meta": {
|
||||
"music": {
|
||||
"action": "",
|
||||
"android_pkg_name": "",
|
||||
"app_type": 1,
|
||||
"appid": 100495085,
|
||||
"desc": "rinahamu/Yunomi",
|
||||
"jumpUrl": "http://music.163.com/song/1338728297/?userid=324076307",
|
||||
"musicUrl": "http://music.163.com/song/media/outer/url?id=1338728297&userid=324076307",
|
||||
"preview": "http://p2.music.126.net/y19E5SadGUmSR8SZxkrNtw==/109951163785855539.jpg",
|
||||
"sourceMsgId": "0",
|
||||
"source_icon": "",
|
||||
"source_url": "",
|
||||
"tag": "网易云音乐",
|
||||
"title": "ファッション"
|
||||
}
|
||||
},
|
||||
"prompt": "[分享]ファッション",
|
||||
"ver": "0.0.0.1",
|
||||
"view": "music"
|
||||
}
|
||||
*/
|
||||
|
||||
@Serializable
|
||||
internal data class LightAppStruct(
|
||||
@SerialName("app")
|
||||
val app: String = "",
|
||||
@SerialName("config")
|
||||
val config: Config = Config(),
|
||||
@SerialName("desc")
|
||||
val desc: String = "",
|
||||
@SerialName("extra")
|
||||
val extra: Extra = Extra(),
|
||||
@SerialName("meta")
|
||||
val meta: Meta = Meta(),
|
||||
@SerialName("prompt")
|
||||
val prompt: String = "",
|
||||
@SerialName("ver")
|
||||
val ver: String = "",
|
||||
@SerialName("view")
|
||||
val view: String = ""
|
||||
) {
|
||||
@Serializable
|
||||
data class Config(
|
||||
@SerialName("autosize")
|
||||
val autosize: Boolean = false,
|
||||
@SerialName("ctime")
|
||||
val ctime: Int = 0,
|
||||
@SerialName("forward")
|
||||
val forward: Boolean = false,
|
||||
@SerialName("token")
|
||||
val token: String = "",
|
||||
@SerialName("type")
|
||||
val type: String = ""
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Extra(
|
||||
@SerialName("app_type")
|
||||
val appType: Int = 0,
|
||||
@SerialName("appid")
|
||||
val appid: Int = 0,
|
||||
@SerialName("uin")
|
||||
val uin: Int = 0
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class Meta(
|
||||
@SerialName("music")
|
||||
val music: Music? = null
|
||||
) {
|
||||
@Serializable
|
||||
data class Music(
|
||||
@SerialName("action")
|
||||
val action: String = "",
|
||||
@SerialName("android_pkg_name")
|
||||
val androidPkgName: String = "",
|
||||
@SerialName("app_type")
|
||||
val appType: Int = 0,
|
||||
@SerialName("appid")
|
||||
val appid: Int = 0,
|
||||
@SerialName("desc")
|
||||
val desc: String = "",
|
||||
@SerialName("jumpUrl")
|
||||
val jumpUrl: String = "",
|
||||
@SerialName("musicUrl")
|
||||
val musicUrl: String = "",
|
||||
@SerialName("preview")
|
||||
val preview: String = "",
|
||||
@SerialName("source_icon")
|
||||
val sourceIcon: String = "",
|
||||
@SerialName("sourceMsgId")
|
||||
val sourceMsgId: String = "",
|
||||
@SerialName("source_url")
|
||||
val sourceUrl: String = "",
|
||||
@SerialName("tag")
|
||||
val tag: String = "",
|
||||
@SerialName("title")
|
||||
val title: String = ""
|
||||
)
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
|
||||
package net.mamoe.mirai.internal.message
|
||||
|
||||
import kotlinx.coroutines.CompletableDeferred
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Deferred
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
@ -136,11 +137,12 @@ internal class OnlineMessageSourceToTempImpl(
|
||||
@Serializable(OnlineMessageSourceToGroupImpl.Serializer::class)
|
||||
internal class OnlineMessageSourceToGroupImpl(
|
||||
coroutineScope: CoroutineScope,
|
||||
override val internalIds: IntArray,
|
||||
override val internalIds: IntArray, // aka random
|
||||
override val time: Int,
|
||||
override val originalMessage: MessageChain,
|
||||
override val sender: Bot,
|
||||
override val target: Group
|
||||
override val target: Group,
|
||||
providedSequenceIds: IntArray? = null,
|
||||
) : OnlineMessageSource.Outgoing.ToGroup(), MessageSourceInternal {
|
||||
object Serializer : MessageSourceSerializerImpl("OnlineMessageSourceToGroup")
|
||||
|
||||
@ -150,7 +152,7 @@ internal class OnlineMessageSourceToGroupImpl(
|
||||
get() = sender
|
||||
override var isRecalledOrPlanned: AtomicBoolean = AtomicBoolean(false)
|
||||
|
||||
private val sequenceIdDeferred: Deferred<IntArray?> = run {
|
||||
private val sequenceIdDeferred: Deferred<IntArray?> = providedSequenceIds?.let { CompletableDeferred(it) } ?: run {
|
||||
val multi = mutableMapOf<Int, Int>()
|
||||
coroutineScope.asyncFromEventOrNull<SendGroupMessageReceipt, IntArray>(
|
||||
timeoutMillis = 3000L * this@OnlineMessageSourceToGroupImpl.internalIds.size
|
||||
|
@ -162,6 +162,7 @@ internal open class QQAndroidClient(
|
||||
|
||||
val apkVersionName: ByteArray get() = protocol.ver.toByteArray() //"8.4.18".toByteArray()
|
||||
val buildVer: String get() = "8.4.18.4810" // 8.2.0.1296 // 8.4.8.4810 // 8.2.7.4410
|
||||
val clientVersion: String = "android ${protocol.ver}" // android 8.5.0
|
||||
|
||||
val buildTime: Long get() = protocol.buildTime
|
||||
val sdkVersion: String get() = protocol.sdkVer
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2019-2020 Mamoe Technologies and contributors.
|
||||
* Copyright 2019-2021 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.
|
||||
@ -95,6 +95,13 @@ internal class MsgComm : ProtoBuf {
|
||||
@ProtoNumber(7) var msgUid: Long = 0L,
|
||||
@ProtoNumber(8) @JvmField val c2cTmpMsgHead: C2CTmpMsgHead? = null,
|
||||
@ProtoNumber(9) @JvmField val groupInfo: GroupInfo? = null,
|
||||
/**
|
||||
* 1: 群消息 by pc tim
|
||||
* 1001: 群消息 sent by android phone
|
||||
*
|
||||
*
|
||||
* 3116: music share, ANDROID_PHONE 发送
|
||||
*/
|
||||
@ProtoNumber(10) @JvmField val fromAppid: Int = 0,
|
||||
@ProtoNumber(11) @JvmField val fromInstid: Int = 0,
|
||||
@ProtoNumber(12) @JvmField val userActive: Int = 0,
|
||||
|
@ -11,6 +11,7 @@ package net.mamoe.mirai.internal.network.protocol.data.proto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
|
||||
@ -962,7 +963,13 @@ internal class OidbSso : ProtoBuf {
|
||||
@ProtoNumber(4) @JvmField val bodybuffer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@ProtoNumber(5) @JvmField val errorMsg: String = "",
|
||||
@ProtoNumber(6) @JvmField val clientVersion: String = ""
|
||||
) : ProtoBuf
|
||||
) : ProtoBuf, Packet {
|
||||
fun checkSuccess(actionName: String) {
|
||||
check(result == 0) {
|
||||
"${actionName.capitalize()} failed. result=$result, errorMsg=$errorMsg"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* Copyright 2019-2021 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
|
||||
*/
|
||||
|
||||
@file:Suppress("unused", "SpellCheckingInspection")
|
||||
|
||||
package net.mamoe.mirai.internal.network.protocol.data.proto
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class OidbCmd0xb77 : ProtoBuf {
|
||||
@Serializable
|
||||
internal class ArkJsonBody(
|
||||
@JvmField @ProtoNumber(10) val jsonStr: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ArkMsgBody(
|
||||
@JvmField @ProtoNumber(1) val app: String = "",
|
||||
@JvmField @ProtoNumber(2) val view: String = "",
|
||||
@JvmField @ProtoNumber(3) val prompt: String = "",
|
||||
@JvmField @ProtoNumber(4) val ver: String = "",
|
||||
@JvmField @ProtoNumber(5) val desc: String = "",
|
||||
@JvmField @ProtoNumber(6) val featureId: Int = 0,
|
||||
@JvmField @ProtoNumber(10) val meta: String = "",
|
||||
@JvmField @ProtoNumber(11) val metaUrl1: String = "",
|
||||
@JvmField @ProtoNumber(12) val metaUrl2: String = "",
|
||||
@JvmField @ProtoNumber(13) val metaUrl3: String = "",
|
||||
@JvmField @ProtoNumber(14) val metaText1: String = "",
|
||||
@JvmField @ProtoNumber(15) val metaText2: String = "",
|
||||
@JvmField @ProtoNumber(16) val metaText3: String = "",
|
||||
@JvmField @ProtoNumber(20) val config: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ArkV1MsgBody(
|
||||
@JvmField @ProtoNumber(1) val app: String = "",
|
||||
@JvmField @ProtoNumber(2) val view: String = "",
|
||||
@JvmField @ProtoNumber(3) val prompt: String = "",
|
||||
@JvmField @ProtoNumber(4) val ver: String = "",
|
||||
@JvmField @ProtoNumber(5) val desc: String = "",
|
||||
@JvmField @ProtoNumber(6) val featureId: Int = 0,
|
||||
@JvmField @ProtoNumber(10) val meta: String = "",
|
||||
@JvmField @ProtoNumber(11) val items: List<TemplateItem> = emptyList(),
|
||||
@JvmField @ProtoNumber(20) val config: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ClientInfo(
|
||||
@JvmField @ProtoNumber(1) val platform: Int = 0,
|
||||
@JvmField @ProtoNumber(2) val sdkVersion: String = "",
|
||||
@JvmField @ProtoNumber(3) val androidPackageName: String = "",
|
||||
@JvmField @ProtoNumber(4) val androidSignature: String = "",
|
||||
@JvmField @ProtoNumber(5) val iosBundleId: String = "",
|
||||
@JvmField @ProtoNumber(6) val pcSign: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ImageInfo(
|
||||
@JvmField @ProtoNumber(1) val md5: String = "",
|
||||
@JvmField @ProtoNumber(2) val uuid: String = "",
|
||||
@JvmField @ProtoNumber(3) val imgType: Int = 0,
|
||||
@JvmField @ProtoNumber(4) val fileSize: Int = 0,
|
||||
@JvmField @ProtoNumber(5) val width: Int = 0,
|
||||
@JvmField @ProtoNumber(6) val height: Int = 0,
|
||||
@JvmField @ProtoNumber(7) val original: Int = 0,
|
||||
@JvmField @ProtoNumber(101) val fileId: Int = 0,
|
||||
@JvmField @ProtoNumber(102) val serverIp: Int = 0,
|
||||
@JvmField @ProtoNumber(103) val serverPort: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class MiniAppMsgBody(
|
||||
@JvmField @ProtoNumber(1) val miniAppAppid: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val miniAppPath: String = "",
|
||||
@JvmField @ProtoNumber(3) val webPageUrl: String = "",
|
||||
@JvmField @ProtoNumber(4) val miniAppType: Int = 0,
|
||||
@JvmField @ProtoNumber(5) val title: String = "",
|
||||
@JvmField @ProtoNumber(6) val desc: String = "",
|
||||
@JvmField @ProtoNumber(10) val jsonStr: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ReqBody(
|
||||
@JvmField @ProtoNumber(1) val appid: Long = 0L,
|
||||
@JvmField @ProtoNumber(2) val appType: Int = 0,
|
||||
@JvmField @ProtoNumber(3) val msgStyle: Int = 0,
|
||||
@JvmField @ProtoNumber(4) val senderUin: Long = 0L,
|
||||
@JvmField @ProtoNumber(5) val clientInfo: ClientInfo? = null,
|
||||
// @JvmField @ProtoNumber(6) val textMsg: String? = null,
|
||||
@JvmField @ProtoNumber(7) val extInfo: ExtInfo? = null,
|
||||
@JvmField @ProtoNumber(10) val sendType: Int = 0,
|
||||
@JvmField @ProtoNumber(11) val recvUin: Long = 0L,
|
||||
@JvmField @ProtoNumber(12) val richMsgBody: RichMsgBody? = null,
|
||||
@JvmField @ProtoNumber(13) val arkMsgBody: ArkMsgBody? = null,
|
||||
// @JvmField @ProtoNumber(14) val recvOpenid: String? = null, // don't be ""
|
||||
@JvmField @ProtoNumber(15) val arkv1MsgBody: ArkV1MsgBody? = null,
|
||||
@JvmField @ProtoNumber(16) val arkJsonBody: ArkJsonBody? = null,
|
||||
@JvmField @ProtoNumber(17) val xmlMsgBody: XmlMsgBody? = null,
|
||||
@JvmField @ProtoNumber(18) val miniAppMsgBody: MiniAppMsgBody? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class ExtInfo(
|
||||
@ProtoNumber(1) @JvmField val customFeatureId: List<Int> = emptyList(),
|
||||
@ProtoNumber(2) @JvmField val apnsWording: String = "",
|
||||
@ProtoNumber(3) @JvmField val groupSaveDbFlag: Int = 0,
|
||||
@ProtoNumber(4) @JvmField val receiverAppId: Int = 0,
|
||||
@ProtoNumber(5) @JvmField val msgSeq: Long = 0L,
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RichMsgBody(
|
||||
@JvmField @ProtoNumber(1) val usingArk: Boolean = false,
|
||||
@JvmField @ProtoNumber(10) val title: String = "",
|
||||
@JvmField @ProtoNumber(11) val summary: String = "",
|
||||
@JvmField @ProtoNumber(12) val brief: String = "",
|
||||
@JvmField @ProtoNumber(13) val url: String = "",
|
||||
@JvmField @ProtoNumber(14) val pictureUrl: String = "",
|
||||
@JvmField @ProtoNumber(15) val action: String = "",
|
||||
@JvmField @ProtoNumber(16) val musicUrl: String = "",
|
||||
@JvmField @ProtoNumber(21) val imageInfo: ImageInfo? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class RspBody(
|
||||
@JvmField @ProtoNumber(1) val wording: String = "",
|
||||
@JvmField @ProtoNumber(2) val jumpResult: Int = 0,
|
||||
@JvmField @ProtoNumber(3) val jumpUrl: String = "",
|
||||
@JvmField @ProtoNumber(4) val level: Int = 0,
|
||||
@JvmField @ProtoNumber(5) val subLevel: Int = 0,
|
||||
@JvmField @ProtoNumber(6) val developMsg: String = ""
|
||||
) : ProtoBuf, Packet
|
||||
|
||||
@Serializable
|
||||
internal class TemplateItem(
|
||||
@JvmField @ProtoNumber(1) val key: String = "",
|
||||
@JvmField @ProtoNumber(2) val type: Int = 0,
|
||||
@JvmField @ProtoNumber(3) val value: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
internal class XmlMsgBody(
|
||||
@JvmField @ProtoNumber(11) val serviceId: Int = 0,
|
||||
@JvmField @ProtoNumber(12) val xml: String = ""
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
@ -157,6 +157,7 @@ internal object KnownPacketFactories {
|
||||
StrangerList.GetStrangerList,
|
||||
StrangerList.DelStranger,
|
||||
SummaryCard.ReqSummaryCard,
|
||||
MusicSharePacket,
|
||||
)
|
||||
|
||||
object IncomingFactories : List<IncomingPacketFactory<*>> by mutableListOf(
|
||||
|
@ -0,0 +1,91 @@
|
||||
/*
|
||||
* Copyright 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.packet.chat
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.internal.QQAndroidBot
|
||||
import net.mamoe.mirai.internal.network.Packet
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OidbCmd0xb77
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.buildOutgoingUniPacket
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.MusicShare
|
||||
|
||||
internal object MusicSharePacket :
|
||||
OutgoingPacketFactory<MusicSharePacket.Response>("OidbSvc.0xb77_9") {
|
||||
|
||||
class Response(
|
||||
val pkg: OidbSso.OIDBSSOPkg,
|
||||
) : Packet {
|
||||
val response by lazy {
|
||||
pkg.bodybuffer.loadAs(OidbCmd0xb77.RspBody.serializer())
|
||||
}
|
||||
|
||||
override fun toString(): String =
|
||||
"MusicSharePacket.Response(success=${pkg.result == 0}, error=${pkg.errorMsg})"
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
return Response(readProtoBuf(OidbSso.OIDBSSOPkg.serializer()))
|
||||
}
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
musicShare: MusicShare,
|
||||
targetUin: Long,
|
||||
targetKind: MessageSourceKind
|
||||
) = buildOutgoingUniPacket(client) {
|
||||
with(musicShare) {
|
||||
val musicType = musicShare.type
|
||||
writeProtoBuf(
|
||||
OidbSso.OIDBSSOPkg.serializer(),
|
||||
OidbSso.OIDBSSOPkg(
|
||||
command = 2935,
|
||||
serviceType = 9,
|
||||
clientVersion = client.clientVersion,
|
||||
bodybuffer = OidbCmd0xb77.ReqBody(
|
||||
appid = musicType.appId,
|
||||
appType = 1,
|
||||
msgStyle = if (jumpUrl.isNotBlank()) 4 else 0, // 有播放连接为4, 无播放连接为0
|
||||
clientInfo = OidbCmd0xb77.ClientInfo(
|
||||
platform = musicType.platform,
|
||||
sdkVersion = musicType.sdkVersion,
|
||||
androidPackageName = musicType.packageName,
|
||||
androidSignature = musicType.signature
|
||||
),
|
||||
extInfo = OidbCmd0xb77.ExtInfo(
|
||||
msgSeq = 0
|
||||
),
|
||||
sendType = when (targetKind) {
|
||||
MessageSourceKind.FRIEND -> 0
|
||||
MessageSourceKind.GROUP -> 1
|
||||
else -> error("Internal error: Unsupported targetKind $targetKind")
|
||||
},
|
||||
recvUin = targetUin,
|
||||
richMsgBody = OidbCmd0xb77.RichMsgBody(
|
||||
title = title,
|
||||
summary = summary,
|
||||
brief = brief,
|
||||
url = jumpUrl,
|
||||
pictureUrl = pictureUrl,
|
||||
musicUrl = musicUrl
|
||||
)
|
||||
).toByteArray(OidbCmd0xb77.ReqBody.serializer())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright 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.packet.chat
|
||||
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.internal.contact.takeSingleContent
|
||||
import net.mamoe.mirai.internal.contact.uin
|
||||
import net.mamoe.mirai.internal.message.OnlineMessageSourceToGroupImpl
|
||||
import net.mamoe.mirai.internal.network.QQAndroidClient
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.MessageSvcPbSendMsg
|
||||
import net.mamoe.mirai.internal.network.protocol.packet.chat.receive.createToGroup
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.MessageSourceKind
|
||||
import net.mamoe.mirai.message.data.MusicShare
|
||||
import kotlin.contracts.InvocationKind
|
||||
import kotlin.contracts.contract
|
||||
|
||||
internal object SendMessageMultiProtocol {
|
||||
inline fun createToGroup(
|
||||
client: QQAndroidClient,
|
||||
group: Group,
|
||||
message: MessageChain,
|
||||
fragmented: Boolean,
|
||||
crossinline sourceCallback: (OnlineMessageSourceToGroupImpl) -> Unit
|
||||
): List<OutgoingPacket> {
|
||||
contract { callsInPlace(sourceCallback, InvocationKind.AT_MOST_ONCE) }
|
||||
|
||||
message.takeSingleContent<MusicShare>()?.let { musicShare ->
|
||||
return listOf(MusicSharePacket(client, musicShare, group.uin, targetKind = MessageSourceKind.GROUP))
|
||||
}
|
||||
|
||||
return MessageSvcPbSendMsg.createToGroup(client, group, message, fragmented, sourceCallback)
|
||||
}
|
||||
}
|
@ -42,11 +42,16 @@ import net.mamoe.mirai.utils.*
|
||||
internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("OnlinePush.PbPushGroupMsg") {
|
||||
internal class SendGroupMessageReceipt(
|
||||
val messageRandom: Int,
|
||||
val sequenceId: Int
|
||||
val sequenceId: Int,
|
||||
val fromAppId: Int,
|
||||
) : Packet, Event, Packet.NoLog, AbstractEvent() {
|
||||
override fun toString(): String {
|
||||
return "OnlinePush.PbPushGroupMsg.SendGroupMessageReceipt(messageRandom=$messageRandom, sequenceId=$sequenceId)"
|
||||
}
|
||||
|
||||
companion object {
|
||||
val EMPTY = SendGroupMessageReceipt(0, 0, 0)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
@ -61,11 +66,13 @@ internal object OnlinePushPbPushGroupMsg : IncomingPacketFactory<Packet?>("Onlin
|
||||
if (isFromSelfAccount) {
|
||||
val messageRandom = pbPushMsg.msg.msgBody.richText.attr?.random ?: return null
|
||||
|
||||
if (bot.client.syncingController.pendingGroupMessageReceiptCacheList.contains { it.messageRandom == messageRandom }) {
|
||||
if (bot.client.syncingController.pendingGroupMessageReceiptCacheList.contains { it.messageRandom == messageRandom }
|
||||
|| msgHead.fromAppid == 3116) {
|
||||
// message sent by bot
|
||||
return SendGroupMessageReceipt(
|
||||
messageRandom,
|
||||
msgHead.msgSeq
|
||||
msgHead.msgSeq,
|
||||
msgHead.fromAppid
|
||||
)
|
||||
}
|
||||
// else: sync form other device
|
||||
|
@ -19,9 +19,11 @@ import kotlinx.serialization.descriptors.SerialDescriptor
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestDataVersion2
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestDataVersion3
|
||||
import net.mamoe.mirai.internal.network.protocol.data.jce.RequestPacket
|
||||
import net.mamoe.mirai.internal.network.protocol.data.proto.OidbSso
|
||||
import net.mamoe.mirai.internal.utils.io.JceStruct
|
||||
import net.mamoe.mirai.internal.utils.io.ProtoBuf
|
||||
import net.mamoe.mirai.internal.utils.io.serialization.tars.Tars
|
||||
import net.mamoe.mirai.internal.utils.soutv
|
||||
import net.mamoe.mirai.utils.read
|
||||
import net.mamoe.mirai.utils.readPacketExact
|
||||
import kotlin.contracts.InvocationKind
|
||||
@ -139,6 +141,14 @@ internal fun <T : ProtoBuf> ByteArray.loadAs(deserializer: DeserializationStrate
|
||||
return KtProtoBuf.decodeFromByteArray(deserializer, this)
|
||||
}
|
||||
|
||||
internal fun <T : ProtoBuf> ByteArray.loadOidb(deserializer: DeserializationStrategy<T>, log: Boolean = false): T {
|
||||
val oidb = loadAs(OidbSso.OIDBSSOPkg.serializer())
|
||||
if (log) {
|
||||
oidb.soutv("OIDB")
|
||||
}
|
||||
return oidb.bodybuffer.loadAs(deserializer)
|
||||
}
|
||||
|
||||
/**
|
||||
* load
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user