mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
Shamrock
: fix #111 and add group sign event
This commit is contained in:
parent
6201d12f5f
commit
fa6634d6af
@ -627,10 +627,16 @@ internal object MessageMaker {
|
||||
else -> {
|
||||
val info = GroupSvc.getTroopMemberInfoByUin(peerId, qq, true).onFailure {
|
||||
LogCenter.log("无法获取群成员信息: $qq", Level.ERROR)
|
||||
}.getOrThrow()
|
||||
at.content = "@${info.troopnick
|
||||
.ifNullOrEmpty(info.friendnick)
|
||||
.ifNullOrEmpty(qq)}"
|
||||
}.getOrNull()
|
||||
if (info != null) {
|
||||
at.content = "@${
|
||||
info.troopnick
|
||||
.ifNullOrEmpty(info.friendnick)
|
||||
.ifNullOrEmpty(qq)
|
||||
}"
|
||||
} else {
|
||||
at.content = "@${data["name"].asStringOrNull.ifNullOrEmpty(qq)}"
|
||||
}
|
||||
at.atType = MsgConstant.ATTYPEONE
|
||||
at.atNtUid = ContactHelper.getUidByUinAsync(qq.toLong())
|
||||
}
|
||||
|
@ -331,7 +331,7 @@ internal sealed class MessageElemConverter: IMessageConvert {
|
||||
MsgConstant.GRAYTIPELEMENTSUBTYPEXMLMSG -> {
|
||||
val notify = tip.xmlElement
|
||||
when(notify.busiId) {
|
||||
/* 群戳一戳 */1061L -> {}
|
||||
/* 群戳一戳 */1061L, /* 群打卡 */1068L -> {}
|
||||
else -> LogCenter.log("不支持的灰条类型(XML): ${notify.busiId}", Level.WARN)
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,7 @@ 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.JsonArray
|
||||
import kotlinx.serialization.json.JsonElement
|
||||
import kotlinx.serialization.json.JsonObject
|
||||
import kotlinx.serialization.json.*
|
||||
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
|
||||
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
|
||||
@ -18,19 +16,6 @@ import moe.fuqiuluo.shamrock.remote.service.data.ForwardMessageResult
|
||||
import moe.fuqiuluo.shamrock.tools.*
|
||||
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
|
||||
|
||||
sealed interface ForwardMsgNode {
|
||||
class MessageIdNode(
|
||||
val id: Int
|
||||
) : ForwardMsgNode
|
||||
|
||||
open class MessageNode(
|
||||
val name: String,
|
||||
val content: JsonElement?
|
||||
) : ForwardMsgNode
|
||||
|
||||
object EmptyNode : MessageNode("", null)
|
||||
}
|
||||
|
||||
internal object SendForwardMessage : IActionHandler() {
|
||||
override suspend fun internalHandle(session: ActionSession): String {
|
||||
val detailType = session.getStringOrNull("detail_type") ?: session.getStringOrNull("message_type")
|
||||
@ -74,7 +59,7 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
suspend operator fun invoke(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
message: JsonArray,
|
||||
messages: JsonArray,
|
||||
echo: JsonElement = EmptyJsonString
|
||||
): String {
|
||||
kotlin.runCatching {
|
||||
@ -83,63 +68,91 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
val msgService = sessionService.msgService
|
||||
val selfUin = TicketSvc.getUin()
|
||||
|
||||
val nodes = message.map {
|
||||
if (it.asJsonObject["type"].asStringOrNull != "node") return@map ForwardMsgNode.EmptyNode // 过滤非node类型消息段
|
||||
it.asJsonObject["data"].asJsonObject.let { data ->
|
||||
if (data.containsKey("content")) {
|
||||
if (data["content"] is JsonArray) {
|
||||
data["content"].asJsonArray.forEach { msg ->
|
||||
if (msg.asJsonObject["type"].asStringOrNull == "node") {
|
||||
LogCenter.log("合并转发消息不支持嵌套", Level.WARN)
|
||||
return@map ForwardMsgNode.EmptyNode
|
||||
}
|
||||
}
|
||||
}
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = data["name"].asStringOrNull ?: "",
|
||||
content = data["content"]
|
||||
)
|
||||
} else ForwardMsgNode.MessageIdNode(data["id"].asInt)
|
||||
val multiNodes = messages.map {
|
||||
if (it.asJsonObject["type"].asStringOrNull != "node") {
|
||||
LogCenter.log("包含非node类型节点", Level.WARN)
|
||||
return@map null
|
||||
}
|
||||
}.map {
|
||||
if (it is ForwardMsgNode.MessageIdNode) {
|
||||
val recordResult = MsgSvc.getMsg(it.id)
|
||||
if (!recordResult.isFailure) {
|
||||
ForwardMsgNode.EmptyNode
|
||||
} else {
|
||||
val record = recordResult.getOrThrow()
|
||||
ForwardMsgNode.MessageNode(
|
||||
name = record.peerName,
|
||||
content = record.toSegments().map { segment ->
|
||||
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)
|
||||
return@map null
|
||||
}
|
||||
} else {
|
||||
it as ForwardMsgNode.MessageNode
|
||||
}
|
||||
}.filter {
|
||||
it.content != null
|
||||
}.map { node ->
|
||||
val result = MessageHelper.sendMessageNoCb(MsgConstant.KCHATTYPEC2C, selfUin, node.content.let { msg ->
|
||||
when (msg) {
|
||||
is JsonArray -> msg
|
||||
is JsonObject -> listOf(msg).jsonArray
|
||||
else -> MessageHelper.decodeCQCode(msg.asString)
|
||||
}.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
|
||||
)
|
||||
}"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
"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.first != 0) {
|
||||
LogCenter.log("合并转发消息节点消息发送失败", Level.WARN)
|
||||
}
|
||||
})
|
||||
if (result.first != 0) {
|
||||
LogCenter.log("合并转发消息节点消息发送失败", Level.WARN)
|
||||
result.second to node.first
|
||||
}
|
||||
return@map result.second
|
||||
}
|
||||
}.filterNotNull()
|
||||
|
||||
val from = MessageHelper.generateContact(MsgConstant.KCHATTYPEC2C, selfUin)
|
||||
val to = MessageHelper.generateContact(chatType, peerId)
|
||||
|
||||
val uniseq = MessageHelper.generateMsgId(chatType)
|
||||
msgService.multiForwardMsg(ArrayList<MultiMsgInfo>().apply {
|
||||
nodes.forEach { add(MultiMsgInfo(it, "Anno")) }
|
||||
multiNodes.forEach { add(MultiMsgInfo(it.first, it.second)) }
|
||||
}.also { it.reverse() }, from, to, MsgSvc.MessageCallback(peerId, uniseq.first))
|
||||
|
||||
return ok(
|
||||
@ -154,7 +167,7 @@ internal object SendForwardMessage : IActionHandler() {
|
||||
return logic("合并转发消息失败(unknown error)", echo)
|
||||
}
|
||||
|
||||
override val requiredParams: Array<String> = arrayOf("message")
|
||||
override val requiredParams: Array<String> = arrayOf("messages")
|
||||
|
||||
override fun path(): String = "send_forward_msg"
|
||||
}
|
@ -29,7 +29,7 @@ import moe.fuqiuluo.shamrock.tools.jsonArray
|
||||
import moe.fuqiuluo.shamrock.tools.respond
|
||||
|
||||
fun Routing.messageAction() {
|
||||
route("/send_group_forward_msg") {
|
||||
route("/send_group_forward_(msg|message)".toRegex()) {
|
||||
post {
|
||||
val groupId = fetchPostOrNull("group_id")
|
||||
val messages = fetchPostJsonArray("messages")
|
||||
@ -40,7 +40,7 @@ fun Routing.messageAction() {
|
||||
}
|
||||
}
|
||||
|
||||
route("/send_private_forward_msg") {
|
||||
route("/send_private_forward_(msg|message)".toRegex()) {
|
||||
post {
|
||||
val userId = fetchPostOrNull("user_id")
|
||||
val messages = fetchPostJsonArray("messages")
|
||||
@ -51,6 +51,18 @@ fun Routing.messageAction() {
|
||||
}
|
||||
}
|
||||
|
||||
route("/send_forward_(msg|message)".toRegex()) {
|
||||
post {
|
||||
val userId = fetchPostOrNull("user_id")
|
||||
val groupId = fetchPostOrNull("group_id")
|
||||
val messages = fetchPostJsonArray("messages")
|
||||
call.respondText(SendForwardMessage(MsgConstant.KCHATTYPEC2C, userId ?: groupId?: "", messages), ContentType.Application.Json)
|
||||
}
|
||||
get {
|
||||
respond(false, Status.InternalHandlerError, "Not support GET method")
|
||||
}
|
||||
}
|
||||
|
||||
getOrPost("/get_forward_msg") {
|
||||
val id = fetchOrThrow("id")
|
||||
call.respondText(GetForwardMsg(id), ContentType.Application.Json)
|
||||
|
@ -25,6 +25,7 @@ import moe.fuqiuluo.shamrock.remote.service.data.push.RequestEvent
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestSubType
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.push.RequestType
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.push.Sender
|
||||
import moe.fuqiuluo.shamrock.remote.service.data.push.SignDetail
|
||||
import moe.fuqiuluo.shamrock.tools.ShamrockDsl
|
||||
import moe.fuqiuluo.shamrock.tools.json
|
||||
import java.util.ArrayList
|
||||
@ -222,6 +223,24 @@ internal object GlobalEventTransmitter: BaseSvc() {
|
||||
* 群聊通知 通知器
|
||||
*/
|
||||
object GroupNoticeTransmitter {
|
||||
suspend fun transGroupSign(time: Long, target: Long, action: String?, rankImg: String?, groupCode: Long): Boolean {
|
||||
pushNotice(NoticeEvent(
|
||||
time = time,
|
||||
selfId = app.longAccountUin,
|
||||
postType = PostType.Notice,
|
||||
type = NoticeType.Notify,
|
||||
subType = NoticeSubType.Sign,
|
||||
userId = target,
|
||||
groupId = groupCode,
|
||||
target = target,
|
||||
signDetail = SignDetail(
|
||||
rankImg = rankImg,
|
||||
action = action
|
||||
)
|
||||
))
|
||||
return true
|
||||
}
|
||||
|
||||
suspend fun transGroupPoke(time: Long, operation: Long, target: Long, action: String?, suffix: String?, actionImg: String?, groupCode: Long): Boolean {
|
||||
pushNotice(NoticeEvent(
|
||||
time = time,
|
||||
|
@ -42,6 +42,8 @@ internal enum class NoticeSubType {
|
||||
@SerialName("kick_me") KickMe,
|
||||
|
||||
@SerialName("poke") Poke,
|
||||
@SerialName("sign") Sign,
|
||||
|
||||
|
||||
@SerialName("title") Title,
|
||||
@SerialName("delete") Delete,
|
||||
@ -87,6 +89,9 @@ internal data class NoticeEvent(
|
||||
// 戳一戳
|
||||
@SerialName("poke_detail") val pokeDetail: PokeDetail? = null,
|
||||
|
||||
// 群打卡
|
||||
@SerialName("sign_detail") val signDetail: SignDetail? = null,
|
||||
|
||||
)
|
||||
|
||||
/**
|
||||
@ -131,4 +136,11 @@ internal data class PokeDetail (
|
||||
val suffix: String? = "",
|
||||
@SerialName("action_img_url")
|
||||
val actionImg: String? = "https://tianquan.gtimg.cn/nudgeaction/item/0/expression.jpg",
|
||||
)
|
||||
|
||||
@Serializable
|
||||
internal data class SignDetail (
|
||||
val action: String? = "今日第1个打卡",
|
||||
@SerialName("rank_img")
|
||||
val rankImg: String? = "",
|
||||
)
|
@ -82,7 +82,7 @@ internal object PrimitiveListener {
|
||||
12 -> onGroupBan(msgTime, pb)
|
||||
16 -> onGroupTitleChange(msgTime, pb)
|
||||
17 -> onGroupRecall(msgTime, pb)
|
||||
20 -> onGroupPoke(msgTime, pb)
|
||||
20 -> onGroupPokeAndGroupSign(msgTime, pb)
|
||||
21 -> onEssenceMessage(msgTime, pb)
|
||||
}
|
||||
}
|
||||
@ -188,6 +188,7 @@ internal object PrimitiveListener {
|
||||
readPacket.discardExact(1)
|
||||
ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt()))
|
||||
} else pb[1, 3, 2]
|
||||
readPacket.release()
|
||||
|
||||
val targetUin = detail[5, 5].asLong
|
||||
|
||||
@ -219,6 +220,7 @@ internal object PrimitiveListener {
|
||||
readPacket.discardExact(1)
|
||||
ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt()))
|
||||
} else pb[1, 3, 2]
|
||||
readPacket.release()
|
||||
|
||||
val groupId = detail[4].asLong
|
||||
val mesSeq = detail[37].asInt
|
||||
@ -254,24 +256,14 @@ internal object PrimitiveListener {
|
||||
}
|
||||
|
||||
|
||||
private suspend fun onGroupPoke(time: Long, pb: ProtoMap) {
|
||||
val groupCode1 = pb[1, 1, 1].asULong
|
||||
|
||||
var groupCode: Long = groupCode1
|
||||
private suspend fun onGroupPokeAndGroupSign(time: Long, pb: ProtoMap) {
|
||||
val groupCode = pb[1, 1, 1].asULong
|
||||
|
||||
val readPacket = ByteReadPacket(pb[1, 3, 2].asByteArray)
|
||||
val groupCode2 = readPacket.readBuf32Long()
|
||||
|
||||
var detail = if (groupCode2 == groupCode1) {
|
||||
groupCode = groupCode2
|
||||
val detail = if (readPacket.readBuf32Long() == groupCode) {
|
||||
readPacket.discardExact(1)
|
||||
ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt()))
|
||||
} else pb[1, 3, 2]
|
||||
if (detail !is ProtoMap) {
|
||||
groupCode = groupCode2
|
||||
readPacket.discardExact(1)
|
||||
detail = ProtoUtils.decodeFromByteArray(readPacket.readBytes(readPacket.readShort().toInt()))
|
||||
}
|
||||
readPacket.release()
|
||||
|
||||
lateinit var target: String
|
||||
@ -279,6 +271,7 @@ internal object PrimitiveListener {
|
||||
var action: String? = null
|
||||
var suffix: String? = null
|
||||
var actionImg: String? = null
|
||||
var rankImg: String? = null
|
||||
detail[26][7]
|
||||
.asList
|
||||
.value
|
||||
@ -287,18 +280,42 @@ internal object PrimitiveListener {
|
||||
when (it[1].asUtf8String) {
|
||||
"uin_str1" -> operation = value
|
||||
"uin_str2" -> target = value
|
||||
// "nick_str1" -> operation_nick = value
|
||||
// "nick_str2" -> operation_nick = value
|
||||
"action_str" -> action = value
|
||||
"alt_str1" -> action = value
|
||||
"suffix_str" -> suffix = value
|
||||
"action_img_url" -> actionImg = value
|
||||
|
||||
"mqq_uin" -> target = value
|
||||
// "mqq_nick" -> operation_nick = value
|
||||
"user_sign" -> action = value
|
||||
"rank_img" -> rankImg = value
|
||||
// "sign_word" -> 我也要打卡
|
||||
}
|
||||
}
|
||||
when (detail[26][2].asInt) {
|
||||
1061 -> {
|
||||
LogCenter.log("群戳一戳($groupCode): $operation $action $target $suffix")
|
||||
if (!GlobalEventTransmitter.GroupNoticeTransmitter
|
||||
.transGroupPoke(time, operation.toLong(), target.toLong(), action, suffix, actionImg, groupCode)
|
||||
) {
|
||||
LogCenter.log("群戳一戳推送失败!", Level.WARN)
|
||||
}
|
||||
}
|
||||
LogCenter.log("群戳一戳($groupCode): $operation $action $target $suffix")
|
||||
|
||||
if (!GlobalEventTransmitter.GroupNoticeTransmitter
|
||||
.transGroupPoke(time, operation.toLong(), target.toLong(), action, suffix, actionImg, groupCode)
|
||||
) {
|
||||
LogCenter.log("群戳一戳推送失败!", Level.WARN)
|
||||
1068 -> {
|
||||
LogCenter.log("群打卡($groupCode): $action $target")
|
||||
if (!GlobalEventTransmitter.GroupNoticeTransmitter
|
||||
.transGroupSign(time, target.toLong(), action, rankImg, groupCode)
|
||||
) {
|
||||
LogCenter.log("群打卡推送失败!", Level.WARN)
|
||||
}
|
||||
}
|
||||
|
||||
else -> {
|
||||
LogCenter.log("onGroupPokeAndGroupSign unknown type ${detail[2].asInt}", Level.WARN)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user