diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/HttpService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/HttpService.kt index 7a4cd98..7884e9a 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/HttpService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/HttpService.kt @@ -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, - 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, - 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, - raw: String, - msgHash: Int - ) { - pushMsg( - record, - elements, - raw, - msgHash, - MsgType.Private, - MsgSubType.Friend - ) - } - - override fun pushGroupMsg( - record: MsgRecord, - elements: List, - 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 initTransmitter() { + submitFlowJob(GlobalScope.launch { + GlobalEventTransmitter.onMessageEvent { (record, event) -> + val respond = pushTo(event) ?: return@onMessageEvent + handleQuicklyReply(record, event.messageId, respond.bodyAsText()) } - ) - } - - 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, - 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) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt index 4954da5..6d5dab1 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketClientService.kt @@ -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 ) : WebSocketClientServlet(address, wsHeaders) { + private val eventJobList = mutableSetOf() - override fun pushSelfPrivateSentMsg( - record: MsgRecord, - elements: List, - 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, - raw: String, - msgHash: Int - ) { - pushMsg( - record, - elements, - raw, - msgHash, - MsgType.Group, - MsgSubType.NORMAL, - postType = PostType.MsgSent - ) - } - - override fun pushPrivateMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) { - pushMsg(record, elements, raw, msgHash, MsgType.Private, MsgSubType.Friend) - } - - override fun pushGroupMsg( - record: MsgRecord, - elements: List, - 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 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 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, - 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) } } \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketService.kt index 9dd4d41..c296bba 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/WebSocketService.kt @@ -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() + + override fun submitFlowJob(job: Job) { + eventJobList.add(job) } - override fun pushSelfPrivateSentMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) { - pushMsg( - record, - elements, - raw, - msgHash, - MsgType.Private, - MsgSubType.Friend, - postType = PostType.MsgSent - ) - } - - override fun pushSelfGroupSentMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) { - pushMsg( - record, - elements, - raw, - msgHash, - MsgType.Group, - MsgSubType.NORMAL, - postType = PostType.MsgSent - ) - } - - override fun pushPrivateMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) { - pushMsg(record, elements, raw, msgHash, MsgType.Private, MsgSubType.Friend) - } - - override fun pushGroupMsg( - record: MsgRecord, - elements: List, - 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 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 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, - 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 + )) + } + } } \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BasePushServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BasePushServlet.kt deleted file mode 100644 index d01ec2c..0000000 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BasePushServlet.kt +++ /dev/null @@ -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, - raw: String, - msgHash: Int - ) - - fun pushSelfGroupSentMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) - - fun pushPrivateMsg( - record: MsgRecord, - elements: List, - raw: String, - msgHash: Int - ) - - fun pushGroupMsg( - record: MsgRecord, - elements: List, - 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()) -} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BaseTransmitServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BaseTransmitServlet.kt new file mode 100644 index 0000000..12cdac2 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/BaseTransmitServlet.kt @@ -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()) +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalEventTransmitter.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalEventTransmitter.kt new file mode 100644 index 0000000..f738101 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalEventTransmitter.kt @@ -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>() + } + private val noticeEventFlow by lazy { + MutableSharedFlow() + } + + 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, + 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, + 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>) { + messageEventFlow.collect(collector) + } + + @ShamrockDsl + suspend fun onNoticeEvent(collector: FlowCollector) { + noticeEventFlow.collect(collector) + } +} + + + diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalPusher.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalPusher.kt deleted file mode 100644 index 62a7391..0000000 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/GlobalPusher.kt +++ /dev/null @@ -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()) - - 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 { - return cacheConn.map { it.value } - } -} - - - diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpPushServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt similarity index 90% rename from xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpPushServlet.kt rename to xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt index 5648785..3a277ea 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpPushServlet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/HttpTransmitServlet.kt @@ -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 pushTo(body: T): HttpResponse? { - if (!allowPush()) return null + if (!allowTransmit()) return null try { if (address.startsWith("http://") || address.startsWith("https://")) { return GlobalClient.post(address) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt index bf0914b..34580ed 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketClientServlet.kt @@ -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 -) : 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 pushTo(body: T) { - if (!allowPush() || isClosed || isClosing) return + if (!allowTransmit() || isClosed || isClosing) return try { send(GlobalJson.encodeToString(body)) } catch (e: Throwable) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketPushServlet.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketTransmitServlet.kt similarity index 94% rename from xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketPushServlet.kt rename to xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketTransmitServlet.kt index 3fde0c8..f3ffe65 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketPushServlet.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/api/WebSocketTransmitServlet.kt @@ -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 = Collections.synchronizedList(mutableListOf()) 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 pushTo(body: T) { - if(!allowPush()) return + if(!allowTransmit()) return try { broadcastTextEvent(GlobalJson.encodeToString(body)) } catch (e: Throwable) { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushMessage.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/MessageEvent.kt similarity index 98% rename from xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushMessage.kt rename to xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/MessageEvent.kt index 9298d78..076ec85 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushMessage.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/MessageEvent.kt @@ -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, diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushNotice.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/NoticeEvent.kt similarity index 96% rename from xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushNotice.kt rename to xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/NoticeEvent.kt index 79b4b22..f9ec9f8 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/PushNotice.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/data/push/NoticeEvent.kt @@ -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, diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/AioListener.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/AioListener.kt index f08227c..09fb7cf 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/AioListener.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/AioListener.kt @@ -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) } } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt index 3309413..1ca6352 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/service/listener/PrimitiveListener.kt @@ -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) { - 130 -> NoticeSubType.Kick - 131 -> NoticeSubType.Leave - 3 -> NoticeSubType.KickMe - else -> NoticeSubType.Kick - }) + 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() diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt index 4871ab6..7e645c7 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/actions/InitRemoteService.kt @@ -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() } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/helper/NTServiceFetcher.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/helper/NTServiceFetcher.kt index 04e6259..f5c6557 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/helper/NTServiceFetcher.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/xposed/helper/NTServiceFetcher.kt @@ -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.")