mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: 支持NT图片合并转发
Signed-off-by: 白池 <whitechi73@outlook.com>
This commit is contained in:
parent
661680e60b
commit
27f837adbe
@ -31,7 +31,7 @@ data class RecvLongMsgInfo(
|
|||||||
data class SendLongMsgInfo(
|
data class SendLongMsgInfo(
|
||||||
@ProtoNumber(1) val type: Int? = null,
|
@ProtoNumber(1) val type: Int? = null,
|
||||||
@ProtoNumber(2) val uid: LongMsgUid? = null,
|
@ProtoNumber(2) val uid: LongMsgUid? = null,
|
||||||
@ProtoNumber(3) val groupUin: Int? = null,
|
@ProtoNumber(3) val groupUin: ULong? = null,
|
||||||
@ProtoNumber(4) val payload: ByteArray? = null,
|
@ProtoNumber(4) val payload: ByteArray? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -1,55 +1 @@
|
|||||||
@file:OptIn(ExperimentalSerializationApi::class)
|
|
||||||
package protobuf.message.multimedia
|
package protobuf.message.multimedia
|
||||||
|
|
||||||
import kotlinx.serialization.ExperimentalSerializationApi
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.protobuf.ProtoNumber
|
|
||||||
import moe.fuqiuluo.symbols.Protobuf
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class RichMediaForPicData(
|
|
||||||
@ProtoNumber(1) val info: MediaInfo?,
|
|
||||||
@ProtoNumber(2) val display: DisplayMediaInfo?,
|
|
||||||
): Protobuf<RichMediaForPicData> {
|
|
||||||
companion object {
|
|
||||||
@Serializable
|
|
||||||
data class MediaInfo(
|
|
||||||
@ProtoNumber(1) val picture: Picture? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Picture(
|
|
||||||
@ProtoNumber(1) val info: PictureInfo? = null,
|
|
||||||
@ProtoNumber(2) val fileId: String? = null,
|
|
||||||
@ProtoNumber(4) val time: ULong? = null,
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class PictureInfo(
|
|
||||||
@ProtoNumber(2) val md5Hex: String? = null,
|
|
||||||
@ProtoNumber(3) val sha: String? = null,
|
|
||||||
@ProtoNumber(4) val name: String? = null,
|
|
||||||
@ProtoNumber(6) val width: Int? = null,
|
|
||||||
@ProtoNumber(7) val height: Int? = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class DisplayMediaInfo(
|
|
||||||
@ProtoNumber(1) val show: Show? = null,
|
|
||||||
) {
|
|
||||||
companion object {
|
|
||||||
@Serializable
|
|
||||||
data class Show(
|
|
||||||
@ProtoNumber(2) val text: String? = null,
|
|
||||||
@ProtoNumber(12) val download: Download? = null
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
data class Download(
|
|
||||||
@ProtoNumber(30) val url: String? = null,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -49,8 +49,8 @@ data class UploadCompletedReq(
|
|||||||
@Serializable
|
@Serializable
|
||||||
data class MsgInfo(
|
data class MsgInfo(
|
||||||
@ProtoNumber(1) val msgInfoBody: List<MsgInfoBody>,
|
@ProtoNumber(1) val msgInfoBody: List<MsgInfoBody>,
|
||||||
@ProtoNumber(2) val extBizInfo: ExtBizInfo,
|
@ProtoNumber(2) val extBizInfo: ExtBizInfo?,
|
||||||
)
|
): Protobuf<MsgInfo>
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class MsgInfoBody(
|
data class MsgInfoBody(
|
||||||
@ -106,7 +106,7 @@ data class UploadReq(
|
|||||||
@ProtoNumber(5) val compatQMsgSceneType: UInt? = null,
|
@ProtoNumber(5) val compatQMsgSceneType: UInt? = null,
|
||||||
@ProtoNumber(6) val extBizInfo: ExtBizInfo? = null,
|
@ProtoNumber(6) val extBizInfo: ExtBizInfo? = null,
|
||||||
@ProtoNumber(7) val clientSeq: UInt? = null,
|
@ProtoNumber(7) val clientSeq: UInt? = null,
|
||||||
@ProtoNumber(8) val noNeedCompatMsg: Boolean = false,
|
@ProtoNumber(8) val noNeedCompatMsg: Boolean? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -114,7 +114,7 @@ data class ExtBizInfo(
|
|||||||
@ProtoNumber(1) val pic: PicExtBizInfo? = null,
|
@ProtoNumber(1) val pic: PicExtBizInfo? = null,
|
||||||
@ProtoNumber(2) val video: VideoExtBizInfo? = null,
|
@ProtoNumber(2) val video: VideoExtBizInfo? = null,
|
||||||
@ProtoNumber(3) val ptt: PttExtBizInfo? = null,
|
@ProtoNumber(3) val ptt: PttExtBizInfo? = null,
|
||||||
@ProtoNumber(10) val busiType: UInt,
|
@ProtoNumber(10) val busiType: UInt?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -132,15 +132,15 @@ data class PttExtBizInfo(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class VideoExtBizInfo(
|
data class VideoExtBizInfo(
|
||||||
@ProtoNumber(1) val fromScene: UInt,
|
@ProtoNumber(1) val fromScene: UInt?,
|
||||||
@ProtoNumber(2) val toScene: UInt,
|
@ProtoNumber(2) val toScene: UInt?,
|
||||||
@ProtoNumber(3) val bytesPbReserve: ByteArray,
|
@ProtoNumber(3) val bytesPbReserve: ByteArray?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class PicExtBizInfo(
|
data class PicExtBizInfo(
|
||||||
@ProtoNumber(1) val bizType: UInt,
|
@ProtoNumber(1) val bizType: UInt?,
|
||||||
@ProtoNumber(2) val textSummary: String,
|
@ProtoNumber(2) val textSummary: String?,
|
||||||
@ProtoNumber(11) val bytesPbReserveC2c: ByteArray? = null,
|
@ProtoNumber(11) val bytesPbReserveC2c: ByteArray? = null,
|
||||||
@ProtoNumber(12) val bytesPbReserveTroop: ByteArray? = null,
|
@ProtoNumber(12) val bytesPbReserveTroop: ByteArray? = null,
|
||||||
@ProtoNumber(1001) val fromScene: UInt? = null,
|
@ProtoNumber(1001) val fromScene: UInt? = null,
|
||||||
@ -156,15 +156,15 @@ data class UploadInfo(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class FileInfo(
|
data class FileInfo(
|
||||||
@ProtoNumber(1) val fileSize: ULong,
|
@ProtoNumber(1) val fileSize: ULong?,
|
||||||
@ProtoNumber(2) val md5: String,
|
@ProtoNumber(2) val md5: String?,
|
||||||
@ProtoNumber(3) val sha1: String,
|
@ProtoNumber(3) val sha1: String?,
|
||||||
@ProtoNumber(4) val name: String,
|
@ProtoNumber(4) val name: String?,
|
||||||
@ProtoNumber(5) val fileType: FileType,
|
@ProtoNumber(5) val fileType: FileType?,
|
||||||
@ProtoNumber(6) val width: UInt,
|
@ProtoNumber(6) val width: UInt?,
|
||||||
@ProtoNumber(7) val height: UInt,
|
@ProtoNumber(7) val height: UInt?,
|
||||||
@ProtoNumber(8) val time: UInt,
|
@ProtoNumber(8) val time: UInt?,
|
||||||
@ProtoNumber(9) val original: UInt,
|
@ProtoNumber(9) val original: UInt?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -217,7 +217,7 @@ data class IndexNode(
|
|||||||
@ProtoNumber(3) val storeId: UInt, // 0为旧服务器 1为nt服务器
|
@ProtoNumber(3) val storeId: UInt, // 0为旧服务器 1为nt服务器
|
||||||
@ProtoNumber(4) val uploadTime: ULong,
|
@ProtoNumber(4) val uploadTime: ULong,
|
||||||
@ProtoNumber(5) val ttl: ULong,
|
@ProtoNumber(5) val ttl: ULong,
|
||||||
@ProtoNumber(6) val subType: UInt,
|
@ProtoNumber(6) val subType: UInt? = null,
|
||||||
@ProtoNumber(7) val storeAppId: UInt? = null
|
@ProtoNumber(7) val storeAppId: UInt? = null
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ class DownloadSafeRsp
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UploadKeyRenewalRsp(
|
data class UploadKeyRenewalRsp(
|
||||||
@ProtoNumber(1) val ukey: String,
|
@ProtoNumber(1) val ukey: String?,
|
||||||
@ProtoNumber(2) val ukeyTtlSec: ULong,
|
@ProtoNumber(2) val ukeyTtlSec: ULong?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -39,7 +39,7 @@ data class MsgInfoAuthRsp(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UploadCompletedRsp(
|
data class UploadCompletedRsp(
|
||||||
@ProtoNumber(1) val msgSeq: ULong
|
@ProtoNumber(1) val msgSeq: ULong?
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -47,13 +47,13 @@ class DeleteRsp
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DownloadRkeyRsp(
|
data class DownloadRkeyRsp(
|
||||||
@ProtoNumber(1) val rkeys: List<RKeyInfo>
|
@ProtoNumber(1) val rkeys: List<RKeyInfo>?
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RKeyInfo(
|
data class RKeyInfo(
|
||||||
@ProtoNumber(1) val rkey: String,
|
@ProtoNumber(1) val rkey: String?,
|
||||||
@ProtoNumber(2) val rkeyTtlSec: ULong,
|
@ProtoNumber(2) val rkeyTtlSec: ULong?,
|
||||||
@ProtoNumber(3) val storeId: UInt = 0u,
|
@ProtoNumber(3) val storeId: UInt = 0u,
|
||||||
@ProtoNumber(4) val rkeyCreateTime: UInt?,
|
@ProtoNumber(4) val rkeyCreateTime: UInt?,
|
||||||
@ProtoNumber(4) val type: UInt?,
|
@ProtoNumber(4) val type: UInt?,
|
||||||
@ -61,8 +61,8 @@ data class RKeyInfo(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class DownloadRsp(
|
data class DownloadRsp(
|
||||||
@ProtoNumber(1) val rkeyParam: String,
|
@ProtoNumber(1) val rkeyParam: String?,
|
||||||
@ProtoNumber(2) val rkeyTtlSec: ULong,
|
@ProtoNumber(2) val rkeyTtlSec: ULong?,
|
||||||
@ProtoNumber(3) val downloadInfo: DownloadInfo?,
|
@ProtoNumber(3) val downloadInfo: DownloadInfo?,
|
||||||
@ProtoNumber(4) val rkeyCreateTime: UInt?
|
@ProtoNumber(4) val rkeyCreateTime: UInt?
|
||||||
)
|
)
|
||||||
@ -80,16 +80,16 @@ data class DownloadInfo(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class VideoExtInfo(
|
data class VideoExtInfo(
|
||||||
@ProtoNumber(1) val videoCodecFormat: UInt,
|
@ProtoNumber(1) val videoCodecFormat: UInt? = null,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class UploadRsp(
|
data class UploadRsp(
|
||||||
@ProtoNumber(1) val ukey: String,
|
@ProtoNumber(1) val ukey: String?,
|
||||||
@ProtoNumber(2) val ukeyTtlSec: ULong,
|
@ProtoNumber(2) val ukeyTtlSec: ULong?,
|
||||||
@ProtoNumber(3) val ipv4: List<Ipv4>,
|
@ProtoNumber(3) val ipv4: List<Ipv4>?,
|
||||||
@ProtoNumber(4) val ipv6: List<Ipv6>,
|
@ProtoNumber(4) val ipv6: List<Ipv6>?,
|
||||||
@ProtoNumber(5) val msgSeq: ULong,
|
@ProtoNumber(5) val msgSeq: ULong?,
|
||||||
@ProtoNumber(6) val msgInfo: MsgInfo? = null,
|
@ProtoNumber(6) val msgInfo: MsgInfo? = null,
|
||||||
@ProtoNumber(7) val ext: List<RichmediaStorageTransInfo>? = null,
|
@ProtoNumber(7) val ext: List<RichmediaStorageTransInfo>? = null,
|
||||||
@ProtoNumber(8) val compatQMsg: ByteArray? = null,
|
@ProtoNumber(8) val compatQMsg: ByteArray? = null,
|
||||||
@ -98,11 +98,11 @@ data class UploadRsp(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class SubFileInfo(
|
data class SubFileInfo(
|
||||||
@ProtoNumber(1) val subType: UInt,
|
@ProtoNumber(1) val subType: UInt?,
|
||||||
@ProtoNumber(2) val ukey: String,
|
@ProtoNumber(2) val ukey: String?,
|
||||||
@ProtoNumber(3) val ukeyTTLSec: ULong,
|
@ProtoNumber(3) val ukeyTTLSec: ULong?,
|
||||||
@ProtoNumber(4) val ipv4: List<Ipv4>,
|
@ProtoNumber(4) val ipv4: List<Ipv4>?,
|
||||||
@ProtoNumber(5) val ipv6: List<Ipv6>,
|
@ProtoNumber(5) val ipv6: List<Ipv6>?,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
@ -132,8 +132,8 @@ data class Ipv6(
|
|||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class RspHead(
|
data class RspHead(
|
||||||
@ProtoNumber(1) val commonHead: CommonHead,
|
@ProtoNumber(1) val commonHead: CommonHead?,
|
||||||
@ProtoNumber(2) val retCode: UInt = 0u,
|
@ProtoNumber(2) val retCode: UInt = 0u,
|
||||||
@ProtoNumber(3) val msg: String
|
@ProtoNumber(3) val msg: String?
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -225,9 +225,22 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
suspend fun uploadMultiMsg(
|
suspend fun uploadMultiMsg(
|
||||||
chatType: Int,
|
chatType: Int,
|
||||||
peerId: String,
|
peerId: String,
|
||||||
fromId: String,
|
fromId: String = peerId,
|
||||||
|
messages: JsonArray,
|
||||||
|
retryCnt: Int
|
||||||
|
): Result<MessageSegment> {
|
||||||
|
return uploadMultiMsg(chatType, peerId, fromId, messages).onFailure {
|
||||||
|
if (retryCnt > 0) {
|
||||||
|
return uploadMultiMsg(chatType, peerId, fromId, messages, retryCnt - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun uploadMultiMsg(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
fromId: String = peerId,
|
||||||
messages: JsonArray,
|
messages: JsonArray,
|
||||||
retryCnt: Int,
|
|
||||||
): Result<MessageSegment> {
|
): Result<MessageSegment> {
|
||||||
var i = -1
|
var i = -1
|
||||||
val desc = MutableList(messages.size) { "" }
|
val desc = MutableList(messages.size) { "" }
|
||||||
@ -237,9 +250,10 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val data = msg.asJsonObject["data"].asJsonObject
|
val data = msg.asJsonObject["data"].asJsonObject
|
||||||
if (data.containsKey("id")) {
|
if (data.containsKey("id")) {
|
||||||
val record = getMsg(data["id"].asInt).getOrElse {
|
val msgId = data["id"].asInt
|
||||||
|
val record = getMsg(msgId).onFailure {
|
||||||
error("合并转发消息节点消息(id = ${data["id"].asInt})获取失败:$it")
|
error("合并转发消息节点消息(id = ${data["id"].asInt})获取失败:$it")
|
||||||
}
|
}.getOrThrow()
|
||||||
PushMsgBody(
|
PushMsgBody(
|
||||||
msgHead = ResponseHead(
|
msgHead = ResponseHead(
|
||||||
peerUid = record.senderUid,
|
peerUid = record.senderUid,
|
||||||
@ -257,9 +271,7 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
msgType = when (record.chatType) {
|
msgType = when (record.chatType) {
|
||||||
MsgConstant.KCHATTYPEC2C -> 9
|
MsgConstant.KCHATTYPEC2C -> 9
|
||||||
MsgConstant.KCHATTYPEGROUP -> 82
|
MsgConstant.KCHATTYPEGROUP -> 82
|
||||||
else -> throw UnsupportedOperationException(
|
else -> throw UnsupportedOperationException("Unsupported chatType: $chatType")
|
||||||
"Unsupported chatType: $chatType"
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
msgSubType = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
msgSubType = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||||
divSeq = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
divSeq = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||||
@ -288,14 +300,16 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
record.peerUin.toString(),
|
record.peerUin.toString(),
|
||||||
"0"
|
"0"
|
||||||
).onEach { segment ->
|
).onEach { segment ->
|
||||||
if (segment.type == "forward")
|
if (segment.type == "forward") {
|
||||||
forwardMsg[segment.data["filename"] as String] =
|
forwardMsg[segment.data["filename"] as String] =
|
||||||
segment.data["id"] as String
|
segment.data["id"] as String
|
||||||
}.toJson()
|
|
||||||
).getOrElse { throw Exception("消息合成失败: $it") }.let {
|
|
||||||
desc[++i] = record.sendMemberName.ifEmpty { record.sendNickName } + ": " + it.first
|
|
||||||
it.second
|
|
||||||
}
|
}
|
||||||
|
}.toJson()
|
||||||
|
).onFailure {
|
||||||
|
error("消息合成失败: ${it.stackTraceToString()}")
|
||||||
|
}.onSuccess {
|
||||||
|
desc[++i] = record.sendMemberName.ifEmpty { record.sendNickName } + ": " + it.first
|
||||||
|
}.getOrThrow().second
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else if (data.containsKey("content")) {
|
} else if (data.containsKey("content")) {
|
||||||
@ -343,22 +357,21 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
elementData["id"].asString
|
elementData["id"].asString
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
).getOrElse { error("消息合成失败: $it") }.let {
|
).onSuccess {
|
||||||
desc[++i] = (data["name"].asStringOrNull ?: data["uin"].asStringOrNull
|
desc[++i] = (data["name"].asStringOrNull ?: data["uin"].asStringOrNull
|
||||||
?: TicketSvc.getNickname()) + ": " + it.first
|
?: TicketSvc.getNickname()) + ": " + it.first
|
||||||
it.second
|
}.onFailure {
|
||||||
}
|
error("消息合成失败: ${it.stackTraceToString()}")
|
||||||
|
}.getOrThrow().second
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else {
|
} else error("消息节点缺少id或content字段")
|
||||||
error("消息节点缺少id或content字段")
|
|
||||||
}
|
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
LogCenter.log("消息节点解析失败:${it.stackTraceToString()}", Level.WARN)
|
LogCenter.log("消息节点解析失败:${it.stackTraceToString()}", Level.WARN)
|
||||||
}.getOrElse {
|
}.getOrNull()
|
||||||
null
|
}.ifEmpty {
|
||||||
|
return Result.failure(Exception("消息节点为空"))
|
||||||
}
|
}
|
||||||
}.ifEmpty { return Result.failure(Exception("消息节点为空")) }
|
|
||||||
|
|
||||||
val payload = LongMsgPayload(
|
val payload = LongMsgPayload(
|
||||||
action = mutableListOf(
|
action = mutableListOf(
|
||||||
@ -380,26 +393,22 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
LogCenter.log(payload.toByteArray().toHexString(), Level.DEBUG)
|
LogCenter.log({ payload.toByteArray().toHexString() }, Level.DEBUG)
|
||||||
|
|
||||||
val req = LongMsgReq(
|
val req = LongMsgReq(
|
||||||
sendInfo = when (chatType) {
|
sendInfo = when (chatType) {
|
||||||
MsgConstant.KCHATTYPEC2C -> SendLongMsgInfo(
|
MsgConstant.KCHATTYPEC2C -> SendLongMsgInfo(
|
||||||
type = 1,
|
type = 1,
|
||||||
uid = LongMsgUid(peerId),
|
uid = LongMsgUid(if(peerId.startsWith("u_")) peerId else ContactHelper.getUidByUinAsync(peerId.toLong()) ),
|
||||||
payload = DeflateTools.gzip(payload.toByteArray())
|
payload = DeflateTools.gzip(payload.toByteArray())
|
||||||
)
|
)
|
||||||
|
|
||||||
MsgConstant.KCHATTYPEGROUP -> SendLongMsgInfo(
|
MsgConstant.KCHATTYPEGROUP -> SendLongMsgInfo(
|
||||||
type = 3,
|
type = 3,
|
||||||
uid = LongMsgUid(fromId),
|
uid = LongMsgUid(fromId),
|
||||||
groupUin = fromId.toInt(),
|
groupUin = fromId.toULong(),
|
||||||
payload = DeflateTools.gzip(payload.toByteArray())
|
payload = DeflateTools.gzip(payload.toByteArray())
|
||||||
)
|
)
|
||||||
|
else -> throw UnsupportedOperationException("Unsupported chatType: $chatType")
|
||||||
else -> throw UnsupportedOperationException(
|
|
||||||
"Unsupported chatType: $chatType"
|
|
||||||
)
|
|
||||||
},
|
},
|
||||||
setting = LongMsgSettings(
|
setting = LongMsgSettings(
|
||||||
field1 = 4,
|
field1 = 4,
|
||||||
@ -407,27 +416,25 @@ internal object MsgSvc : BaseSvc() {
|
|||||||
field3 = 9,
|
field3 = 9,
|
||||||
field4 = 0
|
field4 = 0
|
||||||
)
|
)
|
||||||
)
|
).toByteArray()
|
||||||
|
|
||||||
val buffer = sendBufferAW(
|
val buffer = sendBufferAW("trpc.group.long_msg_interface.MsgService.SsoSendLongMsg", true, req, timeout = 30_000)
|
||||||
"trpc.group.long_msg_interface.MsgService.SsoSendLongMsg",
|
?: return Result.failure(Exception("unable to upload multi message, response timeout"))
|
||||||
true,
|
val rsp = runCatching {
|
||||||
req.toByteArray()
|
buffer.slice(4).decodeProtobuf<LongMsgRsp>()
|
||||||
) ?: return Result.failure(Exception("unable to upload multi message"))
|
}.getOrElse {
|
||||||
val rsp = buffer.slice(4).decodeProtobuf<LongMsgRsp>()
|
buffer.decodeProtobuf<LongMsgRsp>()
|
||||||
|
}
|
||||||
val resId = rsp.sendResult?.resId ?: return Result.failure(Exception("unable to upload multi message"))
|
val resId = rsp.sendResult?.resId ?: return Result.failure(Exception("unable to upload multi message"))
|
||||||
val filename = UUID.randomUUID().toString().uppercase()
|
return Result.success(MessageSegment(
|
||||||
return Result.success(
|
type = "forward",
|
||||||
MessageSegment(
|
data = mapOf(
|
||||||
"forward",
|
|
||||||
mapOf(
|
|
||||||
"id" to resId,
|
"id" to resId,
|
||||||
"filename" to filename,
|
"filename" to UUID.randomUUID().toString(),
|
||||||
"summary" to "查看${desc.size}条转发消息",
|
"summary" to "查看${desc.size}条转发消息",
|
||||||
"desc" to desc.slice(0..if (i < 3) i else 3).joinToString("\n")
|
"desc" to desc.slice(0..if (i < 3) i else 3).joinToString("\n")
|
||||||
)
|
)
|
||||||
)
|
))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun getMultiMsg(resId: String): Result<List<LongMsgAction>> {
|
suspend fun getMultiMsg(resId: String): Result<List<LongMsgAction>> {
|
||||||
|
@ -24,6 +24,8 @@ import protobuf.message.Ptt
|
|||||||
import protobuf.message.RichText
|
import protobuf.message.RichText
|
||||||
import protobuf.message.element.*
|
import protobuf.message.element.*
|
||||||
import protobuf.message.element.commelem.*
|
import protobuf.message.element.commelem.*
|
||||||
|
import protobuf.oidb.cmd0x11c5.C2CUserInfo
|
||||||
|
import protobuf.oidb.cmd0x11c5.GroupUserInfo
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.nio.ByteBuffer
|
import java.nio.ByteBuffer
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@ -68,7 +70,7 @@ internal class ElemMaker {
|
|||||||
|
|
||||||
private var rich = RichText()
|
private var rich = RichText()
|
||||||
private val elems = mutableListOf<Elem>()
|
private val elems = mutableListOf<Elem>()
|
||||||
private var desc = ""
|
private var summary = StringBuilder()
|
||||||
|
|
||||||
fun getRich(): RichText {
|
fun getRich(): RichText {
|
||||||
rich.elements = elems
|
rich.elements = elems
|
||||||
@ -76,7 +78,7 @@ internal class ElemMaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getDesc(): String {
|
fun getDesc(): String {
|
||||||
return desc
|
return summary.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createTextElem(
|
private suspend fun createTextElem(
|
||||||
@ -86,11 +88,12 @@ internal class ElemMaker {
|
|||||||
data: JsonObject
|
data: JsonObject
|
||||||
) {
|
) {
|
||||||
data.checkAndThrow("text")
|
data.checkAndThrow("text")
|
||||||
|
val text = data["text"].asString
|
||||||
val elem = Elem(
|
val elem = Elem(
|
||||||
text = TextMsg(data["text"].asString)
|
text = TextMsg(text)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += data["text"].asString
|
summary.append(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createAtElem(
|
private suspend fun createAtElem(
|
||||||
@ -102,7 +105,6 @@ internal class ElemMaker {
|
|||||||
when (chatType) {
|
when (chatType) {
|
||||||
MsgConstant.KCHATTYPEGROUP -> {
|
MsgConstant.KCHATTYPEGROUP -> {
|
||||||
data.checkAndThrow("qq")
|
data.checkAndThrow("qq")
|
||||||
|
|
||||||
val qq: Long
|
val qq: Long
|
||||||
val type: Int
|
val type: Int
|
||||||
val display = when (val qqStr = data["qq"].asString) {
|
val display = when (val qqStr = data["qq"].asString) {
|
||||||
@ -146,7 +148,7 @@ internal class ElemMaker {
|
|||||||
text = TextMsg(str = display, attr6Buf = attr6.array())
|
text = TextMsg(str = display, attr6Buf = attr6.array())
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += display
|
summary.append(display)
|
||||||
}
|
}
|
||||||
|
|
||||||
MsgConstant.KCHATTYPEC2C -> {
|
MsgConstant.KCHATTYPEC2C -> {
|
||||||
@ -165,7 +167,7 @@ internal class ElemMaker {
|
|||||||
text = TextMsg(str = display)
|
text = TextMsg(str = display)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += display
|
summary.append(display)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> throw UnsupportedOperationException("Unsupported chatType($chatType) for AtMsg")
|
else -> throw UnsupportedOperationException("Unsupported chatType($chatType) for AtMsg")
|
||||||
@ -205,7 +207,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[表情]"
|
summary.append("[表情]")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createImageElem(
|
private suspend fun createImageElem(
|
||||||
@ -215,7 +217,6 @@ internal class ElemMaker {
|
|||||||
data: JsonObject
|
data: JsonObject
|
||||||
) {
|
) {
|
||||||
val isOriginal = data["original"].asBooleanOrNull ?: true
|
val isOriginal = data["original"].asBooleanOrNull ?: true
|
||||||
val isFlash = data["flash"].asBooleanOrNull ?: false
|
|
||||||
val filePath = data["file"].asStringOrNull
|
val filePath = data["file"].asStringOrNull
|
||||||
val url = data["url"].asStringOrNull
|
val url = data["url"].asStringOrNull
|
||||||
var file: File? = null
|
var file: File? = null
|
||||||
@ -255,29 +256,59 @@ internal class ElemMaker {
|
|||||||
picHeight = options.outWidth
|
picHeight = options.outWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
val uploadRet = NtV2RichMediaSvc.tryUploadResourceByNt(
|
val fileInfo = NtV2RichMediaSvc.tryUploadResourceByNt(
|
||||||
chatType = chatType,
|
chatType = chatType,
|
||||||
elementType = MsgConstant.KELEMTYPEPIC,
|
elementType = MsgConstant.KELEMTYPEPIC,
|
||||||
resources = arrayListOf(file),
|
resources = arrayListOf(file),
|
||||||
timeout = 30.seconds
|
timeout = 30.seconds
|
||||||
).getOrThrow().first()
|
).getOrThrow().first()
|
||||||
LogCenter.log({ uploadRet.toString() }, Level.DEBUG)
|
|
||||||
|
|
||||||
val elem = when (chatType) {
|
runCatching {
|
||||||
|
fileInfo.uuid.toUInt()
|
||||||
|
}.onFailure {
|
||||||
|
NtV2RichMediaSvc.requestUploadNtPic(file, fileInfo.md5, fileInfo.sha, fileInfo.fileName, picWidth.toUInt(), picHeight.toUInt(), 5) {
|
||||||
|
when(chatType) {
|
||||||
|
MsgConstant.KCHATTYPEGROUP -> {
|
||||||
|
sceneType = 2u
|
||||||
|
grp = GroupUserInfo(peerId.toULong())
|
||||||
|
}
|
||||||
|
MsgConstant.KCHATTYPEC2C -> {
|
||||||
|
sceneType = 1u
|
||||||
|
c2c = C2CUserInfo(
|
||||||
|
accountType = 2u,
|
||||||
|
uid = ContactHelper.getUidByUinAsync(peerId.toLong())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
else -> error("不支持的合并转发图片类型")
|
||||||
|
}
|
||||||
|
}.onFailure {
|
||||||
|
LogCenter.log("获取MultiMedia图片信息失败: $it", Level.ERROR)
|
||||||
|
}.onSuccess {
|
||||||
|
//LogCenter.log({ "获取MultiMedia图片信息成功: ${it.hashCode()}" }, Level.INFO)
|
||||||
|
elems.add(Elem(
|
||||||
|
commonElem = CommonElem(
|
||||||
|
serviceType = 48,
|
||||||
|
businessType = 10,
|
||||||
|
elem = it.msgInfo!!.toByteArray()
|
||||||
|
)
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}.onSuccess { uuid ->
|
||||||
|
elems.add(when (chatType) {
|
||||||
MsgConstant.KCHATTYPEGROUP -> Elem(
|
MsgConstant.KCHATTYPEGROUP -> Elem(
|
||||||
customFace = CustomFace(
|
customFace = CustomFace(
|
||||||
filePath = uploadRet.fileName,
|
filePath = fileInfo.fileName,
|
||||||
fileId = uploadRet.uuid.toUInt(),
|
fileId = uuid,
|
||||||
serverIp = 0u,
|
serverIp = 0u,
|
||||||
serverPort = 0u,
|
serverPort = 0u,
|
||||||
fileType = FileUtils.getPicType(file).toUInt(),
|
fileType = FileUtils.getPicType(file).toUInt(),
|
||||||
useful = 1u,
|
useful = 1u,
|
||||||
md5 = uploadRet.md5.hex2ByteArray(),
|
md5 = fileInfo.md5.hex2ByteArray(),
|
||||||
bizType = data["subType"].asIntOrNull?.toUInt(),
|
bizType = data["subType"].asIntOrNull?.toUInt(),
|
||||||
imageType = FileUtils.getPicType(file).toUInt(),
|
imageType = FileUtils.getPicType(file).toUInt(),
|
||||||
width = picWidth.toUInt(),
|
width = picWidth.toUInt(),
|
||||||
height = picHeight.toUInt(),
|
height = picHeight.toUInt(),
|
||||||
size = uploadRet.fileSize.toUInt(),
|
size = fileInfo.fileSize.toUInt(),
|
||||||
origin = isOriginal,
|
origin = isOriginal,
|
||||||
thumbWidth = 0u,
|
thumbWidth = 0u,
|
||||||
thumbHeight = 0u,
|
thumbHeight = 0u,
|
||||||
@ -292,22 +323,21 @@ internal class ElemMaker {
|
|||||||
field3 = 0,
|
field3 = 0,
|
||||||
field4 = 0,
|
field4 = 0,
|
||||||
field5 = 0,
|
field5 = 0,
|
||||||
md5Str = uploadRet.md5
|
md5Str = fileInfo.md5
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
MsgConstant.KCHATTYPEC2C -> Elem(
|
MsgConstant.KCHATTYPEC2C -> Elem(
|
||||||
notOnlineImage = NotOnlineImage(
|
notOnlineImage = NotOnlineImage(
|
||||||
filePath = uploadRet.fileName,
|
filePath = fileInfo.fileName,
|
||||||
fileLen = uploadRet.fileSize.toUInt(),
|
fileLen = fileInfo.fileSize.toUInt(),
|
||||||
downloadPath = uploadRet.uuid,
|
downloadPath = fileInfo.uuid,
|
||||||
imgType = FileUtils.getPicType(file).toUInt(),
|
imgType = FileUtils.getPicType(file).toUInt(),
|
||||||
picMd5 = uploadRet.md5.hex2ByteArray(),
|
picMd5 = fileInfo.md5.hex2ByteArray(),
|
||||||
picHeight = picWidth.toUInt(),
|
picHeight = picWidth.toUInt(),
|
||||||
picWidth = picHeight.toUInt(),
|
picWidth = picHeight.toUInt(),
|
||||||
resId = uploadRet.uuid,
|
resId = fileInfo.uuid,
|
||||||
original = isOriginal, // true
|
original = isOriginal, // true
|
||||||
pbReserve = NotOnlineImage.Companion.PbReserve(
|
pbReserve = NotOnlineImage.Companion.PbReserve(
|
||||||
field1 = 0,
|
field1 = 0,
|
||||||
@ -322,15 +352,15 @@ internal class ElemMaker {
|
|||||||
field5 = 0,
|
field5 = 0,
|
||||||
field7 = "",
|
field7 = "",
|
||||||
),
|
),
|
||||||
md5Str = uploadRet.md5
|
md5Str = fileInfo.md5
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
else -> throw LogicException("Not supported chatType($chatType) for PictureMsg")
|
else -> throw LogicException("Not supported chatType($chatType) for PictureMsg")
|
||||||
|
})
|
||||||
}
|
}
|
||||||
elems.add(elem)
|
|
||||||
desc += "[图片]"
|
summary.append("[图片]")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createReplyElem(
|
private suspend fun createReplyElem(
|
||||||
@ -402,7 +432,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[回复消息]"
|
summary.append("[回复消息]")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createJsonElem(
|
private suspend fun createJsonElem(
|
||||||
@ -419,7 +449,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[Json消息]"
|
summary .append( "[Json消息]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createForwardStruct(
|
private suspend fun createForwardStruct(
|
||||||
@ -485,7 +515,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[聊天记录]"
|
this.summary .append( "[聊天记录]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createWeatherElem(
|
private suspend fun createWeatherElem(
|
||||||
@ -517,7 +547,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[天气卡片]"
|
summary .append( "[天气卡片]" )
|
||||||
} else {
|
} else {
|
||||||
throw LogicException("无法获取城市天气")
|
throw LogicException("无法获取城市天气")
|
||||||
}
|
}
|
||||||
@ -542,7 +572,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[戳一戳]"
|
summary .append( "[戳一戳]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createNewDiceElem(
|
private suspend fun createNewDiceElem(
|
||||||
@ -568,7 +598,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[骰子]"
|
summary .append( "[骰子]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createNewRpsElem(
|
private suspend fun createNewRpsElem(
|
||||||
@ -594,7 +624,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[包剪锤]"
|
summary .append( "[包剪锤]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createMarkdownElem(
|
private suspend fun createMarkdownElem(
|
||||||
@ -612,7 +642,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[Markdown消息]"
|
summary.append("[Markdown消息]")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createButtonElem(
|
private suspend fun createButtonElem(
|
||||||
@ -662,7 +692,7 @@ internal class ElemMaker {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
elems.add(elem)
|
elems.add(elem)
|
||||||
desc += "[Button消息]"
|
summary.append("[Button消息]")
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun createRecordElem(
|
private suspend fun createRecordElem(
|
||||||
@ -675,7 +705,7 @@ internal class ElemMaker {
|
|||||||
rich.ptt= Ptt(
|
rich.ptt= Ptt(
|
||||||
|
|
||||||
)
|
)
|
||||||
desc += "[语音消息]"
|
summary .append( "[语音消息]" )
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JsonObject.checkAndThrow(vararg key: String) {
|
private fun JsonObject.checkAndThrow(vararg key: String) {
|
||||||
|
@ -46,6 +46,7 @@ import protobuf.oidb.cmd0x11c5.NtV2RichMediaRsp
|
|||||||
import protobuf.oidb.cmd0x11c5.SceneInfo
|
import protobuf.oidb.cmd0x11c5.SceneInfo
|
||||||
import protobuf.oidb.cmd0x11c5.UploadInfo
|
import protobuf.oidb.cmd0x11c5.UploadInfo
|
||||||
import protobuf.oidb.cmd0x11c5.UploadReq
|
import protobuf.oidb.cmd0x11c5.UploadReq
|
||||||
|
import protobuf.oidb.cmd0x11c5.UploadRsp
|
||||||
import protobuf.oidb.cmd0x11c5.VideoDownloadExt
|
import protobuf.oidb.cmd0x11c5.VideoDownloadExt
|
||||||
import protobuf.oidb.cmd0x388.Cmd0x388ReqBody
|
import protobuf.oidb.cmd0x388.Cmd0x388ReqBody
|
||||||
import protobuf.oidb.cmd0x388.Cmd0x388RspBody
|
import protobuf.oidb.cmd0x388.Cmd0x388RspBody
|
||||||
@ -281,7 +282,6 @@ internal object NtV2RichMediaSvc: BaseSvc() {
|
|||||||
MsgConstant.KCHATTYPEC2C -> MessageHelper.generateContact(chatType, TicketSvc.getUin())
|
MsgConstant.KCHATTYPEC2C -> MessageHelper.generateContact(chatType, TicketSvc.getUin())
|
||||||
else -> Contact(chatType, fetchGroupResUploadTo(), null)
|
else -> Contact(chatType, fetchGroupResUploadTo(), null)
|
||||||
}
|
}
|
||||||
LogCenter.log(contact.toString())
|
|
||||||
val result = mutableListOf<CommonFileInfo>()
|
val result = mutableListOf<CommonFileInfo>()
|
||||||
withTimeoutOrNull(timeout) {
|
withTimeoutOrNull(timeout) {
|
||||||
suspendCancellableCoroutine {
|
suspendCancellableCoroutine {
|
||||||
@ -313,6 +313,11 @@ internal object NtV2RichMediaSvc: BaseSvc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result.isEmpty()) {
|
||||||
|
return Result.failure(Exception("upload failed"))
|
||||||
|
}
|
||||||
|
|
||||||
return Result.success(result)
|
return Result.success(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -392,9 +397,6 @@ internal object NtV2RichMediaSvc: BaseSvc() {
|
|||||||
return Result.failure(Exception("unable to get c2c nt pic"))
|
return Result.failure(Exception("unable to get c2c nt pic"))
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 请求上传Nt图片
|
|
||||||
*/
|
|
||||||
suspend fun requestUploadNtPic(
|
suspend fun requestUploadNtPic(
|
||||||
file: File,
|
file: File,
|
||||||
md5: String,
|
md5: String,
|
||||||
@ -402,8 +404,27 @@ internal object NtV2RichMediaSvc: BaseSvc() {
|
|||||||
name: String,
|
name: String,
|
||||||
width: UInt,
|
width: UInt,
|
||||||
height: UInt,
|
height: UInt,
|
||||||
|
retryCnt: Int,
|
||||||
sceneBuilder: suspend SceneInfo.() -> Unit
|
sceneBuilder: suspend SceneInfo.() -> Unit
|
||||||
) {
|
): Result<UploadRsp> {
|
||||||
|
return runCatching {
|
||||||
|
requestUploadNtPic(file, md5, sha, name, width, height, sceneBuilder).getOrThrow()
|
||||||
|
}.onFailure {
|
||||||
|
if (retryCnt > 0) {
|
||||||
|
return requestUploadNtPic(file, md5, sha, name, width, height, retryCnt - 1, sceneBuilder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun requestUploadNtPic(
|
||||||
|
file: File,
|
||||||
|
md5: String,
|
||||||
|
sha: String,
|
||||||
|
name: String,
|
||||||
|
width: UInt,
|
||||||
|
height: UInt,
|
||||||
|
sceneBuilder: suspend SceneInfo.() -> Unit
|
||||||
|
): Result<UploadRsp> {
|
||||||
val req = NtV2RichMediaReq(
|
val req = NtV2RichMediaReq(
|
||||||
head = MultiMediaReqHead(
|
head = MultiMediaReqHead(
|
||||||
commonHead = CommonHead(
|
commonHead = CommonHead(
|
||||||
@ -443,12 +464,17 @@ internal object NtV2RichMediaSvc: BaseSvc() {
|
|||||||
clientRandomId = Random.nextULong(),
|
clientRandomId = Random.nextULong(),
|
||||||
compatQMsgSceneType = 1u,
|
compatQMsgSceneType = 1u,
|
||||||
clientSeq = Random.nextUInt(),
|
clientSeq = Random.nextUInt(),
|
||||||
noNeedCompatMsg = true
|
noNeedCompatMsg = false
|
||||||
)
|
)
|
||||||
).toByteArray()
|
).toByteArray()
|
||||||
val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_100", 4549, 100, req, true)?.slice(4)
|
val buffer = sendOidbAW("OidbSvcTrpcTcp.0x11c5_100", 4549, 100, req, true, timeout = 3_000)?.slice(4)
|
||||||
val rsp = buffer?.decodeProtobuf<TrpcOidb>()?.buffer?.decodeProtobuf<NtV2RichMediaRsp>()
|
?: return Result.failure(Exception("no response: timeout"))
|
||||||
LogCenter.log("requestUploadPic => rsp: $rsp")
|
val rspBuffer = buffer.decodeProtobuf<TrpcOidb>().buffer
|
||||||
|
val rsp = rspBuffer.decodeProtobuf<NtV2RichMediaRsp>()
|
||||||
|
if (rsp.upload == null) {
|
||||||
|
return Result.failure(Exception("unable to request upload nt pic: ${rsp.head}"))
|
||||||
|
}
|
||||||
|
return Result.success(rsp.upload!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,31 +33,17 @@ internal object SendForwardMessage : IActionHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val peerId = when (chatType) {
|
val peerId = when (chatType) {
|
||||||
MsgConstant.KCHATTYPEGROUP -> session.getLongOrNull("group_id") ?: return noParam(
|
MsgConstant.KCHATTYPEGROUP -> session.getStringOrNull("group_id")
|
||||||
"group_id",
|
|
||||||
session.echo
|
|
||||||
)
|
|
||||||
|
|
||||||
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getLongOrNull("user_id")
|
|
||||||
?: return noParam("user_id", session.echo)
|
|
||||||
|
|
||||||
else -> error("unknown chat type: $chatType")
|
|
||||||
}.toString()
|
|
||||||
val fromId = when (chatType) {
|
|
||||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getLongOrNull("group_id")
|
|
||||||
?: return noParam("group_id", session.echo)
|
?: return noParam("group_id", session.echo)
|
||||||
|
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("user_id")
|
||||||
MsgConstant.KCHATTYPEC2C -> session.getLongOrNull("user_id") ?: return noParam(
|
?: return noParam("user_id", session.echo)
|
||||||
"user_id",
|
|
||||||
session.echo
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> error("unknown chat type: $chatType")
|
else -> error("unknown chat type: $chatType")
|
||||||
}.toString()
|
}
|
||||||
|
val fromId = session.getStringOrNull("group_id")
|
||||||
val retryCnt = session.getIntOrNull("retry_cnt") ?: 5
|
val retryCnt = session.getIntOrNull("retry_cnt") ?: 5
|
||||||
return if (session.isArray("messages")) {
|
return if (session.isArray("messages")) {
|
||||||
val messages = session.getArray("messages")
|
val messages = session.getArray("messages")
|
||||||
invoke(chatType, peerId, fromId, messages, retryCnt, session.echo)
|
invoke(chatType, peerId, fromId ?: peerId, messages, retryCnt, session.echo)
|
||||||
} else {
|
} else {
|
||||||
logic("未知格式合并转发消息", session.echo)
|
logic("未知格式合并转发消息", session.echo)
|
||||||
}
|
}
|
||||||
@ -77,18 +63,16 @@ internal object SendForwardMessage : IActionHandler() {
|
|||||||
echo: JsonElement = EmptyJsonString
|
echo: JsonElement = EmptyJsonString
|
||||||
): String {
|
): String {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val message = MsgSvc.uploadMultiMsg(chatType, peerId, fromId, messages, retryCnt)
|
val message = MsgSvc.uploadMultiMsg(chatType, peerId, fromId, messages, retryCnt).onFailure {
|
||||||
.getOrElse { return logic(it.message ?: "", echo) }
|
return error(it.message ?: it.stackTraceToString(), echo)
|
||||||
|
}.getOrThrow()
|
||||||
val result = MsgSvc.sendToAio(chatType, peerId, listOf(message).toJson(), fromId, retryCnt)
|
val result = MsgSvc.sendToAio(chatType, peerId, listOf(message).toJson(), fromId, retryCnt).onFailure {
|
||||||
.getOrElse { return logic(it.message ?: "", echo) }
|
return error(it.message ?: it.stackTraceToString(), echo)
|
||||||
|
}.getOrThrow()
|
||||||
return ok(
|
return ok(SendForwardMessageResult(
|
||||||
SendForwardMessageResult(
|
|
||||||
msgId = result.msgHashId,
|
msgId = result.msgHashId,
|
||||||
resId = message.data["id"] as String
|
resId = message.data["id"] as String
|
||||||
), echo = echo
|
), echo = echo)
|
||||||
)
|
|
||||||
}.onFailure {
|
}.onFailure {
|
||||||
return error("合并转发消息失败: $it", echo)
|
return error("合并转发消息失败: $it", echo)
|
||||||
}
|
}
|
||||||
|
@ -32,31 +32,17 @@ internal object UploadMultiMessage : IActionHandler() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val peerId = when (chatType) {
|
val peerId = when (chatType) {
|
||||||
MsgConstant.KCHATTYPEGROUP -> session.getLongOrNull("group_id") ?: return noParam(
|
MsgConstant.KCHATTYPEGROUP -> session.getStringOrNull("group_id")
|
||||||
"group_id",
|
|
||||||
session.echo
|
|
||||||
)
|
|
||||||
|
|
||||||
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getLongOrNull("user_id")
|
|
||||||
?: return noParam("user_id", session.echo)
|
|
||||||
|
|
||||||
else -> error("unknown chat type: $chatType")
|
|
||||||
}.toString()
|
|
||||||
val fromId = when (chatType) {
|
|
||||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getLongOrNull("group_id")
|
|
||||||
?: return noParam("group_id", session.echo)
|
?: return noParam("group_id", session.echo)
|
||||||
|
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("user_id")
|
||||||
MsgConstant.KCHATTYPEC2C -> session.getLongOrNull("user_id") ?: return noParam(
|
?: return noParam("user_id", session.echo)
|
||||||
"user_id",
|
|
||||||
session.echo
|
|
||||||
)
|
|
||||||
|
|
||||||
else -> error("unknown chat type: $chatType")
|
else -> error("unknown chat type: $chatType")
|
||||||
}.toString()
|
}
|
||||||
|
val fromId = session.getStringOrNull("group_id")
|
||||||
val retryCnt = session.getIntOrNull("retry_cnt") ?: 5
|
val retryCnt = session.getIntOrNull("retry_cnt") ?: 5
|
||||||
return if (session.isArray("messages")) {
|
return if (session.isArray("messages")) {
|
||||||
val messages = session.getArray("messages")
|
val messages = session.getArray("messages")
|
||||||
invoke(chatType, peerId, fromId, messages, retryCnt, echo = session.echo)
|
invoke(chatType, peerId, fromId ?: peerId, messages, retryCnt, echo = session.echo)
|
||||||
} else {
|
} else {
|
||||||
logic("未知格式合并转发消息", session.echo)
|
logic("未知格式合并转发消息", session.echo)
|
||||||
}
|
}
|
||||||
@ -76,9 +62,10 @@ internal object UploadMultiMessage : IActionHandler() {
|
|||||||
echo: JsonElement = EmptyJsonString
|
echo: JsonElement = EmptyJsonString
|
||||||
): String {
|
): String {
|
||||||
kotlin.runCatching {
|
kotlin.runCatching {
|
||||||
val message = MsgSvc.uploadMultiMsg(chatType, peerId, fromId, messages, retryCnt)
|
MsgSvc.uploadMultiMsg(chatType, peerId, fromId, messages, retryCnt).getOrThrow()
|
||||||
.getOrElse { return logic(it.message ?: "", echo) }
|
}.onFailure {
|
||||||
|
return error("合并转发消息失败: ${it.stackTraceToString()}", echo)
|
||||||
|
}.onSuccess { message ->
|
||||||
return ok(
|
return ok(
|
||||||
UploadForwardMessageResult(
|
UploadForwardMessageResult(
|
||||||
resId = message.data["id"] as String,
|
resId = message.data["id"] as String,
|
||||||
@ -87,8 +74,6 @@ internal object UploadMultiMessage : IActionHandler() {
|
|||||||
desc = message.data["desc"] as String
|
desc = message.data["desc"] as String
|
||||||
), echo = echo
|
), echo = echo
|
||||||
)
|
)
|
||||||
}.onFailure {
|
|
||||||
return error("合并转发消息失败: $it", echo)
|
|
||||||
}
|
}
|
||||||
return logic("合并转发消息失败(unknown error)", echo)
|
return logic("合并转发消息失败(unknown error)", echo)
|
||||||
}
|
}
|
||||||
|
@ -312,16 +312,13 @@ fun Routing.messageAction() {
|
|||||||
val userId = fetchPostOrNull("user_id")
|
val userId = fetchPostOrNull("user_id")
|
||||||
val groupId = fetchPostOrNull("group_id")
|
val groupId = fetchPostOrNull("group_id")
|
||||||
val messages = fetchPostJsonArray("messages")
|
val messages = fetchPostJsonArray("messages")
|
||||||
call.respondText(
|
call.respondText(UploadMultiMessage(
|
||||||
UploadMultiMessage(
|
chatType = chatType,
|
||||||
chatType,
|
peerId = if (chatType == MsgConstant.KCHATTYPEC2C) userId!! else groupId!!,
|
||||||
if (chatType == MsgConstant.KCHATTYPEC2C) userId!! else groupId!!,
|
fromId = groupId ?: userId ?: "",
|
||||||
groupId ?: userId ?: "",
|
messages = messages,
|
||||||
messages,
|
retryCnt = retryCnt
|
||||||
retryCnt
|
), ContentType.Application.Json)
|
||||||
),
|
|
||||||
ContentType.Application.Json
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
get {
|
get {
|
||||||
respond(false, Status.InternalHandlerError, "Not support GET method")
|
respond(false, Status.InternalHandlerError, "Not support GET method")
|
||||||
|
Loading…
x
Reference in New Issue
Block a user