mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
refactor send_forward_msg(暂未完成 请勿使用)
This commit is contained in:
parent
a5cdd64686
commit
1c65aab673
@ -7,4 +7,5 @@ import kotlinx.serialization.protobuf.ProtoNumber
|
||||
data class MessageBody(
|
||||
@ProtoNumber(1) val rich: RichMessage? = null,
|
||||
@ProtoNumber(2) val rawBuffer: ByteArray? = null,
|
||||
@ProtoNumber(3) val MsgEncryptContent: ByteArray? = null
|
||||
)
|
@ -11,8 +11,20 @@ data class MessageContent(
|
||||
@ProtoNumber(5) val msgSeq: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(6) val msgTime: Long? = null,
|
||||
@ProtoNumber(7) val u2: Int? = null,
|
||||
@ProtoNumber(8) val u6: Int? = null,
|
||||
@ProtoNumber(9) val u7: Int? = null,
|
||||
@ProtoNumber(11) val u3: Long? = null,
|
||||
@ProtoNumber(12) val msgRandom: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(14) val u4: Long? = null,
|
||||
@ProtoNumber(28) val u5: Long? = null,
|
||||
)
|
||||
@ProtoNumber(15) val forwardHead: ForwardHead? = null,
|
||||
@ProtoNumber(28) val u5: Long? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class ForwardHead(
|
||||
@ProtoNumber(1) val u1: Int? = null,
|
||||
@ProtoNumber(2) val u2: Int? = null,
|
||||
@ProtoNumber(3) val u3: Int? = null,
|
||||
@ProtoNumber(4) val u4: String? = null,
|
||||
@ProtoNumber(5) val Avatar: String? = null
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ import protobuf.message.element.*
|
||||
@Serializable
|
||||
data class MessageElement(
|
||||
@ProtoNumber(1) val text: TextElement? = null,
|
||||
@ProtoNumber(2) val face: FaceElement? = null,
|
||||
@ProtoNumber(51) val json: JsonElement? = null,
|
||||
@ProtoNumber(53) val commElem: CommonElement? = null,
|
||||
)
|
@ -13,12 +13,19 @@ data class MessageHead(
|
||||
@ProtoNumber(4) val appId: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(5) val receiver: Long? = null,
|
||||
@ProtoNumber(6) val receiverUid: String? = null,
|
||||
@ProtoNumber(7) val forward: MessageForward? = null,
|
||||
@ProtoNumber(8) val groupInfo: GroupInfo? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class MessageForward(
|
||||
@ProtoNumber(6) val friendName: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class GroupInfo(
|
||||
@ProtoNumber(1) val groupCode: ULong = ULong.MIN_VALUE,
|
||||
@ProtoNumber(4) val memberCard: String? = null,
|
||||
@ProtoNumber(5) val u1: Int? = null,
|
||||
@ProtoNumber(7) val groupName: String? = null,
|
||||
)
|
@ -0,0 +1,9 @@
|
||||
package protobuf.message.element
|
||||
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
@Serializable
|
||||
data class FaceElement(
|
||||
@ProtoNumber(1) val id: Int? = null,
|
||||
)
|
62
protobuf/src/main/java/protobuf/message/longmsg/LongMsg.kt
Normal file
62
protobuf/src/main/java/protobuf/message/longmsg/LongMsg.kt
Normal file
@ -0,0 +1,62 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
package protobuf.message.longmsg
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
|
||||
|
||||
@Serializable
|
||||
data class LongMsgSettings(
|
||||
@ProtoNumber(1) val field1: Int? = null,
|
||||
@ProtoNumber(2) val field2: Int? = null,
|
||||
@ProtoNumber(3) val field3: Int? = null,
|
||||
@ProtoNumber(4) val field4: Int? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class LongMsgUid(
|
||||
@ProtoNumber(2) val uid: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RecvLongMsgInfo(
|
||||
@ProtoNumber(1) val uid: LongMsgUid? = null,
|
||||
@ProtoNumber(2) val resId: String? = null,
|
||||
@ProtoNumber(3) val acquire: Boolean? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class SendLongMsgInfo(
|
||||
@ProtoNumber(1) val type: Int? = null,
|
||||
@ProtoNumber(2) val uid: LongMsgUid? = null,
|
||||
@ProtoNumber(3) val groupUin: Int? = null,
|
||||
@ProtoNumber(4) val payload: ByteArray? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class LongMsgReq(
|
||||
@ProtoNumber(1) val recvInfo: RecvLongMsgInfo? = null,
|
||||
@ProtoNumber(2) val sendInfo: SendLongMsgInfo? = null,
|
||||
@ProtoNumber(15) val setting: LongMsgSettings? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class LongMsgRsp(
|
||||
@ProtoNumber(1) val recvResult: RecvLongMsgResult? = null,
|
||||
@ProtoNumber(2) val sendResult: SendLongMsgResult? = null,
|
||||
@ProtoNumber(15) val setting: LongMsgSettings? = null
|
||||
) {
|
||||
companion object {
|
||||
@Serializable
|
||||
data class SendLongMsgResult(
|
||||
@ProtoNumber(3) val resId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class RecvLongMsgResult(
|
||||
@ProtoNumber(3) val resId: String? = null,
|
||||
@ProtoNumber(4) val payload: ByteArray? = null,
|
||||
)
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
@file:OptIn(ExperimentalSerializationApi::class)
|
||||
|
||||
package protobuf.message.longmsg
|
||||
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumber
|
||||
import protobuf.message.MessageBody
|
||||
import protobuf.message.MessageContent
|
||||
import protobuf.message.MessageHead
|
||||
|
||||
@Serializable
|
||||
data class PushMsgBody(
|
||||
@ProtoNumber(1) val head: MessageHead? = null,
|
||||
@ProtoNumber(2) val content: MessageContent? = null,
|
||||
@ProtoNumber(3) val body: MessageBody? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class LongMsgContent(
|
||||
@ProtoNumber(1) val body: List<PushMsgBody>? = null
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class LongMsgAction(
|
||||
@ProtoNumber(1) val command: String? = null,
|
||||
@ProtoNumber(2) val data: LongMsgContent? = null
|
||||
)
|
||||
@Serializable
|
||||
data class LongMsgPayload(
|
||||
@ProtoNumber(2) val action: LongMsgAction? = null
|
||||
)
|
@ -5,12 +5,7 @@ package moe.fuqiuluo.qqinterface.servlet
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.mobileqq.troop.api.ITroopMemberNameService
|
||||
import com.tencent.qqnt.kernel.api.IKernelService
|
||||
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import com.tencent.qqnt.kernel.nativeinterface.TempChatGameSession
|
||||
import com.tencent.qqnt.kernel.nativeinterface.TempChatInfo
|
||||
import com.tencent.qqnt.kernel.nativeinterface.TempChatPrepareInfo
|
||||
import com.tencent.qqnt.kernel.nativeinterface.*
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -18,21 +13,33 @@ import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import kotlinx.serialization.decodeFromByteArray
|
||||
import kotlinx.serialization.encodeToByteArray
|
||||
import kotlinx.serialization.json.JsonArray
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||
import moe.fuqiuluo.shamrock.helper.ContactHelper
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||
import moe.fuqiuluo.shamrock.helper.SendMsgException
|
||||
import moe.fuqiuluo.shamrock.helper.MessageHelper.messageArrayToMessageElements
|
||||
import moe.fuqiuluo.shamrock.remote.structures.SendMsgResult
|
||||
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
import moe.fuqiuluo.shamrock.tools.*
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.msgService
|
||||
import protobuf.message.*
|
||||
import protobuf.message.longmsg.*
|
||||
import tencent.mobileim.structmsg.structmsg.SystemMsg
|
||||
import java.util.UUID
|
||||
import kotlin.collections.slice
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextLong
|
||||
|
||||
internal object MsgSvc: BaseSvc() {
|
||||
internal object MsgSvc : BaseSvc() {
|
||||
suspend fun prepareTempChatFromGroup(
|
||||
groupId: String,
|
||||
peerId: String
|
||||
@ -40,16 +47,19 @@ internal object MsgSvc: BaseSvc() {
|
||||
LogCenter.log("主动临时消息,创建临时会话。", Level.INFO)
|
||||
val msgService = app.getRuntimeService(IKernelService::class.java, "all").msgService
|
||||
?: return Result.failure(Exception("获取消息服务失败"))
|
||||
msgService.prepareTempChat(TempChatPrepareInfo(
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP,
|
||||
ContactHelper.getUidByUinAsync(peerId = peerId.toLong()),
|
||||
app.getRuntimeService(ITroopMemberNameService::class.java, "all").getTroopMemberNameRemarkFirst(groupId, peerId),
|
||||
groupId,
|
||||
EMPTY_BYTE_ARRAY,
|
||||
app.currentUid,
|
||||
"",
|
||||
TempChatGameSession()
|
||||
)) { code, reason ->
|
||||
msgService.prepareTempChat(
|
||||
TempChatPrepareInfo(
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP,
|
||||
ContactHelper.getUidByUinAsync(peerId = peerId.toLong()),
|
||||
app.getRuntimeService(ITroopMemberNameService::class.java, "all")
|
||||
.getTroopMemberNameRemarkFirst(groupId, peerId),
|
||||
groupId,
|
||||
EMPTY_BYTE_ARRAY,
|
||||
app.currentUid,
|
||||
"",
|
||||
TempChatGameSession()
|
||||
)
|
||||
) { code, reason ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("临时会话创建失败: $code, $reason", Level.ERROR)
|
||||
}
|
||||
@ -83,7 +93,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
?: return Result.failure(Exception("没有对应消息映射,消息获取失败"))
|
||||
|
||||
val peerId = mapping.peerId
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, peerId, mapping.subPeerId ?: "")
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, peerId, mapping.subPeerId)
|
||||
|
||||
val msg = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
@ -174,7 +184,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
val mapping = MessageHelper.getMsgMappingByHash(msgHash)
|
||||
?: return -1 to "无法找到消息映射"
|
||||
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, mapping.peerId, mapping.subPeerId ?: "")
|
||||
val contact = MessageHelper.generateContact(mapping.chatType, mapping.peerId, mapping.subPeerId)
|
||||
|
||||
return suspendCancellableCoroutine { continuation ->
|
||||
msgService.recallMsg(contact, arrayListOf(mapping.qqMsgId)) { code, why ->
|
||||
@ -204,7 +214,8 @@ internal object MsgSvc: BaseSvc() {
|
||||
}
|
||||
}
|
||||
}
|
||||
val result = MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, fromId, MessageCallback(peedId, 0))
|
||||
val result =
|
||||
MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, fromId, MessageCallback(peedId, 0))
|
||||
if (result.isFailure) {
|
||||
LogCenter.log("sendToAio: " + result.exceptionOrNull()?.stackTraceToString(), Level.ERROR)
|
||||
return result
|
||||
@ -220,13 +231,54 @@ internal object MsgSvc: BaseSvc() {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun sendMultiMsg(
|
||||
uid: String,
|
||||
groupUin: String?,
|
||||
messages: List<PushMsgBody>,
|
||||
): Result<String> {
|
||||
val payload = LongMsgPayload(
|
||||
action = LongMsgAction(
|
||||
command = "MultiMsg",
|
||||
data = LongMsgContent(
|
||||
messages
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
val req = LongMsgReq(
|
||||
sendInfo = SendLongMsgInfo(
|
||||
type = if (groupUin == null) 1 else 3,
|
||||
uid = LongMsgUid(groupUin ?: uid),
|
||||
groupUin = groupUin?.toInt(),
|
||||
payload = DeflateTools.gzip(ProtoBuf.encodeToByteArray(payload))
|
||||
),
|
||||
setting = LongMsgSettings(
|
||||
field1 = 4,
|
||||
field2 = 2,
|
||||
field3 = 9,
|
||||
field4 = 0
|
||||
)
|
||||
)
|
||||
val buffer = sendBufferAW(
|
||||
"trpc.group.long_msg_interface.MsgService.SsoSendLongMsg",
|
||||
true,
|
||||
ProtoBuf.encodeToByteArray(req)
|
||||
) ?: return Result.failure(Exception("unable to upload multi message"))
|
||||
val rsp = ProtoBuf.decodeFromByteArray<LongMsgRsp>(buffer.slice(4))
|
||||
return rsp.sendResult?.resId?.let { Result.success(it) } ?: Result.failure(Exception("unable to upload multi message"))
|
||||
}
|
||||
|
||||
suspend fun getMultiMsg(resId: String): Result<List<MsgRecord>> {
|
||||
// trpc.group.long_msg_interface.MsgService.SsoRecvLongMsg
|
||||
// 00 00 00 70 0A 60 0A 1A 12 18 75 5F 35 5A 5A 53 6F 38 63 4D 71 70 49 79 63 75 57 5F 78 43 4C 48 6E 77 12 40 4D 6F 61 44 38 77 2B 55 74 43 42 55 45 4C 4F 66 7A 61 72 69 43 7A 4F 5A 44 57 4B 43 6D 68 45 74 4F 65 54 6C 46 66 44 70 2F 73 61 56 77 50 2F 44 52 37 72 4A 2B 4B 4B 47 30 65 71 2B 6C 4B 58 34 18 03 7A 08 08 02 10 02 18 09 20 00
|
||||
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
val contact = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, TicketSvc.getUin())
|
||||
|
||||
val content = "{\"app\":\"com.tencent.multimsg\",\"config\":{\"autosize\":1,\"forward\":1,\"round\":1,\"type\":\"normal\",\"width\":300},\"desc\":\"[聊天记录]\",\"extra\":\"\",\"meta\":{\"detail\":{\"news\":[{\"text\":\"Shamrock: 这是条假消息!\"}],\"resid\":\"$resId\",\"source\":\"聊天记录\",\"summary\":\"转发消息\",\"uniseq\":\"${UUID.randomUUID()}\"}},\"prompt\":\"[聊天记录]\",\"ver\":\"0.0.0.5\",\"view\":\"contact\"}"
|
||||
val content =
|
||||
"{\"app\":\"com.tencent.multimsg\",\"config\":{\"autosize\":1,\"forward\":1,\"round\":1,\"type\":\"normal\",\"width\":300},\"desc\":\"[聊天记录]\",\"extra\":\"\",\"meta\":{\"detail\":{\"news\":[{\"text\":\"Shamrock: 这是条假消息!\"}],\"resid\":\"$resId\",\"source\":\"聊天记录\",\"summary\":\"转发消息\",\"uniseq\":\"${UUID.randomUUID()}\"}},\"prompt\":\"[聊天记录]\",\"ver\":\"0.0.0.5\",\"view\":\"contact\"}"
|
||||
val msgId = PacketSvc.fakeSelfRecvJsonMsg(msgService, content)
|
||||
if (msgId < 0) {
|
||||
return Result.failure(Exception("获取合并转发消息ID失败"))
|
||||
@ -261,7 +313,7 @@ internal object MsgSvc: BaseSvc() {
|
||||
class MessageCallback(
|
||||
private val peerId: String,
|
||||
var msgHash: Int
|
||||
): IOperateCallback {
|
||||
) : IOperateCallback {
|
||||
override fun onResult(code: Int, reason: String?) {
|
||||
if (code != 0 && msgHash != 0) {
|
||||
MessageHelper.removeMsgByHashCode(msgHash)
|
||||
|
@ -50,6 +50,14 @@ internal object TicketSvc: BaseSvc() {
|
||||
return app.longAccountUin
|
||||
}
|
||||
|
||||
fun getUid(): String {
|
||||
return app.currentUid.ifBlank { "u_" }
|
||||
}
|
||||
|
||||
fun getNickname(): String {
|
||||
return app.currentNickname
|
||||
}
|
||||
|
||||
fun getCookie(): String {
|
||||
val uin = getUin()
|
||||
val skey = getRealSkey(uin)
|
||||
|
@ -0,0 +1,96 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.msg
|
||||
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import moe.fuqiuluo.shamrock.helper.ParamsException
|
||||
import moe.fuqiuluo.shamrock.tools.asInt
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import protobuf.message.MessageElement
|
||||
import protobuf.message.element.FaceElement
|
||||
import protobuf.message.element.TextElement
|
||||
|
||||
|
||||
internal typealias IMessageMaker = suspend (Int, Long, String, JsonObject) -> Result<MessageElement>
|
||||
|
||||
internal object MessageElementMaker {
|
||||
private val makerArray = hashMapOf(
|
||||
"text" to MessageElementMaker::createTextElem,
|
||||
"face" to MessageElementMaker::createFaceElem,
|
||||
// "pic" to MessageElementMaker::createImageElem,
|
||||
// "image" to MessageElementMaker::createImageElem,
|
||||
// "voice" to MessageElementMaker::createRecordElem,
|
||||
// "record" to MessageElementMaker::createRecordElem,
|
||||
// "at" to MessageElementMaker::createAtElem,
|
||||
// "video" to MessageElementMaker::createVideoElem,
|
||||
// "markdown" to MessageElementMaker::createMarkdownElem,
|
||||
// "dice" to MessageElementMaker::createDiceElem,
|
||||
// "rps" to MessageElementMaker::createRpsElem,
|
||||
// "poke" to MessageElementMaker::createPokeElem,
|
||||
// "anonymous" to MessageElementMaker::createAnonymousElem,
|
||||
// "share" to MessageElementMaker::createShareElem,
|
||||
// "contact" to MessageElementMaker::createContactElem,
|
||||
// "location" to MessageElementMaker::createLocationElem,
|
||||
// "music" to MessageElementMaker::createMusicElem,
|
||||
// "reply" to MessageElementMaker::createReplyElem,
|
||||
// "touch" to MessageElementMaker::createTouchElem,
|
||||
// "weather" to MessageElementMaker::createWeatherElem,
|
||||
"json" to MessageElementMaker::createJsonElem,
|
||||
//"new_dice" to MessageElementMaker::createNewDiceElem,
|
||||
//"new_rps" to MessageElementMaker::createNewRpsElem,
|
||||
//"basketball" to MessageElementMaker::createBasketballElem,
|
||||
//"node" to MessageMaker::createNodeElem,
|
||||
//"multi_msg" to MessageMaker::createLongMsgStruct,
|
||||
//"bubble_face" to MessageElementMaker::createBubbleFaceElem,
|
||||
)
|
||||
|
||||
private suspend fun createTextElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MessageElement> {
|
||||
data.checkAndThrow("text")
|
||||
val elem = MessageElement(
|
||||
text = TextElement(data["text"].asString)
|
||||
)
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createFaceElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MessageElement> {
|
||||
data.checkAndThrow("id")
|
||||
val elem = MessageElement(
|
||||
face = FaceElement(data["id"].asInt)
|
||||
)
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createJsonElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MessageElement> {
|
||||
data.checkAndThrow("data")
|
||||
|
||||
val elem = MessageElement(
|
||||
json = protobuf.message.element.JsonElement(
|
||||
data = DeflateTools.compress(data.toString().toByteArray())
|
||||
)
|
||||
)
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private fun JsonObject.checkAndThrow(vararg key: String) {
|
||||
key.forEach {
|
||||
if (!containsKey(it)) throw ParamsException(it)
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(type: String): IMessageMaker? = makerArray[type]
|
||||
|
||||
}
|
@ -82,38 +82,38 @@ import kotlin.math.roundToInt
|
||||
import kotlin.random.Random
|
||||
import kotlin.random.nextInt
|
||||
|
||||
internal typealias IMaker = suspend (Int, Long, String, JsonObject) -> Result<MsgElement>
|
||||
internal typealias IMsgMaker = suspend (Int, Long, String, JsonObject) -> Result<MsgElement>
|
||||
|
||||
internal object MessageMaker {
|
||||
private val makerArray = mutableMapOf(
|
||||
"text" to MessageMaker::createTextElem,
|
||||
"face" to MessageMaker::createFaceElem,
|
||||
"pic" to MessageMaker::createImageElem,
|
||||
"image" to MessageMaker::createImageElem,
|
||||
"voice" to MessageMaker::createRecordElem,
|
||||
"record" to MessageMaker::createRecordElem,
|
||||
"at" to MessageMaker::createAtElem,
|
||||
"video" to MessageMaker::createVideoElem,
|
||||
"markdown" to MessageMaker::createMarkdownElem,
|
||||
"dice" to MessageMaker::createDiceElem,
|
||||
"rps" to MessageMaker::createRpsElem,
|
||||
"poke" to MessageMaker::createPokeElem,
|
||||
"anonymous" to MessageMaker::createAnonymousElem,
|
||||
"share" to MessageMaker::createShareElem,
|
||||
"contact" to MessageMaker::createContactElem,
|
||||
"location" to MessageMaker::createLocationElem,
|
||||
"music" to MessageMaker::createMusicElem,
|
||||
"reply" to MessageMaker::createReplyElem,
|
||||
"touch" to MessageMaker::createTouchElem,
|
||||
"weather" to MessageMaker::createWeatherElem,
|
||||
"json" to MessageMaker::createJsonElem,
|
||||
"new_dice" to MessageMaker::createNewDiceElem,
|
||||
"new_rps" to MessageMaker::createNewRpsElem,
|
||||
"basketball" to MessageMaker::createBasketballElem,
|
||||
internal object MsgElementMaker {
|
||||
private val makerArray = hashMapOf(
|
||||
"text" to MsgElementMaker::createTextElem,
|
||||
"face" to MsgElementMaker::createFaceElem,
|
||||
"pic" to MsgElementMaker::createImageElem,
|
||||
"image" to MsgElementMaker::createImageElem,
|
||||
"voice" to MsgElementMaker::createRecordElem,
|
||||
"record" to MsgElementMaker::createRecordElem,
|
||||
"at" to MsgElementMaker::createAtElem,
|
||||
"video" to MsgElementMaker::createVideoElem,
|
||||
"markdown" to MsgElementMaker::createMarkdownElem,
|
||||
"dice" to MsgElementMaker::createDiceElem,
|
||||
"rps" to MsgElementMaker::createRpsElem,
|
||||
"poke" to MsgElementMaker::createPokeElem,
|
||||
"anonymous" to MsgElementMaker::createAnonymousElem,
|
||||
"share" to MsgElementMaker::createShareElem,
|
||||
"contact" to MsgElementMaker::createContactElem,
|
||||
"location" to MsgElementMaker::createLocationElem,
|
||||
"music" to MsgElementMaker::createMusicElem,
|
||||
"reply" to MsgElementMaker::createReplyElem,
|
||||
"touch" to MsgElementMaker::createTouchElem,
|
||||
"weather" to MsgElementMaker::createWeatherElem,
|
||||
"json" to MsgElementMaker::createJsonElem,
|
||||
"new_dice" to MsgElementMaker::createNewDiceElem,
|
||||
"new_rps" to MsgElementMaker::createNewRpsElem,
|
||||
"basketball" to MsgElementMaker::createBasketballElem,
|
||||
//"node" to MessageMaker::createNodeElem,
|
||||
//"multi_msg" to MessageMaker::createLongMsgStruct,
|
||||
"bubble_face" to MessageMaker::createBubbleFaceElem,
|
||||
"inline_keyboard" to MessageMaker::createInlineKeywordElem
|
||||
"bubble_face" to MsgElementMaker::createBubbleFaceElem,
|
||||
"inline_keyboard" to MsgElementMaker::createInlineKeywordElem
|
||||
)
|
||||
|
||||
private suspend fun createInlineKeywordElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
@ -169,7 +169,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createBubbleFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createBubbleFaceElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("id", "count")
|
||||
val faceId = data["id"].asInt
|
||||
val local = QQSysFaceUtil.convertToLocal(faceId)
|
||||
@ -202,21 +207,13 @@ internal object MessageMaker {
|
||||
// SendForwardMessage(MsgConstant.KCHATTYPEC2C, TicketSvc.getUin(), data["content"].asJsonArray)
|
||||
//
|
||||
// }
|
||||
/**\
|
||||
* msgElement.setFaceElement(new FaceElement());
|
||||
* msgElement.getFaceElement().setFaceIndex(114);
|
||||
* msgElement.getFaceElement().setFaceText("/篮球");
|
||||
* msgElement.getFaceElement().setFaceType(3);
|
||||
* msgElement.getFaceElement().setPackId("1");
|
||||
* msgElement.getFaceElement().setStickerId("13");
|
||||
* msgElement.getFaceElement().setRandomType(1);
|
||||
* msgElement.getFaceElement().setImageType(1);
|
||||
* msgElement.getFaceElement().setStickerType(2);
|
||||
* msgElement.getFaceElement().setSourceType(1);
|
||||
* msgElement.getFaceElement().setSurpriseId("");
|
||||
* msgElement.getFaceElement().setResultId(String.valueOf(new Random().nextInt(5) + 1));
|
||||
*/
|
||||
private suspend fun createBasketballElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
|
||||
private suspend fun createBasketballElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEFACE
|
||||
val face = FaceElement()
|
||||
@ -227,14 +224,19 @@ internal object MessageMaker {
|
||||
face.stickerId = "13"
|
||||
face.sourceType = 1
|
||||
face.stickerType = 2
|
||||
face.resultId = Random.nextInt(1 .. 5).toString()
|
||||
face.resultId = Random.nextInt(1..5).toString()
|
||||
face.surpriseId = ""
|
||||
face.randomType = 1
|
||||
elem.faceElement = face
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createNewRpsElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createNewRpsElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEFACE
|
||||
val face = FaceElement()
|
||||
@ -252,7 +254,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createNewDiceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createNewDiceElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEFACE
|
||||
val face = FaceElement()
|
||||
@ -370,7 +377,7 @@ internal object MessageMaker {
|
||||
LogCenter.log("无法获取被回复消息", Level.ERROR)
|
||||
}
|
||||
|
||||
if(data.containsKey("text")) {
|
||||
if (data.containsKey("text")) {
|
||||
data.checkAndThrow("qq", "time", "seq")
|
||||
reply.replayMsgSeq = data["seq"].asLong
|
||||
reply.sourceMsgText = data["text"].asString
|
||||
@ -389,21 +396,23 @@ internal object MessageMaker {
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("type")
|
||||
|
||||
when(val type = data["type"].asString) {
|
||||
when (val type = data["type"].asString) {
|
||||
"qq" -> {
|
||||
data.checkAndThrow("id")
|
||||
val id = data["id"].asString
|
||||
if(!MusicHelper.tryShareQQMusicById(chatType, peerId.toLong(), msgId, id)) {
|
||||
if (!MusicHelper.tryShareQQMusicById(chatType, peerId.toLong(), msgId, id)) {
|
||||
LogCenter.log("无法发送QQ音乐分享", Level.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
"163" -> {
|
||||
data.checkAndThrow("id")
|
||||
val id = data["id"].asString
|
||||
if(!MusicHelper.tryShare163MusicById(chatType, peerId.toLong(), msgId, id)) {
|
||||
if (!MusicHelper.tryShare163MusicById(chatType, peerId.toLong(), msgId, id)) {
|
||||
LogCenter.log("无法发送网易云音乐分享", Level.ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
"custom" -> {
|
||||
data.checkAndThrow("url", "audio", "title")
|
||||
ArkMsgSvc.tryShareMusic(
|
||||
@ -418,13 +427,19 @@ internal object MessageMaker {
|
||||
data["audio"].asString
|
||||
)
|
||||
}
|
||||
|
||||
else -> LogCenter.log("不支持的音乐分享类型: $type", Level.ERROR)
|
||||
}
|
||||
|
||||
return Result.failure(ActionMsgException)
|
||||
}
|
||||
|
||||
private suspend fun createLocationElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createLocationElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("lat", "lon")
|
||||
|
||||
val lat = data["lat"].asString.toDouble()
|
||||
@ -437,7 +452,12 @@ internal object MessageMaker {
|
||||
return Result.failure(ActionMsgException)
|
||||
}
|
||||
|
||||
private suspend fun createContactElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createContactElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("id")
|
||||
val type = data["type"].asStringOrNull ?: data["kind"].asStringOrNull
|
||||
val id = data["id"].asString
|
||||
@ -448,10 +468,12 @@ internal object MessageMaker {
|
||||
val ark = ArkElement(CardSvc.getSharePrivateArkMsg(id.toLong()), null, null)
|
||||
elem.arkElement = ark
|
||||
}
|
||||
|
||||
"group" -> {
|
||||
val ark = ArkElement(GroupSvc.getShareTroopArkMsg(id.toLong()), null, null)
|
||||
elem.arkElement = ark
|
||||
}
|
||||
|
||||
else -> throw IllegalParamsException("type")
|
||||
}
|
||||
|
||||
@ -460,7 +482,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createShareElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createShareElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("title", "url")
|
||||
|
||||
val url = data["url"].asString
|
||||
@ -525,11 +552,21 @@ internal object MessageMaker {
|
||||
return Result.failure(ActionMsgException)
|
||||
}
|
||||
|
||||
private suspend fun createAnonymousElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createAnonymousElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
return Result.failure(ActionMsgException)
|
||||
}
|
||||
|
||||
private suspend fun createPokeElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createPokeElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("type", "id")
|
||||
val elem = MsgElement()
|
||||
val face = FaceElement()
|
||||
@ -544,8 +581,8 @@ internal object MessageMaker {
|
||||
face.vaspokeName = ""
|
||||
face.vaspokeMinver = ""
|
||||
face.pokeStrength = (data["strength"].asIntOrNull ?: data["cnt"].asIntOrNull
|
||||
?: data["count"].asIntOrNull ?: data["time"].asIntOrNull ?: 0).also {
|
||||
if(it < 0 || it > 3) throw IllegalParamsException("strength")
|
||||
?: data["count"].asIntOrNull ?: data["time"].asIntOrNull ?: 0).also {
|
||||
if (it < 0 || it > 3) throw IllegalParamsException("strength")
|
||||
}
|
||||
face.msgType = 0
|
||||
face.faceBubbleCount = 0
|
||||
@ -556,7 +593,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createFaceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createFaceElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("id")
|
||||
|
||||
val serverId = data["id"].asInt
|
||||
@ -575,15 +617,15 @@ internal object MessageMaker {
|
||||
face.faceIndex = serverId
|
||||
face.faceText = QQSysFaceUtil.getFaceDescription(QQSysFaceUtil.convertToLocal(serverId))
|
||||
if (serverId == 394) {
|
||||
face.stickerId = 40.toString()
|
||||
face.stickerId = "40"
|
||||
face.packId = "1"
|
||||
face.sourceType = 1
|
||||
face.stickerType = 3
|
||||
face.randomType = 1
|
||||
face.resultId = data["result"].asStringOrNull ?: Random.nextInt(1 .. 5).toString()
|
||||
face.resultId = data["result"].asStringOrNull ?: Random.nextInt(1..5).toString()
|
||||
} else if (big) {
|
||||
face.imageType = 0
|
||||
face.stickerId = 30.toString()
|
||||
face.stickerId = "30"
|
||||
face.packId = "1"
|
||||
face.sourceType = 1
|
||||
face.stickerType = 1
|
||||
@ -597,7 +639,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createRpsElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createRpsElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEMARKETFACE
|
||||
val market = MarketFaceElement(
|
||||
@ -612,7 +659,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createDiceElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createDiceElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEMARKETFACE
|
||||
val market = MarketFaceElement(
|
||||
@ -627,7 +679,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createMarkdownElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createMarkdownElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("content")
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEMARKDOWN
|
||||
@ -636,7 +693,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createVideoElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createVideoElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("file")
|
||||
|
||||
val file = data["file"].asString.let {
|
||||
@ -672,7 +734,8 @@ internal object MessageMaker {
|
||||
)
|
||||
if (!QQNTWrapperUtil.CppProxy.fileIsExist(originalPath) || QQNTWrapperUtil.CppProxy.getFileSize(
|
||||
originalPath
|
||||
) != file.length()) {
|
||||
) != file.length()
|
||||
) {
|
||||
QQNTWrapperUtil.CppProxy.copyFile(file.absolutePath, originalPath)
|
||||
AudioUtils.obtainVideoCover(file.absolutePath, thumbPath!!)
|
||||
}
|
||||
@ -711,23 +774,26 @@ internal object MessageMaker {
|
||||
val qq = data["qq"].asString
|
||||
|
||||
val at = TextElement()
|
||||
when(qq) {
|
||||
when (qq) {
|
||||
"0", "all" -> {
|
||||
at.content = "@全体成员"
|
||||
at.atType = MsgConstant.ATTYPEALL
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
"online" -> {
|
||||
at.content = "@在线成员"
|
||||
at.atType = MsgConstant.ATTYPEONLINE
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
"admin" -> {
|
||||
at.content = "@管理员"
|
||||
at.atRoleId = 1
|
||||
at.atType = MsgConstant.ATTYPEROLE
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
else -> {
|
||||
val name = data["name"].asStringOrNull
|
||||
if (name == null) {
|
||||
@ -757,7 +823,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createRecordElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createRecordElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
var file = data["file"].asStringOrNull?.let {
|
||||
val md5 = it.replace(regex = "[{}\\-]".toRegex(), replacement = "")
|
||||
.replace(" ", "")
|
||||
@ -785,11 +856,13 @@ internal object MessageMaker {
|
||||
ptt.duration = QRoute.api(IAIOPttApi::class.java)
|
||||
.getPttFileDuration(file.absolutePath)
|
||||
}
|
||||
|
||||
MediaType.Amr -> {
|
||||
LogCenter.log({ "Amr: $file" }, Level.DEBUG)
|
||||
ptt.duration = AudioUtils.getDurationSec(file)
|
||||
ptt.formatType = MsgConstant.KPTTFORMATTYPEAMR
|
||||
}
|
||||
|
||||
MediaType.Pcm -> {
|
||||
LogCenter.log({ "Pcm To Silk: $file" }, Level.DEBUG)
|
||||
val result = AudioUtils.pcmToSilk(file)
|
||||
@ -797,6 +870,7 @@ internal object MessageMaker {
|
||||
file = result.first
|
||||
ptt.formatType = MsgConstant.KPTTFORMATTYPESILK
|
||||
}
|
||||
|
||||
else -> {
|
||||
LogCenter.log({ "Audio To SILK: $file" }, Level.DEBUG)
|
||||
val result = AudioUtils.audioToSilk(file)
|
||||
@ -813,12 +887,13 @@ internal object MessageMaker {
|
||||
// QQNTWrapperUtil.CppProxy.copyFile(file.absolutePath, originalPath)
|
||||
//}
|
||||
|
||||
if(!(Transfer with when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(peerId)
|
||||
MsgConstant.KCHATTYPEC2C -> Private(peerId)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> Private(peerId)
|
||||
else -> error("Not supported chatType($chatType) for RecordMsg")
|
||||
} trans VoiceResource(file))) {
|
||||
if (!(Transfer with when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(peerId)
|
||||
MsgConstant.KCHATTYPEC2C -> Private(peerId)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> Private(peerId)
|
||||
else -> error("Not supported chatType($chatType) for RecordMsg")
|
||||
} trans VoiceResource(file))
|
||||
) {
|
||||
return Result.failure(RuntimeException("上传语音失败: $file"))
|
||||
}
|
||||
|
||||
@ -848,7 +923,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createImageElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createImageElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
val isOriginal = data["original"].asBooleanOrNull ?: true
|
||||
val isFlash = data["flash"].asBooleanOrNull ?: false
|
||||
val filePath = data["file"].asStringOrNull
|
||||
@ -889,7 +969,8 @@ internal object MessageMaker {
|
||||
)
|
||||
if (!QQNTWrapperUtil.CppProxy.fileIsExist(originalPath) || QQNTWrapperUtil.CppProxy.getFileSize(
|
||||
originalPath
|
||||
) != file.length()) {
|
||||
) != file.length()
|
||||
) {
|
||||
val thumbPath = msgService.getRichMediaFilePathForMobileQQSend(
|
||||
RichMediaFilePathInfo(
|
||||
2, 0, pic.md5HexStr, file.name, 2, 720, null, "", true
|
||||
@ -927,7 +1008,12 @@ internal object MessageMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createTextElem(chatType: Int, msgId: Long, peerId: String, data: JsonObject): Result<MsgElement> {
|
||||
private suspend fun createTextElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MsgElement> {
|
||||
data.checkAndThrow("text")
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPETEXT
|
||||
@ -943,5 +1029,5 @@ internal object MessageMaker {
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(type: String): IMaker? = makerArray[type]
|
||||
operator fun get(type: String): IMsgMaker? = makerArray[type]
|
||||
}
|
@ -1,6 +1,5 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.msg.convert
|
||||
|
||||
import com.tencent.mobileqq.qmmkv.QMMKV
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||
import kotlinx.serialization.json.add
|
||||
@ -19,8 +18,6 @@ import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import mqq.app.MobileQQ
|
||||
import kotlin.jvm.internal.Intrinsics
|
||||
|
||||
internal sealed class MessageElemConverter: IMessageConvert {
|
||||
/**
|
||||
|
@ -16,7 +16,8 @@ import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.MessageMaker
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.MessageElementMaker
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.MsgElementMaker
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||
import moe.fuqiuluo.shamrock.helper.db.MessageMapping
|
||||
import moe.fuqiuluo.shamrock.remote.structures.SendMsgResult
|
||||
@ -26,8 +27,8 @@ import moe.fuqiuluo.shamrock.tools.asJsonObjectOrNull
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
import protobuf.message.MessageElement
|
||||
import kotlin.coroutines.resume
|
||||
import kotlin.coroutines.suspendCoroutine
|
||||
import kotlin.math.abs
|
||||
|
||||
internal object MessageHelper {
|
||||
@ -39,7 +40,7 @@ internal object MessageHelper {
|
||||
fromId: String = peerId
|
||||
): SendMsgResult {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.qqMsgId, peerId, decodeCQCode(message)).also {
|
||||
val msg = messageArrayToMsgElements(chatType, uniseq.qqMsgId, peerId, decodeCQCode(message)).also {
|
||||
if (it.second.isEmpty() && !it.first) {
|
||||
error("消息合成失败,请查看日志或者检查输入。")
|
||||
} else if (it.second.isEmpty()) {
|
||||
@ -82,7 +83,7 @@ internal object MessageHelper {
|
||||
callback: IOperateCallback
|
||||
): Result<SendMsgResult> {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
val msg = messageArrayToMsgElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
@ -166,7 +167,7 @@ internal object MessageHelper {
|
||||
fromId: String = peerId
|
||||
): SendMsgResult {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
val msg = messageArrayToMsgElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
@ -224,7 +225,7 @@ internal object MessageHelper {
|
||||
fromId: String = peerId
|
||||
): SendMsgResult {
|
||||
val uniseq = generateMsgId(chatType)
|
||||
val msg = messageArrayToMessageElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
val msg = messageArrayToMsgElements(chatType, uniseq.qqMsgId, peerId, message).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second.filter {
|
||||
it.elementType != -1
|
||||
@ -276,12 +277,41 @@ internal object MessageHelper {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun messageArrayToMessageElements(chatType: Int, msgId: Long, targetUin: String, messageList: JsonArray): Pair<Boolean, ArrayList<MsgElement>> {
|
||||
suspend fun messageArrayToMsgElements(chatType: Int, msgId: Long, targetUin: String, messageList: JsonArray): Pair<Boolean, ArrayList<MsgElement>> {
|
||||
val msgList = arrayListOf<MsgElement>()
|
||||
var hasActionMsg = false
|
||||
messageList.forEach {
|
||||
val msg = it.jsonObject
|
||||
val maker = MessageMaker[msg["type"].asString]
|
||||
val maker = MsgElementMaker[msg["type"].asString]
|
||||
if (maker != null) {
|
||||
try {
|
||||
val data = msg["data"].asJsonObjectOrNull ?: EmptyJsonObject
|
||||
maker(chatType, msgId, targetUin, data).onSuccess { msgElem ->
|
||||
msgList.add(msgElem)
|
||||
}.onFailure {
|
||||
if (it.javaClass != ActionMsgException::class.java) {
|
||||
throw it
|
||||
} else {
|
||||
hasActionMsg = true
|
||||
}
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
LogCenter.log(e.stackTraceToString(), Level.ERROR)
|
||||
}
|
||||
} else {
|
||||
LogCenter.log("不支持的消息类型: ${msg["type"].asString}", Level.ERROR)
|
||||
return false to arrayListOf()
|
||||
}
|
||||
}
|
||||
return hasActionMsg to msgList
|
||||
}
|
||||
|
||||
suspend fun messageArrayToMessageElements(chatType: Int, msgId: Long, targetUin: String, messageList: JsonArray): Pair<Boolean, ArrayList<MessageElement>> {
|
||||
val msgList = arrayListOf<MessageElement>()
|
||||
var hasActionMsg = false
|
||||
messageList.forEach {
|
||||
val msg = it.jsonObject
|
||||
val maker = MessageElementMaker[msg["type"].asString]
|
||||
if (maker != null) {
|
||||
try {
|
||||
val data = msg["data"].asJsonObjectOrNull ?: EmptyJsonObject
|
||||
|
@ -1,7 +1,6 @@
|
||||
package moe.fuqiuluo.shamrock.remote.action.handlers
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MultiMsgInfo
|
||||
import kotlinx.serialization.json.*
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||
@ -14,8 +13,11 @@ import moe.fuqiuluo.shamrock.remote.action.ActionSession
|
||||
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.ForwardMessageResult
|
||||
import moe.fuqiuluo.shamrock.tools.*
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
import moe.fuqiuluo.symbols.OneBotHandler
|
||||
import protobuf.message.*
|
||||
import protobuf.message.longmsg.PushMsgBody
|
||||
import java.util.*
|
||||
import kotlin.random.Random
|
||||
|
||||
@OneBotHandler("send_forward_msg")
|
||||
internal object SendForwardMessage : IActionHandler() {
|
||||
@ -37,14 +39,26 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
return noParam("detail_type/message_type", session.echo)
|
||||
}
|
||||
}
|
||||
val peerId = when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> session.getStringOrNull("group_id") ?: return noParam("group_id", session.echo)
|
||||
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("user_id") ?: return noParam("user_id", session.echo)
|
||||
val peerId = when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> session.getStringOrNull("group_id") ?: return noParam(
|
||||
"group_id",
|
||||
session.echo
|
||||
)
|
||||
|
||||
MsgConstant.KCHATTYPEC2C, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("user_id")
|
||||
?: return noParam("user_id", session.echo)
|
||||
|
||||
else -> error("unknown chat type: $chatType")
|
||||
}
|
||||
val fromId = when(chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("group_id") ?: return noParam("group_id", session.echo)
|
||||
MsgConstant.KCHATTYPEC2C -> session.getStringOrNull("user_id") ?: return noParam("user_id", session.echo)
|
||||
val fromId = when (chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> session.getStringOrNull("group_id")
|
||||
?: return noParam("group_id", session.echo)
|
||||
|
||||
MsgConstant.KCHATTYPEC2C -> session.getStringOrNull("user_id") ?: return noParam(
|
||||
"user_id",
|
||||
session.echo
|
||||
)
|
||||
|
||||
else -> error("unknown chat type: $chatType")
|
||||
}
|
||||
return if (session.isArray("messages")) {
|
||||
@ -68,103 +82,184 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
kotlin.runCatching {
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val msgService = sessionService.msgService
|
||||
val selfUin = TicketSvc.getUin()
|
||||
var uid: String? = null
|
||||
var groupUin: String? = null
|
||||
|
||||
val multiNodes = messages.map {
|
||||
if (it.asJsonObject["type"].asStringOrNull != "node") {
|
||||
LogCenter.log("包含非node类型节点", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
if (it.asJsonObject["data"] !is JsonObject) {
|
||||
LogCenter.log("data字段错误", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
it.asJsonObject["data"].asJsonObject.let { data ->
|
||||
if (data.containsKey("id")) {
|
||||
val record = MsgSvc.getMsg(data["id"].asInt).getOrNull()
|
||||
if (record == null) {
|
||||
LogCenter.log("合并转发消息节点消息获取失败:${data["id"]}", Level.WARN)
|
||||
return@map null
|
||||
} else {
|
||||
record.peerName to record.toSegments().map { segment ->
|
||||
segment.toJson()
|
||||
}.json
|
||||
}
|
||||
} else if (data.containsKey("content")) {
|
||||
(data["name"].asStringOrNull ?: "Anno") to when (val raw = data["content"]) {
|
||||
is JsonObject -> raw.asJsonArray
|
||||
is JsonArray -> raw.asJsonArray
|
||||
else -> MessageHelper.decodeCQCode(raw.asString)
|
||||
}
|
||||
} else {
|
||||
LogCenter.log("消息节点缺少id或content字段", Level.WARN)
|
||||
var i = -1
|
||||
val desc = MutableList(messages.size) { "" }
|
||||
|
||||
val msgs = messages.map { msg ->
|
||||
val data = msg.asJsonObject["data"].asJsonObject
|
||||
if (data.containsKey("id")) {
|
||||
val record = MsgSvc.getMsg(data["id"].asInt).getOrElse {
|
||||
LogCenter.log("合并转发消息节点消息(id = ${data["id"].asInt})获取失败:$it", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
}.let { node ->
|
||||
val content = node.second.map { msg ->
|
||||
when (msg.asJsonObject["type"].asStringOrNull ?: "text") {
|
||||
"at" -> {
|
||||
buildJsonObject {
|
||||
put("type", "text")
|
||||
putJsonObject("data") {
|
||||
put(
|
||||
"text", "@${
|
||||
msg.asJsonObject["data"].asJsonObject["name"].asStringOrNull.ifNullOrEmpty(
|
||||
msg.asJsonObject["data"].asJsonObject["qq"].asString
|
||||
)
|
||||
}"
|
||||
)
|
||||
uid = record.peerUid
|
||||
if (record.chatType == MsgConstant.KCHATTYPEGROUP) groupUin = record.peerUin.toString()
|
||||
PushMsgBody(
|
||||
head = MessageHead(
|
||||
peerUid = record.senderUid,
|
||||
groupInfo = if (record.chatType == MsgConstant.KCHATTYPEGROUP) GroupInfo(
|
||||
groupCode = record.peerUin.toULong(),
|
||||
memberCard = record.sendMemberName,
|
||||
u1 = 2
|
||||
) else null
|
||||
),
|
||||
content = MessageContent(
|
||||
msgType = record.msgType,
|
||||
msgViaRandom = record.msgId,
|
||||
msgSeq = record.msgSeq,
|
||||
msgTime = record.msgTime,
|
||||
u2 = 1,
|
||||
u6 = 0,
|
||||
u7 = 0,
|
||||
forwardHead = ForwardHead(
|
||||
u1 = 0,
|
||||
u2 = 0,
|
||||
u3 = if (record.chatType == MsgConstant.KCHATTYPEGROUP) 0 else 2,
|
||||
u4 = "",
|
||||
Avatar = ""
|
||||
)
|
||||
),
|
||||
body = MessageBody(
|
||||
rich = RichMessage(
|
||||
elements = MessageHelper.messageArrayToMessageElements(
|
||||
record.chatType,
|
||||
record.msgId,
|
||||
record.peerUin.toString(),
|
||||
record.elements.toSegments(record.chatType, record.peerUin.toString(), "0").also {
|
||||
desc[++i] = record.peerName + ": "
|
||||
}.map {
|
||||
when (it.type) {
|
||||
"text" -> desc[i] += it.data["text"] as String
|
||||
|
||||
"at" -> desc[i] += "@${it.data["name"] as String? ?: it.data["qq"] as String}"
|
||||
|
||||
"face" -> desc[i] += "[表情]"
|
||||
|
||||
"voice" -> desc[i] += "[语音]"
|
||||
|
||||
"node" -> desc[i] += "[合并转发消息]"
|
||||
}
|
||||
|
||||
it.toJson()
|
||||
}.json
|
||||
).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second
|
||||
)
|
||||
)
|
||||
)
|
||||
} else if (data.containsKey("content")) {
|
||||
PushMsgBody(
|
||||
head = MessageHead(
|
||||
peerUid = data["uid"]?.asString ?: TicketSvc.getUid()
|
||||
),
|
||||
content = MessageContent(
|
||||
msgType = 529,
|
||||
msgViaRandom = 4,
|
||||
msgSeq = data["seq"]?.asLong ?: 0,
|
||||
msgTime = System.currentTimeMillis() / 1000,
|
||||
u2 = 1,
|
||||
u6 = 0,
|
||||
u7 = 0,
|
||||
forwardHead = ForwardHead(
|
||||
u1 = 0,
|
||||
u2 = 0,
|
||||
u3 = 2,
|
||||
u4 = "",
|
||||
Avatar = ""
|
||||
)
|
||||
),
|
||||
body = MessageBody(
|
||||
rich = RichMessage(
|
||||
elements = MessageHelper.messageArrayToMessageElements(
|
||||
1,
|
||||
Random.nextLong(),
|
||||
data["uin"]?.asString ?: TicketSvc.getUin(),
|
||||
when (data["content"]) {
|
||||
is JsonObject -> listOf(data["content"] as JsonObject).json
|
||||
is JsonArray -> data["content"] as JsonArray
|
||||
else -> MessageHelper.decodeCQCode(data["content"].asString)
|
||||
}.also {
|
||||
desc[++i] = "${
|
||||
data["name"].asStringOrNull ?: data["uin"].asStringOrNull
|
||||
?: TicketSvc.getNickname()
|
||||
}: "
|
||||
}.onEach {
|
||||
when (it.asJsonObject["type"].asString) {
|
||||
"text" -> desc[i] += it.asJsonObject["data"].asJsonObject["text"].asString
|
||||
|
||||
"at" -> desc[i] += "@${it.asJsonObject["data"].asJsonObject["name"].asStringOrNull ?: it.asJsonObject["data"].asJsonObject["qq"].asString}"
|
||||
|
||||
"face" -> desc[i] += "[表情]"
|
||||
|
||||
"voice" -> desc[i] += "[语音]"
|
||||
|
||||
"node" -> desc[i] += "[合并转发消息]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"voice" -> {
|
||||
buildJsonObject {
|
||||
put("type", "text")
|
||||
putJsonObject("data") {
|
||||
put("text", "[语音]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"node" -> {
|
||||
LogCenter.log("合并转发消息暂时不支持嵌套", Level.WARN)
|
||||
buildJsonObject {
|
||||
put("type", "text")
|
||||
putJsonObject("data") {
|
||||
put("text", "[合并转发消息]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else -> msg
|
||||
}
|
||||
}.json
|
||||
|
||||
val result = MessageHelper.sendMessageNoCb(MsgConstant.KCHATTYPEC2C, selfUin, content)
|
||||
if (result.qqMsgId == 0L) {
|
||||
LogCenter.log("合并转发消息节点消息发送失败", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
result.qqMsgId to node.first
|
||||
).also {
|
||||
if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。")
|
||||
}.second
|
||||
)
|
||||
)
|
||||
)
|
||||
} else {
|
||||
LogCenter.log("消息节点缺少id或content字段", Level.WARN)
|
||||
null
|
||||
}
|
||||
}.filterNotNull()
|
||||
}.filterNotNull().ifEmpty { return logic("消息节点为空", echo) }
|
||||
|
||||
val from = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, selfUin)
|
||||
val to = MessageHelper.generateContact(chatType, peerId, fromId)
|
||||
|
||||
val uniseq = MessageHelper.generateMsgId(chatType)
|
||||
msgService.multiForwardMsg(ArrayList<MultiMsgInfo>().apply {
|
||||
multiNodes.forEach { add(MultiMsgInfo(it.first, it.second)) }
|
||||
}.also { it.reverse() }, from, to, MsgSvc.MessageCallback(peerId, uniseq.msgHashId))
|
||||
val resid = MsgSvc.sendMultiMsg(uid ?: TicketSvc.getUid(), groupUin, msgs)
|
||||
.getOrElse { return logic(it.message ?: "", echo) }
|
||||
val uniseq = UUID.randomUUID().toString().uppercase()
|
||||
|
||||
val result = MsgSvc.sendToAio(
|
||||
chatType, peerId,
|
||||
listOf(
|
||||
hashMapOf(
|
||||
"type" to "json", "data" to hashMapOf(
|
||||
"data" to hashMapOf(
|
||||
"app" to "com.tencent.multimsg",
|
||||
"config" to hashMapOf(
|
||||
"autosize" to 1,
|
||||
"forward" to 1,
|
||||
"round" to 1,
|
||||
"type" to "normal",
|
||||
"width" to 300
|
||||
).json,
|
||||
"desc" to "[聊天记录]",
|
||||
"extra" to hashMapOf(
|
||||
"filename" to uniseq,
|
||||
"tsum" to 2
|
||||
).json.toString() + "\n",
|
||||
"meta" to hashMapOf(
|
||||
"detail" to hashMapOf(
|
||||
"news" to desc.slice(0..if (i < 3) i else 3)
|
||||
.map { hashMapOf("text" to it).json }.json,
|
||||
"resid" to resid,
|
||||
"source" to "群聊的聊天记录",
|
||||
"summary" to "查看${msgs.size}条转发消息",
|
||||
"uniseq" to uniseq
|
||||
).json
|
||||
).json,
|
||||
"prompt" to "[聊天记录]",
|
||||
"ver" to "0.0.0.5",
|
||||
"view" to "contact"
|
||||
).json,
|
||||
"resid" to resid
|
||||
).json
|
||||
).json
|
||||
).json, fromId, 3
|
||||
).getOrElse { return logic(it.message ?: "", echo) }
|
||||
|
||||
return ok(
|
||||
ForwardMessageResult(
|
||||
msgId = uniseq.msgHashId,
|
||||
forwardId = ""
|
||||
msgId = result.msgHashId,
|
||||
forwardId = resid
|
||||
), echo = echo
|
||||
)
|
||||
}.onFailure {
|
||||
|
@ -120,18 +120,14 @@ internal object SendMessage: IActionHandler() {
|
||||
//if (!ContactHelper.checkContactAvailable(chatType, peerId)) {
|
||||
// return logic("contact is not found", echo = echo)
|
||||
//}
|
||||
val result = MsgSvc.sendToAio(chatType, peerId, message, fromId = fromId, retryCnt)
|
||||
if (result.isFailure) {
|
||||
return logic(result.exceptionOrNull()?.message ?: "", echo)
|
||||
}
|
||||
val sendMsgResult = result.getOrThrow()
|
||||
if (sendMsgResult.msgHashId <= 0) {
|
||||
val result = MsgSvc.sendToAio(chatType, peerId, message, fromId = fromId, retryCnt).getOrElse { return logic(it.message ?: "", echo) }
|
||||
if (result.msgHashId <= 0) {
|
||||
return logic("send message failed", echo = echo)
|
||||
}
|
||||
recallDuration?.let { autoRecall(sendMsgResult.msgHashId, it) }
|
||||
recallDuration?.let { autoRecall(result.msgHashId, it) }
|
||||
return ok(MessageResult(
|
||||
msgId = sendMsgResult.msgHashId,
|
||||
time = (sendMsgResult.msgTime * 0.001).toLong()
|
||||
msgId = result.msgHashId,
|
||||
time = (result.msgTime * 0.001).toLong()
|
||||
), echo)
|
||||
}
|
||||
|
||||
|
@ -144,7 +144,7 @@ internal object AioListener : IKernelMsgListener {
|
||||
}
|
||||
|
||||
MsgConstant.KCHATTYPEGUILD -> {
|
||||
LogCenter.log("频道消息(guildId = ${record.guildId}, sender=${record.senderUid}, id = [$msgHash | ${record.msgId}], msg = $rawMsg)")
|
||||
LogCenter.log("频道消息(guildId = ${record.guildId}, sender = ${record.senderUid}, id = [$msgHash | ${record.msgId}], msg = $rawMsg)")
|
||||
if (!GlobalEventTransmitter.MessageTransmitter
|
||||
.transGuildMessage(record, record.elements, rawMsg, msgHash, postType = postType)
|
||||
) {
|
||||
@ -169,7 +169,6 @@ internal object AioListener : IKernelMsgListener {
|
||||
GlobalScope.launch {
|
||||
try {
|
||||
val msgHash = MessageHelper.generateMsgIdHash(record.chatType, record.msgId)
|
||||
|
||||
val peerId = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEGUILD -> record.guildId
|
||||
else -> record.peerUin.toString()
|
||||
|
@ -65,16 +65,14 @@ val Map<String, Any>.json: JsonObject
|
||||
get() {
|
||||
val map = hashMapOf<String, JsonElement>()
|
||||
forEach { (key, any) ->
|
||||
if (any != null) {
|
||||
when (any) {
|
||||
is JsonElement -> map[key] = any
|
||||
is Number -> map[key] = any.json
|
||||
is String -> map[key] = any.json
|
||||
is Boolean -> map[key] = any.json
|
||||
is Map<*, *> -> map[key] = (any as Map<String, Any>).json
|
||||
is Collection<*> -> map[key] = (any as Collection<Any>).json
|
||||
else -> error("unknown object type: ${any::class.java}")
|
||||
}
|
||||
when (any) {
|
||||
is JsonElement -> map[key] = any
|
||||
is Number -> map[key] = any.json
|
||||
is String -> map[key] = any.json
|
||||
is Boolean -> map[key] = any.json
|
||||
is Map<*, *> -> map[key] = (any as Map<String, Any>).json
|
||||
is Collection<*> -> map[key] = (any as Collection<Any>).json
|
||||
else -> error("unknown object type: ${any::class.java}")
|
||||
}
|
||||
}
|
||||
return map.jsonObject
|
||||
|
Loading…
x
Reference in New Issue
Block a user