Shamrock: support /get_guild_member_list

This commit is contained in:
白池 2024-02-01 15:42:24 +08:00
parent e629981218
commit a22dc50f14
6 changed files with 123 additions and 14 deletions

View File

@ -24,8 +24,6 @@ public final class GProRoleMemberList {
}
public GProRoleMemberList(GProGuildRole gProGuildRole, ArrayList<GProUser> arrayList) {
this.role = new GProGuildRole();
this.members = new ArrayList<>();
this.role = gProGuildRole;
this.members = arrayList;
}

View File

@ -3,5 +3,5 @@ package com.tencent.qqnt.kernel.nativeinterface;
import java.util.ArrayList;
public interface IGProFetchMemberListWithRoleCallback {
void onFetchMemberListWithRoleCallback(int result, String reason, boolean finish, long nextIndex, long nextRoleIdIndex, boolean isSmallGuild, int u, ArrayList<GProRoleMemberList> roleList);
void onFetchMemberListWithRoleCallback(int result, String reason, boolean finish, long nextIndex, long nextRoleIdIndex, boolean isSmallGuild, int seq, ArrayList<GProRoleMemberList> roleList);
}

View File

@ -4,11 +4,15 @@ package moe.fuqiuluo.qqinterface.servlet
import com.tencent.mobileqq.qqguildsdk.api.IGPSService
import com.tencent.qqnt.kernel.nativeinterface.GProRoleMemberList
import com.tencent.qqnt.kernel.nativeinterface.IGProFetchMemberListWithRoleCallback
import kotlinx.coroutines.suspendCancellableCoroutine
import kotlinx.coroutines.withTimeoutOrNull
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import kotlinx.serialization.protobuf.ProtoBuf
import moe.fuqiuluo.qqinterface.servlet.structures.GProChannelInfo
import moe.fuqiuluo.qqinterface.servlet.structures.GetGuildMemberListNextToken
import moe.fuqiuluo.qqinterface.servlet.structures.GuildInfo
import moe.fuqiuluo.qqinterface.servlet.structures.GuildStatus
import moe.fuqiuluo.qqinterface.servlet.structures.SlowModeInfo
@ -29,6 +33,7 @@ import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57Rsp
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57U1
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57U2
import tencent.im.oidb.oidb_sso
import kotlin.coroutines.resume
internal object GProSvc: BaseSvc() {
fun getSelfTinyId(): ULong {
@ -94,13 +99,40 @@ internal object GProSvc: BaseSvc() {
kernelGProService.refreshGuildInfo(guildId.toLong(), true, 1)
}
suspend fun getGuildMemberList(guildId: ULong): Result<List<GProRoleMemberList>> {
suspend fun getGuildMemberList(
guildId: ULong,
startIndex: Long = 0,
roleIndex: Long = 1,
count: Int = 50,
fetchAll: Boolean = false,
result: ArrayList<GProRoleMemberList> = arrayListOf()
): Result<Pair<GetGuildMemberListNextToken, ArrayList<GProRoleMemberList>>> {
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
//kernelGProService.fetchMemberListWithRole()
val fetchGuildMemberListResult: Pair<GetGuildMemberListNextToken, ArrayList<GProRoleMemberList>> = (withTimeoutOrNull(5000) {
suspendCancellableCoroutine {
kernelGProService.fetchMemberListWithRole(guildId.toLong(), 0, startIndex, roleIndex, count, 0) { code, reason, finish, nextIndex, nextRoleIdIndex, _, seq, roleList ->
if (code == 0) {
it.resume(GetGuildMemberListNextToken(nextIndex, nextRoleIdIndex, seq, finish) to roleList)
} else {
LogCenter.log("fetchMemberListWithRole failed: $code($reason)", Level.WARN)
it.resume(null)
}
}
}
}) ?: return Result.failure(Exception("unable to fetch guild member list"))
return Result.failure(Exception("todo"))
val nextToken = fetchGuildMemberListResult.first
val roleList = fetchGuildMemberListResult.second
result.addAll(roleList)
return if (fetchAll) {
if (!fetchGuildMemberListResult.first.finish) {
getGuildMemberList(guildId, nextToken.startIndex, nextToken.roleIndex, count, true, result)
} else {
Result.success(nextToken.copy(finish = true) to result)
}
} else {
Result.success(nextToken to result)
}
}
suspend fun getSelfGuildInfo(): Result<GProUserInfo> {

View File

@ -51,4 +51,28 @@ data class SlowModeInfo(
@SerialName("slow_mode_text") val slowModeText: String,
@SerialName("speak_frequency") val speakFrequency: Int,
@SerialName("slow_mode_circle") val slowModeCircle: Int
)
)
@Serializable
data class GetGuildMemberListNextToken(
@SerialName("start_index") val startIndex: Long,
@SerialName("role_index") val roleIndex: Long,
@SerialName("seq") val seq: Int,
@SerialName("finish") val finish: Boolean
)
@Serializable
data class GuildMemberInfo(
@SerialName("tiny_id") val tinyId: Long,
@SerialName("title") val title: String,
@SerialName("nickname") val nickname: String,
@SerialName("role_id") val roleId: Long,
@SerialName("role_name") val roleName: String,
@SerialName("role_color") val roleColor: Long,
@SerialName("join_time") val joinTime: Long,
@SerialName("robot_type") val robotType: Int,
@SerialName("type") val type: Int,
@SerialName("in_black") val inBlack: Boolean,
@SerialName("platform") val platform: Int,
)

View File

@ -1,23 +1,77 @@
@file:OptIn(ExperimentalSerializationApi::class)
package moe.fuqiuluo.shamrock.remote.action.handlers
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromByteArray
import kotlinx.serialization.encodeToByteArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.protobuf.ProtoBuf
import moe.fuqiuluo.qqinterface.servlet.GProSvc
import moe.fuqiuluo.qqinterface.servlet.structures.GetGuildMemberListNextToken
import moe.fuqiuluo.qqinterface.servlet.structures.GuildMemberInfo
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.remote.action.ActionSession
import moe.fuqiuluo.shamrock.remote.action.IActionHandler
import moe.fuqiuluo.shamrock.tools.EmptyJsonString
import moe.fuqiuluo.shamrock.tools.hex2ByteArray
import moe.fuqiuluo.shamrock.tools.toHexString
import moe.fuqiuluo.symbols.OneBotHandler
@OneBotHandler("get_guild_member_list")
internal object GetGuildMemberList: IActionHandler() {
override suspend fun internalHandle(session: ActionSession): String {
val guildId = session.getString("guild_id")
return invoke(guildId.toULong(), session.echo)
val all = session.getBooleanOrDefault("all", false)
return invoke(guildId.toULong(), all, session.getStringOrNull("next_token") ?: "", session.echo)
}
suspend operator fun invoke(guildId: ULong, echo: JsonElement = EmptyJsonString): String {
GProSvc.getGuildMemberList(guildId)
return ""
suspend operator fun invoke(guildId: ULong, all: Boolean, nextTokenStr: String, echo: JsonElement = EmptyJsonString): String {
val curNextToken = if (nextTokenStr.isEmpty()) null else ProtoBuf.decodeFromByteArray<GetGuildMemberListNextToken>(nextTokenStr.hex2ByteArray())
val result = GProSvc.getGuildMemberList(
guildId = guildId,
fetchAll = all,
startIndex = curNextToken?.startIndex ?: 0,
roleIndex = curNextToken?.roleIndex ?: 1,
count = 50
)
result.onFailure {
return error(it.message ?: "unable to fetch guild member list", echo)
}
val nextToken = result.getOrThrow().first
val members = arrayListOf<GuildMemberInfo>()
result.getOrThrow().second.forEach {
it.members.forEach { user ->
members.add(GuildMemberInfo(
tinyId = user.tinyId,
title = user.memberName,
nickname = user.nickName,
roleId = user.roleManagementTag.roleId,
roleName = user.roleManagementTag.tagName,
roleColor = user.roleManagementTag.color,
joinTime = user.joinTime,
robotType = user.robotType,
type = user.type,
inBlack = user.inBlack,
platform = user.platform
))
}
}
return ok(GetGuildMemberListResult(
members = members,
finish = nextToken.finish,
nextToken = ProtoBuf.encodeToByteArray(nextToken).toHexString(),
))
}
override val requiredParams: Array<String> = arrayOf("guild_id")
@Serializable
data class GetGuildMemberListResult(
@SerialName("members") val members: List<GuildMemberInfo>,
@SerialName("next_token") val nextToken: String,
@SerialName("finished") val finish: Boolean
)
}

View File

@ -26,7 +26,8 @@ fun Routing.guildAction() {
getOrPost("/get_guild_member_list") {
val guildId = fetchOrThrow("guild_id")
call.respondText(GetGuildMemberList(guildId.toULong()), ContentType.Application.Json)
val all = fetchGetOrNull("all")?.toBoolean() ?: false
call.respondText(GetGuildMemberList(guildId.toULong(), all, fetchOrNull("next_token") ?: ""), ContentType.Application.Json)
}
getOrPost("/get_guild_meta_by_guest") {