ShamrockPublic: アクティブな一時チャットを許可する

Signed-off-by: WhiteChi <whitechi73@outlook.com>
This commit is contained in:
WhiteChi 2023-11-03 15:12:06 +08:00
parent c30e3db1a1
commit 259de3d3aa
10 changed files with 122 additions and 24 deletions

View File

@ -0,0 +1,28 @@
package com.tencent.mobileqq.troop.api;
import mqq.app.api.IRuntimeService;
import com.tencent.mobileqq.data.troop.TroopMemberInfo;
public interface ITroopMemberNameService extends IRuntimeService {
String getTroopMemberColorNick(String str, String str2);
String getTroopMemberName(TroopMemberInfo troopMemberInfo);
String getTroopMemberName(String str, String str2);
String getTroopMemberName(String str, String str2, String str3, String str4);
String getTroopMemberName(String str, String str2, boolean z, boolean z2);
//void getTroopMemberNameAsync(String str, String str2, a aVar);
String getTroopMemberNameInUI(String str, String str2);
String getTroopMemberNameRemarkFirst(String str, String str2);
String getTroopMemberNameWithoutRemark(String str, String str2);
String getTroopMemberNick(String str, String str2);
String getTroopMemberNickByTroopCode(String str, String str2);
}

View File

@ -1,7 +1,9 @@
package com.tencent.qqnt.kernel.api.impl;
import com.tencent.qqnt.kernel.nativeinterface.IKernelMsgListener;
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback;
import com.tencent.qqnt.kernel.nativeinterface.RichMediaFilePathInfo;
import com.tencent.qqnt.kernel.nativeinterface.TempChatPrepareInfo;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -18,4 +20,8 @@ public class MsgService {
public String getRichMediaFilePathForMobileQQSend(@NotNull RichMediaFilePathInfo richMediaFilePathInfo) {
return null;
}
public void prepareTempChat(TempChatPrepareInfo tempChatPrepareInfo, IOperateCallback cb) {
}
}

View File

@ -56,20 +56,14 @@ public final class TempChatPrepareInfo {
return "TempChatPrepareInfo{chatType=" + this.chatType + ",peerUid=" + this.peerUid + ",peerNickname=" + this.peerNickname + ",fromGroupCode=" + this.fromGroupCode + ",sig=" + this.sig + ",selfUid=" + this.selfUid + ",selfPhone=" + this.selfPhone + ",gameSession=" + this.gameSession + ",}";
}
public TempChatPrepareInfo(int i2, String str, String str2, String str3, byte[] bArr, String str4, String str5, TempChatGameSession tempChatGameSession) {
this.peerUid = "";
this.peerNickname = "";
this.fromGroupCode = "";
this.sig = new byte[0];
this.selfUid = "";
this.selfPhone = "";
this.chatType = i2;
this.peerUid = str;
this.peerNickname = str2;
this.fromGroupCode = str3;
this.sig = bArr;
this.selfUid = str4;
this.selfPhone = str5;
this.gameSession = tempChatGameSession;
public TempChatPrepareInfo(int chatType, String peerId, String nickName, String fromGroup, byte[] sig, String selfUid, String selfPhone, TempChatGameSession session) {
this.chatType = chatType;
this.peerUid = peerId;
this.peerNickname = nickName;
this.fromGroupCode = fromGroup;
this.sig = sig;
this.selfUid = selfUid;
this.selfPhone = selfPhone;
this.gameSession = session;
}
}

View File

@ -81,6 +81,10 @@ public abstract class AppRuntime {
return !"0".equals(getCurrentAccountUin()) ? getCurrentAccountUin() : "";
}
public String getCurrentUid() {
return "";
}
public long getLongAccountUin() {
return 0;
}

View File

@ -1,15 +1,24 @@
package moe.fuqiuluo.qqinterface.servlet
import com.tencent.mobileqq.qroute.QRoute
import com.tencent.mobileqq.troop.api.ITroopMemberNameService
import com.tencent.qqnt.kernel.api.IKernelService
import com.tencent.qqnt.kernel.nativeinterface.IOperateCallback
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import com.tencent.qqnt.kernel.nativeinterface.TempChatGameSession
import com.tencent.qqnt.kernel.nativeinterface.TempChatPrepareInfo
import com.tencent.qqnt.msg.api.IMsgService
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.json.JsonArray
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.helper.ContactHelper
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.MessageHelper
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.fuqiuluo.shamrock.xposed.helper.msgService
import kotlin.coroutines.resume
import kotlin.coroutines.suspendCoroutine
@ -18,6 +27,27 @@ internal object MsgSvc: BaseSvc() {
return Result.failure(Exception("Not implemented"))
}
suspend fun prepareTempChatFromGroup(
groupId: String,
peerId: String
): Result<Unit> {
LogCenter.log("主动临时消息,创建临时会话。", Level.INFO)
val msgService = app.getRuntimeService(IKernelService::class.java, "all").msgService
?: return Result.failure(Exception("获取消息服务失败"))
msgService.prepareTempChat(TempChatPrepareInfo(
MsgConstant.KCHATTYPETEMPC2CFROMGROUP,
ContactHelper.getUidByUinAsync(peerId = peerId.toLong()),
app.getRuntimeService(ITroopMemberNameService::class.java, "all")
.getTroopMemberNameRemarkFirst(groupId, peerId),
groupId, EMPTY_BYTE_ARRAY, app.currentUid, "", TempChatGameSession()
)) { code, reason ->
if (code != 0) {
LogCenter.log("临时会话创建失败: $code, $reason", Level.ERROR)
}
}
return Result.success(Unit)
}
/**
* 正常获取
*/
@ -139,6 +169,17 @@ internal object MsgSvc: BaseSvc() {
): Pair<Long, Int> {
//LogCenter.log(message.toString(), Level.ERROR)
//callback.msgHash = result.second 什么垃圾代码万一cb比你快你不就寄了
// 主动临时消息
when(chatType) {
MsgConstant.KCHATTYPETEMPC2CFROMGROUP -> {
prepareTempChatFromGroup(fromId, peedId).onFailure {
LogCenter.log("主动临时消息,创建临时会话失败。", Level.ERROR)
return -1L to 0
}
}
}
return MessageHelper.sendMessageWithoutMsgId(chatType, peedId, message, MessageCallback(peedId, 0), fromId)
}

