From 7952453137174380ff4e16d9542e6d6afef86ad6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=99=BD=E6=B1=A0?= <98259561+whitechi73@users.noreply.github.com> Date: Sat, 3 Feb 2024 05:45:25 +0800 Subject: [PATCH] `Shamrock`: support `/get_guild_roles` --- ...FetchChannelInvisibleRoleListCallback.java | 7 +++ ...oFetchChannelLiveableRoleListCallback.java | 7 +++ .../IGProFetchRoleListPermissionCallback.java | 7 +++ .../IGProFetchRolePermissionCallback.java | 7 +++ .../nativeinterface/IKernelGuildService.java | 15 ++++- .../fuqiuluo/qqinterface/servlet/BaseSvc.kt | 24 +++++++- .../fuqiuluo/qqinterface/servlet/GProSvc.kt | 12 ++++ .../remote/action/handlers/GetGuildRoles.kt | 61 +++++++++++++++++++ .../shamrock/remote/api/GuildAction.kt | 14 +++++ 9 files changed, 149 insertions(+), 5 deletions(-) create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelInvisibleRoleListCallback.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelLiveableRoleListCallback.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRoleListPermissionCallback.java create mode 100644 qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRolePermissionCallback.java create mode 100644 xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGuildRoles.kt diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelInvisibleRoleListCallback.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelInvisibleRoleListCallback.java new file mode 100644 index 00000000..8ccb5057 --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelInvisibleRoleListCallback.java @@ -0,0 +1,7 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +import java.util.ArrayList; + +public interface IGProFetchChannelInvisibleRoleListCallback { + void onFetchChannelInvisibleRoleList(int code, String reason, ArrayList roles); +} \ No newline at end of file diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelLiveableRoleListCallback.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelLiveableRoleListCallback.java new file mode 100644 index 00000000..5fe4352f --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchChannelLiveableRoleListCallback.java @@ -0,0 +1,7 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +import java.util.ArrayList; + +public interface IGProFetchChannelLiveableRoleListCallback { + void onFetchChannelLiveableRoleList(int code, String reason, int seq, ArrayList roles); +} \ No newline at end of file diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRoleListPermissionCallback.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRoleListPermissionCallback.java new file mode 100644 index 00000000..da23732e --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRoleListPermissionCallback.java @@ -0,0 +1,7 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +import java.util.ArrayList; + +public interface IGProFetchRoleListPermissionCallback { + void onFetchRoleListPermissionCallback(int code, String msg, ArrayList roles, ArrayList lvRoles, ArrayList myRoles, long unused); +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRolePermissionCallback.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRolePermissionCallback.java new file mode 100644 index 00000000..a590914d --- /dev/null +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IGProFetchRolePermissionCallback.java @@ -0,0 +1,7 @@ +package com.tencent.qqnt.kernel.nativeinterface; + +import java.util.ArrayList; + +public interface IGProFetchRolePermissionCallback { + void onFetchRolePermissionCallback(int code, String msg, GProGuildRole role, GProRolePermission permission, ArrayList permissionDescs, ArrayList permissionCategories); +} diff --git a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IKernelGuildService.java b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IKernelGuildService.java index cf6df795..22ebca62 100644 --- a/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IKernelGuildService.java +++ b/qqinterface/src/main/java/com/tencent/qqnt/kernel/nativeinterface/IKernelGuildService.java @@ -32,7 +32,7 @@ public interface IKernelGuildService { //void fetchGuestGuildInfoWithChannelList(String guildId, String str2, int i2, int seq, String str3, // IGProFetchGuestGuildInfoWithChannelListCallback iGProFetchGuestGuildInfoWithChannelListCallback); - GProGuild getGuildInfoFromCache(long j2); + GProGuild getGuildInfoFromCache(long guildId); // 第一次请求: startIndex = 0 , roleIdIndex = 2 void fetchMemberListWithRole(long guildId, long channelId, long startIndex, long roleIndex, int count, int seq, IGProFetchMemberListWithRoleCallback cb); @@ -41,14 +41,23 @@ public interface IKernelGuildService { void refreshGuildInfoOnly(long j2, boolean z, int i2); - void fetchMemberRoles(long guildId, long channelId, long tinyId, int seq, IGProFetchMemberRolesCallback cb); - void refreshGuildUserProfileInfo(long guildId, long tinyId, int seq); void fetchUserInfo(long guildId, long channelId, ArrayList tinyIdList, int seq, IGProGetUserInfoCallback cb); + @Deprecated(since = "QQ新版本不支持创建话题子频道") void fetchTopFeeds(long guildId, long channelId, IGProFetchTopFeedsCallback cb); + void fetchChannelInvisibleRoleList(long guildId, long channelId, IGProFetchChannelInvisibleRoleListCallback cb); + + void fetchChannelLiveableRoleList(long guildId, long channelId, IGProFetchChannelLiveableRoleListCallback cb); + + void fetchMemberRoles(long guildId, long channelId, long tinyId, int seq, IGProFetchMemberRolesCallback cb); + + void fetchRoleListWithPermission(long guildId, int seq, IGProFetchRoleListPermissionCallback cb); + + void fetchRoleWithPermission(long guildId, long roleId, int seq, IGProFetchRolePermissionCallback cb); + GProSimpleProfile getSimpleProfile(long guildId, long tinyId, int seq); GProFaceAuthInfo getFaceAuthInfo(); diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt index a43bd8df..3e35eaff 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/BaseSvc.kt @@ -44,7 +44,7 @@ internal abstract class BaseSvc { suspend fun sendOidbAW(cmd: String, cmdId: Int, serviceId: Int, data: ByteArray, trpc: Boolean = false, timeout: Long = 5000L): ByteArray? { val seq = MsfCore.getNextSeq() - return withTimeoutOrNull(timeout) { + val buffer = withTimeoutOrNull(timeout) { suspendCancellableCoroutine { continuation -> GlobalScope.launch(Dispatchers.Default) { DynamicReceiver.register(IPCRequest(cmd, seq) { @@ -59,6 +59,16 @@ internal abstract class BaseSvc { if (it == null) DynamicReceiver.unregister(seq) }?.copyOf() + try { + if (buffer != null && buffer.size >= 5 && buffer[4] == 120.toByte()) { + val builder = BytePacketBuilder() + val deBuffer = DeflateTools.uncompress(buffer.slice(4)) + builder.writeInt(deBuffer.size) + builder.writeFully(deBuffer) + return builder.build().readBytes() + } + } catch (_: Exception) { } + return buffer } suspend fun sendBufferAW(cmd: String, isPb: Boolean, data: ByteArray, timeout: Long = 5000L): ByteArray? { @@ -141,7 +151,7 @@ internal abstract class BaseSvc { protected suspend fun sendAW(toServiceMsg: ToServiceMsg, timeout: Long = 5000L): ByteArray? { val seq = MsfCore.getNextSeq() - return withTimeoutOrNull(timeout) { + val buffer = withTimeoutOrNull(timeout) { suspendCancellableCoroutine { continuation -> GlobalScope.launch(Dispatchers.Default) { DynamicReceiver.register(IPCRequest(toServiceMsg.serviceCmd, seq) { @@ -155,6 +165,16 @@ internal abstract class BaseSvc { }.also { if (it == null) DynamicReceiver.unregister(seq) }?.copyOf() + try { + if (buffer != null && buffer.size >= 5 && buffer[4] == 120.toByte()) { + val builder = BytePacketBuilder() + val deBuffer = DeflateTools.uncompress(buffer.slice(4)) + builder.writeInt(deBuffer.size) + builder.writeFully(deBuffer) + return builder.build().readBytes() + } + } catch (_: Exception) { } + return buffer } protected fun sendExtra(cmd: String, builder: (Bundle) -> Unit) { diff --git a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GProSvc.kt b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GProSvc.kt index d6643d0c..e0aa48dc 100644 --- a/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GProSvc.kt +++ b/xposed/src/main/java/moe/fuqiuluo/qqinterface/servlet/GProSvc.kt @@ -284,4 +284,16 @@ internal object GProSvc: BaseSvc() { return result } + + suspend fun getGuildRoles(guildId: ULong): Result> { + val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService + val roles: List = withTimeoutOrNull(5000) { + suspendCancellableCoroutine { + kernelGProService.fetchRoleListWithPermission(guildId.toLong(), 1) { code, _, roles, _, _, _ -> + if (code != 0) it.resume(null) else it.resume(roles) + } + } + } ?: return Result.failure(Exception("unable to fetch guild roles")) + return Result.success(roles) + } } \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGuildRoles.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGuildRoles.kt new file mode 100644 index 00000000..70d13b87 --- /dev/null +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/action/handlers/GetGuildRoles.kt @@ -0,0 +1,61 @@ +package moe.fuqiuluo.shamrock.remote.action.handlers + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +import moe.fuqiuluo.qqinterface.servlet.GProSvc +import moe.fuqiuluo.shamrock.remote.action.ActionSession +import moe.fuqiuluo.shamrock.remote.action.IActionHandler +import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberProfile.Permission +import moe.fuqiuluo.shamrock.tools.EmptyJsonString +import moe.fuqiuluo.symbols.OneBotHandler + +@OneBotHandler("get_guild_roles") +internal object GetGuildRoles: IActionHandler() { + override suspend fun internalHandle(session: ActionSession): String { + val guildId = session.getString("guild_id").toULong() + return invoke(guildId, session.echo) + } + + suspend operator fun invoke(guildId: ULong, echo: JsonElement = EmptyJsonString): String { + val result = GProSvc.getGuildRoles(guildId).onFailure { + return error(it.message ?: "unable to fetch guild roles", echo) + }.getOrThrow() + return ok(GetGuildRolesResult(result.map { + GuildRole( + color = it.color, + disabled = it.count <= 0, + independent = it.isChannelRole, + maxCount = it.memberLimit, + memberCount = it.count, + owned = it.bHoist, + roleId = it.roleId, + roleName = it.name, + permission = it.rolePermissions.permissionList.map { + Permission(it.rootId, it.childIds) + }, + ) + }), echo = echo) + } + + override val requiredParams: Array = arrayOf("guild_id") + + @Serializable + data class GetGuildRolesResult( + @SerialName("roles") val roles: List + ) + + @Serializable + data class GuildRole( + @SerialName("argb_color") val color: Long, + @SerialName("disabled") val disabled: Boolean, + @SerialName("independent") val independent: Boolean, + @SerialName("max_count") val maxCount: Int, + @SerialName("member_count") val memberCount: Int, + @SerialName("owned") val owned: Boolean, + @SerialName("role_id") val roleId: Long, + @SerialName("role_name") val roleName: String, + @SerialName("permission") val permission: List, + ) + +} \ No newline at end of file diff --git a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/GuildAction.kt b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/GuildAction.kt index 78c32334..cfc7484e 100644 --- a/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/GuildAction.kt +++ b/xposed/src/main/java/moe/fuqiuluo/shamrock/remote/api/GuildAction.kt @@ -9,10 +9,12 @@ import io.ktor.server.routing.post import io.ktor.server.routing.route import moe.fuqiuluo.shamrock.helper.MessageHelper import moe.fuqiuluo.shamrock.remote.action.handlers.GetGProChannelList +import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildFeeds import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildList import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberList import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMemberProfile import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildMetaByGuest +import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildRoles import moe.fuqiuluo.shamrock.remote.action.handlers.GetGuildServiceProfile import moe.fuqiuluo.shamrock.remote.action.handlers.SendGuildMessage import moe.fuqiuluo.shamrock.remote.action.handlers.SendMessage @@ -109,4 +111,16 @@ fun Routing.guildAction() { }, ContentType.Application.Json) } } + + getOrPost("/get_guild_feeds") { + val guildId = fetchOrThrow("guild_id").toULong() + val channelId = fetchOrNull("channel_id")?.toULong() ?: 0uL + val from = fetchOrNull("from")?.toInt() ?: 0 + call.respondText(GetGuildFeeds(guildId, channelId, from), ContentType.Application.Json) + } + + getOrPost("/get_guild_roles") { + val guildId = fetchOrThrow("guild_id").toULong() + call.respondText(GetGuildRoles(guildId), ContentType.Application.Json) + } } \ No newline at end of file