Shamrock: 调整推送器逻辑

Signed-off-by: WhiteChi <whitechi73@outlook.com>
This commit is contained in:
WhiteChi 2023-10-28 00:02:18 +08:00
parent 85cb9d221c
commit debcb4f192
16 changed files with 542 additions and 1074 deletions

View File

@ -3,333 +3,52 @@ package moe.fuqiuluo.shamrock.remote.service
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import moe.fuqiuluo.shamrock.helper.MessageHelper
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.MsgSvc
import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonPrimitive
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
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.config.ShamrockConfig
import moe.fuqiuluo.shamrock.remote.service.api.HttpTransmitServlet
import moe.fuqiuluo.shamrock.remote.service.data.push.*
import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
internal object HttpService: HttpPushServlet() {
internal object HttpService: HttpTransmitServlet() {
private val actionMsgTypes = arrayOf(
"record", "voice", "video", "markdown"
)
override fun pushSelfPrivateSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Private,
MsgSubType.Friend,
postType = PostType.MsgSent
)
override fun submitFlowJob(job: Job) {
// HTTP 回调不会触发断连无需释放之前的JOB
}
override fun pushSelfGroupSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Group,
MsgSubType.NORMAL,
postType = PostType.MsgSent
)
override fun cancelFlowJobs() {
}
override fun pushPrivateMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Private,
MsgSubType.Friend
)
override fun initTransmitter() {
submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onMessageEvent { (record, event) ->
val respond = pushTo(event) ?: return@onMessageEvent
handleQuicklyReply(record, event.messageId, respond.bodyAsText())
}
override fun pushGroupMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record, elements, raw, msgHash, MsgType.Group, MsgSubType.NORMAL,
role = when (record.senderUin) {
GroupSvc.getOwner(record.peerUin.toString()) -> MemberRole.Owner
in GroupSvc.getAdminList(record.peerUin.toString()) -> MemberRole.Admin
else -> MemberRole.Member
}
)
}
override fun pushGroupPoke(time: Long, operation: Long, userId: Long, groupId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = operation,
userId = operation,
groupId = groupId,
target = userId,
)
}
override fun pushPrivateMsgRecall(time: Long, operation: Long, msgHash: Int, tip: String) {
pushNotice(
time = time,
type = NoticeType.FriendRecall,
operation = operation,
userId = operation,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupMsgRecall(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
msgHash: Int,
tip: String
) {
pushNotice(
time = time,
type = NoticeType.GroupRecall,
operation = operation,
userId = userId,
groupId = groupId,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupBan(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
duration: Int
) {
pushNotice(
time,
NoticeType.GroupBan,
if (duration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban,
operation,
userId,
groupId,
duration
)
}
override fun pushGroupMemberDecreased(
time: Long,
target: Long,
groupId: Long,
operation: Long,
type: NoticeType,
subType: NoticeSubType
) {
pushNotice(
time,
type,
subType,
operation,
target,
groupId
)
}
override fun pushGroupAdminChange(time: Long, target: Long, groupId: Long, setAdmin: Boolean) {
pushNotice(
time,
NoticeType.GroupAdminChange,
if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet,
0,
target,
groupId
)
}
override fun pushGroupFileCome(
time: Long,
userId: Long,
groupId: Long,
fileId: String,
fileName: String,
fileSize: Long,
bizId: Int,
url: String
) {
pushNotice(
time = time,
type = NoticeType.GroupUpload,
groupId = groupId,
operation = userId,
userId = userId,
groupFileMsg = GroupFileMsg(
id = fileId,
name = fileName,
size = fileSize,
busid = bizId.toLong(),
url = url
)
)
}
override fun pushC2CPoke(time: Long, userId: Long, targetId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = userId,
userId = userId,
target = targetId,
sender = userId
)
}
override fun pushC2CFileCome(
time: Long,
sender: Long,
fileId: String,
fileSubId: String,
fileName: String,
fileSize: Long,
expireTime: Long,
url: String
) {
pushNotice(
time = time,
type = NoticeType.PrivateUpload,
operation = sender,
userId = sender,
sender = sender,
privateFileMsg = PrivateFileMsg(
id = fileId,
name = fileName,
size = fileSize,
url = url,
subId = fileSubId,
expire = expireTime
)
)
}
private fun pushNotice(
time: Long,
type: NoticeType,
subType: NoticeSubType = NoticeSubType.None,
operation: Long,
userId: Long,
groupId: Long = 0,
duration: Int = 0,
msgHash: Int = 0,
target: Long = 0,
sender: Long = 0,
tip: String = "",
groupFileMsg: GroupFileMsg? = null,
privateFileMsg: PrivateFileMsg? = null
) {
GlobalScope.launch {
pushTo(PushNotice(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = type,
subType = subType,
operatorId = operation,
userId = userId,
groupId = groupId,
duration = duration,
target = target,
msgId = msgHash,
tip = tip,
file = groupFileMsg,
senderId = sender,
privateFile = privateFileMsg
))
}
}
private fun pushMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int,
msgType: MsgType,
subType: MsgSubType,
role: MemberRole = MemberRole.Member,
postType: PostType = PostType.Msg
) {
val uin = TicketSvc.getUin().toLong()
GlobalScope.launch {
val respond = pushTo(PushMessage(
time = record.msgTime,
selfId = app.longAccountUin,
postType = postType,
messageType = msgType,
subType = subType,
messageId = msgHash,
groupId = 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,
userId = record.senderUin,
message = if(ShamrockConfig.useCQ()) raw.json
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
it.toJson()
}.json,
rawMessage = raw,
font = 0,
sender = Sender(
userId = record.senderUin,
nickname = record.sendNickName,
card = record.sendMemberName,
role = role,
title = "",
level = "",
)
)) ?: return@launch
handleQuicklyReply(
record,
msgHash,
respond.bodyAsText()
)
})
submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onNoticeEvent { event ->
pushTo(event)
}
})
LogCenter.log("HttpService: 初始化服务", Level.WARN)
}
private suspend fun handleQuicklyReply(record: MsgRecord, msgHash: Int, jsonText: String) {

View File

@ -6,6 +6,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketClientServlet
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
@ -14,295 +15,39 @@ import moe.fuqiuluo.shamrock.tools.json
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
internal class WebSocketClientService(
override val address: String,
wsHeaders: Map<String, String>
) : WebSocketClientServlet(address, wsHeaders) {
private val eventJobList = mutableSetOf<Job>()
override fun pushSelfPrivateSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Private,
MsgSubType.Friend,
postType = PostType.MsgSent
)
override fun submitFlowJob(job: Job) {
eventJobList.add(job)
}
override fun pushSelfGroupSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Group,
MsgSubType.NORMAL,
postType = PostType.MsgSent
)
override fun initTransmitter() {
HttpService.submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onMessageEvent { (_, event) ->
pushTo(event)
}
})
HttpService.submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onNoticeEvent { event ->
pushTo(event)
}
})
LogCenter.log("WebSocketClientService: 初始化服务", Level.WARN)
}
override fun pushPrivateMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(record, elements, raw, msgHash, MsgType.Private, MsgSubType.Friend)
}
override fun pushGroupMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record, elements, raw, msgHash, MsgType.Group, MsgSubType.NORMAL,
role = when (record.senderUin) {
GroupSvc.getOwner(record.peerUin.toString()) -> MemberRole.Owner
in GroupSvc.getAdminList(record.peerUin.toString()) -> MemberRole.Admin
else -> MemberRole.Member
}
)
}
override fun pushGroupPoke(time: Long, operation: Long, userId: Long, groupId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = operation,
userId = operation,
groupId = groupId,
target = userId
)
}
override fun pushPrivateMsgRecall(time: Long, operation: Long, msgHash: Int, tip: String) {
pushNotice(
time = time,
type = NoticeType.FriendRecall,
operation = operation,
userId = operation,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupMsgRecall(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
msgHash: Int,
tip: String
) {
pushNotice(
time = time,
type = NoticeType.GroupRecall,
operation = operation,
userId = userId,
groupId = groupId,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupBan(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
duration: Int
) {
pushNotice(
time,
NoticeType.GroupBan,
if (duration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban,
operation,
userId,
groupId,
duration
)
}
override fun pushGroupMemberDecreased(
time: Long,
target: Long,
groupId: Long,
operation: Long,
type: NoticeType,
subType: NoticeSubType
) {
pushNotice(time, type, subType, operation, target, groupId)
}
override fun pushGroupAdminChange(time: Long, target: Long, groupId: Long, setAdmin: Boolean) {
pushNotice(
time,
NoticeType.GroupAdminChange,
if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet,
0,
target,
groupId
)
}
override fun pushGroupFileCome(
time: Long,
userId: Long,
groupId: Long,
fileId: String,
fileName: String,
fileSize: Long,
bizId: Int,
url: String
) {
pushNotice(
time = time,
type = NoticeType.GroupUpload,
groupId = groupId,
operation = userId,
userId = userId,
groupFileMsg = GroupFileMsg(
id = fileId,
name = fileName,
size = fileSize,
busid = bizId.toLong(),
url = url
)
)
}
override fun pushC2CPoke(time: Long, userId: Long, targetId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = userId,
userId = userId,
target = targetId,
sender = userId
)
}
override fun pushC2CFileCome(
time: Long,
sender: Long,
fileId: String,
fileSubId: String,
fileName: String,
fileSize: Long,
expireTime: Long,
url: String
) {
pushNotice(
time = time,
type = NoticeType.PrivateUpload,
operation = sender,
userId = sender,
sender = sender,
privateFileMsg = PrivateFileMsg(
id = fileId,
name = fileName,
size = fileSize,
url = url,
subId = fileSubId,
expire = expireTime
)
)
}
private fun pushNotice(
time: Long,
type: NoticeType,
subType: NoticeSubType = NoticeSubType.None,
operation: Long,
userId: Long,
groupId: Long = 0,
duration: Int = 0,
msgHash: Int = 0,
target: Long = 0,
sender: Long = 0,
tip: String = "",
groupFileMsg: GroupFileMsg? = null,
privateFileMsg: PrivateFileMsg? = null
) {
GlobalScope.launch {
pushTo(
PushNotice(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = type,
subType = subType,
operatorId = operation,
userId = userId,
groupId = groupId,
duration = duration,
target = target,
msgId = msgHash,
tip = tip,
file = groupFileMsg,
senderId = sender,
privateFile = privateFileMsg
)
)
}
}
private fun pushMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int,
msgType: MsgType,
subType: MsgSubType,
role: MemberRole = MemberRole.Member,
postType: PostType = PostType.Msg
) {
val uin = TicketSvc.getUin().toLong()
GlobalScope.launch {
pushTo(
PushMessage(
time = record.msgTime,
selfId = app.longAccountUin,
postType = postType,
messageType = msgType,
subType = subType,
messageId = msgHash,
groupId = 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,
userId = record.senderUin,
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegments(record.chatType, record.peerUin.toString()).map {
it.toJson()
}.json,
rawMessage = raw,
font = 0,
sender = Sender(
userId = record.senderUin,
nickname = record.sendNickName,
card = record.sendMemberName,
role = role,
title = "",
level = "",
)
)
)
override fun cancelFlowJobs() {
eventJobList.removeIf { job ->
job.cancel()
return@removeIf true
}
LogCenter.log("WebSocketClientService: 释放服务", Level.WARN)
}
}

View File

@ -2,316 +2,52 @@
package moe.fuqiuluo.shamrock.remote.service
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.TicketSvc
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
import moe.fuqiuluo.shamrock.helper.ErrorTokenException
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketPushServlet
import moe.fuqiuluo.shamrock.remote.service.api.WebSocketTransmitServlet
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.remote.service.data.BotStatus
import moe.fuqiuluo.shamrock.remote.service.data.Self
import moe.fuqiuluo.shamrock.remote.service.data.push.*
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
import moe.fuqiuluo.shamrock.tools.json
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
import org.java_websocket.WebSocket
import org.java_websocket.handshake.ClientHandshake
import java.net.URI
internal class WebSocketService(port: Int): WebSocketPushServlet(port) {
fun pushMetaLifecycle() {
GlobalScope.launch {
val runtime = AppRuntimeFetcher.appRuntime
val curUin = runtime.currentAccountUin
pushTo(PushMetaEvent(
time = System.currentTimeMillis() / 1000,
selfId = app.longAccountUin,
postType = PostType.Meta,
type = MetaEventType.LifeCycle,
subType = MetaSubType.Connect,
status = BotStatus(
Self("qq", curUin.toLong()), runtime.isLogin, status = "正常", good = true
),
interval = 15000
))
}
internal class WebSocketService(port: Int): WebSocketTransmitServlet(port) {
private val eventJobList = mutableSetOf<Job>()
override fun submitFlowJob(job: Job) {
eventJobList.add(job)
}
override fun pushSelfPrivateSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Private,
MsgSubType.Friend,
postType = PostType.MsgSent
)
override fun initTransmitter() {
HttpService.submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onMessageEvent { (_, event) ->
pushTo(event)
}
})
HttpService.submitFlowJob(GlobalScope.launch {
GlobalEventTransmitter.onNoticeEvent { event ->
pushTo(event)
}
})
LogCenter.log("WebSocketService: 初始化服务", Level.WARN)
}
override fun pushSelfGroupSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record,
elements,
raw,
msgHash,
MsgType.Group,
MsgSubType.NORMAL,
postType = PostType.MsgSent
)
}
override fun pushPrivateMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(record, elements, raw, msgHash, MsgType.Private, MsgSubType.Friend)
}
override fun pushGroupMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
) {
pushMsg(
record, elements, raw, msgHash, MsgType.Group, MsgSubType.NORMAL,
role = when (record.senderUin) {
GroupSvc.getOwner(record.peerUin.toString()) -> MemberRole.Owner
in GroupSvc.getAdminList(record.peerUin.toString()) -> MemberRole.Admin
else -> MemberRole.Member
}
)
}
override fun pushGroupPoke(time: Long, operation: Long, userId: Long, groupId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = operation,
userId = operation,
groupId = groupId,
target = userId
)
}
override fun pushPrivateMsgRecall(time: Long, operation: Long, msgHash: Int, tip: String) {
pushNotice(
time = time,
type = NoticeType.FriendRecall,
operation = operation,
userId = operation,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupMsgRecall(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
msgHash: Int,
tip: String
) {
pushNotice(
time = time,
type = NoticeType.GroupRecall,
operation = operation,
userId = userId,
groupId = groupId,
msgHash = msgHash,
tip = tip
)
}
override fun pushGroupBan(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
duration: Int
) {
pushNotice(time, NoticeType.GroupBan, if (duration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban, operation, userId, groupId, duration)
}
override fun pushGroupMemberDecreased(
time: Long,
target: Long,
groupId: Long,
operation: Long,
type: NoticeType,
subType: NoticeSubType
) {
pushNotice(time, type, subType, operation, target, groupId)
}
override fun pushGroupAdminChange(time: Long, target: Long, groupId: Long, setAdmin: Boolean) {
pushNotice(time, NoticeType.GroupAdminChange, if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet, 0, target, groupId)
}
override fun pushGroupFileCome(
time: Long,
userId: Long,
groupId: Long,
fileId: String,
fileName: String,
fileSize: Long,
bizId: Int,
url: String
) {
pushNotice(
time = time,
type = NoticeType.GroupUpload,
groupId = groupId,
operation = userId,
userId = userId,
groupFileMsg = GroupFileMsg(
id = fileId,
name = fileName,
size = fileSize,
busid = bizId.toLong(),
url = url
)
)
}
override fun pushC2CPoke(time: Long, userId: Long, targetId: Long) {
pushNotice(
time = time,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operation = userId,
userId = userId,
target = targetId,
sender = userId
)
}
override fun pushC2CFileCome(
time: Long,
sender: Long,
fileId: String,
fileSubId: String,
fileName: String,
fileSize: Long,
expireTime: Long,
url: String
) {
pushNotice(
time = time,
type = NoticeType.PrivateUpload,
operation = sender,
userId = sender,
sender = sender,
privateFileMsg = PrivateFileMsg(
id = fileId,
name = fileName,
size = fileSize,
url = url,
subId = fileSubId,
expire = expireTime
)
)
}
private fun pushNotice(
time: Long,
type: NoticeType,
subType: NoticeSubType = NoticeSubType.None,
operation: Long,
userId: Long,
groupId: Long = 0,
duration: Int = 0,
msgHash: Int = 0,
target: Long = 0,
sender: Long = 0,
tip: String = "",
groupFileMsg: GroupFileMsg? = null,
privateFileMsg: PrivateFileMsg? = null
) {
GlobalScope.launch {
pushTo(
PushNotice(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = type,
subType = subType,
operatorId = operation,
userId = userId,
groupId = groupId,
duration = duration,
target = target,
msgId = msgHash,
tip = tip,
file = groupFileMsg,
senderId = sender,
privateFile = privateFileMsg
)
)
}
}
private fun pushMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int,
msgType: MsgType,
subType: MsgSubType,
role: MemberRole = MemberRole.Member,
postType: PostType = PostType.Msg
) {
val uin = TicketSvc.getUin().toLong()
GlobalScope.launch {
pushTo(PushMessage(
time = record.msgTime,
selfId = app.longAccountUin,
postType = postType,
messageType = msgType,
subType = subType,
messageId = msgHash,
groupId = 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,
userId = record.senderUin,
message = if (ShamrockConfig.useCQ()) raw.json else elements.toSegments(record.chatType, record.peerUin.toString()).map {
it.toJson()
}.json,
rawMessage = raw,
font = 0,
sender = Sender(
userId = record.senderUin,
nickname = record.sendNickName,
card = record.sendMemberName,
role = role,
title = "",
level = "",
)
))
override fun cancelFlowJobs() {
eventJobList.removeIf { job ->
job.cancel()
return@removeIf true
}
LogCenter.log("WebSocketService: 释放服务", Level.WARN)
}
override fun onOpen(conn: WebSocket, handshake: ClientHandshake) {
@ -337,4 +73,22 @@ internal class WebSocketService(port: Int): WebSocketPushServlet(port) {
}
LogCenter.log({ "WSServer连接(${conn.remoteSocketAddress.address.hostAddress}:${conn.remoteSocketAddress.port}$path)" }, Level.DEBUG)
}
private fun pushMetaLifecycle() {
GlobalScope.launch {
val runtime = AppRuntimeFetcher.appRuntime
val curUin = runtime.currentAccountUin
pushTo(PushMetaEvent(
time = System.currentTimeMillis() / 1000,
selfId = app.longAccountUin,
postType = PostType.Meta,
type = MetaEventType.LifeCycle,
subType = MetaSubType.Connect,
status = BotStatus(
Self("qq", curUin.toLong()), runtime.isLogin, status = "正常", good = true
),
interval = 15000
))
}
}
}

View File

@ -1,108 +0,0 @@
package moe.fuqiuluo.shamrock.remote.service.api
import com.tencent.mobileqq.app.QQAppInterface
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
import oicq.wlogin_sdk.tools.MD5
internal interface BasePushServlet {
val address: String
fun allowPush(): Boolean
fun pushSelfPrivateSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
)
fun pushSelfGroupSentMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
)
fun pushPrivateMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
)
fun pushGroupMsg(
record: MsgRecord,
elements: List<MsgElement>,
raw: String,
msgHash: Int
)
fun pushGroupPoke(time: Long, operation: Long, userId: Long, groupId: Long)
//fun pushPrivatePoke(time: Long, operation: Long, userId: Long, sender: Long)
fun pushPrivateMsgRecall(time: Long, operation: Long, msgHash: Int, tip: String)
fun pushGroupMsgRecall(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
msgHash: Int,
tip: String
)
fun pushGroupBan(
time: Long,
operation: Long,
userId: Long,
groupId: Long,
duration: Int
)
fun pushGroupMemberDecreased(
time: Long,
target: Long,
groupId: Long,
operation: Long = 0,
type: NoticeType,
subType: NoticeSubType
)
fun pushGroupAdminChange(time: Long, target: Long, groupId: Long, setAdmin: Boolean)
fun pushGroupFileCome(
time: Long,
userId: Long,
groupId: Long,
fileId: String,
fileName: String,
fileSize: Long,
bizId: Int,
url: String
)
fun pushC2CPoke(time: Long, userId: Long, targetId: Long)
fun pushC2CFileCome(
msgTime: Long,
sender: Long,
fileId: String,
fileSubId: String,
fileName: String,
fileSize: Long,
expireTime: Long,
url: String
)
val app: QQAppInterface
get() = AppRuntimeFetcher.appRuntime as QQAppInterface
val id: String
get() = MD5.getMD5String(address.toByteArray())
}