View File

@ -44,6 +44,7 @@ internal object MessageHelper {
if(callback is MsgSvc.MessageCallback) {
callback.msgHash = uniseq.first
}
service.sendMsg(
generateContact(chatType, peerId, fromId),
uniseq.second,

View File

@ -81,10 +81,13 @@ internal object SendMessage: IActionHandler() {
MsgSvc.sendToAio(chatType, peerId, msg, fromId = fromId)
}
}
if (result.first <= 0) {
return logic("send message failed", echo = echo)
}
return ok(MessageResult(
msgId = result.second,
time = result.first * 0.001
), echo)
), echo = echo)
}
// 消息段格式消息
@ -95,6 +98,9 @@ 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) {
return logic("send message failed", echo = echo)
}
return ok(MessageResult(
msgId = result.second,
time = result.first * 0.001

View File

@ -12,10 +12,23 @@ internal object SendPrivateMessage: IActionHandler() {
return if (session.isString("message")) {
val autoEscape = session.getBooleanOrDefault("auto_escape", false)
val message = session.getString("message")
SendMessage(chatTYpe, userId, message, autoEscape, echo = session.echo, fromId = groupId ?: userId)
SendMessage.invoke(
chatType = chatTYpe,
peerId = userId,
message = message,
autoEscape = autoEscape,
echo = session.echo,
fromId = groupId ?: userId
)
} else {
val message = session.getArray("message")
SendMessage(chatTYpe, userId, message, session.echo, fromId = groupId ?: userId)
SendMessage(
chatType = chatTYpe,
peerId = userId,
message = message,
echo = session.echo,
fromId = groupId ?: userId
)
}
}

View File

@ -42,13 +42,13 @@ fun Routing.messageAction() {
}
post {
val msgType = fetchPostOrThrow("message_type")
val peerIdKey = if(msgType == "group") "group_id" else "user_id"
val chatType = MessageHelper.obtainMessageTypeByDetailType(msgType)
val peerId = fetchPostOrThrow(if(msgType == "group") "group_id" else "user_id")
call.respondText(if (isJsonData() && !isJsonString("message")) {
SendMessage(chatType, fetchPostOrThrow(peerIdKey), fetchPostJsonArray("message"))
SendMessage(chatType, peerId, fetchPostJsonArray("message"))
} else {
val autoEscape = fetchPostOrNull("auto_escape")?.toBooleanStrict() ?: false
SendMessage(chatType, fetchPostOrThrow(peerIdKey), fetchPostOrThrow("message"), autoEscape)
SendMessage(chatType, peerId, fetchPostOrThrow("message"), autoEscape)
})
}
}

View File

@ -25,6 +25,8 @@ import io.ktor.http.parseUrlEncodedParameters
import io.ktor.server.request.httpMethod
import io.ktor.server.routing.route
import kotlinx.serialization.json.JsonElement
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.entries.CommonResult
import moe.fuqiuluo.shamrock.remote.entries.EmptyObject
import moe.fuqiuluo.shamrock.remote.entries.Status
@ -88,7 +90,7 @@ suspend fun ApplicationCall.fetchPostOrThrow(key: String): String {
}
fun ApplicationCall.isJsonData(): Boolean {
return ContentType.Application.Json == request.contentType()
return ContentType.Application.Json == request.contentType() || ContentType.Application.ProblemJson == request.contentType()
}
suspend fun ApplicationCall.fetchPostOrNull(key: String): String? {
@ -102,6 +104,7 @@ suspend fun ApplicationCall.fetchPostOrNull(key: String): String? {
if (isJsonData()) {
Json.parseToJsonElement(receiveText()).jsonObject.also {
attributes.put(jsonKey, it)
attributes.put(isJsonKey, true)
}[key].asStringOrNull
} else if (
ContentType.Application.FormUrlEncoded == request.contentType()
@ -113,7 +116,7 @@ suspend fun ApplicationCall.fetchPostOrNull(key: String): String? {
receiveTextAsUnknown(key)
}
}.getOrElse {
receiveTextAsUnknown(key)
throw IllegalArgumentException("JSON数据格式不合法")
}
}
@ -177,6 +180,7 @@ suspend fun PipelineContext<Unit, ApplicationCall>.isJsonString(key: String): Bo
} else {
Json.parseToJsonElement(call.receiveText()).jsonObject.also {
call.attributes.put(jsonKey, it)
call.attributes.put(isJsonKey, true)
}
}
return data[key] is JsonPrimitive
@ -245,6 +249,7 @@ suspend fun PipelineContext<Unit, ApplicationCall>.fetchPostJsonArray(key: Strin
} else {
Json.parseToJsonElement(call.receiveText()).jsonObject.also {
call.attributes.put(jsonKey, it)
call.attributes.put(isJsonKey, true)
}
}
return data[key].asJsonArray