mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: 优化消息转换器
Signed-off-by: WhiteChi <whitechi73@outlook.com>
This commit is contained in:
parent
f9e444a549
commit
7ec4a95303
@ -357,6 +357,7 @@ private fun FunctionCard(
|
|||||||
return@Function true
|
return@Function true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
Function(
|
Function(
|
||||||
title = "专业级接口",
|
title = "专业级接口",
|
||||||
desc = "如果你不知道你在做什么,请不要开启本功能。",
|
desc = "如果你不知道你在做什么,请不要开启本功能。",
|
||||||
@ -366,7 +367,7 @@ private fun FunctionCard(
|
|||||||
ShamrockConfig.setPro(ctx, it)
|
ShamrockConfig.setPro(ctx, it)
|
||||||
AppRuntime.log("专业级API = $it", Level.WARN)
|
AppRuntime.log("专业级API = $it", Level.WARN)
|
||||||
return@Function true
|
return@Function true
|
||||||
}
|
}*/
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,7 @@ import moe.fuqiuluo.shamrock.tools.*
|
|||||||
import java.lang.Exception
|
import java.lang.Exception
|
||||||
|
|
||||||
@Serializable
|
@Serializable
|
||||||
data class Region(
|
internal data class Region(
|
||||||
val adcode: Int,
|
val adcode: Int,
|
||||||
val province: String?,
|
val province: String?,
|
||||||
val city: String?
|
val city: String?
|
||||||
|
@ -1,305 +0,0 @@
|
|||||||
package moe.fuqiuluo.qqinterface.servlet.msg
|
|
||||||
|
|
||||||
import moe.fuqiuluo.shamrock.helper.ContactHelper
|
|
||||||
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
|
||||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
|
||||||
import kotlinx.serialization.json.JsonElement
|
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
|
||||||
import moe.fuqiuluo.shamrock.tools.*
|
|
||||||
import moe.fuqiuluo.shamrock.helper.db.ImageDB
|
|
||||||
import moe.fuqiuluo.shamrock.helper.db.ImageMapping
|
|
||||||
import moe.fuqiuluo.shamrock.helper.Level
|
|
||||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
|
||||||
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
|
||||||
|
|
||||||
internal typealias MsgSegment = ArrayList<HashMap<String, JsonElement>>
|
|
||||||
|
|
||||||
internal suspend fun MsgRecord.toSegment(): MsgSegment {
|
|
||||||
return MsgConvert.convertMsgRecordToMsgSegment(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal suspend fun MsgRecord.toCQCode(): String {
|
|
||||||
return MsgConvert.convertMsgRecordToCQCode(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal suspend fun List<MsgElement>.toSegment(chatType: Int, peerId: String): MsgSegment {
|
|
||||||
return MsgConvert.convertMsgElementsToMsgSegment(chatType, this, peerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String): String {
|
|
||||||
return MsgConvert.convertMsgElementsToCQCode(this, chatType, peerId)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal object MsgConvert {
|
|
||||||
suspend fun convertMsgRecordToCQCode(record: MsgRecord, chatType: Int = record.chatType): String {
|
|
||||||
return MessageHelper.encodeCQCode(convertMsgElementsToMsgSegment(
|
|
||||||
chatType,
|
|
||||||
record.elements,
|
|
||||||
record.peerUin.toString()
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun convertMsgElementsToCQCode(
|
|
||||||
elements: List<MsgElement>,
|
|
||||||
chatType: Int,
|
|
||||||
peerId: String
|
|
||||||
): String {
|
|
||||||
if(elements.isEmpty()) {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return MessageHelper.encodeCQCode(convertMsgElementsToMsgSegment(chatType, elements, peerId))
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun convertMsgRecordToMsgSegment(record: MsgRecord, chatType: Int = record.chatType): ArrayList<HashMap<String, JsonElement>> {
|
|
||||||
return convertMsgElementsToMsgSegment(chatType, record.elements, record.peerUin.toString())
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun convertMsgElementsToMsgSegment(
|
|
||||||
chatType: Int,
|
|
||||||
elements: List<MsgElement>,
|
|
||||||
peerId: String
|
|
||||||
): ArrayList<HashMap<String, JsonElement>> {
|
|
||||||
val messageData = arrayListOf<HashMap<String, JsonElement>>()
|
|
||||||
elements.forEach {
|
|
||||||
try {
|
|
||||||
val segment = covertMsgElementToMsgSegment(chatType, peerId, it)
|
|
||||||
if (segment != null) {
|
|
||||||
messageData.add(segment)
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
LogCenter.log("消息element转换错误:$e", Level.WARN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return messageData
|
|
||||||
}
|
|
||||||
|
|
||||||
suspend fun covertMsgElementToMsgSegment(chatType: Int, peerId: String, element: MsgElement): HashMap<String, JsonElement>? {
|
|
||||||
when (element.elementType) {
|
|
||||||
MsgConstant.KELEMTYPETEXT -> {
|
|
||||||
val text = element.textElement
|
|
||||||
return if (text.atType != MsgConstant.ATTYPEUNKNOWN) {
|
|
||||||
hashMapOf(
|
|
||||||
"type" to "at".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"qq" to ContactHelper.getUinByUidAsync(text.atNtUid).json,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
hashMapOf(
|
|
||||||
"type" to "text".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"text" to text.content.json
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEFACE -> {
|
|
||||||
val face = element.faceElement
|
|
||||||
if (face.faceType == 5) {
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "poke".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"type" to face.pokeType.json,
|
|
||||||
"id" to face.vaspokeId.json,
|
|
||||||
"strength" to face.pokeStrength.json
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "face".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"id" to face.faceIndex.json
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEPIC -> {
|
|
||||||
val image = element.picElement
|
|
||||||
val md5 = image.md5HexStr ?: image.fileName
|
|
||||||
.replace("{", "")
|
|
||||||
.replace("}", "")
|
|
||||||
.replace("-", "").split(".")[0]
|
|
||||||
|
|
||||||
ImageDB.getInstance().imageMappingDao().insert(
|
|
||||||
ImageMapping(md5.uppercase(), chatType, image.fileSize)
|
|
||||||
)
|
|
||||||
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "image".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"file" to md5.json,
|
|
||||||
"url" to when(chatType) {
|
|
||||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(md5)
|
|
||||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPicDownUrl(md5)
|
|
||||||
else -> error("Not supported chat type: $chatType, convertMsgElementsToMsgSegment::Pic")
|
|
||||||
}.json
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEPTT -> {
|
|
||||||
val record = element.pttElement
|
|
||||||
|
|
||||||
val md5 = if (record.fileName.startsWith("silk"))
|
|
||||||
record.fileName.substring(5)
|
|
||||||
else record.md5HexStr
|
|
||||||
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "record".json,
|
|
||||||
"data" to JsonObject(hashMapOf(
|
|
||||||
"file" to md5.json,
|
|
||||||
"url" to when(chatType) {
|
|
||||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPttDownUrl("0", record.md5HexStr, record.fileUuid)
|
|
||||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPttDownUrl("0", record.fileUuid)
|
|
||||||
else -> error("Not supported chat type: $chatType, convertMsgElementsToMsgSegment::Pic")
|
|
||||||
}.json
|
|
||||||
).also {
|
|
||||||
if(record.voiceChangeType != MsgConstant.KPTTVOICECHANGETYPENONE) {
|
|
||||||
it["magic"] = "1".json
|
|
||||||
}
|
|
||||||
if (it["url"].asString.isBlank()) {
|
|
||||||
it.remove("url")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEVIDEO -> {
|
|
||||||
val video = element.videoElement
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "video".json,
|
|
||||||
"data" to JsonObject(hashMapOf(
|
|
||||||
"file" to video.fileName.json,
|
|
||||||
"url" to when(chatType) {
|
|
||||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", video.fileName, video.fileUuid)
|
|
||||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", video.fileName, video.fileUuid)
|
|
||||||
else -> error("Not supported chat type: $chatType, convertMsgElementsToMsgSegment::Pic")
|
|
||||||
}.json
|
|
||||||
).also {
|
|
||||||
if (it["url"].asString.isBlank()) {
|
|
||||||
it.remove("url")
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEMARKETFACE -> {
|
|
||||||
val face = element.marketFaceElement
|
|
||||||
when (face.emojiId.lowercase()) {
|
|
||||||
"4823d3adb15df08014ce5d6796b76ee1" -> return hashMapOf("type" to "dice".json)
|
|
||||||
"83c8a293ae65ca140f348120a77448ee" -> return hashMapOf("type" to "rps".json)
|
|
||||||
else -> LogCenter.log("暂不支持的超表: ${face.emojiId}", Level.WARN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEARKSTRUCT -> {
|
|
||||||
try {
|
|
||||||
val data = element.arkElement.bytesData.asJsonObject
|
|
||||||
val app = data["app"].asString
|
|
||||||
when (app) {
|
|
||||||
"com.tencent.troopsharecard" -> {
|
|
||||||
val info = data["meta"].asJsonObject["contact"].asJsonObject
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "contact".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"type" to "group".json,
|
|
||||||
"id" to info["jumpUrl"].asString.split("group_code=")[1].json,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
"com.tencent.contact.lua" -> {
|
|
||||||
val info = data["meta"].asJsonObject["contact"].asJsonObject
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "contact".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"type" to "private".json,
|
|
||||||
"id" to info["jumpUrl"].asString.split("uin=")[1].json,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/*"com.tencent.structmsg" -> {
|
|
||||||
val info = data["meta"].asJsonObject["news"].asJsonObject
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "share".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"url" to info["jumpUrl"]!!,
|
|
||||||
"title" to info["title"]!!,
|
|
||||||
"content" to info["desc"]!!,
|
|
||||||
"image" to info["preview"]!!
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}*/
|
|
||||||
"com.tencent.map" -> {
|
|
||||||
val info = data["meta"].asJsonObject["Location.Search"].asJsonObject
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "location".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"lat" to info["lat"]!!,
|
|
||||||
"lon" to info["lng"]!!,
|
|
||||||
"content" to info["address"]!!,
|
|
||||||
"title" to info["name"]!!
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "json".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"data" to element.arkElement.bytesData.json,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
LogCenter.log(e.stackTraceToString(), Level.WARN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEREPLY -> {
|
|
||||||
val reply = element.replyElement
|
|
||||||
val msgId = reply.replayMsgId
|
|
||||||
val msgHash = if (msgId != 0L) {
|
|
||||||
MessageHelper.generateMsgIdHash(chatType, msgId)
|
|
||||||
} else {
|
|
||||||
MessageDB.getInstance().messageMappingDao()
|
|
||||||
.queryByMsgSeq(chatType, peerId, reply.replayMsgSeq?.toInt() ?: 0)?.msgHashId
|
|
||||||
?: MessageHelper.generateMsgIdHash(chatType, reply.sourceMsgIdInRecords)
|
|
||||||
}
|
|
||||||
|
|
||||||
return hashMapOf(
|
|
||||||
"type" to "reply".json,
|
|
||||||
"data" to JsonObject(mapOf(
|
|
||||||
"id" to msgHash.json,
|
|
||||||
))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEGRAYTIP -> {
|
|
||||||
val tip = element.grayTipElement
|
|
||||||
when(val tipType = tip.subElementType) {
|
|
||||||
MsgConstant.GRAYTIPELEMENTSUBTYPEJSON -> {
|
|
||||||
val notify = tip.jsonGrayTipElement
|
|
||||||
when(notify.busiId) {
|
|
||||||
/* 新人入群 */ 17L,
|
|
||||||
/* 群戳一戳 */1061L, /* 群撤回 */1014L -> {}
|
|
||||||
else -> LogCenter.log("不支持的灰条类型(JSON): $tipType", Level.WARN)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
MsgConstant.GRAYTIPELEMENTSUBTYPEXMLMSG -> {
|
|
||||||
val notify = tip.xmlElement
|
|
||||||
when(notify.busiId) {
|
|
||||||
/* 群戳一戳 */12L -> {}
|
|
||||||
else -> LogCenter.log("不支持的灰条类型(XML): $tipType", Level.WARN)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
else -> LogCenter.log("不支持的提示类型: $tip", Level.WARN)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MsgConstant.KELEMTYPEFILE -> {
|
|
||||||
// TODO(自发消息 / 其他客户端同步文件消息处理?)
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
else -> LogCenter.log("不支持的Elem转消息段: ${element.elementType}", Level.WARN)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -0,0 +1,116 @@
|
|||||||
|
package moe.fuqiuluo.qqinterface.servlet.msg.convert
|
||||||
|
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||||
|
import kotlinx.serialization.json.JsonElement
|
||||||
|
import moe.fuqiuluo.shamrock.helper.Level
|
||||||
|
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||||
|
import moe.fuqiuluo.shamrock.helper.MessageHelper
|
||||||
|
import moe.fuqiuluo.shamrock.tools.json
|
||||||
|
|
||||||
|
internal typealias MessageSegmentList = ArrayList<MessageSegment>
|
||||||
|
|
||||||
|
internal data class MessageSegment(
|
||||||
|
val type: String,
|
||||||
|
val data: Map<String, Any> = emptyMap()
|
||||||
|
) {
|
||||||
|
fun toJson(): Map<String, JsonElement> {
|
||||||
|
return hashMapOf(
|
||||||
|
"type" to type.json,
|
||||||
|
"data" to data.json
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun MsgRecord.toSegments(): ArrayList<MessageSegment> {
|
||||||
|
return MessageConvert.convertMessageRecordToMsgSegment(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun MsgRecord.toCQCode(): String {
|
||||||
|
return MessageConvert.convertMessageRecordToCQCode(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun List<MsgElement>.toSegments(chatType: Int, peerId: String): MessageSegmentList {
|
||||||
|
return MessageConvert.convertMessageElementsToMsgSegment(chatType, this, peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal suspend fun List<MsgElement>.toCQCode(chatType: Int, peerId: String): String {
|
||||||
|
return MessageConvert.convertMsgElementsToCQCode(this, chatType, peerId)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal object MessageConvert {
|
||||||
|
private val convertMap by lazy {
|
||||||
|
mutableMapOf<Int, IMessageConvert>(
|
||||||
|
MsgConstant.KELEMTYPETEXT to MessageElemConverter.TextConverter,
|
||||||
|
MsgConstant.KELEMTYPEFACE to MessageElemConverter.FaceConverter,
|
||||||
|
MsgConstant.KELEMTYPEPIC to MessageElemConverter.ImageConverter,
|
||||||
|
MsgConstant.KELEMTYPEPTT to MessageElemConverter.VoiceConverter,
|
||||||
|
MsgConstant.KELEMTYPEVIDEO to MessageElemConverter.VideoConverter,
|
||||||
|
MsgConstant.KELEMTYPEMARKETFACE to MessageElemConverter.MarketFaceConverter,
|
||||||
|
MsgConstant.KELEMTYPEARKSTRUCT to MessageElemConverter.StructJsonConverter,
|
||||||
|
MsgConstant.KELEMTYPEREPLY to MessageElemConverter.ReplyConverter,
|
||||||
|
MsgConstant.KELEMTYPEGRAYTIP to MessageElemConverter.GrayTipsConverter,
|
||||||
|
MsgConstant.KELEMTYPEFILE to MessageElemConverter.FileConverter
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun convertMessageElementsToMsgSegment(
|
||||||
|
chatType: Int,
|
||||||
|
elements: List<MsgElement>,
|
||||||
|
peerId: String
|
||||||
|
): ArrayList<MessageSegment> {
|
||||||
|
val messageData = arrayListOf<MessageSegment>()
|
||||||
|
elements.forEach {
|
||||||
|
kotlin.runCatching {
|
||||||
|
val elementId = it.elementType
|
||||||
|
val converter = convertMap[elementId]
|
||||||
|
converter?.convert(chatType, peerId, it)
|
||||||
|
?: throw UnsupportedOperationException("不支持的消息element类型:$elementId")
|
||||||
|
}.onSuccess {
|
||||||
|
messageData.add(it)
|
||||||
|
}.onFailure {
|
||||||
|
if (it is UnknownError) {
|
||||||
|
// 不处理的消息类型,抛出unknown error
|
||||||
|
} else {
|
||||||
|
LogCenter.log("消息element转换错误:$it", Level.WARN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return messageData
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun convertMessageRecordToMsgSegment(record: MsgRecord, chatType: Int = record.chatType): ArrayList<MessageSegment> {
|
||||||
|
return convertMessageElementsToMsgSegment(chatType, record.elements, record.peerUin.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun convertMsgElementsToCQCode(
|
||||||
|
elements: List<MsgElement>,
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String
|
||||||
|
): String {
|
||||||
|
if(elements.isEmpty()) {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
val msgList = convertMessageElementsToMsgSegment(chatType, elements, peerId).map {
|
||||||
|
it.toJson()
|
||||||
|
}
|
||||||
|
return MessageHelper.encodeCQCode(msgList)
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun convertMessageRecordToCQCode(record: MsgRecord, chatType: Int = record.chatType): String {
|
||||||
|
return MessageHelper.encodeCQCode(
|
||||||
|
convertMessageElementsToMsgSegment(
|
||||||
|
chatType,
|
||||||
|
record.elements,
|
||||||
|
record.peerUin.toString()
|
||||||
|
).map { it.toJson() }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun interface IMessageConvert {
|
||||||
|
suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,318 @@
|
|||||||
|
package moe.fuqiuluo.qqinterface.servlet.msg.convert
|
||||||
|
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||||
|
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||||
|
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
||||||
|
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.db.ImageDB
|
||||||
|
import moe.fuqiuluo.shamrock.helper.db.ImageMapping
|
||||||
|
import moe.fuqiuluo.shamrock.helper.db.MessageDB
|
||||||
|
import moe.fuqiuluo.shamrock.tools.asJsonObject
|
||||||
|
import moe.fuqiuluo.shamrock.tools.asString
|
||||||
|
import moe.fuqiuluo.shamrock.tools.json
|
||||||
|
|
||||||
|
internal sealed class MessageElemConverter: IMessageConvert {
|
||||||
|
/**
|
||||||
|
* 文本 / 艾特 消息转换消息段
|
||||||
|
*/
|
||||||
|
object TextConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
|
||||||
|
val text = element.textElement
|
||||||
|
return if (text.atType != MsgConstant.ATTYPEUNKNOWN) {
|
||||||
|
MessageSegment(
|
||||||
|
type = "at",
|
||||||
|
data = hashMapOf(
|
||||||
|
"qq" to ContactHelper.getUinByUidAsync(text.atNtUid),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
MessageSegment(
|
||||||
|
type = "text",
|
||||||
|
data = hashMapOf(
|
||||||
|
"text" to text.content
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 小表情 / 戳一戳 消息转换消息段
|
||||||
|
*/
|
||||||
|
object FaceConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(chatType: Int, peerId: String, element: MsgElement): MessageSegment {
|
||||||
|
val face = element.faceElement
|
||||||
|
if (face.faceType == 5) {
|
||||||
|
return MessageSegment(
|
||||||
|
type = "poke",
|
||||||
|
data = hashMapOf(
|
||||||
|
"type" to face.pokeType,
|
||||||
|
"id" to face.vaspokeId,
|
||||||
|
"strength" to face.pokeStrength
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return MessageSegment(
|
||||||
|
type = "face",
|
||||||
|
data = hashMapOf(
|
||||||
|
"id" to face.faceIndex
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图片消息转换消息段
|
||||||
|
*/
|
||||||
|
object ImageConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val image = element.picElement
|
||||||
|
val md5 = image.md5HexStr ?: image.fileName
|
||||||
|
.replace("{", "")
|
||||||
|
.replace("}", "")
|
||||||
|
.replace("-", "").split(".")[0]
|
||||||
|
|
||||||
|
ImageDB.getInstance().imageMappingDao().insert(
|
||||||
|
ImageMapping(md5.uppercase(), chatType, image.fileSize)
|
||||||
|
)
|
||||||
|
|
||||||
|
return MessageSegment(
|
||||||
|
type = "image",
|
||||||
|
data = hashMapOf(
|
||||||
|
"file" to md5,
|
||||||
|
"url" to when(chatType) {
|
||||||
|
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(md5)
|
||||||
|
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPicDownUrl(md5)
|
||||||
|
else -> unknownChatType(chatType)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 语音消息转换消息段
|
||||||
|
*/
|
||||||
|
object VoiceConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val record = element.pttElement
|
||||||
|
|
||||||
|
val md5 = if (record.fileName.startsWith("silk"))
|
||||||
|
record.fileName.substring(5)
|
||||||
|
else record.md5HexStr
|
||||||
|
|
||||||
|
return MessageSegment(
|
||||||
|
type = "record",
|
||||||
|
data = hashMapOf(
|
||||||
|
"file" to md5,
|
||||||
|
"url" to when(chatType) {
|
||||||
|
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPttDownUrl("0", record.md5HexStr, record.fileUuid)
|
||||||
|
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPttDownUrl("0", record.fileUuid)
|
||||||
|
else -> unknownChatType(chatType)
|
||||||
|
}
|
||||||
|
).also {
|
||||||
|
if(record.voiceChangeType != MsgConstant.KPTTVOICECHANGETYPENONE) {
|
||||||
|
it["magic"] = "1".json
|
||||||
|
}
|
||||||
|
if ((it["url"] as String).isBlank()) {
|
||||||
|
it.remove("url")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 视频消息转换消息段
|
||||||
|
*/
|
||||||
|
object VideoConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val video = element.videoElement
|
||||||
|
return MessageSegment(
|
||||||
|
type = "video",
|
||||||
|
data = hashMapOf(
|
||||||
|
"file" to video.fileName,
|
||||||
|
"url" to when(chatType) {
|
||||||
|
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", video.fileName, video.fileUuid)
|
||||||
|
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", video.fileName, video.fileUuid)
|
||||||
|
else -> unknownChatType(chatType)
|
||||||
|
}
|
||||||
|
).also {
|
||||||
|
if ((it["url"] as String).isBlank())
|
||||||
|
it.remove("url")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 商城大表情消息转换消息段
|
||||||
|
*/
|
||||||
|
object MarketFaceConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val face = element.marketFaceElement
|
||||||
|
return when (face.emojiId.lowercase()) {
|
||||||
|
"4823d3adb15df08014ce5d6796b76ee1" -> MessageSegment("dice")
|
||||||
|
"83c8a293ae65ca140f348120a77448ee" -> MessageSegment("rps")
|
||||||
|
else -> MessageSegment(
|
||||||
|
type = "mface",
|
||||||
|
data = hashMapOf(
|
||||||
|
"id" to face.emojiId
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JSON消息转消息段
|
||||||
|
*/
|
||||||
|
object StructJsonConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val data = element.arkElement.bytesData.asJsonObject
|
||||||
|
return when (data["app"].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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回复消息转消息段
|
||||||
|
*/
|
||||||
|
object ReplyConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val reply = element.replyElement
|
||||||
|
val msgId = reply.replayMsgId
|
||||||
|
val msgHash = if (msgId != 0L) {
|
||||||
|
MessageHelper.generateMsgIdHash(chatType, msgId)
|
||||||
|
} else {
|
||||||
|
MessageDB.getInstance().messageMappingDao()
|
||||||
|
.queryByMsgSeq(chatType, peerId, reply.replayMsgSeq?.toInt() ?: 0)?.msgHashId
|
||||||
|
?: MessageHelper.generateMsgIdHash(chatType, reply.sourceMsgIdInRecords)
|
||||||
|
}
|
||||||
|
|
||||||
|
return MessageSegment(
|
||||||
|
type = "reply",
|
||||||
|
data = mapOf(
|
||||||
|
"id" to msgHash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 灰色提示条消息过滤
|
||||||
|
*/
|
||||||
|
object GrayTipsConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
val tip = element.grayTipElement
|
||||||
|
when(val tipType = tip.subElementType) {
|
||||||
|
MsgConstant.GRAYTIPELEMENTSUBTYPEJSON -> {
|
||||||
|
val notify = tip.jsonGrayTipElement
|
||||||
|
when(notify.busiId) {
|
||||||
|
/* 新人入群 */ 17L,
|
||||||
|
/* 群戳一戳 */1061L, /* 群撤回 */1014L -> {}
|
||||||
|
else -> LogCenter.log("不支持的灰条类型(JSON): $tipType", Level.WARN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MsgConstant.GRAYTIPELEMENTSUBTYPEXMLMSG -> {
|
||||||
|
val notify = tip.xmlElement
|
||||||
|
when(notify.busiId) {
|
||||||
|
/* 群戳一戳 */12L -> {}
|
||||||
|
else -> LogCenter.log("不支持的灰条类型(XML): $tipType", Level.WARN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> LogCenter.log("不支持的提示类型: $tip", Level.WARN)
|
||||||
|
}
|
||||||
|
// 提示类消息,这里提供的是一个xml,不具备解析通用性
|
||||||
|
// 在这里不推送
|
||||||
|
throw UnknownError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件消息转换消息段
|
||||||
|
*/
|
||||||
|
object FileConverter: MessageElemConverter() {
|
||||||
|
override suspend fun convert(
|
||||||
|
chatType: Int,
|
||||||
|
peerId: String,
|
||||||
|
element: MsgElement
|
||||||
|
): MessageSegment {
|
||||||
|
// 使用其他地方的推送,而不是使用消息
|
||||||
|
throw UnknownError()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun unknownChatType(chatType: Int) {
|
||||||
|
throw UnsupportedOperationException("Not supported chat type: $chatType")
|
||||||
|
}
|
||||||
|
}
|
@ -169,7 +169,7 @@ internal object MessageHelper {
|
|||||||
return arrayList.jsonArray
|
return arrayList.jsonArray
|
||||||
}
|
}
|
||||||
|
|
||||||
fun encodeCQCode(msg: ArrayList<HashMap<String, JsonElement>>): String {
|
fun encodeCQCode(msg: List<Map<String, JsonElement>>): String {
|
||||||
return nativeEncodeCQCode(msg.map {
|
return nativeEncodeCQCode(msg.map {
|
||||||
val params = hashMapOf<String, String>()
|
val params = hashMapOf<String, String>()
|
||||||
it.forEach { (key, value) ->
|
it.forEach { (key, value) ->
|
||||||
|
@ -62,7 +62,7 @@ internal object HTTPServer {
|
|||||||
weatherAction()
|
weatherAction()
|
||||||
otherAction()
|
otherAction()
|
||||||
guildAction()
|
guildAction()
|
||||||
if (ShamrockConfig.isPro()) {
|
if (ShamrockConfig.isDev()) {
|
||||||
qsign()
|
qsign()
|
||||||
obtainProtocolData()
|
obtainProtocolData()
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,7 @@ import moe.fuqiuluo.shamrock.remote.action.IActionHandler
|
|||||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageDetail
|
import moe.fuqiuluo.shamrock.remote.service.data.MessageDetail
|
||||||
import moe.fuqiuluo.shamrock.remote.service.data.MessageSender
|
import moe.fuqiuluo.shamrock.remote.service.data.MessageSender
|
||||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.msg.MsgConvert
|
import moe.fuqiuluo.qqinterface.servlet.msg.convert.MessageConvert
|
||||||
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
|
||||||
|
|
||||||
internal object GetMsg: IActionHandler() {
|
internal object GetMsg: IActionHandler() {
|
||||||
@ -31,7 +31,9 @@ internal object GetMsg: IActionHandler() {
|
|||||||
sender = MessageSender(
|
sender = MessageSender(
|
||||||
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid
|
msg.senderUin, msg.sendNickName, "unknown", 0, msg.senderUid
|
||||||
),
|
),
|
||||||
message = MsgConvert.convertMsgRecordToMsgSegment(msg),
|
message = MessageConvert.convertMessageRecordToMsgSegment(msg).map {
|
||||||
|
it.toJson()
|
||||||
|
},
|
||||||
peerId = msg.peerUin,
|
peerId = msg.peerUin,
|
||||||
groupId = if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
groupId = if (msg.chatType == MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0,
|
||||||
targetId = if (msg.chatType != MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0
|
targetId = if (msg.chatType != MsgConstant.KCHATTYPEGROUP) msg.peerUin else 0
|
||||||
|
@ -17,6 +17,7 @@ import kotlinx.serialization.json.JsonElement
|
|||||||
import kotlinx.serialization.json.JsonPrimitive
|
import kotlinx.serialization.json.JsonPrimitive
|
||||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.msg.*
|
import moe.fuqiuluo.qqinterface.servlet.msg.*
|
||||||
|
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.HttpPushServlet
|
import moe.fuqiuluo.shamrock.remote.service.api.HttpPushServlet
|
||||||
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
||||||
import moe.fuqiuluo.shamrock.remote.service.data.push.*
|
import moe.fuqiuluo.shamrock.remote.service.data.push.*
|
||||||
@ -308,7 +309,10 @@ internal object HttpService: HttpPushServlet() {
|
|||||||
targetId = if(msgType != MsgType.Private) 0 else record.peerUin,
|
targetId = if(msgType != MsgType.Private) 0 else record.peerUin,
|
||||||
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
||||||
userId = record.senderUin,
|
userId = record.senderUin,
|
||||||
message = if(ShamrockConfig.useCQ()) raw.json else elements.toSegment(record.chatType, record.peerUin.toString()).json,
|
message = if(ShamrockConfig.useCQ()) raw.json
|
||||||
|
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
|
||||||
|
it.toJson()
|
||||||
|
}.json,
|
||||||
rawMessage = raw,
|
rawMessage = raw,
|
||||||
font = 0,
|
font = 0,
|
||||||
sender = Sender(
|
sender = Sender(
|
||||||
|
@ -13,7 +13,7 @@ import moe.fuqiuluo.shamrock.remote.service.data.push.*
|
|||||||
import moe.fuqiuluo.shamrock.tools.json
|
import moe.fuqiuluo.shamrock.tools.json
|
||||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.msg.toSegment
|
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||||
|
|
||||||
internal class WebSocketClientService(
|
internal class WebSocketClientService(
|
||||||
override val address: String,
|
override val address: String,
|
||||||
@ -288,10 +288,9 @@ internal class WebSocketClientService(
|
|||||||
targetId = if (msgType != MsgType.Private) 0 else record.peerUin,
|
targetId = if (msgType != MsgType.Private) 0 else record.peerUin,
|
||||||
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
||||||
userId = record.senderUin,
|
userId = record.senderUin,
|
||||||
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegment(
|
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegments(record.chatType, record.peerUin.toString()).map {
|
||||||
record.chatType,
|
it.toJson()
|
||||||
record.peerUin.toString()
|
}.json,
|
||||||
).json,
|
|
||||||
rawMessage = raw,
|
rawMessage = raw,
|
||||||
font = 0,
|
font = 0,
|
||||||
sender = Sender(
|
sender = Sender(
|
||||||
|
@ -9,7 +9,7 @@ import kotlinx.coroutines.GlobalScope
|
|||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||||
import moe.fuqiuluo.qqinterface.servlet.msg.toSegment
|
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||||
import moe.fuqiuluo.shamrock.helper.ErrorTokenException
|
import moe.fuqiuluo.shamrock.helper.ErrorTokenException
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketPushServlet
|
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketPushServlet
|
||||||
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
||||||
@ -297,7 +297,9 @@ internal class WebSocketService(port: Int): WebSocketPushServlet(port) {
|
|||||||
targetId = if(msgType != MsgType.Private) 0 else record.peerUin,
|
targetId = if(msgType != MsgType.Private) 0 else record.peerUin,
|
||||||
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
peerId = if (record.senderUin == uin) record.peerUin else uin,
|
||||||
userId = record.senderUin,
|
userId = record.senderUin,
|
||||||
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegment(record.chatType, record.peerUin.toString()).json,
|
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegments(record.chatType, record.peerUin.toString()).map {
|
||||||
|
it.toJson()
|
||||||
|
}.json,
|
||||||
rawMessage = raw,
|
rawMessage = raw,
|
||||||
font = 0,
|
font = 0,
|
||||||
sender = Sender(
|
sender = Sender(
|
||||||
|
@ -179,4 +179,9 @@ internal object ShamrockConfig {
|
|||||||
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
|
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
|
||||||
return mmkv.getInt("ssl_port", getPort())
|
return mmkv.getInt("ssl_port", getPort())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isDev(): Boolean {
|
||||||
|
val mmkv = MMKVFetcher.mmkvWithId("shamrock_config")
|
||||||
|
return mmkv.getBoolean("dev", false)
|
||||||
|
}
|
||||||
}
|
}
|
@ -17,7 +17,7 @@ internal data class MessageDetail(
|
|||||||
@SerialName("message_id") val msgId: Int,
|
@SerialName("message_id") val msgId: Int,
|
||||||
@SerialName("real_id") val realId: Int,
|
@SerialName("real_id") val realId: Int,
|
||||||
@SerialName("sender") val sender: MessageSender,
|
@SerialName("sender") val sender: MessageSender,
|
||||||
@SerialName("message") val message: ArrayList<HashMap<String, JsonElement>>,
|
@SerialName("message") val message: List<Map<String, JsonElement>>,
|
||||||
@SerialName("group_id") val groupId: Long = 0,
|
@SerialName("group_id") val groupId: Long = 0,
|
||||||
@SerialName("peer_id") val peerId: Long,
|
@SerialName("peer_id") val peerId: Long,
|
||||||
@SerialName("target_id") val targetId: Long = 0,
|
@SerialName("target_id") val targetId: Long = 0,
|
||||||
|
@ -7,7 +7,7 @@ import com.tencent.qqnt.kernel.nativeinterface.*
|
|||||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||||
import kotlinx.coroutines.GlobalScope
|
import kotlinx.coroutines.GlobalScope
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.fuqiuluo.qqinterface.servlet.msg.toCQCode
|
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toCQCode
|
||||||
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
|
||||||
import moe.fuqiuluo.shamrock.remote.service.api.GlobalPusher
|
import moe.fuqiuluo.shamrock.remote.service.api.GlobalPusher
|
||||||
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
|
||||||
|
Loading…
x
Reference in New Issue
Block a user