196 lines
8.2 KiB
Kotlin

@file:OptIn(ExperimentalSerializationApi::class)
package moe.fuqiuluo.qqinterface.servlet
import com.tencent.mobileqq.qqguildsdk.api.IGPSService
import com.tencent.qqnt.kernel.nativeinterface.GProRoleMemberList
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.GuildInfo
import moe.fuqiuluo.qqinterface.servlet.structures.GuildStatus
import moe.fuqiuluo.qqinterface.servlet.structures.SlowModeInfo
import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.tools.slice
import moe.fuqiuluo.shamrock.utils.PlatformUtils
import moe.fuqiuluo.shamrock.xposed.helper.NTServiceFetcher
import moe.whitechi73.protobuf.oidb.cmd0xf88.GProFilter
import moe.whitechi73.protobuf.oidb.cmd0xf88.GProUserInfo
import moe.whitechi73.protobuf.oidb.cmd0xf88.Oidb0xf88Req
import moe.whitechi73.protobuf.oidb.cmd0xf88.Oidb0xf88Rsp
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57Filter
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57GuildInfo
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57MetaInfo
import moe.whitechi73.protobuf.oidb.cmx0xf57.Oidb0xf57Req
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
internal object GProSvc: BaseSvc() {
fun getSelfTinyId(): ULong {
val service = app.getRuntimeService(IGPSService::class.java, "all")
return service.selfTinyId.toULong()
}
suspend fun getGuildInfo(guildId: ULong): Result<Oidb0xf57MetaInfo> {
val respBuffer = sendOidbAW("OidbSvcTrpcTcp.0xf57_9", 0xf57, 9, ProtoBuf.encodeToByteArray(Oidb0xf57Req(
filter = Oidb0xf57Filter(
u1 = Oidb0xf57U1(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u),
u2 = Oidb0xf57U2(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u)
),
guildInfo = Oidb0xf57GuildInfo(guildId = guildId)
)))
val body = oidb_sso.OIDBSSOPkg()
if (respBuffer == null) {
return Result.failure(Exception("unable to send packet"))
}
body.mergeFrom(respBuffer.slice(4))
return runCatching {
ProtoBuf.decodeFromByteArray<Oidb0xf57Rsp>(
body.bytes_bodybuffer.get().toByteArray()
).metaInfo
}
}
fun getChannelList(guildId: ULong, refresh: Boolean = false): Result<ArrayList<GProChannelInfo>> {
if (refresh) {
refreshGuildInfo(guildId)
}
val result = arrayListOf<GProChannelInfo>()
app.getRuntimeService(IGPSService::class.java, "all").getChannelList(guildId.toString()).forEach {
result.add(GProChannelInfo(
ownerGuildId = guildId,
guildId = it.guildId,
channelId = it.channelUin.toLong(),
channelUin = it.channelUin.toLong(),
channelName = it.channelName ?: "",
channelType = it.type,
createTime = it.createTime,
creatorTinyId = it.creatorId.toLong(),
talkPermission = it.talkPermission,
visibleType = it.visibleType,
currentSlowMode = it.slowModeKey,
slowModes = it.gProSlowModeInfoList.map {
SlowModeInfo(it.slowModeKey, it.slowModeText, it.speakFrequency, it.slowModeCircle)
},
appIconUrl = it.iconUrl,
jumpType = it.appChannelJumpType,
jumpSwitch = it.jumpSwitch,
jumpUrl = it.appChannelJumpUrl,
categoryId = it.categoryId,
myTalkPermission = it.myTalkPermissionType,
maxMemberCount = it.channelMemberMax
))
}
return Result.success(result)
}
fun refreshGuildInfo(guildId: ULong) {
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
kernelGProService.refreshGuildInfo(guildId.toLong(), true, 1)
}
suspend fun getGuildMemberList(guildId: ULong): Result<List<GProRoleMemberList>> {
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
//kernelGProService.fetchMemberListWithRole()
return Result.failure(Exception("todo"))
}
suspend fun getSelfGuildInfo(): Result<GProUserInfo> {
val selfTinyId = getSelfTinyId()
return getUserGuildInfo(0u, selfTinyId)
}
suspend fun getUserGuildInfo(
guildId: ULong,
memberTinyId: ULong
): Result<GProUserInfo> {
val respBuffer = sendOidbAW("OidbSvcTrpcTcp.0xf88_1", 0xf88, 1, ProtoBuf.encodeToByteArray(Oidb0xf88Req(
filter = GProFilter(1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u, 1u),
memberId = 0uL,
tinyId = memberTinyId,
guildId = guildId
)))
val body = oidb_sso.OIDBSSOPkg()
if (respBuffer == null) {
return Result.failure(Exception("unable to send packet"))
}
body.mergeFrom(respBuffer.slice(4))
return runCatching {
ProtoBuf.decodeFromByteArray<Oidb0xf88Rsp>(
body.bytes_bodybuffer.get().toByteArray()
).userInfo!!
}
}
private fun getGuildListByOldApi(result: ArrayList<GuildInfo>) {
app.getRuntimeService(IGPSService::class.java, "all").guildList?.forEach {
result.add(GuildInfo(
guildId = it.guildID.toLong(),
guildName = it.guildName ?: "",
guildDisplayId = it.guildNumber ?: "",
profile = it.profile ?: "",
status = GuildStatus(
isEnable = !it.isFrozen && !it.isBanned,
isBanned = it.isBanned,
isFrozen = it.isFrozen
),
ownerId = 0,
shutUpTime = it.shutUpExpireTime,
allowSearch = it.allowSearch
))
}
}
private fun getGuildListByNt(result: ArrayList<GuildInfo>) {
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
kernelGProService.guildListFromCache.forEach {
if (it.result != 0) return@forEach
val guildInfo = it.guildInfo
result.add(GuildInfo(
guildId = it.guildId,
guildName = guildInfo.guildName ?: "",
guildDisplayId = guildInfo.guildNumber ?: "",
profile = guildInfo.profile ?: "",
status = GuildStatus(
isEnable = guildInfo.guildStatus?.isEnable == 1,
isBanned = guildInfo.guildStatus?.isBanned == 1,
isFrozen = guildInfo.guildStatus?.isFrozen == 1
),
ownerId = guildInfo.ownerTinyid,
shutUpTime = guildInfo.shutupExpireTime,
allowSearch = guildInfo.allowSearch == 1
))
}
}
fun getGuildList(refresh: Boolean = false, forceOldApi: Boolean): ArrayList<GuildInfo> {
val kernelGProService = NTServiceFetcher.kernelService.wrapperSession.guildService
if (refresh) {
kernelGProService.refreshGuildList(true)
kernelGProService.guildListFromCache.forEach {
refreshGuildInfo(it.guildId.toULong())
}
}
val result = arrayListOf<GuildInfo>()
if (PlatformUtils.getQQVersionCode() < PlatformUtils.QQ_9_0_8_VER || forceOldApi) {
getGuildListByOldApi(result)
} else {
runCatching {
getGuildListByNt(result)
}.onFailure {
LogCenter.log("GetGuildListByNt failed: ${it.stackTraceToString()}", Level.ERROR)
getGuildListByOldApi(result) // 防止QQ更新API导致无法获取
}
}
return result
}
}