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
75633f78c4
commit
87629666f2
@ -6,14 +6,15 @@ import kotlinx.serialization.protobuf.ProtoNumber
|
||||
@Serializable
|
||||
data class MessageContent(
|
||||
@ProtoNumber(1) val msgType: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(2) val msgSubType: Int = Int.MIN_VALUE,
|
||||
@ProtoNumber(2) val msgSubType: Int? = null,
|
||||
@ProtoNumber(3) val u1: Int? = null,
|
||||
@ProtoNumber(4) val msgViaRandom: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(5) val msgSeq: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(5) val msgSeq_: Long? = null,
|
||||
@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(11) val msgSeq: Long? = null,
|
||||
@ProtoNumber(12) val msgRandom: Long = Long.MIN_VALUE,
|
||||
@ProtoNumber(14) val u4: Long? = null,
|
||||
@ProtoNumber(15) val forwardHead: ForwardHead? = null,
|
||||
|
@ -9,5 +9,5 @@ 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,
|
||||
@ProtoNumber(53) val comm: CommonElement? = null,
|
||||
)
|
||||
|
@ -299,14 +299,15 @@ internal object MsgSvc : BaseSvc() {
|
||||
time = msg.content?.msgTime?.toInt() ?: 0,
|
||||
msgType = MessageHelper.obtainDetailTypeByMsgType(chatType),
|
||||
msgId = 0, // MessageHelper.generateMsgIdHash(chatType, msg.content!!.msgViaRandom), msgViaRandom 为空
|
||||
realId = msg.content!!.msgSeq.toInt(),
|
||||
realId = msg.content!!.msgSeq?.toInt() ?: 0,
|
||||
sender = MessageSender(
|
||||
msg.head?.peer ?: 0,
|
||||
msg.head?.groupInfo?.memberCard?.ifEmpty { msg.head?.forward?.friendName } ?: "",
|
||||
msg.head?.groupInfo?.memberCard?.ifEmpty { msg.head?.forward?.friendName }
|
||||
?: msg.head?.forward?.friendName ?: "",
|
||||
"unknown",
|
||||
0,
|
||||
msg.head?.peerUid ?: "u_",
|
||||
msg.head?.peerUid?: "u_"
|
||||
msg.head?.peerUid ?: "",
|
||||
msg.head?.peerUid ?: ""
|
||||
),
|
||||
message = msg.body?.rich?.elements?.toSegments(chatType, msg.head?.peer.toString(), "0")
|
||||
?.toListMap() ?: emptyList(),
|
||||
|
@ -66,7 +66,7 @@ internal object PacketSvc: BaseSvc() {
|
||||
msgViaRandom = msgSeq,
|
||||
msgTime = System.currentTimeMillis() / 1000,
|
||||
u2 = 1,
|
||||
u3 = msgSeq,
|
||||
msgSeq_ = msgSeq,
|
||||
msgRandom = msgService.getMsgUniqueId(System.currentTimeMillis()),
|
||||
u4 = msgSeq - 2,
|
||||
u5 = msgSeq
|
||||
|
@ -6,6 +6,9 @@ import kotlinx.io.core.readUInt
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.MessageSegment
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import protobuf.message.MessageElement
|
||||
|
||||
|
||||
@ -23,6 +26,8 @@ internal suspend fun List<MessageElement>.toSegments(
|
||||
2
|
||||
} else if (msg.json != null) {
|
||||
51
|
||||
} else if (msg.comm != null) {
|
||||
53
|
||||
} else
|
||||
throw UnsupportedOperationException("不支持的消息element类型:$msg")
|
||||
val converter = MessageElementConverter[elementType]
|
||||
@ -45,13 +50,13 @@ internal typealias IMessageElementConverter = suspend (Int, String, String, Mess
|
||||
|
||||
internal object MessageElementConverter {
|
||||
private val convertMap = hashMapOf(
|
||||
1 to MessageElementConverter::convertTextElem,
|
||||
1 to MessageElementConverter::convertTextElem,
|
||||
// MsgConstant.KELEMTYPEFACE to MessageElementConverter::convertFaceElem,
|
||||
// MsgConstant.KELEMTYPEPIC to MessageElementConverter::convertImageElem,
|
||||
// MsgConstant.KELEMTYPEPTT to MessageElementConverter::convertVoiceElem,
|
||||
// MsgConstant.KELEMTYPEVIDEO to MessageElementConverter::convertVideoElem,
|
||||
// MsgConstant.KELEMTYPEMARKETFACE to MessageElementConverter::convertMarketFaceElem,
|
||||
// MsgConstant.KELEMTYPEARKSTRUCT to MessageElementConverter::convertStructJsonElem,
|
||||
51 to MessageElementConverter::convertStructJsonElem,
|
||||
// MsgConstant.KELEMTYPEREPLY to MessageElementConverter::convertReplyElem,
|
||||
// MsgConstant.KELEMTYPEGRAYTIP to MessageElementConverter::convertGrayTipsElem,
|
||||
// MsgConstant.KELEMTYPEFILE to MessageElementConverter::convertFileElem,
|
||||
@ -328,71 +333,74 @@ internal object MessageElementConverter {
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// /**
|
||||
// * JSON消息转消息段
|
||||
// */
|
||||
// private suspend fun convertStructJsonElem(
|
||||
// chatType: Int,
|
||||
// peerId: String,
|
||||
// subPeer: String,
|
||||
// element: MessageElement
|
||||
// ): MessageSegment {
|
||||
// val data = element.arkElement.bytesData.asJsonObject
|
||||
// return when (data["app"].asString) {
|
||||
// "com.tencent.multimsg" -> {
|
||||
// val info = data["meta"].asJsonObject["detail"].asJsonObject
|
||||
// MessageSegment(
|
||||
// type = "forward",
|
||||
// data = mapOf(
|
||||
// "id" to info["resid"].asString
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// "com.tencent.troopsharecard" -> {
|
||||
// val info = data["meta"].asJsonObject["contact"].asJsonObject
|
||||
// MessageSegment(
|
||||
// type = "contact",
|
||||
// data = hashMapOf(
|
||||
// "type" to "group",
|
||||
// "id" to info["jumpUrl"].asString.split("group_code=")[1]
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// "com.tencent.contact.lua" -> {
|
||||
// val info = data["meta"].asJsonObject["contact"].asJsonObject
|
||||
// MessageSegment(
|
||||
// type = "contact",
|
||||
// data = hashMapOf(
|
||||
// "type" to "private",
|
||||
// "id" to info["jumpUrl"].asString.split("uin=")[1]
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// "com.tencent.map" -> {
|
||||
// val info = data["meta"].asJsonObject["Location.Search"].asJsonObject
|
||||
// MessageSegment(
|
||||
// type = "location",
|
||||
// data = hashMapOf(
|
||||
// "lat" to info["lat"].asString,
|
||||
// "lon" to info["lng"].asString,
|
||||
// "content" to info["address"].asString,
|
||||
// "title" to info["name"].asString
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
//
|
||||
// else -> MessageSegment(
|
||||
// type = "json",
|
||||
// data = mapOf(
|
||||
// "data" to element.arkElement.bytesData.asJsonObject.toString()
|
||||
// )
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//
|
||||
/**
|
||||
* JSON消息转消息段
|
||||
*/
|
||||
private suspend fun convertStructJsonElem(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
subPeer: String,
|
||||
element: MessageElement
|
||||
): MessageSegment {
|
||||
val data = element.json!!.data!!
|
||||
val jsonStr =
|
||||
(if (data[0].toInt() == 1) DeflateTools.uncompress(data.sliceArray(1 until data.size)) else data.sliceArray(1 until data.size)).toString()
|
||||
val json = jsonStr.asJsonObject
|
||||
return when (json["app"].asString) {
|
||||
"com.tencent.multimsg" -> {
|
||||
val info = json["meta"].asJsonObject["detail"].asJsonObject
|
||||
MessageSegment(
|
||||
type = "forward",
|
||||
data = mapOf(
|
||||
"id" to info["resid"].asString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"com.tencent.troopsharecard" -> {
|
||||
val info = json["meta"].asJsonObject["contact"].asJsonObject
|
||||
MessageSegment(
|
||||
type = "contact",
|
||||
data = hashMapOf(
|
||||
"type" to "group",
|
||||
"id" to info["jumpUrl"].asString.split("group_code=")[1]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"com.tencent.contact.lua" -> {
|
||||
val info = json["meta"].asJsonObject["contact"].asJsonObject
|
||||
MessageSegment(
|
||||
type = "contact",
|
||||
data = hashMapOf(
|
||||
"type" to "private",
|
||||
"id" to info["jumpUrl"].asString.split("uin=")[1]
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
"com.tencent.map" -> {
|
||||
val info = json["meta"].asJsonObject["Location.Search"].asJsonObject
|
||||
MessageSegment(
|
||||
type = "location",
|
||||
data = hashMapOf(
|
||||
"lat" to info["lat"].asString,
|
||||
"lon" to info["lng"].asString,
|
||||
"content" to info["address"].asString,
|
||||
"title" to info["name"].asString
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> MessageSegment(
|
||||
type = "json",
|
||||
data = mapOf(
|
||||
"data" to jsonStr
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 回复消息转消息段
|
||||
// */
|
||||
|
@ -1,14 +1,20 @@
|
||||
package moe.fuqiuluo.qqinterface.servlet.msg.messageelement
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import moe.fuqiuluo.qqinterface.servlet.GProSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||
import moe.fuqiuluo.shamrock.helper.*
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.helper.ParamsException
|
||||
import moe.fuqiuluo.shamrock.tools.asInt
|
||||
import moe.fuqiuluo.shamrock.tools.asString
|
||||
import moe.fuqiuluo.shamrock.tools.*
|
||||
import moe.fuqiuluo.shamrock.utils.DeflateTools
|
||||
import protobuf.message.MessageElement
|
||||
import protobuf.message.element.FaceElement
|
||||
import protobuf.message.element.JsonElement
|
||||
import protobuf.message.element.TextElement
|
||||
import java.nio.ByteBuffer
|
||||
|
||||
internal typealias IMessageElementMaker = suspend (Int, Long, String, JsonObject) -> Result<MessageElement>
|
||||
|
||||
@ -20,7 +26,7 @@ internal object MessageElementMaker {
|
||||
// "image" to MessageElementMaker::createImageElem,
|
||||
// "voice" to MessageElementMaker::createRecordElem,
|
||||
// "record" to MessageElementMaker::createRecordElem,
|
||||
// "at" to MessageElementMaker::createAtElem,
|
||||
"at" to MessageElementMaker::createAtElem,
|
||||
// "video" to MessageElementMaker::createVideoElem,
|
||||
// "markdown" to MessageElementMaker::createMarkdownElem,
|
||||
// "dice" to MessageElementMaker::createDiceElem,
|
||||
@ -71,6 +77,88 @@ internal object MessageElementMaker {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun createAtElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
peerId: String,
|
||||
data: JsonObject
|
||||
): Result<MessageElement> {
|
||||
return if (chatType == MsgConstant.KCHATTYPEGROUP) {
|
||||
data.checkAndThrow("qq")
|
||||
|
||||
val qq: Long
|
||||
val type: Int
|
||||
lateinit var display: String
|
||||
when (val qqStr = data["qq"].asString) {
|
||||
"0", "all" -> {
|
||||
qq = 0
|
||||
type = 1
|
||||
display = "@全体成员"
|
||||
}
|
||||
|
||||
"online" -> {
|
||||
qq = 0
|
||||
type = 64
|
||||
display = "@在线成员"
|
||||
}
|
||||
|
||||
else -> {
|
||||
qq = qqStr.toLong()
|
||||
type = 0
|
||||
display =
|
||||
"@" + (data["name"].asStringOrNull ?: GroupSvc.getTroopMemberInfoByUinV2(peerId, qqStr, true)
|
||||
.onSuccess {
|
||||
it.troopnick
|
||||
.ifEmpty { it.friendnick }
|
||||
.ifEmpty { qqStr }
|
||||
}.onFailure {
|
||||
LogCenter.log("无法获取群成员信息: $qqStr", Level.ERROR)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val attr6: ByteBuffer = ByteBuffer.allocate(6)
|
||||
attr6.put(byteArrayOf(0, 1, 0, 0, 0))
|
||||
attr6.putChar(display.length.toChar())
|
||||
attr6.putChar(type.toChar())
|
||||
attr6.putBuf32Long(qq)
|
||||
attr6.put(byteArrayOf(0, 0))
|
||||
val elem = MessageElement(
|
||||
text = TextElement(text = display, attr6Buf = attr6.array())
|
||||
)
|
||||
Result.success(elem)
|
||||
} else if (chatType == MsgConstant.KCHATTYPEGUILD) {
|
||||
data.checkAndThrow("qq")
|
||||
|
||||
val qq: Long
|
||||
val type: Int
|
||||
lateinit var display: String
|
||||
when (val qqStr = data["qq"].asString) {
|
||||
"0", "all" -> {
|
||||
type = 2
|
||||
display = "@全体成员"
|
||||
}
|
||||
|
||||
else -> {
|
||||
qq = qqStr.toLong()
|
||||
type = 2
|
||||
display =
|
||||
"@" + (data["name"].asStringOrNull ?: GProSvc.getUserGuildInfo(0UL, 0UL)
|
||||
.onSuccess {
|
||||
it.nickName.ifNullOrEmpty(qqStr)
|
||||
}.onFailure {
|
||||
LogCenter.log("无法获取频道组成员信息: $qqStr", Level.ERROR)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
val elem = MessageElement(
|
||||
text = TextElement(text = display, pbReserve = TextElement.Companion.TextResvAttr(atType = type))
|
||||
)
|
||||
Result.success(elem)
|
||||
} else Result.failure(ActionMsgException)
|
||||
}
|
||||
|
||||
private suspend fun createJsonElem(
|
||||
chatType: Int,
|
||||
msgId: Long,
|
||||
|
@ -69,7 +69,7 @@ internal object MsgElementConverter {
|
||||
//MsgConstant.KELEMTYPEMULTIFORWARD to MsgElementConverter::convertXmlMultiMsgElem,
|
||||
//MsgConstant.KELEMTYPESTRUCTLONGMSG to MsgElementConverter::convertXmlLongMsgElem,
|
||||
MsgConstant.KELEMTYPEFACEBUBBLE to MsgElementConverter::convertBubbleFaceElem,
|
||||
MsgConstant.KELEMTYPEINLINEKEYBOARD to MsgElementConverter::convertInlineKeyboardElem,
|
||||
MsgConstant.KELEMTYPEINLINEKEYBOARD to MsgElementConverter::convertInlineKeyboardElem
|
||||
)
|
||||
|
||||
operator fun get(type: Int): IMsgElementConverter? = convertMap[type]
|
||||
|
@ -755,12 +755,6 @@ internal object MsgElementMaker {
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
"online" -> {
|
||||
at.content = "@在线成员"
|
||||
at.atType = MsgConstant.ATTYPEONLINE
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
"admin" -> {
|
||||
at.content = "@管理员"
|
||||
at.atRoleId = 1
|
||||
@ -768,6 +762,12 @@ internal object MsgElementMaker {
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
"online" -> {
|
||||
at.content = "@在线成员"
|
||||
at.atType = MsgConstant.ATTYPEONLINE
|
||||
at.atNtUid = "0"
|
||||
}
|
||||
|
||||
else -> {
|
||||
val name = data["name"].asStringOrNull
|
||||
if (name == null) {
|
||||
|
@ -95,11 +95,14 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
LogCenter.log("合并转发消息节点消息(id = ${data["id"].asInt})获取失败:$it", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
uid = record.peerUid
|
||||
if (record.chatType == MsgConstant.KCHATTYPEGROUP) groupUin = record.peerUin.toString()
|
||||
PushMsgBody(
|
||||
head = MessageHead(
|
||||
peerUid = record.senderUid,
|
||||
receiverUid = record.peerUid,
|
||||
forward = MessageForward(
|
||||
friendName = record.sendNickName
|
||||
),
|
||||
groupInfo = if (record.chatType == MsgConstant.KCHATTYPEGROUP) GroupInfo(
|
||||
groupCode = record.peerUin.toULong(),
|
||||
memberCard = record.sendMemberName,
|
||||
@ -108,22 +111,25 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
),
|
||||
content = MessageContent(
|
||||
msgType = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> 529
|
||||
MsgConstant.KCHATTYPEC2C -> 9
|
||||
MsgConstant.KCHATTYPEGROUP -> 82
|
||||
else -> throw UnsupportedOperationException(
|
||||
"Unsupported chatType: $chatType"
|
||||
)
|
||||
},
|
||||
msgSubType = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||
u1 = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||
msgViaRandom = record.msgId,
|
||||
msgSeq = record.msgSeq,
|
||||
msgSeq_ = record.msgSeq, // idk what this is(i++)
|
||||
msgTime = record.msgTime,
|
||||
u2 = 1,
|
||||
u6 = 0,
|
||||
u7 = 0,
|
||||
msgSeq = if (record.chatType == MsgConstant.KCHATTYPEC2C) record.msgSeq else null, // seq for dm
|
||||
forwardHead = ForwardHead(
|
||||
u1 = 0,
|
||||
u2 = 0,
|
||||
u3 = if (record.chatType == MsgConstant.KCHATTYPEGROUP) 0 else 2,
|
||||
u3 = 0,
|
||||
ub641 = "",
|
||||
Avatar = ""
|
||||
)
|
||||
@ -164,17 +170,23 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
PushMsgBody(
|
||||
head = MessageHead(
|
||||
peer = data["uin"]?.asLong ?: TicketSvc.getUin().toLong(),
|
||||
peerUid = data["uid"]?.asString ?: TicketSvc.getUid()
|
||||
|
||||
peerUid = data["uid"]?.asString ?: TicketSvc.getUid(),
|
||||
receiverUid = TicketSvc.getUid(),
|
||||
forward = MessageForward(
|
||||
friendName = data["name"]?.asStringOrNull ?: TicketSvc.getNickname()
|
||||
)
|
||||
),
|
||||
content = MessageContent(
|
||||
msgType = 529,
|
||||
msgViaRandom = 4,
|
||||
msgSeq = data["seq"]?.asLong ?: Random.nextLong(),
|
||||
msgType = 9,
|
||||
msgSubType = 175,
|
||||
u1 = 175,
|
||||
msgViaRandom = Random.nextLong(),
|
||||
msgSeq_ = data["seq"]?.asLong ?: Random.nextLong(),
|
||||
msgTime = data["time"]?.asLong ?: (System.currentTimeMillis() / 1000),
|
||||
u2 = 1,
|
||||
u6 = 0,
|
||||
u7 = 0,
|
||||
msgSeq = data["seq"]?.asLong ?: Random.nextLong(),
|
||||
forwardHead = ForwardHead(
|
||||
u1 = 0,
|
||||
u2 = 0,
|
||||
|
@ -111,9 +111,9 @@ internal object PrimitiveListener {
|
||||
private fun onGroupMessage(msgTime: Long, body: MessageBody) {
|
||||
runCatching {
|
||||
body.rich?.elements?.filter {
|
||||
it.commElem != null && it.commElem!!.type == 48
|
||||
it.comm != null && it.comm!!.type == 48
|
||||
}?.map {
|
||||
ProtoBuf.decodeFromByteArray<RichMediaForPicData>(it.commElem!!.data!!)
|
||||
ProtoBuf.decodeFromByteArray<RichMediaForPicData>(it.comm!!.data!!)
|
||||
}?.forEach {
|
||||
it.display?.show?.download?.url?.let {
|
||||
RKEY_PATTERN.matcher(it).takeIf {
|
||||
|
Loading…
x
Reference in New Issue
Block a user