View File

@ -0,0 +1,28 @@
package moe.fuqiuluo.shamrock.remote.service.api
import com.tencent.mobileqq.app.QQAppInterface
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import kotlinx.coroutines.Job
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import oicq.wlogin_sdk.tools.MD5
internal interface BaseTransmitServlet {
val address: String
fun allowTransmit(): Boolean
fun submitFlowJob(job: Job)
fun cancelFlowJobs()
fun initTransmitter()
val app: QQAppInterface
get() = AppRuntimeFetcher.appRuntime as QQAppInterface
val id: String
get() = MD5.getMD5String(address.toByteArray())
}

View File

@ -0,0 +1,347 @@
package moe.fuqiuluo.shamrock.remote.service.api
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.MutableSharedFlow
import moe.fuqiuluo.qqinterface.servlet.BaseSvc
import moe.fuqiuluo.qqinterface.servlet.GroupSvc
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toSegments
import moe.fuqiuluo.shamrock.remote.service.HttpService
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.remote.service.data.push.GroupFileMsg
import moe.fuqiuluo.shamrock.remote.service.data.push.MemberRole
import moe.fuqiuluo.shamrock.remote.service.data.push.MsgSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.MsgType
import moe.fuqiuluo.shamrock.remote.service.data.push.PostType
import moe.fuqiuluo.shamrock.remote.service.data.push.MessageEvent
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeEvent
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.remote.service.data.push.PrivateFileMsg
import moe.fuqiuluo.shamrock.remote.service.data.push.Sender
import moe.fuqiuluo.shamrock.tools.ShamrockDsl
import moe.fuqiuluo.shamrock.tools.json
import java.util.ArrayList
internal object GlobalEventTransmitter: BaseSvc() {
private val messageEventFlow by lazy {
MutableSharedFlow<Pair<MsgRecord, MessageEvent>>()
}
private val noticeEventFlow by lazy {
MutableSharedFlow<NoticeEvent>()
}
private fun pushNotice(noticeEvent: NoticeEvent) = noticeEventFlow.tryEmit(noticeEvent)
private fun transMessageEvent(record: MsgRecord, message: MessageEvent) = messageEventFlow.tryEmit(record to message)
/**
* 消息 手淫器
*/
object MessageTransmitter {
/**
* 推送群聊消息
*/
suspend fun transGroupMessage(
record: MsgRecord,
elements: ArrayList<MsgElement>,
rawMsg: String,
msgHash: Int,
postType: PostType = PostType.Msg
): Boolean {
val uin = app.longAccountUin
return transMessageEvent(record,
MessageEvent(
time = record.msgTime,
selfId = uin,
postType = postType,
messageType = MsgType.Group,
subType = MsgSubType.NORMAL,
messageId = msgHash,
groupId = record.peerUin,
peerId = uin,
userId = record.senderUin,
message = if(ShamrockConfig.useCQ()) rawMsg.json
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
it.toJson()
}.json,
rawMessage = rawMsg,
font = 0,
sender = Sender(
userId = record.senderUin,
nickname = record.sendNickName,
card = record.sendMemberName,
role = when (record.senderUin) {
GroupSvc.getOwner(record.peerUin.toString()) -> MemberRole.Owner
in GroupSvc.getAdminList(record.peerUin.toString()) -> MemberRole.Admin
else -> MemberRole.Member
},
title = "",
level = "",
)
)
)
}
/**
* 推送私聊消息
*/
suspend fun transPrivateMessage(
record: MsgRecord,
elements: ArrayList<MsgElement>,
rawMsg: String,
msgHash: Int,
postType: PostType = PostType.Msg
): Boolean {
val uin = app.longAccountUin
return transMessageEvent(record,
MessageEvent(
time = record.msgTime,
selfId = uin,
postType = postType,
messageType = MsgType.Private,
subType = MsgSubType.Friend,
messageId = msgHash,
targetId = record.peerUin,
peerId = uin,
userId = record.senderUin,
message = if(ShamrockConfig.useCQ()) rawMsg.json
else elements.toSegments(record.chatType, record.peerUin.toString()).map {
it.toJson()
}.json,
rawMessage = rawMsg,
font = 0,
sender = Sender(
userId = record.senderUin,
nickname = record.sendNickName,
card = record.sendMemberName,
role = when (record.senderUin) {
GroupSvc.getOwner(record.peerUin.toString()) -> MemberRole.Owner
in GroupSvc.getAdminList(record.peerUin.toString()) -> MemberRole.Admin
else -> MemberRole.Member
},
title = "",
level = "",
)
)
)
}
}
/**
* 文件通知 通知器
*/
object FileNoticeTransmitter {
/**
* 推送私聊文件事件
*/
fun transPrivateFileEvent(
msgTime: Long,
userId: Long,
fileId: String,
fileSubId: String,
fileName: String,
fileSize: Long,
expireTime: Long,
url: String
): Boolean {
return pushNotice(NoticeEvent(
time = msgTime,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.PrivateUpload,
operatorId = userId,
userId = userId,
senderId = userId,
privateFile = PrivateFileMsg(
id = fileId,
name = fileName,
size = fileSize,
url = url,
subId = fileSubId,
expire = expireTime
)
))
}
/**
* 推送私聊文件事件
*/
fun transGroupFileEvent(
msgTime: Long,
userId: Long,
groupId: Long,
uuid: String,
fileName: String,
fileSize: Long,
bizId: Int,
url: String
): Boolean {
return pushNotice(NoticeEvent(
time = msgTime,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.GroupUpload,
operatorId = userId,
userId = userId,
groupId = groupId,
file = GroupFileMsg(
id = uuid,
name = fileName,
size = fileSize,
busid = bizId.toLong(),
url = url
)
))
}
}
/**
* 群聊通知 通知器
*/
object GroupNoticeTransmitter {
fun transGroupPoke(time: Long, operation: Long, target: Long, groupCode: Long): Boolean {
return pushNotice(NoticeEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operatorId = operation,
userId = operation,
groupId = groupCode,
target = target
))
}
fun transGroupMemberNumChanged(
time: Long,
target: Long,
groupCode: Long,
operation: Long,
noticeType: NoticeType,
noticeSubType: NoticeSubType
): Boolean {
return pushNotice(NoticeEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = noticeType,
subType = noticeSubType,
operatorId = operation,
userId = operation,
senderId = operation,
target = target,
groupId = groupCode
))
}
fun transGroupAdminChanged(
msgTime: Long,
target: Long,
groupCode: Long,
setAdmin: Boolean
): Boolean {
return pushNotice(NoticeEvent(
time = msgTime,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.GroupAdminChange,
subType = if (setAdmin) NoticeSubType.Set else NoticeSubType.UnSet,
operatorId = 0,
target = target,
groupId = groupCode
))
}
fun transGroupBan(
msgTime: Long,
operation: Long,
target: Long,
groupCode: Long,
duration: Int
): Boolean {
return pushNotice(NoticeEvent(
time = msgTime,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.GroupBan,
subType = if (duration == 0) NoticeSubType.LiftBan else NoticeSubType.Ban,
operatorId = operation,
userId = operation,
senderId = operation,
target = target,
groupId = groupCode,
duration = duration
))
}
fun transGroupMsgRecall(
time: Long,
operator: Long,
target: Long,
groupCode: Long,
msgHash: Int,
tipText: String
): Boolean {
return pushNotice(NoticeEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.GroupRecall,
operatorId = operator,
userId = target,
msgId = msgHash,
tip = tipText,
groupId = groupCode
))
}
}
/**
* 私聊通知 通知器
*/
object PrivateNoticeTransmitter {
fun transPrivatePoke(msgTime: Long, operation: Long, target: Long): Boolean {
return pushNotice(NoticeEvent(
time = msgTime,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.Notify,
subType = NoticeSubType.Poke,
operatorId = operation,
userId = operation,
senderId = operation,
target = target
))
}
fun transPrivateRecall(time: Long, operation: Long, msgHashId: Int, tipText: String): Boolean {
return pushNotice(NoticeEvent(
time = time,
selfId = app.longAccountUin,
postType = PostType.Notice,
type = NoticeType.FriendRecall,
subType = NoticeSubType.Poke,
operatorId = operation,
userId = operation,
msgId = msgHashId,
tip = tipText
))
}
}
@ShamrockDsl
suspend fun onMessageEvent(collector: FlowCollector<Pair<MsgRecord, MessageEvent>>) {
messageEventFlow.collect(collector)
}
@ShamrockDsl
suspend fun onNoticeEvent(collector: FlowCollector<NoticeEvent>) {
noticeEventFlow.collect(collector)
}
}

