diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/MsgSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/MsgSvc.kt index 054a713..7a8aaa0 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/MsgSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/MsgSvc.kt @@ -16,10 +16,8 @@ import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.time.withTimeoutOrNull import kotlinx.coroutines.withTimeoutOrNull import kotlinx.serialization.json.JsonArray -import moe.fuqiuluo.proto.protobufOf import moe.fuqiuluo.shamrock.helper.ContactHelper import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.LogCenter @@ -174,22 +172,36 @@ internal object MsgSvc: BaseSvc() { chatType: Int, peedId: String, message: JsonArray, - fromId: String = peedId - ): Pair { + fromId: String = peedId, + retryCnt: Int = 3 + ): Result> { //LogCenter.log(message.toString(), Level.ERROR) //callback.msgHash = result.second 什么垃圾代码,万一cb比你快,你不就寄了? // 主动临时消息 - when(chatType) { + when (chatType) { MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> { prepareTempChatFromGroup(fromId, peedId).onFailure { LogCenter.log("主动临时消息,创建临时会话失败。", Level.ERROR) - return -1L to 0 + return Result.failure(Exception("主动临时消息,创建临时会话失败。")) } } } - - return MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, MessageCallback(peedId, 0), fromId) + val result = MessageHelper.sendMessageWithoutMsgId( + chatType, + peedId, + message, + fromId, + MessageCallback(peedId, 0) + ) + return if (result.isFailure && retryCnt > 0) { + // 可能网络问题出现红色感叹号,重试 + // 例如 rich media transfer failed + delay(100) + sendToAio(chatType, peedId, message, fromId, retryCnt - 1) + } else { + result + } } suspend fun getMultiMsg(resId: String): Result> { diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt index 9b12d6f..75393e1 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/helper/MessageHelper.kt @@ -6,6 +6,10 @@ import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback import com.tencent.qqnt.kernel.nativeinterface.MsgConstant import com.tencent.qqnt.kernel.nativeinterface.MsgElement import com.tencent.qqnt.msg.api.IMsgService +import kotlinx.coroutines.DelicateCoroutinesApi +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeoutOrNull import kotlinx.serialization.json.JsonArray import kotlinx.serialization.json.JsonElement import kotlinx.serialization.json.JsonObject @@ -20,6 +24,8 @@ import moe.fuqiuluo.shamrock.tools.asJsonObjectOrNull import moe.fuqiuluo.shamrock.tools.asString import moe.fuqiuluo.shamrock.tools.json import moe.fuqiuluo.shamrock.tools.jsonArray +import kotlin.coroutines.resume +import kotlin.coroutines.suspendCoroutine import kotlin.math.abs internal object MessageHelper { @@ -36,31 +42,62 @@ internal object MessageHelper { }.second.filter { it.elementType != -1 } as ArrayList - return sendMessageWithoutMsgId(chatType, peerId, msg, callback, fromId) + return sendMessageWithoutMsgId(chatType, peerId, msg, fromId, callback) } + @OptIn(DelicateCoroutinesApi::class) suspend fun sendMessageWithoutMsgId( chatType: Int, peerId: String, message: JsonArray, - callback: IOperateCallback, - fromId: String = peerId - ): Pair { + fromId: String = peerId, + callback: IOperateCallback + ): Result> { val uniseq = generateMsgId(chatType) val msg = messageArrayToMessageElements(chatType, uniseq.second, peerId, message).also { if (it.second.isEmpty() && !it.first) error("消息合成失败,请查看日志或者检查输入。") }.second.filter { it.elementType != -1 } as ArrayList - return sendMessageWithoutMsgId(chatType, peerId, msg, callback, fromId) + val totalSize = msg.filter { + it.elementType == MsgConstant.KELEMTYPEPIC || + it.elementType == MsgConstant.KELEMTYPEPTT || + it.elementType == MsgConstant.KELEMTYPEVIDEO + }.map { + (it.picElement?.fileSize ?: 0) + (it.pttElement?.fileSize + ?: 0) + (it.videoElement?.fileSize ?: 0) + }.reduceOrNull { a, b -> a + b } ?: 0 + + val estimateTime = (totalSize / (300 * 1024)) * 1000 + 5000 + lateinit var sendResultPair: Pair + val sendRet = withTimeoutOrNull>(estimateTime) { + suspendCoroutine { + GlobalScope.launch { + sendResultPair = sendMessageWithoutMsgId( + chatType, + peerId, + msg, + fromId + ) { code, message -> + callback.onResult(code, message) + it.resume(code to message) + } + } + } + } + if (sendRet?.first != 0) { + return Result.failure(Exception(sendRet?.second ?: "发送消息超时")) + } + return Result.success(sendResultPair) +// return sendMessageWithoutMsgId(chatType, peerId, msg, fromId, callback) } suspend fun sendMessageWithoutMsgId( chatType: Int, peerId: String, message: ArrayList, - callback: IOperateCallback, - fromId: String = peerId + fromId: String = peerId, + callback: IOperateCallback ): Pair { return sendMessageWithoutMsgId(generateContact(chatType, peerId, fromId), message, callback) } diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt index 5ac060e..80965f6 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/SendMessage.kt @@ -92,12 +92,16 @@ internal object SendMessage: IActionHandler() { MsgSvc.sendToAio(chatType, peerId, msg, fromId = fromId) } } - if (result.first <= 0) { + if (result.isFailure) { + return logic(result.exceptionOrNull()?.message ?: "", echo) + } + val pair = result.getOrNull() ?: Pair(0L, 0) + if (pair.first <= 0) { return logic("send message failed", echo = echo) } return ok(MessageResult( - msgId = result.second, - time = (result.first * 0.001).toLong() + msgId = pair.second, + time = (pair.first * 0.001).toLong() ), echo = echo) } @@ -109,12 +113,16 @@ internal object SendMessage: IActionHandler() { // return logic("contact is not found", echo = echo) //} val result = MsgSvc.sendToAio(chatType, peerId, message, fromId = fromId) - if (result.first <= 0) { + if (result.isFailure) { + return logic(result.exceptionOrNull()?.message ?: "", echo) + } + val pair = result.getOrNull() ?: Pair(0L, 0) + if (pair.first <= 0) { return logic("send message failed", echo = echo) } return ok(MessageResult( - msgId = result.second, - time = (result.first * 0.001).toLong() + msgId = pair.second, + time = (pair.first * 0.001).toLong() ), echo) }