View File

@ -1,34 +0,0 @@
package moe.fuqiuluo.shamrock.remote.service.api
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import java.util.Collections
internal object GlobalPusher {
private val cacheConn = Collections.synchronizedMap(mutableMapOf<String, BasePushServlet>())
fun register(servlet: BasePushServlet){
if (ShamrockConfig.isIgnoreAllEvent()) {
return
}
LogCenter.log("推送器注册(id = ${servlet.id}): ${servlet.toString().split(".").last()}", Level.WARN)
if (!cacheConn.containsKey(servlet.id) && !cacheConn.containsValue(servlet)) {
cacheConn[servlet.id] = servlet
}
}
fun unregister(servlet: BasePushServlet){
LogCenter.log("推送器注销(id = ${servlet.id}): ${servlet.toString().split(".").last()}", Level.WARN)
if (cacheConn.containsKey(servlet.id) || cacheConn.containsValue(servlet)) {
cacheConn.remove(servlet.id)
}
}
operator fun invoke(): List<BasePushServlet> {
return cacheConn.map { it.value }
}
}

View File

@ -1,6 +1,5 @@
package moe.fuqiuluo.shamrock.remote.service.api
import com.arthenica.ffmpegkit.BuildConfig
import io.ktor.client.network.sockets.ConnectTimeoutException
import io.ktor.client.plugins.HttpRequestTimeoutException
import io.ktor.client.request.header
@ -9,6 +8,7 @@ import io.ktor.client.request.setBody
import io.ktor.client.statement.HttpResponse
import io.ktor.http.ContentType
import io.ktor.http.contentType
import kotlinx.coroutines.Job
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.tools.GlobalClient
import moe.fuqiuluo.shamrock.helper.Level
@ -19,16 +19,15 @@ import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
import java.net.SocketException
internal abstract class HttpPushServlet : BasePushServlet {
override val address: String
get() = ShamrockConfig.getWebHookAddress()
internal abstract class HttpTransmitServlet : BaseTransmitServlet {
override val address: String by lazy { ShamrockConfig.getWebHookAddress() }
override fun allowPush(): Boolean {
override fun allowTransmit(): Boolean {
return ShamrockConfig.allowWebHook()
}
protected suspend inline fun <reified T> pushTo(body: T): HttpResponse? {
if (!allowPush()) return null
if (!allowTransmit()) return null
try {
if (address.startsWith("http://") || address.startsWith("https://")) {
return GlobalClient.post(address) {

View File

@ -2,12 +2,13 @@
package moe.fuqiuluo.shamrock.remote.service.api
import io.ktor.client.statement.bodyAsText
import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import moe.fuqiuluo.shamrock.remote.action.ActionManager
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.entries.EmptyObject
@ -17,6 +18,7 @@ import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.HttpService
import moe.fuqiuluo.shamrock.remote.service.data.BotStatus
import moe.fuqiuluo.shamrock.remote.service.data.Self
import moe.fuqiuluo.shamrock.remote.service.data.push.MetaEventType
@ -24,7 +26,6 @@ import moe.fuqiuluo.shamrock.remote.service.data.push.MetaSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.PostType
import moe.fuqiuluo.shamrock.remote.service.data.push.PushMetaEvent
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
import org.java_websocket.client.WebSocketClient
import org.java_websocket.handshake.ServerHandshake
import java.lang.Exception
@ -34,16 +35,17 @@ import kotlin.concurrent.timer
internal abstract class WebSocketClientServlet(
url: String,
wsHeaders: Map<String, String>
) : BasePushServlet, WebSocketClient(URI(url), wsHeaders) {
override fun allowPush(): Boolean {
) : BaseTransmitServlet, WebSocketClient(URI(url), wsHeaders) {
override fun allowTransmit(): Boolean {
return ShamrockConfig.openWebSocketClient()
}
override fun onOpen(handshakedata: ServerHandshake?) {
LogCenter.log("WebSocketClient onOpen: ${handshakedata?.httpStatus}, ${handshakedata?.httpStatusMessage}")
startHeartbeatTimer()
pushMetaLifecycle()
GlobalPusher.register(this)
initTransmitter()
}
override fun onMessage(message: String) {
@ -79,16 +81,16 @@ internal abstract class WebSocketClientServlet(
override fun onClose(code: Int, reason: String?, remote: Boolean) {
LogCenter.log("WebSocketClient onClose: $code, $reason, $remote")
GlobalPusher.unregister(this)
cancelFlowJobs()
}
override fun onError(ex: Exception?) {
LogCenter.log("WebSocketClient onError: ${ex?.message}")
GlobalPusher.unregister(this)
cancelFlowJobs()
}
protected inline fun <reified T> pushTo(body: T) {
if (!allowPush() || isClosed || isClosing) return
if (!allowTransmit() || isClosed || isClosing) return
try {
send(GlobalJson.encodeToString(body))
} catch (e: Throwable) {

View File

@ -21,7 +21,6 @@ import moe.fuqiuluo.shamrock.tools.*
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
import org.java_websocket.WebSocket
import org.java_websocket.server.WebSocketServer
import java.net.InetSocketAddress
@ -29,15 +28,15 @@ import java.net.URI
import java.util.Collections
import kotlin.concurrent.timer
internal abstract class WebSocketPushServlet(
internal abstract class WebSocketTransmitServlet(
port: Int
) : BasePushServlet, WebSocketServer(InetSocketAddress(port)) {
) : BaseTransmitServlet, WebSocketServer(InetSocketAddress(port)) {
protected val eventReceivers: MutableList<WebSocket> = Collections.synchronizedList(mutableListOf<WebSocket>())
override val address: String
get() = "-"
override fun allowPush(): Boolean {
override fun allowTransmit(): Boolean {
return ShamrockConfig.openWebSocket()
}
@ -102,16 +101,16 @@ internal abstract class WebSocketPushServlet(
override fun onError(conn: WebSocket, ex: Exception?) {
LogCenter.log("WSServer Error: " + ex?.stackTraceToString(), Level.ERROR)
GlobalPusher.unregister(this)
cancelFlowJobs()
}
override fun onStart() {
GlobalPusher.register(this)
initTransmitter()
LogCenter.log("WSServer start running on ws://0.0.0.0:$port!")
}
protected inline fun <reified T> pushTo(body: T) {
if(!allowPush()) return
if(!allowTransmit()) return
try {
broadcastTextEvent(GlobalJson.encodeToString(body))
} catch (e: Throwable) {

View File

@ -41,7 +41,7 @@ internal enum class PostType {
* 不要使用继承的方式实现通用字段那样会很难维护
*/
@Serializable
internal data class PushMessage (
internal data class MessageEvent (
@SerialName("time") val time: Long,
@SerialName("self_id") val selfId: Long,
@SerialName("post_type") val postType: PostType,

View File

@ -39,7 +39,7 @@ internal enum class NoticeSubType {
* 不要使用继承的方式实现通用字段那样会很难维护
*/
@Serializable
internal data class PushNotice(
internal data class NoticeEvent(
@SerialName("time") val time: Long,
@SerialName("self_id") val selfId: Long,
@SerialName("post_type") val postType: PostType,
@ -50,7 +50,7 @@ internal data class PushNotice(
@SerialName("user_id") val userId: Long = 0,
@SerialName("sender_id") val senderId: Long = 0,
@SerialName("duration") val duration: Int = 0,
@SerialName("message_id") val msgId: Int,
@SerialName("message_id") val msgId: Int = 0,
@SerialName("tip_text") val tip: String = "",
@SerialName("target_id") val target: Long = 0,
@SerialName("file") val file: GroupFileMsg? = null,

View File

@ -1,7 +1,6 @@
@file:OptIn(DelicateCoroutinesApi::class)
package moe.fuqiuluo.shamrock.remote.service.listener
import android.util.Log
import moe.fuqiuluo.shamrock.helper.MessageHelper
import com.tencent.qqnt.kernel.nativeinterface.*
import kotlinx.coroutines.DelicateCoroutinesApi
@ -9,10 +8,11 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import moe.fuqiuluo.qqinterface.servlet.msg.convert.toCQCode
import moe.fuqiuluo.qqinterface.servlet.transfile.RichProtoSvc
import moe.fuqiuluo.shamrock.remote.service.api.GlobalPusher
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.remote.service.data.push.PostType
import java.util.ArrayList
import java.util.HashMap
@ -52,8 +52,10 @@ internal object AioListener: IKernelMsgListener {
if (rule.white?.contains(record.peerUin) == false) return
}
GlobalPusher().forEach {
it.pushGroupMsg(record, record.elements, rawMsg, msgHash)
if(!GlobalEventTransmitter.MessageTransmitter.transGroupMessage(
record, record.elements, rawMsg, msgHash
)) {
LogCenter.log("群消息推送失败 -> MessageTransmitter", Level.WARN)
}
}
MsgConstant.KCHATTYPEC2C -> {
@ -63,8 +65,10 @@ internal object AioListener: IKernelMsgListener {
if (rule.white?.contains(record.peerUin) == false) return
}
GlobalPusher().forEach {
it.pushPrivateMsg(record, record.elements, rawMsg, msgHash)
if(!GlobalEventTransmitter.MessageTransmitter.transPrivateMessage(
record, record.elements, rawMsg, msgHash
)) {
LogCenter.log("私聊消息推送失败 -> MessageTransmitter", Level.WARN)
}
}
else -> LogCenter.log("不支持PUSH事件: ${record.chatType}")
@ -98,14 +102,12 @@ internal object AioListener: IKernelMsgListener {
when (record.chatType) {
MsgConstant.KCHATTYPEGROUP -> {
GlobalPusher().forEach {
it.pushSelfGroupSentMsg(record, record.elements, rawMsg, msgHash)
}
GlobalEventTransmitter.MessageTransmitter
.transGroupMessage(record, record.elements, rawMsg, msgHash, PostType.MsgSent)
}
MsgConstant.KCHATTYPEC2C -> {
GlobalPusher().forEach {
it.pushSelfPrivateSentMsg(record, record.elements, rawMsg, msgHash)
}
GlobalEventTransmitter.MessageTransmitter
.transPrivateMessage(record, record.elements, rawMsg, msgHash, PostType.MsgSent)
}
else -> LogCenter.log("不支持SELF PUSH事件: ${record.chatType}")
}
@ -220,8 +222,9 @@ internal object AioListener: IKernelMsgListener {
val fileSubId = fileMsg.fileSubId ?: ""
val url = RichProtoSvc.getC2CFileDownUrl(fileId, fileSubId)
GlobalPusher().forEach {
it.pushC2CFileCome(record.msgTime, userId, fileId, fileSubId, fileName, fileSize, expireTime, url)
if(!GlobalEventTransmitter.FileNoticeTransmitter
.transPrivateFileEvent(record.msgTime, userId, fileId, fileSubId, fileName, fileSize, expireTime, url)) {
LogCenter.log("私聊文件消息推送失败 -> FileNoticeTransmitter", Level.WARN)
}
}
@ -242,8 +245,9 @@ internal object AioListener: IKernelMsgListener {
val url = RichProtoSvc.getGroupFileDownUrl(record.peerUin, uuid, bizId)
GlobalPusher().forEach {
it.pushGroupFileCome(record.msgTime, userId, groupId, uuid, fileName, fileSize, bizId, url)
if(!GlobalEventTransmitter.FileNoticeTransmitter
.transGroupFileEvent(record.msgTime, userId, groupId, uuid, fileName, fileSize, bizId, url)) {
LogCenter.log("群聊文件消息推送失败 -> FileNoticeTransmitter", Level.WARN)
}
}

View File

@ -18,15 +18,14 @@ import moe.fuqiuluo.proto.asUtf8String
import moe.fuqiuluo.proto.ProtoUtils
import moe.fuqiuluo.proto.asByteArray
import moe.fuqiuluo.proto.asList
import moe.fuqiuluo.proto.asMap
import moe.fuqiuluo.proto.asULong
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.remote.service.api.GlobalPusher
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeSubType
import moe.fuqiuluo.shamrock.remote.service.data.push.NoticeType
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.tools.readBuf32Long
import moe.fuqiuluo.shamrock.tools.toHexString
import moe.fuqiuluo.shamrock.xposed.helper.PacketHandler
@ -90,7 +89,10 @@ internal object PrimitiveListener {
}
LogCenter.log("私聊戳一戳: $operation -> $target")
GlobalPusher().forEach { it.pushC2CPoke(msgTime, operation.toLong(), target.toLong()) }
if(!GlobalEventTransmitter.PrivateNoticeTransmitter
.transPrivatePoke(msgTime, operation.toLong(), target.toLong())) {
LogCenter.log("私聊戳一戳推送失败!", Level.WARN)
}
}
private fun onGroupPoke(time: Long, pb: ProtoMap) {
@ -127,7 +129,10 @@ internal object PrimitiveListener {
}
LogCenter.log("群戳一戳($groupCode): $operation -> $target")
GlobalPusher().forEach { it.pushGroupPoke(time, operation.toLong(), target.toLong(), groupCode) }
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupPoke(time, operation.toLong(), target.toLong(), groupCode)) {
LogCenter.log("群戳一戳推送失败!", Level.WARN)
}
}
private suspend fun onC2CRecall(time: Long, pb: ProtoMap) {
@ -143,8 +148,9 @@ internal object PrimitiveListener {
LogCenter.log("私聊消息撤回: $operation, seq = $msgSeq, hash = ${mapping.msgHashId}, tip = $tipText")
GlobalPusher().forEach {
it.pushPrivateMsgRecall(time, operation, mapping.msgHashId, tipText)
if(!GlobalEventTransmitter.PrivateNoticeTransmitter
.transPrivateRecall(time, operation, mapping.msgHashId, tipText)) {
LogCenter.log("私聊消息撤回推送失败!", Level.WARN)
}
}
@ -157,12 +163,13 @@ internal object PrimitiveListener {
LogCenter.log("群成员增加($groupCode): $target, type = $type")
GlobalPusher().forEach {
it.pushGroupMemberDecreased(time, target, groupCode, operation, NoticeType.GroupMemIncrease, when(type) {
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged(time, target, groupCode, operation, NoticeType.GroupMemIncrease, when(type) {
130 -> NoticeSubType.Approve
131 -> NoticeSubType.Invite
else -> NoticeSubType.Approve
})
})) {
LogCenter.log("群成员增加推送失败!", Level.WARN)
}
}
@ -176,13 +183,14 @@ internal object PrimitiveListener {
val target = ContactHelper.getUinByUidAsync(targetUid).toLong()
LogCenter.log("群成员减少($groupCode): $target, type = $type")
GlobalPusher().forEach {
it.pushGroupMemberDecreased(time, target, groupCode, operation, NoticeType.GroupMemDecrease, when(type) {
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMemberNumChanged(time, target, groupCode, operation, NoticeType.GroupMemDecrease, when(type) {
130 -> NoticeSubType.Kick
131 -> NoticeSubType.Leave
3 -> NoticeSubType.KickMe
else -> NoticeSubType.Kick
})
})) {
LogCenter.log("群成员减少推送失败!", Level.WARN)
}
}
@ -200,8 +208,9 @@ internal object PrimitiveListener {
val target = ContactHelper.getUinByUidAsync(targetUid).toLong()
LogCenter.log("群管理员变动($groupCode): $target, isSetAdmin = $isSetAdmin")
GlobalPusher().forEach {
it.pushGroupAdminChange(msgTime, target, groupCode, isSetAdmin)
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupAdminChanged(msgTime, target, groupCode, isSetAdmin)) {
LogCenter.log("群管理员变动推送失败!", Level.WARN)
}
}
@ -214,8 +223,9 @@ internal object PrimitiveListener {
val target = ContactHelper.getUinByUidAsync(targetUid).toLong()
LogCenter.log("群禁言($groupCode): $operation -> $target, 时长 = ${duration}s")
GlobalPusher().forEach {
it.pushGroupBan(msgTime, operation, target, groupCode, duration)
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupBan(msgTime, operation, target, groupCode, duration)) {
LogCenter.log("群禁言推送失败!", Level.WARN)
}
}
@ -246,8 +256,9 @@ internal object PrimitiveListener {
LogCenter.log("群消息撤回($groupCode): $operator -> $target, seq = $msgSeq, hash = $msgHash, tip = $tipText")
GlobalPusher().forEach {
it.pushGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText)
if(!GlobalEventTransmitter.GroupNoticeTransmitter
.transGroupMsgRecall(time, operator, target, groupCode, msgHash, tipText)) {
LogCenter.log("群消息撤回推送失败!", Level.WARN)
}
} finally {
readPacket.release()

View File

@ -8,12 +8,13 @@ import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import moe.fuqiuluo.shamrock.remote.service.WebSocketClientService
import moe.fuqiuluo.shamrock.remote.service.WebSocketService
import moe.fuqiuluo.shamrock.remote.service.api.GlobalPusher
import moe.fuqiuluo.shamrock.remote.service.api.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.remote.service.config.ShamrockConfig
import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.HTTPServer
import moe.fuqiuluo.shamrock.remote.service.HttpService
import moe.fuqiuluo.shamrock.tools.ShamrockVersion
import moe.fuqiuluo.shamrock.xposed.helper.AppRuntimeFetcher
import mqq.app.MobileQQ
@ -34,7 +35,7 @@ internal class InitRemoteService : IAction {
if (!PlatformUtils.isMqqPackage()) return
if (ShamrockConfig.allowWebHook()) {
GlobalPusher.register(moe.fuqiuluo.shamrock.remote.service.HttpService)
HttpService.initTransmitter()
}
if (ShamrockConfig.openWebSocket()) {
@ -84,7 +85,7 @@ internal class InitRemoteService : IAction {
wsClient.connect()
timer(initialDelay = 5000L, period = 5000L) {
if (wsClient.isClosed || wsClient.isClosing) {
GlobalPusher.unregister(wsClient)
wsClient.cancelFlowJobs()
wsClient = WebSocketClientService(url, wsHeaders)
wsClient.connect()
}

View File

@ -73,6 +73,7 @@ internal object NTServiceFetcher {
LogCenter.log("Register MSG listener successfully.")
msgService.addMsgListener(AioListener)
// 接口缺失 暂不使用
//groupService.addKernelGroupListener(GroupEventListener)
//LogCenter.log("Register Group listener successfully.")