mirror of
https://github.com/whitechi73/OpenShamrock.git
synced 2024-08-14 13:12:17 +08:00
update kritor
This commit is contained in:
parent
4a396b0935
commit
c014e85faa
@ -37,17 +37,18 @@ android {
|
||||
dependencies {
|
||||
protobuf(files("kritor/protos"))
|
||||
|
||||
implementation("com.google.protobuf:protobuf-java:4.26.0")
|
||||
|
||||
implementation(kotlinx("coroutines-core", "1.8.0"))
|
||||
implementation("com.google.protobuf:protobuf-java:3.25.3")
|
||||
|
||||
implementation(grpc("stub", "1.62.2"))
|
||||
implementation(grpc("kotlin-stub", "1.4.1"))
|
||||
implementation(grpc("protobuf", "1.62.2"))
|
||||
implementation(grpc("kotlin-stub", "1.4.1"))
|
||||
}
|
||||
|
||||
protobuf {
|
||||
protoc {
|
||||
artifact = "com.google.protobuf:protoc:3.25.3"
|
||||
artifact = "com.google.protobuf:protoc:4.26.0"
|
||||
}
|
||||
plugins {
|
||||
create("grpc") {
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 2b29978a5864492267f4afd2b040b890e2f3c182
|
||||
Subproject commit c49df3074cf193cdbdc49c3c29fda66a0d0110e8
|
@ -5,22 +5,9 @@ package moe.fuqiuluo.ksp.impl
|
||||
|
||||
import com.google.devtools.ksp.KspExperimental
|
||||
import com.google.devtools.ksp.getAnnotationsByType
|
||||
import com.google.devtools.ksp.getClassDeclarationByName
|
||||
import com.google.devtools.ksp.getJavaClassByName
|
||||
import com.google.devtools.ksp.getKotlinClassByName
|
||||
import com.google.devtools.ksp.processing.CodeGenerator
|
||||
import com.google.devtools.ksp.processing.Dependencies
|
||||
import com.google.devtools.ksp.processing.KSPLogger
|
||||
import com.google.devtools.ksp.processing.Resolver
|
||||
import com.google.devtools.ksp.processing.SymbolProcessor
|
||||
import com.google.devtools.ksp.processing.*
|
||||
import com.google.devtools.ksp.symbol.KSAnnotated
|
||||
import com.google.devtools.ksp.symbol.KSClassDeclaration
|
||||
import com.google.devtools.ksp.symbol.KSDeclaration
|
||||
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
|
||||
import com.google.devtools.ksp.symbol.KSType
|
||||
import com.google.devtools.ksp.symbol.KSTypeParameter
|
||||
import com.google.devtools.ksp.symbol.Modifier
|
||||
import com.google.devtools.ksp.validate
|
||||
import com.squareup.kotlinpoet.FileSpec
|
||||
import com.squareup.kotlinpoet.FunSpec
|
||||
import com.squareup.kotlinpoet.KModifier
|
||||
@ -67,15 +54,16 @@ class GrpcProcessor(
|
||||
}
|
||||
funcBuilder.addStatement("return EMPTY_BYTE_ARRAY")
|
||||
fileSpec
|
||||
.addStatement("import io.kritor.*")
|
||||
.addStatement("import io.kritor.authentication.*")
|
||||
.addStatement("import io.kritor.core.*")
|
||||
.addStatement("import io.kritor.contact.*")
|
||||
.addStatement("import io.kritor.group.*")
|
||||
.addStatement("import io.kritor.friend.*")
|
||||
.addStatement("import io.kritor.customization.*")
|
||||
.addStatement("import io.kritor.developer.*")
|
||||
.addStatement("import io.kritor.file.*")
|
||||
.addStatement("import io.kritor.friend.*")
|
||||
.addStatement("import io.kritor.group.*")
|
||||
.addStatement("import io.kritor.guild.*")
|
||||
.addStatement("import io.kritor.message.*")
|
||||
.addStatement("import io.kritor.web.*")
|
||||
.addStatement("import io.kritor.developer.*")
|
||||
.addFunction(funcBuilder.build())
|
||||
.addImport("moe.fuqiuluo.symbols", "EMPTY_BYTE_ARRAY")
|
||||
runCatching {
|
||||
|
@ -4,11 +4,12 @@ package kritor.client
|
||||
import com.google.protobuf.ByteString
|
||||
import io.grpc.ManagedChannel
|
||||
import io.grpc.ManagedChannelBuilder
|
||||
import io.kritor.ReverseServiceGrpcKt
|
||||
import io.kritor.event.*
|
||||
import io.kritor.ReqCode
|
||||
import io.kritor.Request
|
||||
import io.kritor.Response
|
||||
import io.kritor.common.Request
|
||||
import io.kritor.common.Response
|
||||
import io.kritor.event.EventServiceGrpcKt
|
||||
import io.kritor.event.EventStructure
|
||||
import io.kritor.event.EventType
|
||||
import io.kritor.reverse.ReverseServiceGrpcKt
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
@ -113,7 +114,7 @@ internal class KritorClient(
|
||||
val rsp = handleGrpc(request.cmd, request.buf.toByteArray())
|
||||
senderChannel.emit(Response.newBuilder()
|
||||
.setCmd(request.cmd)
|
||||
.setCode(ReqCode.SUCCESS)
|
||||
.setCode(Response.ResponseCode.SUCCESS)
|
||||
.setMsg("success")
|
||||
.setSeq(request.seq)
|
||||
.setBuf(ByteString.copyFrom(rsp))
|
||||
@ -121,7 +122,7 @@ internal class KritorClient(
|
||||
}.onFailure {
|
||||
senderChannel.emit(Response.newBuilder()
|
||||
.setCmd(request.cmd)
|
||||
.setCode(ReqCode.INTERNAL)
|
||||
.setCode(Response.ResponseCode.INTERNAL)
|
||||
.setMsg(it.stackTraceToString())
|
||||
.setSeq(request.seq)
|
||||
.setBuf(ByteString.EMPTY)
|
||||
|
@ -18,8 +18,7 @@ class KritorServer(
|
||||
private val server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
|
||||
.executor(Dispatchers.IO.asExecutor())
|
||||
.intercept(AuthInterceptor)
|
||||
.addService(Authentication)
|
||||
.addService(ContactService)
|
||||
.addService(AuthenticationService)
|
||||
.addService(CoreService)
|
||||
.addService(FriendService)
|
||||
.addService(GroupService)
|
||||
|
@ -2,23 +2,19 @@ package kritor.service
|
||||
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.AuthCode
|
||||
import io.kritor.AuthReq
|
||||
import io.kritor.AuthRsp
|
||||
import io.kritor.AuthenticationServiceGrpcKt
|
||||
import io.kritor.GetAuthStateReq
|
||||
import io.kritor.GetAuthStateRsp
|
||||
import io.kritor.authentication.*
|
||||
import io.kritor.authentication.AuthenticateResponse.AuthenticateResponseCode
|
||||
import kritor.auth.AuthInterceptor
|
||||
import moe.fuqiuluo.shamrock.config.ActiveTicket
|
||||
import moe.fuqiuluo.shamrock.config.ShamrockConfig
|
||||
import qq.service.QQInterfaces
|
||||
|
||||
internal object Authentication: AuthenticationServiceGrpcKt.AuthenticationServiceCoroutineImplBase() {
|
||||
@Grpc("Authentication", "Auth")
|
||||
override suspend fun auth(request: AuthReq): AuthRsp {
|
||||
internal object AuthenticationService: AuthenticationServiceGrpcKt.AuthenticationServiceCoroutineImplBase() {
|
||||
@Grpc("AuthenticationService", "Authenticate")
|
||||
override suspend fun authenticate(request: AuthenticateRequest): AuthenticateResponse {
|
||||
if (QQInterfaces.app.account != request.account) {
|
||||
return AuthRsp.newBuilder().apply {
|
||||
code = AuthCode.NO_ACCOUNT
|
||||
return AuthenticateResponse.newBuilder().apply {
|
||||
code = AuthenticateResponseCode.NO_ACCOUNT
|
||||
msg = "No such account"
|
||||
}.build()
|
||||
}
|
||||
@ -29,36 +25,36 @@ internal object Authentication: AuthenticationServiceGrpcKt.AuthenticationServic
|
||||
val ticket = ShamrockConfig.getProperty(activeTicketName + if (index == 0) "" else ".$index", null)
|
||||
if (ticket.isNullOrEmpty()) {
|
||||
if (index == 0) {
|
||||
return AuthRsp.newBuilder().apply {
|
||||
code = AuthCode.OK
|
||||
return AuthenticateResponse.newBuilder().apply {
|
||||
code = AuthenticateResponseCode.OK
|
||||
msg = "OK"
|
||||
}.build()
|
||||
} else {
|
||||
break
|
||||
}
|
||||
} else if (ticket == request.ticket) {
|
||||
return AuthRsp.newBuilder().apply {
|
||||
code = AuthCode.OK
|
||||
return AuthenticateResponse.newBuilder().apply {
|
||||
code = AuthenticateResponseCode.OK
|
||||
msg = "OK"
|
||||
}.build()
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
return AuthRsp.newBuilder().apply {
|
||||
code = AuthCode.NO_TICKET
|
||||
return AuthenticateResponse.newBuilder().apply {
|
||||
code = AuthenticateResponseCode.NO_TICKET
|
||||
msg = "Invalid ticket"
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("Authentication", "GetAuthState")
|
||||
override suspend fun getAuthState(request: GetAuthStateReq): GetAuthStateRsp {
|
||||
@Grpc("AuthenticationService", "GetAuthenticationState")
|
||||
override suspend fun getAuthenticationState(request: GetAuthenticationStateRequest): GetAuthenticationStateResponse {
|
||||
if (request.account != QQInterfaces.app.account) {
|
||||
throw StatusRuntimeException(Status.CANCELLED.withDescription("No such account"))
|
||||
}
|
||||
|
||||
return GetAuthStateRsp.newBuilder().apply {
|
||||
isRequiredAuth = AuthInterceptor.getAllTicket().isNotEmpty()
|
||||
return GetAuthenticationStateResponse.newBuilder().apply {
|
||||
isRequired = AuthInterceptor.getAllTicket().isNotEmpty()
|
||||
}.build()
|
||||
}
|
||||
}
|
@ -1,187 +0,0 @@
|
||||
package kritor.service
|
||||
|
||||
import android.os.Bundle
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileCardBlacklistApi
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileProtocolConst.*
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileProtocolService
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.contact.ContactServiceGrpcKt
|
||||
import io.kritor.contact.GetUidRequest
|
||||
import io.kritor.contact.GetUidResponse
|
||||
import io.kritor.contact.GetUinByUidRequest
|
||||
import io.kritor.contact.GetUinByUidResponse
|
||||
import io.kritor.contact.IsBlackListUserRequest
|
||||
import io.kritor.contact.IsBlackListUserResponse
|
||||
import io.kritor.contact.ProfileCard
|
||||
import io.kritor.contact.ProfileCardRequest
|
||||
import io.kritor.contact.SetProfileCardRequest
|
||||
import io.kritor.contact.SetProfileCardResponse
|
||||
import io.kritor.contact.StrangerExt
|
||||
import io.kritor.contact.StrangerInfo
|
||||
import io.kritor.contact.StrangerInfoRequest
|
||||
import io.kritor.contact.VoteUserRequest
|
||||
import io.kritor.contact.VoteUserResponse
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import qq.service.QQInterfaces
|
||||
import qq.service.contact.ContactHelper
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
internal object ContactService : ContactServiceGrpcKt.ContactServiceCoroutineImplBase() {
|
||||
@Grpc("ContactService", "VoteUser")
|
||||
override suspend fun voteUser(request: VoteUserRequest): VoteUserResponse {
|
||||
ContactHelper.voteUser(
|
||||
when (request.accountCase!!) {
|
||||
VoteUserRequest.AccountCase.ACCOUNT_UIN -> request.accountUin
|
||||
VoteUserRequest.AccountCase.ACCOUNT_UID -> ContactHelper.getUinByUidAsync(request.accountUid).toLong()
|
||||
VoteUserRequest.AccountCase.ACCOUNT_NOT_SET -> throw StatusRuntimeException(
|
||||
Status.INVALID_ARGUMENT
|
||||
.withDescription("account not set")
|
||||
)
|
||||
}, request.voteCount
|
||||
).onFailure {
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withDescription(it.stackTraceToString())
|
||||
)
|
||||
}
|
||||
return VoteUserResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "GetProfileCard")
|
||||
override suspend fun getProfileCard(request: ProfileCardRequest): ProfileCard {
|
||||
val uin = when (request.accountCase!!) {
|
||||
ProfileCardRequest.AccountCase.ACCOUNT_UIN -> request.accountUin
|
||||
ProfileCardRequest.AccountCase.ACCOUNT_UID -> ContactHelper.getUinByUidAsync(request.accountUid).toLong()
|
||||
ProfileCardRequest.AccountCase.ACCOUNT_NOT_SET -> throw StatusRuntimeException(
|
||||
Status.INVALID_ARGUMENT
|
||||
.withDescription("account not set")
|
||||
)
|
||||
}
|
||||
|
||||
val contact = ContactHelper.getProfileCard(uin)
|
||||
|
||||
contact.onFailure {
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withDescription(it.stackTraceToString())
|
||||
)
|
||||
}
|
||||
|
||||
contact.onSuccess {
|
||||
return ProfileCard.newBuilder().apply {
|
||||
this.uin = it.uin.toLong()
|
||||
this.uid = if (request.hasAccountUid()) request.accountUid
|
||||
else ContactHelper.getUidByUinAsync(it.uin.toLong())
|
||||
this.name = it.strNick ?: ""
|
||||
this.remark = it.strReMark ?: ""
|
||||
this.level = it.iQQLevel
|
||||
this.birthday = it.lBirthday
|
||||
this.loginDay = it.lLoginDays.toInt()
|
||||
this.voteCnt = it.lVoteCount.toInt()
|
||||
this.qid = it.qid ?: ""
|
||||
this.isSchoolVerified = it.schoolVerifiedFlag
|
||||
}.build()
|
||||
}
|
||||
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withDescription("logic failed")
|
||||
)
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "GetStrangerInfo")
|
||||
override suspend fun getStrangerInfo(request: StrangerInfoRequest): StrangerInfo {
|
||||
val userId = request.uin
|
||||
val info = ContactHelper.refreshAndGetProfileCard(userId).onFailure {
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withCause(it)
|
||||
.withDescription("Unable to fetch stranger info")
|
||||
)
|
||||
}.getOrThrow()
|
||||
|
||||
return StrangerInfo.newBuilder().apply {
|
||||
this.uid = ContactHelper.getUidByUinAsync(userId)
|
||||
this.uin = (info.uin ?: "0").toLong()
|
||||
this.name = info.strNick ?: ""
|
||||
this.level = info.iQQLevel
|
||||
this.loginDay = info.lLoginDays.toInt()
|
||||
this.voteCnt = info.lVoteCount.toInt()
|
||||
this.qid = info.qid ?: ""
|
||||
this.isSchoolVerified = info.schoolVerifiedFlag
|
||||
this.ext = StrangerExt.newBuilder().apply {
|
||||
this.bigVip = info.bBigClubVipOpen == 1.toByte()
|
||||
this.hollywoodVip = info.bHollywoodVipOpen == 1.toByte()
|
||||
this.qqVip = info.bQQVipOpen == 1.toByte()
|
||||
this.superVip = info.bSuperQQOpen == 1.toByte()
|
||||
this.voted = info.bVoted == 1.toByte()
|
||||
}.build().toByteString()
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "GetUid")
|
||||
override suspend fun getUid(request: GetUidRequest): GetUidResponse {
|
||||
return GetUidResponse.newBuilder().apply {
|
||||
request.uinList.forEach {
|
||||
putUid(it, ContactHelper.getUidByUinAsync(it))
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "GetUinByUid")
|
||||
override suspend fun getUinByUid(request: GetUinByUidRequest): GetUinByUidResponse {
|
||||
return GetUinByUidResponse.newBuilder().apply {
|
||||
request.uidList.forEach {
|
||||
putUin(it, ContactHelper.getUinByUidAsync(it).toLong())
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "SetProfileCard")
|
||||
override suspend fun setProfileCard(request: SetProfileCardRequest): SetProfileCardResponse {
|
||||
val bundle = Bundle()
|
||||
val service = QQInterfaces.app
|
||||
.getRuntimeService(IProfileProtocolService::class.java, "all")
|
||||
if (request.hasNickName()) {
|
||||
bundle.putString(KEY_NICK, request.nickName)
|
||||
}
|
||||
if (request.hasCompany()) {
|
||||
bundle.putString(KEY_COMPANY, request.company)
|
||||
}
|
||||
if (request.hasEmail()) {
|
||||
bundle.putString(KEY_EMAIL, request.email)
|
||||
}
|
||||
if (request.hasCollege()) {
|
||||
bundle.putString(KEY_COLLEGE, request.college)
|
||||
}
|
||||
if (request.hasPersonalNote()) {
|
||||
bundle.putString(KEY_PERSONAL_NOTE, request.personalNote)
|
||||
}
|
||||
|
||||
if (request.hasBirthday()) {
|
||||
bundle.putInt(KEY_BIRTHDAY, request.birthday)
|
||||
}
|
||||
if (request.hasAge()) {
|
||||
bundle.putInt(KEY_AGE, request.age)
|
||||
}
|
||||
|
||||
service.setProfileDetail(bundle)
|
||||
return super.setProfileCard(request)
|
||||
}
|
||||
|
||||
@Grpc("ContactService", "IsBlackListUser")
|
||||
override suspend fun isBlackListUser(request: IsBlackListUserRequest): IsBlackListUserResponse {
|
||||
val blacklistApi = QRoute.api(IProfileCardBlacklistApi::class.java)
|
||||
val isBlack = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
blacklistApi.isBlackOrBlackedUin(request.uin.toString()) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
} ?: false
|
||||
return IsBlackListUserResponse.newBuilder().setIsBlackListUser(isBlack).build()
|
||||
}
|
||||
}
|
@ -9,8 +9,6 @@ import moe.fuqiuluo.shamrock.tools.ShamrockVersion
|
||||
import moe.fuqiuluo.shamrock.utils.DownloadUtils
|
||||
import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||
import moe.fuqiuluo.shamrock.utils.MD5
|
||||
import moe.fuqiuluo.shamrock.utils.MMKVFetcher
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import mqq.app.MobileQQ
|
||||
import qq.service.QQInterfaces.Companion.app
|
||||
import qq.service.contact.ContactHelper
|
||||
@ -25,14 +23,6 @@ internal object CoreService : CoreServiceGrpcKt.CoreServiceCoroutineImplBase() {
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("CoreService", "ClearCache")
|
||||
override suspend fun clearCache(request: ClearCacheRequest): ClearCacheResponse {
|
||||
FileUtils.clearCache()
|
||||
MMKVFetcher.mmkvWithId("audio2silk")
|
||||
.clear()
|
||||
return ClearCacheResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("CoreService", "GetCurrentAccount")
|
||||
override suspend fun getCurrentAccount(request: GetCurrentAccountRequest): GetCurrentAccountResponse {
|
||||
return GetCurrentAccountResponse.newBuilder().apply {
|
||||
@ -108,15 +98,4 @@ internal object CoreService : CoreServiceGrpcKt.CoreServiceCoroutineImplBase() {
|
||||
}
|
||||
return SwitchAccountResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("CoreService", "GetDeviceBattery")
|
||||
override suspend fun getDeviceBattery(request: GetDeviceBatteryRequest): GetDeviceBatteryResponse {
|
||||
return GetDeviceBatteryResponse.newBuilder().apply {
|
||||
PlatformUtils.getDeviceBattery().let {
|
||||
this.battery = it.battery
|
||||
this.scale = it.scale
|
||||
this.status = it.status
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
}
|
@ -2,9 +2,31 @@ package kritor.service
|
||||
|
||||
import com.google.protobuf.ByteString
|
||||
import io.kritor.developer.*
|
||||
import moe.fuqiuluo.shamrock.utils.FileUtils
|
||||
import moe.fuqiuluo.shamrock.utils.MMKVFetcher
|
||||
import moe.fuqiuluo.shamrock.utils.PlatformUtils
|
||||
import qq.service.QQInterfaces
|
||||
|
||||
internal object DeveloperService: DeveloperServiceGrpcKt.DeveloperServiceCoroutineImplBase() {
|
||||
@Grpc("DeveloperService", "ClearCache")
|
||||
override suspend fun clearCache(request: ClearCacheRequest): ClearCacheResponse {
|
||||
FileUtils.clearCache()
|
||||
MMKVFetcher.mmkvWithId("audio2silk")
|
||||
.clear()
|
||||
return ClearCacheResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("DeveloperService", "GetDeviceBattery")
|
||||
override suspend fun getDeviceBattery(request: GetDeviceBatteryRequest): GetDeviceBatteryResponse {
|
||||
return GetDeviceBatteryResponse.newBuilder().apply {
|
||||
PlatformUtils.getDeviceBattery().let {
|
||||
this.battery = it.battery
|
||||
this.scale = it.scale
|
||||
this.status = it.status
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("DeveloperService", "SendPacket")
|
||||
override suspend fun sendPacket(request: SendPacketRequest): SendPacketResponse {
|
||||
return SendPacketResponse.newBuilder().apply {
|
||||
|
@ -1,23 +1,33 @@
|
||||
package kritor.service
|
||||
|
||||
import android.os.Bundle
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileCardBlacklistApi
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileProtocolConst
|
||||
import com.tencent.mobileqq.profilecard.api.IProfileProtocolService
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.friend.*
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import qq.service.QQInterfaces
|
||||
import qq.service.contact.ContactHelper
|
||||
import qq.service.friend.FriendHelper
|
||||
import kotlin.coroutines.resume
|
||||
|
||||
internal object FriendService: FriendServiceGrpcKt.FriendServiceCoroutineImplBase() {
|
||||
internal object FriendService : FriendServiceGrpcKt.FriendServiceCoroutineImplBase() {
|
||||
@Grpc("FriendService", "GetFriendList")
|
||||
override suspend fun getFriendList(request: GetFriendListRequest): GetFriendListResponse {
|
||||
val friendList = FriendHelper.getFriendList(if(request.hasRefresh()) request.refresh else false).onFailure {
|
||||
throw StatusRuntimeException(Status.INTERNAL
|
||||
val friendList = FriendHelper.getFriendList(if (request.hasRefresh()) request.refresh else false).onFailure {
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withDescription(it.stackTraceToString())
|
||||
)
|
||||
}.getOrThrow()
|
||||
|
||||
return GetFriendListResponse.newBuilder().apply {
|
||||
friendList.forEach {
|
||||
this.addFriendList(FriendData.newBuilder().apply {
|
||||
this.addFriendsInfo(FriendInfo.newBuilder().apply {
|
||||
uin = it.uin.toLong()
|
||||
uid = ContactHelper.getUidByUinAsync(uin)
|
||||
qid = ""
|
||||
@ -27,10 +37,208 @@ internal object FriendService: FriendServiceGrpcKt.FriendServiceCoroutineImplBas
|
||||
level = 0
|
||||
gender = it.gender.toInt()
|
||||
groupId = it.groupid
|
||||
ext = FriendExt.newBuilder().build().toByteString()
|
||||
|
||||
ext = ExtInfo.newBuilder().build()
|
||||
})
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "GetFriendProfileCard")
|
||||
override suspend fun getFriendProfileCard(request: GetFriendProfileCardRequest): GetFriendProfileCardResponse {
|
||||
return GetFriendProfileCardResponse.newBuilder().apply {
|
||||
request.targetUinsList.forEach {
|
||||
ContactHelper.getProfileCard(it).getOrThrow().let { info ->
|
||||
addFriendsProfileCard(ProfileCard.newBuilder().apply {
|
||||
this.uin = info.uin.toLong()
|
||||
this.uid = ContactHelper.getUidByUinAsync(info.uin.toLong())
|
||||
this.nick = info.strNick
|
||||
this.remark = info.strReMark
|
||||
this.level = info.iQQLevel
|
||||
this.birthday = info.lBirthday
|
||||
this.loginDay = info.lLoginDays.toInt()
|
||||
this.voteCnt = info.lVoteCount.toInt()
|
||||
this.qid = info.qid ?: ""
|
||||
this.isSchoolVerified = info.schoolVerifiedFlag
|
||||
|
||||
this.ext = ExtInfo.newBuilder().apply {
|
||||
this.bigVip = info.bBigClubVipOpen == 1.toByte()
|
||||
this.hollywoodVip = info.bHollywoodVipOpen == 1.toByte()
|
||||
this.qqVip = info.bQQVipOpen == 1.toByte()
|
||||
this.superVip = info.bSuperQQOpen == 1.toByte()
|
||||
this.voted = info.bVoted == 1.toByte()
|
||||
}.build()
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
request.targetUidsList.forEach {
|
||||
ContactHelper.getProfileCard(ContactHelper.getUinByUidAsync(it).toLong()).getOrThrow().let { info ->
|
||||
addFriendsProfileCard(ProfileCard.newBuilder().apply {
|
||||
this.uin = info.uin.toLong()
|
||||
this.uid = it
|
||||
this.nick = info.strNick
|
||||
this.remark = info.strReMark
|
||||
this.level = info.iQQLevel
|
||||
this.birthday = info.lBirthday
|
||||
this.loginDay = info.lLoginDays.toInt()
|
||||
this.voteCnt = info.lVoteCount.toInt()
|
||||
this.qid = info.qid ?: ""
|
||||
this.isSchoolVerified = info.schoolVerifiedFlag
|
||||
|
||||
this.ext = ExtInfo.newBuilder().apply {
|
||||
this.bigVip = info.bBigClubVipOpen == 1.toByte()
|
||||
this.hollywoodVip = info.bHollywoodVipOpen == 1.toByte()
|
||||
this.qqVip = info.bQQVipOpen == 1.toByte()
|
||||
this.superVip = info.bSuperQQOpen == 1.toByte()
|
||||
this.voted = info.bVoted == 1.toByte()
|
||||
}.build()
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "GetStrangerProfileCard")
|
||||
override suspend fun getStrangerProfileCard(request: GetStrangerProfileCardRequest): GetStrangerProfileCardResponse {
|
||||
return GetStrangerProfileCardResponse.newBuilder().apply {
|
||||
request.targetUinsList.forEach {
|
||||
ContactHelper.refreshAndGetProfileCard(it).getOrThrow().let { info ->
|
||||
addStrangersProfileCard(ProfileCard.newBuilder().apply {
|
||||
this.uin = info.uin.toLong()
|
||||
this.uid = ContactHelper.getUidByUinAsync(info.uin.toLong())
|
||||
this.nick = info.strNick
|
||||
this.level = info.iQQLevel
|
||||
this.birthday = info.lBirthday
|
||||
this.loginDay = info.lLoginDays.toInt()
|
||||
this.voteCnt = info.lVoteCount.toInt()
|
||||
this.qid = info.qid ?: ""
|
||||
this.isSchoolVerified = info.schoolVerifiedFlag
|
||||
|
||||
this.ext = ExtInfo.newBuilder().apply {
|
||||
this.bigVip = info.bBigClubVipOpen == 1.toByte()
|
||||
this.hollywoodVip = info.bHollywoodVipOpen == 1.toByte()
|
||||
this.qqVip = info.bQQVipOpen == 1.toByte()
|
||||
this.superVip = info.bSuperQQOpen == 1.toByte()
|
||||
this.voted = info.bVoted == 1.toByte()
|
||||
}.build()
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
request.targetUidsList.forEach {
|
||||
ContactHelper.refreshAndGetProfileCard(ContactHelper.getUinByUidAsync(it).toLong()).getOrThrow()
|
||||
.let { info ->
|
||||
addStrangersProfileCard(ProfileCard.newBuilder().apply {
|
||||
this.uin = info.uin.toLong()
|
||||
this.uid = it
|
||||
this.nick = info.strNick
|
||||
this.level = info.iQQLevel
|
||||
this.birthday = info.lBirthday
|
||||
this.loginDay = info.lLoginDays.toInt()
|
||||
this.voteCnt = info.lVoteCount.toInt()
|
||||
this.qid = info.qid ?: ""
|
||||
this.isSchoolVerified = info.schoolVerifiedFlag
|
||||
|
||||
this.ext = ExtInfo.newBuilder().apply {
|
||||
this.bigVip = info.bBigClubVipOpen == 1.toByte()
|
||||
this.hollywoodVip = info.bHollywoodVipOpen == 1.toByte()
|
||||
this.qqVip = info.bQQVipOpen == 1.toByte()
|
||||
this.superVip = info.bSuperQQOpen == 1.toByte()
|
||||
this.voted = info.bVoted == 1.toByte()
|
||||
}.build()
|
||||
}.build())
|
||||
}
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "SetProfileCard")
|
||||
override suspend fun setProfileCard(request: SetProfileCardRequest): SetProfileCardResponse {
|
||||
val bundle = Bundle()
|
||||
val service = QQInterfaces.app
|
||||
.getRuntimeService(IProfileProtocolService::class.java, "all")
|
||||
if (request.hasNickName()) {
|
||||
bundle.putString(IProfileProtocolConst.KEY_NICK, request.nickName)
|
||||
}
|
||||
if (request.hasCompany()) {
|
||||
bundle.putString(IProfileProtocolConst.KEY_COMPANY, request.company)
|
||||
}
|
||||
if (request.hasEmail()) {
|
||||
bundle.putString(IProfileProtocolConst.KEY_EMAIL, request.email)
|
||||
}
|
||||
if (request.hasCollege()) {
|
||||
bundle.putString(IProfileProtocolConst.KEY_COLLEGE, request.college)
|
||||
}
|
||||
if (request.hasPersonalNote()) {
|
||||
bundle.putString(IProfileProtocolConst.KEY_PERSONAL_NOTE, request.personalNote)
|
||||
}
|
||||
|
||||
if (request.hasBirthday()) {
|
||||
bundle.putInt(IProfileProtocolConst.KEY_BIRTHDAY, request.birthday)
|
||||
}
|
||||
if (request.hasAge()) {
|
||||
bundle.putInt(IProfileProtocolConst.KEY_AGE, request.age)
|
||||
}
|
||||
|
||||
service.setProfileDetail(bundle)
|
||||
return super.setProfileCard(request)
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "IsBlackListUser")
|
||||
override suspend fun isBlackListUser(request: IsBlackListUserRequest): IsBlackListUserResponse {
|
||||
val uin = when (request.targetCase!!) {
|
||||
IsBlackListUserRequest.TargetCase.TARGET_UIN -> request.targetUin.toString()
|
||||
IsBlackListUserRequest.TargetCase.TARGET_UID -> ContactHelper.getUinByUidAsync(request.targetUid)
|
||||
IsBlackListUserRequest.TargetCase.TARGET_NOT_SET -> throw StatusRuntimeException(
|
||||
Status.INVALID_ARGUMENT
|
||||
.withDescription("account not set")
|
||||
)
|
||||
}
|
||||
val blacklistApi = QRoute.api(IProfileCardBlacklistApi::class.java)
|
||||
val isBlack = withTimeoutOrNull(5000) {
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
blacklistApi.isBlackOrBlackedUin(uin) {
|
||||
continuation.resume(it)
|
||||
}
|
||||
}
|
||||
} ?: false
|
||||
return IsBlackListUserResponse.newBuilder().setIsBlackListUser(isBlack).build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "VoteUser")
|
||||
override suspend fun voteUser(request: VoteUserRequest): VoteUserResponse {
|
||||
ContactHelper.voteUser(
|
||||
when (request.targetCase!!) {
|
||||
VoteUserRequest.TargetCase.TARGET_UIN -> request.targetUin
|
||||
VoteUserRequest.TargetCase.TARGET_UID -> ContactHelper.getUinByUidAsync(request.targetUid).toLong()
|
||||
VoteUserRequest.TargetCase.TARGET_NOT_SET -> throw StatusRuntimeException(
|
||||
Status.INVALID_ARGUMENT
|
||||
.withDescription("account not set")
|
||||
)
|
||||
}, request.voteCount
|
||||
).onFailure {
|
||||
throw StatusRuntimeException(
|
||||
Status.INTERNAL
|
||||
.withDescription(it.stackTraceToString())
|
||||
)
|
||||
}
|
||||
return VoteUserResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "GetUidByUin")
|
||||
override suspend fun getUidByUin(request: GetUidRequest): GetUidResponse {
|
||||
return GetUidResponse.newBuilder().apply {
|
||||
request.targetUinsList.forEach {
|
||||
putUidMap(it, ContactHelper.getUidByUinAsync(it))
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("FriendService", "GetUinByUid")
|
||||
override suspend fun getUinByUid(request: GetUinByUidRequest): GetUinByUidResponse {
|
||||
return GetUinByUidResponse.newBuilder().apply {
|
||||
request.targetUidsList.forEach {
|
||||
putUinMap(it, ContactHelper.getUinByUidAsync(it).toLong())
|
||||
}
|
||||
}.build()
|
||||
}
|
||||
}
|
@ -17,7 +17,7 @@ import qq.service.file.GroupFileHelper.getGroupFileSystemInfo
|
||||
import tencent.im.oidb.cmd0x6d6.oidb_0x6d6
|
||||
import tencent.im.oidb.oidb_sso
|
||||
|
||||
internal object GroupFileService: GroupFileServiceGrpcKt.GroupFileServiceCoroutineImplBase() {
|
||||
internal object GroupFileService : GroupFileServiceGrpcKt.GroupFileServiceCoroutineImplBase() {
|
||||
@Grpc("GroupFileService", "CreateFolder")
|
||||
override suspend fun createFolder(request: CreateFolderRequest): CreateFolderResponse {
|
||||
val data = Oidb0x6d7ReqBody(
|
||||
@ -49,13 +49,15 @@ internal object GroupFileService: GroupFileServiceGrpcKt.GroupFileServiceCorouti
|
||||
|
||||
@Grpc("GroupFileService", "DeleteFolder")
|
||||
override suspend fun deleteFolder(request: DeleteFolderRequest): DeleteFolderResponse {
|
||||
val fromServiceMsg = QQInterfaces.sendOidbAW("OidbSvc.0x6d7_1", 1751, 1, Oidb0x6d7ReqBody(
|
||||
val fromServiceMsg = QQInterfaces.sendOidbAW(
|
||||
"OidbSvc.0x6d7_1", 1751, 1, Oidb0x6d7ReqBody(
|
||||
deleteFolder = DeleteFolderReq(
|
||||
groupCode = request.groupId.toULong(),
|
||||
appId = 3u,
|
||||
folderId = request.folderId
|
||||
)
|
||||
).toByteArray()) ?: throw StatusRuntimeException(Status.INTERNAL.withDescription("unable to send oidb request"))
|
||||
).toByteArray()
|
||||
) ?: throw StatusRuntimeException(Status.INTERNAL.withDescription("unable to send oidb request"))
|
||||
if (fromServiceMsg.wupBuffer == null) {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withDescription("oidb request failed"))
|
||||
}
|
||||
@ -97,14 +99,16 @@ internal object GroupFileService: GroupFileServiceGrpcKt.GroupFileServiceCorouti
|
||||
|
||||
@Grpc("GroupFileService", "RenameFolder")
|
||||
override suspend fun renameFolder(request: RenameFolderRequest): RenameFolderResponse {
|
||||
val fromServiceMsg = QQInterfaces.sendOidbAW("OidbSvc.0x6d7_3", 1751, 3, Oidb0x6d7ReqBody(
|
||||
val fromServiceMsg = QQInterfaces.sendOidbAW(
|
||||
"OidbSvc.0x6d7_3", 1751, 3, Oidb0x6d7ReqBody(
|
||||
renameFolder = RenameFolderReq(
|
||||
groupCode = request.groupId.toULong(),
|
||||
appId = 3u,
|
||||
folderId = request.folderId,
|
||||
folderName = request.name
|
||||
)
|
||||
).toByteArray()) ?: throw StatusRuntimeException(Status.INTERNAL.withDescription("unable to send oidb request"))
|
||||
).toByteArray()
|
||||
) ?: throw StatusRuntimeException(Status.INTERNAL.withDescription("unable to send oidb request"))
|
||||
if (fromServiceMsg.wupBuffer == null) {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withDescription("oidb request failed"))
|
||||
}
|
||||
@ -122,17 +126,11 @@ internal object GroupFileService: GroupFileServiceGrpcKt.GroupFileServiceCorouti
|
||||
return getGroupFileSystemInfo(request.groupId)
|
||||
}
|
||||
|
||||
@Grpc("GroupFileService", "GetRootFiles")
|
||||
override suspend fun getRootFiles(request: GetRootFilesRequest): GetRootFilesResponse {
|
||||
return GetRootFilesResponse.newBuilder().apply {
|
||||
val response = GroupFileHelper.getGroupFiles(request.groupId)
|
||||
this.addAllFiles(response.filesList)
|
||||
this.addAllFolders(response.foldersList)
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("GroupFileService", "GetFiles")
|
||||
override suspend fun getFiles(request: GetFilesRequest): GetFilesResponse {
|
||||
return GroupFileHelper.getGroupFiles(request.groupId, request.folderId)
|
||||
@Grpc("GroupFileService", "GetFileList")
|
||||
override suspend fun getFileList(request: GetFileListRequest): GetFileListResponse {
|
||||
return if (request.hasFolderId())
|
||||
GroupFileHelper.getGroupFiles(request.groupId, request.folderId)
|
||||
else
|
||||
GroupFileHelper.getGroupFiles(request.groupId)
|
||||
}
|
||||
}
|
@ -212,7 +212,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
}.getOrThrow()
|
||||
return GetGroupListResponse.newBuilder().apply {
|
||||
groupList.forEach { groupInfo ->
|
||||
this.addGroupInfo(GroupInfo.newBuilder().apply {
|
||||
this.addGroupsInfo(GroupInfo.newBuilder().apply {
|
||||
groupId = groupInfo.troopcode.toLong()
|
||||
groupName = groupInfo.troopname.ifNullOrEmpty { groupInfo.troopRemark }
|
||||
.ifNullOrEmpty { groupInfo.newTroopName } ?: ""
|
||||
@ -231,8 +231,8 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
override suspend fun getGroupMemberInfo(request: GetGroupMemberInfoRequest): GetGroupMemberInfoResponse {
|
||||
val memberInfo = GroupHelper.getTroopMemberInfoByUin(
|
||||
request.groupId.toString(), when (request.targetCase!!) {
|
||||
GetGroupMemberInfoRequest.TargetCase.UIN -> request.uin
|
||||
GetGroupMemberInfoRequest.TargetCase.UID -> ContactHelper.getUinByUidAsync(request.uid).toLong()
|
||||
GetGroupMemberInfoRequest.TargetCase.TARGET_UID -> request.targetUin
|
||||
GetGroupMemberInfoRequest.TargetCase.TARGET_UIN -> ContactHelper.getUinByUidAsync(request.targetUid).toLong()
|
||||
else -> throw StatusRuntimeException(
|
||||
Status.INVALID_ARGUMENT
|
||||
.withDescription("target not set")
|
||||
@ -246,8 +246,8 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
return GetGroupMemberInfoResponse.newBuilder().apply {
|
||||
groupMemberInfo = GroupMemberInfo.newBuilder().apply {
|
||||
uid =
|
||||
if (request.targetCase == GetGroupMemberInfoRequest.TargetCase.UID) request.uid else ContactHelper.getUidByUinAsync(
|
||||
request.uin
|
||||
if (request.targetCase == GetGroupMemberInfoRequest.TargetCase.TARGET_UID) request.targetUid else ContactHelper.getUidByUinAsync(
|
||||
request.targetUin
|
||||
)
|
||||
uin = memberInfo.memberuin?.toLong() ?: 0
|
||||
nick = memberInfo.troopnick
|
||||
@ -264,7 +264,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
shutUpTimestamp = memberInfo.gagTimeStamp
|
||||
|
||||
distance = memberInfo.distance
|
||||
addAllHonor((memberInfo.honorList ?: "")
|
||||
addAllHonors((memberInfo.honorList ?: "")
|
||||
.split("|")
|
||||
.filter { it.isNotBlank() }
|
||||
.map { it.toInt() })
|
||||
@ -286,7 +286,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
}.getOrThrow()
|
||||
return GetGroupMemberListResponse.newBuilder().apply {
|
||||
memberList.forEach { memberInfo ->
|
||||
this.addGroupMemberInfo(GroupMemberInfo.newBuilder().apply {
|
||||
this.addGroupMembersInfo(GroupMemberInfo.newBuilder().apply {
|
||||
uid = ContactHelper.getUidByUinAsync(memberInfo.memberuin?.toLong() ?: 0)
|
||||
uin = memberInfo.memberuin?.toLong() ?: 0
|
||||
nick = memberInfo.troopnick
|
||||
@ -303,7 +303,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
shutUpTimestamp = memberInfo.gagTimeStamp
|
||||
|
||||
distance = memberInfo.distance
|
||||
addAllHonor((memberInfo.honorList ?: "")
|
||||
addAllHonors((memberInfo.honorList ?: "")
|
||||
.split("|")
|
||||
.filter { it.isNotBlank() }
|
||||
.map { it.toInt() })
|
||||
@ -323,7 +323,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
}.getOrThrow()
|
||||
return GetProhibitedUserListResponse.newBuilder().apply {
|
||||
prohibitedList.forEach {
|
||||
this.addProhibitedUserInfo(ProhibitedUserInfo.newBuilder().apply {
|
||||
this.addProhibitedUsersInfo(ProhibitedUserInfo.newBuilder().apply {
|
||||
uid = ContactHelper.getUidByUinAsync(it.memberUin)
|
||||
uin = it.memberUin
|
||||
prohibitedTime = it.shutuptimestap
|
||||
@ -380,7 +380,7 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
|
||||
.map { it.toInt() }.forEach {
|
||||
val honor = decodeHonor(member.memberuin.toLong(), it, member.mHonorRichFlag)
|
||||
if (honor != null) {
|
||||
addGroupHonorInfo(GroupHonorInfo.newBuilder().apply {
|
||||
addGroupHonorsInfo(GroupHonorInfo.newBuilder().apply {
|
||||
uid = ContactHelper.getUidByUinAsync(member.memberuin.toLong())
|
||||
uin = member.memberuin.toLong()
|
||||
nick = member.troopnick
|
||||
|
@ -7,9 +7,8 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.event.MessageEvent
|
||||
import io.kritor.common.*
|
||||
import io.kritor.message.*
|
||||
import io.kritor.message.EssenceMessage
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
@ -55,7 +54,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
uniseq
|
||||
).onFailure {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withCause(it))
|
||||
}.getOrThrow()
|
||||
}.getOrThrow().toString()
|
||||
}.build()
|
||||
}
|
||||
|
||||
@ -89,8 +88,8 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
return SendMessageByResIdResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("MessageService", "ClearMessages")
|
||||
override suspend fun clearMessages(request: ClearMessagesRequest): ClearMessagesResponse {
|
||||
@Grpc("MessageService", "SetMessageReaded")
|
||||
override suspend fun setMessageReaded(request: SetMessageReadRequest): SetMessageReadResponse {
|
||||
val contact = request.contact
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
@ -105,7 +104,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
Scene.UNRECOGNIZED -> throw StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription("Unrecognized scene"))
|
||||
}
|
||||
service.clearMsgRecords(Contact(chatType, contact.peer, contact.subPeer), null)
|
||||
return ClearMessagesResponse.newBuilder().build()
|
||||
return SetMessageReadResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("MessageService", "RecallMessage")
|
||||
@ -126,7 +125,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
val kernelService = NTServiceFetcher.kernelService
|
||||
val sessionService = kernelService.wrapperSession
|
||||
val service = sessionService.msgService
|
||||
service.recallMsg(contact, arrayListOf(request.messageId)) { code, msg ->
|
||||
service.recallMsg(contact, arrayListOf(request.messageId.toLong())) { code, msg ->
|
||||
if (code != 0) {
|
||||
LogCenter.log("消息撤回失败: $code:$msg", Level.WARN)
|
||||
}
|
||||
@ -153,7 +152,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
val msg: MsgRecord = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId)) { code, _, msgRecords ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId.toLong())) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords.first())
|
||||
} else {
|
||||
@ -167,13 +166,13 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
} ?: throw StatusRuntimeException(Status.NOT_FOUND.withDescription("Message not found"))
|
||||
|
||||
return GetMessageResponse.newBuilder().apply {
|
||||
this.message = MessageEvent.newBuilder().apply {
|
||||
this.messageId = msg.msgId
|
||||
this.message = PushMessageBody.newBuilder().apply {
|
||||
this.messageId = msg.msgId.toString()
|
||||
this.contact = request.contact
|
||||
this.sender = Sender.newBuilder().apply {
|
||||
this.uid = msg.senderUid ?: ""
|
||||
this.uin = msg.senderUin
|
||||
this.nick = msg.sendNickName ?: ""
|
||||
this.uid = msg.senderUid ?: ""
|
||||
}.build()
|
||||
this.messageSeq = msg.msgSeq
|
||||
this.addAllElements(msg.elements.toKritorReqMessages(contact))
|
||||
@ -213,8 +212,8 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
} ?: throw StatusRuntimeException(Status.NOT_FOUND.withDescription("Message not found"))
|
||||
|
||||
return GetMessageBySeqResponse.newBuilder().apply {
|
||||
this.message = MessageEvent.newBuilder().apply {
|
||||
this.messageId = msg.msgId
|
||||
this.message = PushMessageBody.newBuilder().apply {
|
||||
this.messageId = msg.msgId.toString()
|
||||
this.contact = request.contact
|
||||
this.sender = Sender.newBuilder().apply {
|
||||
this.uin = msg.senderUin
|
||||
@ -245,7 +244,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
val msgs: List<MsgRecord> = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgs(contact, request.startMessageId, request.count, true) { code, _, msgRecords ->
|
||||
service.getMsgs(contact, request.startMessageId.toLong(), request.count, true) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords)
|
||||
} else {
|
||||
@ -260,8 +259,8 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
|
||||
return GetHistoryMessageResponse.newBuilder().apply {
|
||||
msgs.forEach {
|
||||
addMessages(MessageEvent.newBuilder().apply {
|
||||
this.messageId = it.msgId
|
||||
addMessages(PushMessageBody.newBuilder().apply {
|
||||
this.messageId = it.msgId.toString()
|
||||
this.contact = request.contact
|
||||
this.sender = Sender.newBuilder().apply {
|
||||
this.uin = it.senderUin
|
||||
@ -292,9 +291,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
}
|
||||
|
||||
val forwardMessage = ForwardMessageHelper.uploadMultiMsg(
|
||||
contact.chatType,
|
||||
contact.longPeer().toString(),
|
||||
contact.guildId,
|
||||
contact,
|
||||
request.messagesList
|
||||
).onFailure {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withCause(it))
|
||||
@ -312,11 +309,11 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
MessageHelper.getForwardMsg(request.resId).onFailure {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withCause(it))
|
||||
}.getOrThrow().map { detail ->
|
||||
MessageEvent.newBuilder().apply {
|
||||
PushMessageBody.newBuilder().apply {
|
||||
this.time = detail.time
|
||||
this.messageId = detail.qqMsgId
|
||||
this.messageId = detail.qqMsgId.toString()
|
||||
this.messageSeq = detail.msgSeq
|
||||
this.contact = io.kritor.message.Contact.newBuilder().apply {
|
||||
this.contact = io.kritor.common.Contact.newBuilder().apply {
|
||||
this.scene = when (detail.msgType) {
|
||||
MsgConstant.KCHATTYPEC2C -> Scene.FRIEND
|
||||
MsgConstant.KCHATTYPEGROUP -> Scene.GROUP
|
||||
@ -347,13 +344,13 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
}.build()
|
||||
}
|
||||
|
||||
@Grpc("MessageService", "DeleteEssenceMsg")
|
||||
override suspend fun deleteEssenceMsg(request: DeleteEssenceMsgRequest): DeleteEssenceMsgResponse {
|
||||
@Grpc("MessageService", "DeleteEssenceMessage")
|
||||
override suspend fun deleteEssenceMessage(request: DeleteEssenceMessageRequest): DeleteEssenceMessageResponse {
|
||||
val contact = MessageHelper.generateContact(MsgConstant.KCHATTYPEGROUP, request.groupId.toString())
|
||||
val msg: MsgRecord = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId)) { code, _, msgRecords ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId.toLong())) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords.first())
|
||||
} else {
|
||||
@ -367,17 +364,17 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
} ?: throw StatusRuntimeException(Status.NOT_FOUND.withDescription("Message not found"))
|
||||
if (MessageHelper.deleteEssenceMessage(request.groupId, msg.msgSeq, msg.msgRandom) == null)
|
||||
throw StatusRuntimeException(Status.NOT_FOUND.withDescription("delete essence message failed"))
|
||||
return DeleteEssenceMsgResponse.newBuilder().build()
|
||||
return DeleteEssenceMessageResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("MessageService", "GetEssenceMessages")
|
||||
override suspend fun getEssenceMessages(request: GetEssenceMessagesRequest): GetEssenceMessagesResponse {
|
||||
@Grpc("MessageService", "GetEssenceMessageList")
|
||||
override suspend fun getEssenceMessageList(request: GetEssenceMessageListRequest): GetEssenceMessageListResponse {
|
||||
val contact = MessageHelper.generateContact(MsgConstant.KCHATTYPEGROUP, request.groupId.toString())
|
||||
return GetEssenceMessagesResponse.newBuilder().apply {
|
||||
return GetEssenceMessageListResponse.newBuilder().apply {
|
||||
MessageHelper.getEssenceMessageList(request.groupId, request.page, request.pageSize).onFailure {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withCause(it))
|
||||
}.getOrThrow().forEach {
|
||||
addEssenceMessage(EssenceMessage.newBuilder().apply {
|
||||
addMessages(EssenceMessageBody.newBuilder().apply {
|
||||
withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
@ -393,10 +390,10 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
}
|
||||
}
|
||||
}?.let {
|
||||
this.messageId = it.msgId
|
||||
this.messageId = it.msgId.toString()
|
||||
}
|
||||
this.messageSeq = it.messageSeq
|
||||
this.msgTime = it.senderTime.toInt()
|
||||
this.messageTime = it.senderTime.toInt()
|
||||
this.senderNick = it.senderNick
|
||||
this.senderUin = it.senderId
|
||||
this.operationTime = it.operatorTime.toInt()
|
||||
@ -414,7 +411,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
val msg: MsgRecord = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId)) { code, _, msgRecords ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId.toLong())) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords.first())
|
||||
} else {
|
||||
@ -432,8 +429,8 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
return SetEssenceMessageResponse.newBuilder().build()
|
||||
}
|
||||
|
||||
@Grpc("MessageService", "SetMessageCommentEmoji")
|
||||
override suspend fun setMessageCommentEmoji(request: SetMessageCommentEmojiRequest): SetMessageCommentEmojiResponse {
|
||||
@Grpc("MessageService", "ReactMessageWithEmoji")
|
||||
override suspend fun reactMessageWithEmoji(request: ReactMessageWithEmojiRequest): ReactMessageWithEmojiResponse {
|
||||
val contact = request.contact.let {
|
||||
MessageHelper.generateContact(
|
||||
when (it.scene!!) {
|
||||
@ -450,7 +447,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
val msg: MsgRecord = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId)) { code, _, msgRecords ->
|
||||
service.getMsgsByMsgId(contact, arrayListOf(request.messageId.toLong())) { code, _, msgRecords ->
|
||||
if (code == 0 && msgRecords.isNotEmpty()) {
|
||||
continuation.resume(msgRecords.first())
|
||||
} else {
|
||||
@ -468,6 +465,6 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
|
||||
request.faceId.toString(),
|
||||
request.isComment
|
||||
)
|
||||
return SetMessageCommentEmojiResponse.newBuilder().build()
|
||||
return ReactMessageWithEmojiResponse.newBuilder().build()
|
||||
}
|
||||
}
|
@ -11,9 +11,9 @@ internal object QsignService: QsignServiceGrpcKt.QsignServiceCoroutineImplBase()
|
||||
override suspend fun sign(request: SignRequest): SignResponse {
|
||||
return SignResponse.newBuilder().apply {
|
||||
val result = FEKit.getInstance().getSign(request.command, request.buffer.toByteArray(), request.seq, request.uin)
|
||||
this.sign = ByteString.copyFrom(result.sign)
|
||||
this.token = ByteString.copyFrom(result.token)
|
||||
this.extra = ByteString.copyFrom(result.extra)
|
||||
this.secSig = ByteString.copyFrom(result.sign)
|
||||
this.secDeviceToken = ByteString.copyFrom(result.token)
|
||||
this.secExtra = ByteString.copyFrom(result.extra)
|
||||
}.build()
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,9 @@ package moe.fuqiuluo.shamrock.internals
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import io.kritor.event.*
|
||||
import io.kritor.message.Contact
|
||||
import io.kritor.message.Sender
|
||||
import io.kritor.common.PushMessageBody
|
||||
import io.kritor.common.Contact
|
||||
import io.kritor.common.Sender
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.flow.FlowCollector
|
||||
@ -17,7 +18,7 @@ import qq.service.msg.toKritorEventMessages
|
||||
|
||||
internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
private val MessageEventFlow by lazy {
|
||||
MutableSharedFlow<Pair<MsgRecord, MessageEvent>>()
|
||||
MutableSharedFlow<Pair<MsgRecord, PushMessageBody>>()
|
||||
}
|
||||
private val noticeEventFlow by lazy {
|
||||
MutableSharedFlow<NoticeEvent>()
|
||||
@ -30,7 +31,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
|
||||
private suspend fun pushRequest(requestEvent: RequestsEvent) = requestEventFlow.emit(requestEvent)
|
||||
|
||||
private suspend fun transMessageEvent(record: MsgRecord, message: MessageEvent) =
|
||||
private suspend fun transMessageEvent(record: MsgRecord, message: PushMessageBody) =
|
||||
MessageEventFlow.emit(record to message)
|
||||
|
||||
object MessageTransmitter {
|
||||
@ -38,9 +39,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
record: MsgRecord,
|
||||
elements: ArrayList<MsgElement>,
|
||||
): Boolean {
|
||||
transMessageEvent(record, MessageEvent.newBuilder().apply {
|
||||
transMessageEvent(record, PushMessageBody.newBuilder().apply {
|
||||
this.time = record.msgTime.toInt()
|
||||
this.messageId = record.msgId
|
||||
this.messageId = record.msgId.toString()
|
||||
this.messageSeq = record.msgSeq
|
||||
this.contact = Contact.newBuilder().apply {
|
||||
this.scene = scene
|
||||
@ -61,9 +62,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
record: MsgRecord,
|
||||
elements: ArrayList<MsgElement>,
|
||||
): Boolean {
|
||||
transMessageEvent(record, MessageEvent.newBuilder().apply {
|
||||
transMessageEvent(record, PushMessageBody.newBuilder().apply {
|
||||
this.time = record.msgTime.toInt()
|
||||
this.messageId = record.msgId
|
||||
this.messageId = record.msgId.toString()
|
||||
this.messageSeq = record.msgSeq
|
||||
this.contact = Contact.newBuilder().apply {
|
||||
this.scene = scene
|
||||
@ -86,9 +87,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupCode: Long,
|
||||
fromNick: String,
|
||||
): Boolean {
|
||||
transMessageEvent(record, MessageEvent.newBuilder().apply {
|
||||
transMessageEvent(record, PushMessageBody.newBuilder().apply {
|
||||
this.time = record.msgTime.toInt()
|
||||
this.messageId = record.msgId
|
||||
this.messageId = record.msgId.toString()
|
||||
this.messageSeq = record.msgSeq
|
||||
this.contact = Contact.newBuilder().apply {
|
||||
this.scene = scene
|
||||
@ -109,9 +110,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
record: MsgRecord,
|
||||
elements: ArrayList<MsgElement>,
|
||||
): Boolean {
|
||||
transMessageEvent(record, MessageEvent.newBuilder().apply {
|
||||
transMessageEvent(record, PushMessageBody.newBuilder().apply {
|
||||
this.time = record.msgTime.toInt()
|
||||
this.messageId = record.msgId
|
||||
this.messageId = record.msgId.toString()
|
||||
this.messageSeq = record.msgSeq
|
||||
this.contact = Contact.newBuilder().apply {
|
||||
this.scene = scene
|
||||
@ -147,12 +148,12 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
url: String
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.FRIEND_FILE_COME
|
||||
this.type = NoticeEvent.NoticeType.FRIEND_FILE_COME
|
||||
this.time = msgTime.toInt()
|
||||
this.friendFileCome = FriendFileComeNotice.newBuilder().apply {
|
||||
this.friendFileUploaded = FriendFileUploadedNotice.newBuilder().apply {
|
||||
this.fileId = fileId
|
||||
this.fileName = fileName
|
||||
this.operator = userId
|
||||
this.operatorUin = userId
|
||||
this.fileSize = fileSize
|
||||
this.expireTime = expireTime.toInt()
|
||||
this.fileSubId = fileSubId
|
||||
@ -176,11 +177,11 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
url: String
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_FILE_COME
|
||||
this.type = NoticeEvent.NoticeType.GROUP_FILE_COME
|
||||
this.time = msgTime.toInt()
|
||||
this.groupFileCome = GroupFileComeNotice.newBuilder().apply {
|
||||
this.groupFileUploaded = GroupFileUploadedNotice.newBuilder().apply {
|
||||
this.groupId = groupId
|
||||
this.operator = userId
|
||||
this.operatorUin = userId
|
||||
this.fileId = uuid
|
||||
this.fileName = fileName
|
||||
this.fileSize = fileSize
|
||||
@ -204,9 +205,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupCode: Long
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_SIGN
|
||||
this.type = NoticeEvent.NoticeType.GROUP_SIGN
|
||||
this.time = time.toInt()
|
||||
this.groupSign = GroupSignNotice.newBuilder().apply {
|
||||
this.groupSignIn = GroupSignInNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
this.targetUin = target
|
||||
this.action = action ?: ""
|
||||
@ -227,12 +228,13 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupCode: Long
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_POKE
|
||||
this.type = NoticeEvent.NoticeType.GROUP_POKE
|
||||
this.time = time.toInt()
|
||||
this.groupPoke = GroupPokeNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
this.action = action ?: ""
|
||||
this.target = target
|
||||
this.operator = operator
|
||||
this.targetUin = target
|
||||
this.operatorUin = operator
|
||||
this.suffix = suffix ?: ""
|
||||
this.actionImage = actionImg ?: ""
|
||||
}.build()
|
||||
@ -247,10 +249,10 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupCode: Long,
|
||||
operator: Long,
|
||||
operatorUid: String,
|
||||
type: GroupMemberIncreasedType
|
||||
type: GroupMemberIncreasedNotice.GroupMemberIncreasedType
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_MEMBER_INCREASE
|
||||
this.type = NoticeEvent.NoticeType.GROUP_MEMBER_INCREASE
|
||||
this.time = time.toInt()
|
||||
this.groupMemberIncrease = GroupMemberIncreasedNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
@ -271,10 +273,10 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupCode: Long,
|
||||
operator: Long,
|
||||
operatorUid: String,
|
||||
type: GroupMemberDecreasedType
|
||||
type: GroupMemberDecreasedNotice.GroupMemberDecreasedType
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_MEMBER_INCREASE
|
||||
this.type = NoticeEvent.NoticeType.GROUP_MEMBER_INCREASE
|
||||
this.time = time.toInt()
|
||||
this.groupMemberDecrease = GroupMemberDecreasedNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
@ -296,9 +298,9 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
setAdmin: Boolean
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_ADMIN_CHANGED
|
||||
this.type = NoticeEvent.NoticeType.GROUP_ADMIN_CHANGED
|
||||
this.time = msgTime.toInt()
|
||||
this.groupAdminChanged = GroupAdminChangedNotice.newBuilder().apply {
|
||||
this.groupAdminChange = GroupAdminChangedNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
this.targetUid = targetUid
|
||||
this.targetUin = target
|
||||
@ -315,12 +317,12 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
isOpen: Boolean
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_WHOLE_BAN
|
||||
this.type = NoticeEvent.NoticeType.GROUP_WHOLE_BAN
|
||||
this.time = msgTime.toInt()
|
||||
this.groupWholeBan = GroupWholeBanNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
this.isWholeBan = isOpen
|
||||
this.operator = operator
|
||||
this.isBan = isOpen
|
||||
this.operatorUin = operator
|
||||
}.build()
|
||||
}.build())
|
||||
return true
|
||||
@ -336,17 +338,17 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
duration: Int
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_MEMBER_BANNED
|
||||
this.type = NoticeEvent.NoticeType.GROUP_MEMBER_BANNED
|
||||
this.time = msgTime.toInt()
|
||||
this.groupMemberBanned = GroupMemberBannedNotice.newBuilder().apply {
|
||||
this.groupMemberBan = GroupMemberBanNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
this.operatorUid = operatorUid
|
||||
this.operatorUin = operator
|
||||
this.targetUid = targetUid
|
||||
this.targetUin = target
|
||||
this.duration = duration
|
||||
this.type = if (duration > 0) GroupMemberBanType.BAN
|
||||
else GroupMemberBanType.LIFT_BAN
|
||||
this.type = if (duration > 0) GroupMemberBanNotice.GroupMemberBanType.BAN
|
||||
else GroupMemberBanNotice.GroupMemberBanType.LIFT_BAN
|
||||
}.build()
|
||||
}.build())
|
||||
return true
|
||||
@ -363,7 +365,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
tipText: String
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_RECALL
|
||||
this.type = NoticeEvent.NoticeType.GROUP_RECALL
|
||||
this.time = time.toInt()
|
||||
this.groupRecall = GroupRecallNotice.newBuilder().apply {
|
||||
this.groupId = groupCode
|
||||
@ -371,7 +373,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
this.operatorUin = operator
|
||||
this.targetUid = targetUid
|
||||
this.targetUin = target
|
||||
this.messageId = msgId
|
||||
this.messageId = msgId.toString()
|
||||
this.tipText = tipText
|
||||
}.build()
|
||||
}.build())
|
||||
@ -381,11 +383,18 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
suspend fun transCardChange(
|
||||
time: Long,
|
||||
targetId: Long,
|
||||
oldCard: String,
|
||||
newCard: String,
|
||||
groupId: Long
|
||||
): Boolean {
|
||||
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeEvent.NoticeType.GROUP_CARD_CHANGED
|
||||
this.time = time.toInt()
|
||||
this.groupCardChanged = GroupCardChangedNotice.newBuilder().apply {
|
||||
this.groupId = groupId
|
||||
this.targetUin = targetId
|
||||
this.newCard = newCard
|
||||
}.build()
|
||||
}.build())
|
||||
return true
|
||||
}
|
||||
|
||||
@ -396,7 +405,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
groupId: Long
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_MEMBER_UNIQUE_TITLE_CHANGED
|
||||
this.type = NoticeEvent.NoticeType.GROUP_MEMBER_UNIQUE_TITLE_CHANGED
|
||||
this.time = time.toInt()
|
||||
this.groupMemberUniqueTitleChanged = GroupUniqueTitleChangedNotice.newBuilder().apply {
|
||||
this.groupId = groupId
|
||||
@ -416,13 +425,13 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
subType: UInt
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.GROUP_ESSENCE_CHANGED
|
||||
this.type = NoticeEvent.NoticeType.GROUP_ESSENCE_CHANGED
|
||||
this.time = time.toInt()
|
||||
this.groupEssenceChanged = EssenceMessageNotice.newBuilder().apply {
|
||||
this.groupEssenceChanged = GroupEssenceMessageNotice.newBuilder().apply {
|
||||
this.groupId = groupId
|
||||
this.messageId = msgId
|
||||
this.sender = senderUin
|
||||
this.operator = operatorUin
|
||||
this.messageId = msgId.toString()
|
||||
this.targetUin = senderUin
|
||||
this.operatorUin = operatorUin
|
||||
this.subType = subType.toInt()
|
||||
}.build()
|
||||
}.build())
|
||||
@ -443,12 +452,11 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
actionImg: String?
|
||||
): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.FRIEND_POKE
|
||||
this.type = NoticeEvent.NoticeType.FRIEND_POKE
|
||||
this.time = msgTime.toInt()
|
||||
this.friendPoke = FriendPokeNotice.newBuilder().apply {
|
||||
this.action = action ?: ""
|
||||
this.target = target
|
||||
this.operator = operator
|
||||
this.operatorUin = operator
|
||||
this.suffix = suffix ?: ""
|
||||
this.actionImage = actionImg ?: ""
|
||||
}.build()
|
||||
@ -458,11 +466,11 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
|
||||
suspend fun transPrivateRecall(time: Long, operator: Long, msgId: Long, tipText: String): Boolean {
|
||||
pushNotice(NoticeEvent.newBuilder().apply {
|
||||
this.type = NoticeType.FRIEND_RECALL
|
||||
this.type = NoticeEvent.NoticeType.FRIEND_RECALL
|
||||
this.time = time.toInt()
|
||||
this.friendRecall = FriendRecallNotice.newBuilder().apply {
|
||||
this.operator = operator
|
||||
this.messageId = msgId
|
||||
this.operatorUin = operator
|
||||
this.messageId = msgId.toString()
|
||||
this.tipText = tipText
|
||||
}.build()
|
||||
}.build())
|
||||
@ -477,7 +485,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
object RequestTransmitter {
|
||||
suspend fun transFriendApp(time: Long, operator: Long, tipText: String, flag: String): Boolean {
|
||||
pushRequest(RequestsEvent.newBuilder().apply {
|
||||
this.type = RequestType.FRIEND_APPLY
|
||||
this.type = RequestsEvent.RequestType.FRIEND_APPLY
|
||||
this.time = time.toInt()
|
||||
this.friendApply = FriendApplyRequest.newBuilder().apply {
|
||||
this.applierUin = operator
|
||||
@ -490,30 +498,28 @@ internal object GlobalEventTransmitter : QQInterfaces() {
|
||||
|
||||
suspend fun transGroupApply(
|
||||
time: Long,
|
||||
applier: Long,
|
||||
applierUin: Long,
|
||||
applierUid: String,
|
||||
reason: String,
|
||||
groupCode: Long,
|
||||
flag: String,
|
||||
type: GroupApplyType
|
||||
flag: String
|
||||
): Boolean {
|
||||
pushRequest(RequestsEvent.newBuilder().apply {
|
||||
this.type = RequestType.GROUP_APPLY
|
||||
this.type = RequestsEvent.RequestType.GROUP_APPLY
|
||||
this.time = time.toInt()
|
||||
this.groupApply = GroupApplyRequest.newBuilder().apply {
|
||||
this.applierUid = applierUid
|
||||
this.applierUin = applier
|
||||
this.applierUin = applierUin
|
||||
this.groupId = groupCode
|
||||
this.reason = reason
|
||||
this.flag = flag
|
||||
this.type = type
|
||||
}.build()
|
||||
}.build())
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
suspend inline fun onMessageEvent(collector: FlowCollector<Pair<MsgRecord, MessageEvent>>) {
|
||||
suspend inline fun onMessageEvent(collector: FlowCollector<Pair<MsgRecord, PushMessageBody>>) {
|
||||
MessageEventFlow.collect {
|
||||
GlobalScope.launch {
|
||||
collector.emit(it)
|
||||
|
@ -2,7 +2,7 @@ package qq.service.contact
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import io.kritor.message.Scene
|
||||
import io.kritor.common.Scene
|
||||
|
||||
suspend fun Contact.longPeer(): Long {
|
||||
return when(this.chatType) {
|
||||
@ -12,7 +12,7 @@ suspend fun Contact.longPeer(): Long {
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun io.kritor.message.Contact.longPeer(): Long {
|
||||
suspend fun io.kritor.common.Contact.longPeer(): Long {
|
||||
return when(this.scene) {
|
||||
Scene.GROUP -> peer.toLong()
|
||||
Scene.FRIEND, Scene.STRANGER, Scene.STRANGER_FROM_GROUP -> if (peer.startsWith("u_")) ContactHelper.getUinByUidAsync(peer).toLong() else peer.toLong()
|
||||
|
@ -5,11 +5,7 @@ package qq.service.file
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.file.File
|
||||
import io.kritor.file.Folder
|
||||
import io.kritor.file.GetFileSystemInfoResponse
|
||||
import io.kritor.file.GetFilesRequest
|
||||
import io.kritor.file.GetFilesResponse
|
||||
import io.kritor.file.*
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
import moe.fuqiuluo.shamrock.helper.LogCenter
|
||||
import moe.fuqiuluo.shamrock.tools.EMPTY_BYTE_ARRAY
|
||||
@ -77,7 +73,7 @@ internal object GroupFileHelper: QQInterfaces() {
|
||||
}.build()
|
||||
}
|
||||
|
||||
suspend fun getGroupFiles(groupId: Long, folderId: String = "/"): GetFilesResponse {
|
||||
suspend fun getGroupFiles(groupId: Long, folderId: String = "/"): GetFileListResponse {
|
||||
val fileSystemInfo = getGroupFileSystemInfo(groupId)
|
||||
val fromServiceMsg = sendOidbAW("OidbSvc.0x6d8_1", 1752, 1, oidb_0x6d8.ReqBody().also {
|
||||
it.file_list_info_req.set(oidb_0x6d8.GetFileListReqBody().apply {
|
||||
@ -150,7 +146,7 @@ internal object GroupFileHelper: QQInterfaces() {
|
||||
throw StatusRuntimeException(Status.INTERNAL.withDescription("unable to fetch oidb response"))
|
||||
}
|
||||
|
||||
return GetFilesResponse.newBuilder().apply {
|
||||
return GetFileListResponse.newBuilder().apply {
|
||||
this.addAllFiles(files)
|
||||
this.addAllFolders(folders)
|
||||
}.build()
|
||||
|
@ -14,7 +14,7 @@ import qq.service.bdh.RichProtoSvc
|
||||
import qq.service.kernel.SimpleKernelMsgListener
|
||||
import qq.service.msg.MessageHelper
|
||||
|
||||
object AioListener: SimpleKernelMsgListener() {
|
||||
object AioListener : SimpleKernelMsgListener() {
|
||||
override fun onRecvMsg(records: ArrayList<MsgRecord>) {
|
||||
records.forEach {
|
||||
GlobalScope.launch {
|
||||
@ -60,7 +60,12 @@ object AioListener: SimpleKernelMsgListener() {
|
||||
|
||||
LogCenter.log("私聊临时消息(private = ${record.senderUin}, groupId=$groupCode)")
|
||||
|
||||
if (!GlobalEventTransmitter.MessageTransmitter.transTempMessage(record, record.elements, groupCode, fromNick)
|
||||
if (!GlobalEventTransmitter.MessageTransmitter.transTempMessage(
|
||||
record,
|
||||
record.elements,
|
||||
groupCode,
|
||||
fromNick
|
||||
)
|
||||
) {
|
||||
LogCenter.log("私聊临时消息推送失败 -> MessageTransmitter", Level.WARN)
|
||||
}
|
||||
@ -137,4 +142,10 @@ object AioListener: SimpleKernelMsgListener() {
|
||||
LogCenter.log("群聊文件消息推送失败 -> FileNoticeTransmitter", Level.WARN)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
override fun onRecvSysMsg(arrayList: ArrayList<Byte>?) {
|
||||
LogCenter.log("onRecvSysMsg")
|
||||
LogCenter.log(arrayList?.toByteArray()?.toHexString() ?: "")
|
||||
}
|
||||
}
|
@ -5,9 +5,8 @@ import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.qphone.base.remote.FromServiceMsg
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.kritor.event.GroupApplyType
|
||||
import io.kritor.event.GroupMemberDecreasedType
|
||||
import io.kritor.event.GroupMemberIncreasedType
|
||||
import io.kritor.event.GroupMemberDecreasedNotice.GroupMemberDecreasedType
|
||||
import io.kritor.event.GroupMemberIncreasedNotice.GroupMemberIncreasedType
|
||||
import kotlinx.coroutines.DelicateCoroutinesApi
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.launch
|
||||
@ -595,7 +594,7 @@ internal object PrimitiveListener {
|
||||
}
|
||||
LogCenter.log("入群申请($groupCode) $applier: \"$reason\", seq: $msgSeq")
|
||||
if (!GlobalEventTransmitter.RequestTransmitter
|
||||
.transGroupApply(time, applier, applierUid, reason, groupCode, flag, GroupApplyType.GROUP_APPLY_ADD)
|
||||
.transGroupApply(time, applier, applierUid, reason, groupCode, flag)
|
||||
) {
|
||||
LogCenter.log("入群申请推送失败!", Level.WARN)
|
||||
}
|
||||
@ -630,7 +629,7 @@ internal object PrimitiveListener {
|
||||
}
|
||||
LogCenter.log("邀请入群申请($groupCode): $applier")
|
||||
if (!GlobalEventTransmitter.RequestTransmitter
|
||||
.transGroupApply(time, applier, applierUid, "", groupCode, flag, GroupApplyType.GROUP_APPLY_ADD)
|
||||
.transGroupApply(time, applier, applierUid, "", groupCode, flag)
|
||||
) {
|
||||
LogCenter.log("邀请入群申请推送失败!", Level.WARN)
|
||||
}
|
||||
@ -658,7 +657,7 @@ internal object PrimitiveListener {
|
||||
"$time;$groupCode;$uin"
|
||||
}
|
||||
if (!GlobalEventTransmitter.RequestTransmitter
|
||||
.transGroupApply(time, invitor, invitorUid, "", groupCode, flag, GroupApplyType.GROUP_APPLY_INVITE)
|
||||
.transGroupApply(time, invitor, invitorUid, "", groupCode, flag)
|
||||
) {
|
||||
LogCenter.log("邀请入群推送失败!", Level.WARN)
|
||||
}
|
||||
|
@ -1,14 +1,15 @@
|
||||
package qq.service.msg
|
||||
|
||||
import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.grpc.Status
|
||||
import io.grpc.StatusRuntimeException
|
||||
import io.kritor.message.ForwardElement
|
||||
import io.kritor.message.ForwardMessageBody
|
||||
import io.kritor.message.Scene
|
||||
import io.kritor.common.ForwardElement
|
||||
import io.kritor.common.ForwardMessageBody
|
||||
import io.kritor.common.Scene
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
@ -30,9 +31,7 @@ import kotlin.time.Duration.Companion.seconds
|
||||
|
||||
internal object ForwardMessageHelper : QQInterfaces() {
|
||||
suspend fun uploadMultiMsg(
|
||||
chatType: Int,
|
||||
peerId: String,
|
||||
fromId: String = peerId,
|
||||
contact: Contact,
|
||||
messages: List<ForwardMessageBody>,
|
||||
): Result<ForwardElement> {
|
||||
var i = -1
|
||||
@ -41,20 +40,8 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
|
||||
val msgs = messages.mapNotNull { msg ->
|
||||
kotlin.runCatching {
|
||||
val contact = msg.contact.let {
|
||||
MessageHelper.generateContact(
|
||||
when (it.scene!!) {
|
||||
Scene.GROUP -> MsgConstant.KCHATTYPEGROUP
|
||||
Scene.FRIEND -> MsgConstant.KCHATTYPEC2C
|
||||
Scene.GUILD -> MsgConstant.KCHATTYPEGUILD
|
||||
Scene.STRANGER_FROM_GROUP -> MsgConstant.KCHATTYPETEMPC2CFROMGROUP
|
||||
Scene.NEARBY -> MsgConstant.KCHATTYPETEMPC2CFROMUNKNOWN
|
||||
Scene.STRANGER -> MsgConstant.KCHATTYPETEMPC2CFROMUNKNOWN
|
||||
Scene.UNRECOGNIZED -> throw StatusRuntimeException(Status.INVALID_ARGUMENT.withDescription("Unrecognized scene"))
|
||||
}, it.peer, it.subPeer
|
||||
)
|
||||
}
|
||||
if (msg.hasMessageId()) {
|
||||
when (msg.forwardMessageCase) {
|
||||
ForwardMessageBody.ForwardMessageCase.MESSAGE_ID -> {
|
||||
val record: MsgRecord = withTimeoutOrNull(5000) {
|
||||
val service = QRoute.api(IMsgService::class.java)
|
||||
suspendCancellableCoroutine { continuation ->
|
||||
@ -90,7 +77,7 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
msgType = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> 9
|
||||
MsgConstant.KCHATTYPEGROUP -> 82
|
||||
else -> throw UnsupportedOperationException("Unsupported chatType: $chatType")
|
||||
else -> throw UnsupportedOperationException("Unsupported chatType: ${contact.chatType}")
|
||||
},
|
||||
msgSubType = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||
divSeq = if (record.chatType == MsgConstant.KCHATTYPEC2C) 175 else null,
|
||||
@ -117,14 +104,17 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
}.getOrThrow().second
|
||||
)
|
||||
)
|
||||
} else {
|
||||
}
|
||||
|
||||
ForwardMessageBody.ForwardMessageCase.MESSAGE -> {
|
||||
val _msg = msg.message
|
||||
PushMsgBody(
|
||||
msgHead = if (msg.hasSender()) ResponseHead(
|
||||
peer = if (msg.sender.hasUin()) msg.sender.uin else TicketHelper.getUin().toLong(),
|
||||
peerUid = msg.sender.uid,
|
||||
msgHead = if (_msg.hasSender()) ResponseHead(
|
||||
peer = if (_msg.sender.hasUin()) _msg.sender.uin else TicketHelper.getUin().toLong(),
|
||||
peerUid = _msg.sender.uid,
|
||||
receiverUid = TicketHelper.getUid(),
|
||||
forward = ResponseForward(
|
||||
friendName = if (msg.sender.hasNick()) msg.sender.nick else TicketHelper.getNickname()
|
||||
friendName = if (_msg.sender.hasNick()) _msg.sender.nick else TicketHelper.getNickname()
|
||||
)
|
||||
) else ResponseHead(
|
||||
peer = TicketHelper.getUin().toLong(),
|
||||
@ -139,12 +129,12 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
msgSubType = 175,
|
||||
divSeq = 175,
|
||||
msgViaRandom = Random.nextLong(),
|
||||
sequence = msg.messageSeq.toLong(),
|
||||
msgTime = msg.messageTime.toLong(),
|
||||
sequence = _msg.messageSeq,
|
||||
msgTime = _msg.time.toLong(),
|
||||
u2 = 1,
|
||||
u6 = 0,
|
||||
u7 = 0,
|
||||
msgSeq = msg.messageSeq.toLong(),
|
||||
msgSeq = _msg.messageSeq,
|
||||
forwardHead = ForwardHead(
|
||||
u1 = 0,
|
||||
u2 = 0,
|
||||
@ -154,15 +144,18 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
)
|
||||
),
|
||||
body = MsgBody(
|
||||
richText = msg.elementsList.toRichText(contact).onSuccess {
|
||||
richText = _msg.elementsList.toRichText(contact).onSuccess {
|
||||
desc[++i] =
|
||||
(if (msg.hasSender() && msg.sender.hasNick()) msg.sender.nick else TicketHelper.getNickname()) + ": " + it.first
|
||||
(if (_msg.hasSender() && _msg.sender.hasNick()) _msg.sender.nick else TicketHelper.getNickname()) + ": " + it.first
|
||||
}.onFailure {
|
||||
error("消息合成失败: ${it.stackTraceToString()}")
|
||||
}.getOrThrow().second
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
else -> null
|
||||
}
|
||||
}.onFailure {
|
||||
LogCenter.log("消息节点解析失败:${it.stackTraceToString()}", Level.WARN)
|
||||
}.getOrNull()
|
||||
@ -192,21 +185,21 @@ internal object ForwardMessageHelper : QQInterfaces() {
|
||||
)
|
||||
|
||||
val req = LongMsgReq(
|
||||
sendInfo = when (chatType) {
|
||||
sendInfo = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> SendLongMsgInfo(
|
||||
type = 1,
|
||||
uid = LongMsgUid(if (peerId.startsWith("u_")) peerId else ContactHelper.getUidByUinAsync(peerId.toLong())),
|
||||
uid = LongMsgUid(contact.peerUid),
|
||||
payload = DeflateTools.gzip(payload.toByteArray())
|
||||
)
|
||||
|
||||
MsgConstant.KCHATTYPEGROUP -> SendLongMsgInfo(
|
||||
type = 3,
|
||||
uid = LongMsgUid(fromId),
|
||||
groupUin = fromId.toULong(),
|
||||
uid = LongMsgUid(contact.peerUid),
|
||||
groupUin = contact.peerUid.toULong(),
|
||||
payload = DeflateTools.gzip(payload.toByteArray())
|
||||
)
|
||||
|
||||
else -> throw UnsupportedOperationException("Unsupported chatType: $chatType")
|
||||
else -> throw UnsupportedOperationException("Unsupported chatType: ${contact.chatType}")
|
||||
},
|
||||
setting = LongMsgSettings(
|
||||
field1 = 4,
|
||||
|
@ -5,7 +5,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.kritor.message.*
|
||||
import io.kritor.common.*
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.ActionMsgException
|
||||
@ -135,8 +135,8 @@ private object MsgConvertor {
|
||||
|
||||
val elem = Element.newBuilder()
|
||||
elem.setImage(ImageElement.newBuilder().apply {
|
||||
this.file = md5
|
||||
this.url = when (record.chatType) {
|
||||
this.fileMd5 = md5
|
||||
this.fileUrl = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEDISC, MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(
|
||||
originalUrl = originalUrl,
|
||||
md5 = md5,
|
||||
@ -175,7 +175,7 @@ private object MsgConvertor {
|
||||
else -> throw UnsupportedOperationException("Not supported chat type: ${record.chatType}")
|
||||
}
|
||||
this.type =
|
||||
if (image.isFlashPic == true) ImageType.FLASH else if (image.original) ImageType.ORIGIN else ImageType.COMMON
|
||||
if (image.isFlashPic == true) ImageElement.ImageType.FLASH else if (image.original) ImageElement.ImageType.ORIGIN else ImageElement.ImageType.COMMON
|
||||
this.subType = image.picSubType
|
||||
})
|
||||
|
||||
@ -191,7 +191,7 @@ private object MsgConvertor {
|
||||
else ptt.md5HexStr
|
||||
|
||||
elem.setVoice(VoiceElement.newBuilder().apply {
|
||||
this.url = when (record.chatType) {
|
||||
this.fileUrl = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPttDownUrl("0", ptt.fileUuid)
|
||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupPttDownUrl(
|
||||
"0",
|
||||
@ -201,7 +201,7 @@ private object MsgConvertor {
|
||||
|
||||
else -> throw UnsupportedOperationException("Not supported chat type: ${record.chatType}")
|
||||
}
|
||||
this.file = md5
|
||||
this.fileMd5 = md5
|
||||
this.magic = ptt.voiceChangeType != MsgConstant.KPTTVOICECHANGETYPENONE
|
||||
})
|
||||
|
||||
@ -219,8 +219,8 @@ private object MsgConvertor {
|
||||
}
|
||||
} else video.fileName.split(".")[0].hex2ByteArray()
|
||||
elem.setVideo(VideoElement.newBuilder().apply {
|
||||
this.file = md5.toHexString()
|
||||
this.url = when (record.chatType) {
|
||||
this.fileMd5 = md5.toHexString()
|
||||
this.fileUrl = when (record.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
@ -304,9 +304,9 @@ private object MsgConvertor {
|
||||
}
|
||||
if (sourceRecords.isNullOrEmpty()) {
|
||||
LogCenter.log("无法查询到回复的消息ID: seq = $msgSeq", Level.WARN)
|
||||
this.messageId = reply.replayMsgId
|
||||
this.messageId = reply.replayMsgId.toString()
|
||||
} else {
|
||||
this.messageId = sourceRecords.first().msgId
|
||||
this.messageId = sourceRecords.first().msgId.toString()
|
||||
}
|
||||
})
|
||||
return Result.success(elem.build())
|
||||
|
@ -4,7 +4,9 @@ package qq.service.msg
|
||||
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import io.kritor.message.*
|
||||
import io.kritor.common.*
|
||||
import io.kritor.common.Element.ElementType
|
||||
import io.kritor.common.ImageElement.ImageType
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUInt
|
||||
@ -62,9 +64,9 @@ suspend fun List<Elem>.toKritorResponseMessages(contact: Contact): ArrayList<Ele
|
||||
kritorMessages.add(Element.newBuilder().apply {
|
||||
this.type = ElementType.IMAGE
|
||||
this.image = ImageElement.newBuilder().apply {
|
||||
this.fileName = md5
|
||||
this.fileMd5 = md5
|
||||
this.type = if (customFace.origin == true) ImageType.ORIGIN else ImageType.COMMON
|
||||
this.url = when (contact.chatType) {
|
||||
this.fileUrl = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEDISC, MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(
|
||||
origUrl,
|
||||
md5
|
||||
@ -82,9 +84,9 @@ suspend fun List<Elem>.toKritorResponseMessages(contact: Contact): ArrayList<Ele
|
||||
kritorMessages.add(Element.newBuilder().apply {
|
||||
this.type = ElementType.IMAGE
|
||||
this.image = ImageElement.newBuilder().apply {
|
||||
this.fileName = md5
|
||||
this.fileMd5 = md5
|
||||
this.type = if (element.notOnlineImage?.original == true) ImageType.ORIGIN else ImageType.COMMON
|
||||
this.url = when (contact.chatType) {
|
||||
this.fileUrl = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEDISC, MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(
|
||||
origUrl,
|
||||
md5
|
||||
@ -112,7 +114,7 @@ suspend fun List<Elem>.toKritorResponseMessages(contact: Contact): ArrayList<Ele
|
||||
kritorMessages.add(Element.newBuilder().apply {
|
||||
this.type = ElementType.REPLY
|
||||
this.reply = ReplyElement.newBuilder().apply {
|
||||
this.messageId = msgId
|
||||
this.messageId = msgId.toString()
|
||||
}.build()
|
||||
}.build())
|
||||
} else if (element.lightApp != null) {
|
||||
@ -256,7 +258,7 @@ suspend fun List<Elem>.toKritorResponseMessages(contact: Contact): ArrayList<Ele
|
||||
})
|
||||
}.build()
|
||||
})
|
||||
this.applicationId = buttonExtra.field1?.appid?.toLong() ?: 0L
|
||||
this.botAppid = buttonExtra.field1?.appid?.toLong() ?: 0L
|
||||
}.build()).build()
|
||||
)
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
package qq.service.msg
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import android.util.Base64
|
||||
import androidx.exifinterface.media.ExifInterface
|
||||
import com.tencent.mobileqq.emoticon.QQSysFaceUtil
|
||||
import com.tencent.mobileqq.pb.ByteStringMicro
|
||||
@ -9,17 +8,18 @@ import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.qphone.base.remote.ToServiceMsg
|
||||
import com.tencent.qqnt.aio.adapter.api.IAIOPttApi
|
||||
import com.tencent.qqnt.kernel.nativeinterface.*
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.FaceElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MarkdownElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MarketFaceElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.ReplyElement
|
||||
import com.tencent.qqnt.kernel.nativeinterface.TextElement
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.kritor.message.AtElement
|
||||
import io.kritor.message.Button
|
||||
import io.kritor.message.Element
|
||||
import io.kritor.message.ElementType
|
||||
import io.kritor.message.ElementType.*
|
||||
import io.kritor.message.ImageElement
|
||||
import io.kritor.message.ImageType
|
||||
import io.kritor.message.MusicPlatform
|
||||
import io.kritor.message.Scene
|
||||
import io.kritor.message.VoiceElement
|
||||
import io.kritor.common.*
|
||||
import io.kritor.common.Element.ElementType
|
||||
import io.kritor.common.ImageElement.ImageType
|
||||
import io.kritor.common.MusicElement.MusicPlatform
|
||||
import io.kritor.common.VideoElement
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.config.EnableOldBDH
|
||||
@ -77,27 +77,27 @@ private typealias NtConvertor = suspend (Contact, Long, Element) -> Result<MsgEl
|
||||
|
||||
object NtMsgConvertor {
|
||||
private val ntConvertors = mapOf<ElementType, NtConvertor>(
|
||||
TEXT to ::textConvertor,
|
||||
AT to ::atConvertor,
|
||||
FACE to ::faceConvertor,
|
||||
BUBBLE_FACE to ::bubbleFaceConvertor,
|
||||
REPLY to ::replyConvertor,
|
||||
IMAGE to ::imageConvertor,
|
||||
VOICE to ::voiceConvertor,
|
||||
VIDEO to ::videoConvertor,
|
||||
BASKETBALL to ::basketballConvertor,
|
||||
DICE to ::diceConvertor,
|
||||
RPS to ::rpsConvertor,
|
||||
POKE to ::pokeConvertor,
|
||||
MUSIC to ::musicConvertor,
|
||||
WEATHER to ::weatherConvertor,
|
||||
LOCATION to ::locationConvertor,
|
||||
SHARE to ::shareConvertor,
|
||||
CONTACT to ::contactConvertor,
|
||||
JSON to ::jsonConvertor,
|
||||
FORWARD to ::forwardConvertor,
|
||||
MARKDOWN to ::markdownConvertor,
|
||||
BUTTON to ::buttonConvertor,
|
||||
ElementType.TEXT to ::textConvertor,
|
||||
ElementType.AT to ::atConvertor,
|
||||
ElementType.FACE to ::faceConvertor,
|
||||
ElementType.BUBBLE_FACE to ::bubbleFaceConvertor,
|
||||
ElementType.REPLY to ::replyConvertor,
|
||||
ElementType.IMAGE to ::imageConvertor,
|
||||
ElementType.VOICE to ::voiceConvertor,
|
||||
ElementType.VIDEO to ::videoConvertor,
|
||||
ElementType.BASKETBALL to ::basketballConvertor,
|
||||
ElementType.DICE to ::diceConvertor,
|
||||
ElementType.RPS to ::rpsConvertor,
|
||||
ElementType.POKE to ::pokeConvertor,
|
||||
ElementType.MUSIC to ::musicConvertor,
|
||||
ElementType.WEATHER to ::weatherConvertor,
|
||||
ElementType.LOCATION to ::locationConvertor,
|
||||
ElementType.SHARE to ::shareConvertor,
|
||||
ElementType.CONTACT to ::contactConvertor,
|
||||
ElementType.JSON to ::jsonConvertor,
|
||||
ElementType.FORWARD to ::forwardConvertor,
|
||||
ElementType.MARKDOWN to ::markdownConvertor,
|
||||
ElementType.BUTTON to ::buttonConvertor,
|
||||
)
|
||||
|
||||
suspend fun convertToNtMsgs(contact: Contact, msgId: Long, msgs: Messages): ArrayList<MsgElement> {
|
||||
@ -135,24 +135,6 @@ object NtMsgConvertor {
|
||||
|
||||
val elem = MsgElement()
|
||||
val at = TextElement()
|
||||
if (sourceAt.at.accountCase == AtElement.AccountCase.UIN) {
|
||||
val uin = sourceAt.at.uin
|
||||
if (uin == 0L) {
|
||||
at.content = "@全体成员"
|
||||
at.atType = MsgConstant.ATTYPEALL
|
||||
at.atNtUid = "0"
|
||||
} else {
|
||||
val info = GroupHelper.getTroopMemberInfoByUinV2(contact.peerUid, uin.toString(), true).onFailure {
|
||||
LogCenter.log("无法获取群成员信息: contact=$contact, id=${uin}", Level.WARN)
|
||||
}.getOrNull()
|
||||
at.content = "@${
|
||||
info?.troopnick.ifNullOrEmpty { info?.friendnick }
|
||||
?: uin.toString()
|
||||
}"
|
||||
at.atType = MsgConstant.ATTYPEONE
|
||||
at.atNtUid = ContactHelper.getUidByUinAsync(uin)
|
||||
}
|
||||
} else {
|
||||
val uid = sourceAt.at.uid
|
||||
if (uid == "all" || uid == "0") {
|
||||
at.content = "@全体成员"
|
||||
@ -170,7 +152,6 @@ object NtMsgConvertor {
|
||||
at.atType = MsgConstant.ATTYPEONE
|
||||
at.atNtUid = uid
|
||||
}
|
||||
}
|
||||
elem.textElement = at
|
||||
elem.elementType = MsgConstant.KELEMTYPETEXT
|
||||
return Result.success(elem)
|
||||
@ -215,7 +196,11 @@ object NtMsgConvertor {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun bubbleFaceConvertor(contact: Contact, msgId: Long, sourceBubbleFace: Element): Result<MsgElement> {
|
||||
private suspend fun bubbleFaceConvertor(
|
||||
contact: Contact,
|
||||
msgId: Long,
|
||||
sourceBubbleFace: Element
|
||||
): Result<MsgElement> {
|
||||
val faceId = sourceBubbleFace.bubbleFace.id
|
||||
val local = QQSysFaceUtil.convertToLocal(faceId)
|
||||
val name = QQSysFaceUtil.getFaceDescription(local)
|
||||
@ -242,7 +227,7 @@ object NtMsgConvertor {
|
||||
element.elementType = MsgConstant.KELEMTYPEREPLY
|
||||
val reply = ReplyElement()
|
||||
|
||||
reply.replayMsgId = sourceReply.reply.messageId
|
||||
reply.replayMsgId = sourceReply.reply.messageId.toLong()
|
||||
reply.sourceMsgIdInRecords = reply.replayMsgId
|
||||
|
||||
if (reply.replayMsgId == 0L) {
|
||||
@ -251,7 +236,8 @@ object NtMsgConvertor {
|
||||
|
||||
withTimeoutOrNull(3000) {
|
||||
suspendCancellableCoroutine {
|
||||
QRoute.api(IMsgService::class.java).getMsgsByMsgId(contact, arrayListOf(reply.replayMsgId)) { _, _, records ->
|
||||
QRoute.api(IMsgService::class.java)
|
||||
.getMsgsByMsgId(contact, arrayListOf(reply.replayMsgId)) { _, _, records ->
|
||||
it.resume(records)
|
||||
}
|
||||
}
|
||||
@ -270,25 +256,31 @@ object NtMsgConvertor {
|
||||
private suspend fun imageConvertor(contact: Contact, msgId: Long, sourceImage: Element): Result<MsgElement> {
|
||||
val isOriginal = sourceImage.image.type == ImageType.ORIGIN
|
||||
val isFlash = sourceImage.image.type == ImageType.FLASH
|
||||
val file = when(sourceImage.image.dataCase!!) {
|
||||
val file = when (sourceImage.image.dataCase!!) {
|
||||
ImageElement.DataCase.FILE_NAME -> {
|
||||
val fileMd5 = sourceImage.image.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "").split(".")[0].lowercase()
|
||||
val fileMd5 = sourceImage.image.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "")
|
||||
.split(".")[0].lowercase()
|
||||
FileUtils.getFileByMd5(fileMd5)
|
||||
}
|
||||
|
||||
ImageElement.DataCase.FILE_PATH -> {
|
||||
val filePath = sourceImage.image.filePath
|
||||
File(filePath).inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}
|
||||
}
|
||||
ImageElement.DataCase.FILE_BASE64 -> {
|
||||
FileUtils.saveFileToCache(ByteArrayInputStream(
|
||||
Base64.decode(sourceImage.image.fileBase64, Base64.DEFAULT)
|
||||
))
|
||||
|
||||
ImageElement.DataCase.FILE -> {
|
||||
FileUtils.saveFileToCache(
|
||||
ByteArrayInputStream(
|
||||
sourceImage.image.file.toByteArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
ImageElement.DataCase.URL -> {
|
||||
|
||||
ImageElement.DataCase.FILE_URL -> {
|
||||
val tmp = FileUtils.getTmpFile()
|
||||
if(DownloadUtils.download(sourceImage.image.url, tmp)) {
|
||||
if (DownloadUtils.download(sourceImage.image.fileUrl, tmp)) {
|
||||
tmp.inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}.also {
|
||||
@ -296,16 +288,20 @@ object NtMsgConvertor {
|
||||
}
|
||||
} else {
|
||||
tmp.delete()
|
||||
return Result.failure(LogicException("图片资源下载失败: ${sourceImage.image.url}"))
|
||||
return Result.failure(LogicException("图片资源下载失败: ${sourceImage.image.fileUrl}"))
|
||||
}
|
||||
}
|
||||
|
||||
ImageElement.DataCase.DATA_NOT_SET -> return Result.failure(IllegalArgumentException("ImageElement data is not set"))
|
||||
}
|
||||
|
||||
if (EnableOldBDH.get()) {
|
||||
Transfer with when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(contact.peerUid)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(contact.longPeer().toString())
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(
|
||||
contact.longPeer().toString()
|
||||
)
|
||||
|
||||
MsgConstant.KCHATTYPEGUILD -> Troop(contact.peerUid)
|
||||
else -> return Result.failure(Exception("Not supported chatType(${contact.chatType}) for PictureMsg"))
|
||||
} trans PictureResource(file)
|
||||
@ -360,25 +356,29 @@ object NtMsgConvertor {
|
||||
}
|
||||
|
||||
private suspend fun voiceConvertor(contact: Contact, msgId: Long, sourceVoice: Element): Result<MsgElement> {
|
||||
var file = when(sourceVoice.voice.dataCase!!) {
|
||||
var file = when (sourceVoice.voice.dataCase!!) {
|
||||
VoiceElement.DataCase.FILE_NAME -> {
|
||||
val fileMd5 = sourceVoice.voice.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "").split(".")[0].lowercase()
|
||||
val fileMd5 = sourceVoice.voice.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "")
|
||||
.split(".")[0].lowercase()
|
||||
FileUtils.getFileByMd5(fileMd5)
|
||||
}
|
||||
|
||||
VoiceElement.DataCase.FILE_PATH -> {
|
||||
val filePath = sourceVoice.voice.filePath
|
||||
File(filePath).inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}
|
||||
}
|
||||
VoiceElement.DataCase.FILE_BASE64 -> {
|
||||
FileUtils.saveFileToCache(ByteArrayInputStream(
|
||||
Base64.decode(sourceVoice.voice.fileBase64, Base64.DEFAULT)
|
||||
))
|
||||
|
||||
VoiceElement.DataCase.FILE -> {
|
||||
FileUtils.saveFileToCache(
|
||||
sourceVoice.voice.file.toByteArray().inputStream()
|
||||
)
|
||||
}
|
||||
VoiceElement.DataCase.URL -> {
|
||||
|
||||
VoiceElement.DataCase.FILE_URL -> {
|
||||
val tmp = FileUtils.getTmpFile()
|
||||
if(DownloadUtils.download(sourceVoice.voice.url, tmp)) {
|
||||
if (DownloadUtils.download(sourceVoice.voice.fileUrl, tmp)) {
|
||||
tmp.inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}.also {
|
||||
@ -386,9 +386,10 @@ object NtMsgConvertor {
|
||||
}
|
||||
} else {
|
||||
tmp.delete()
|
||||
return Result.failure(LogicException("音频资源下载失败: ${sourceVoice.voice.url}"))
|
||||
return Result.failure(LogicException("音频资源下载失败: ${sourceVoice.voice.fileUrl}"))
|
||||
}
|
||||
}
|
||||
|
||||
VoiceElement.DataCase.DATA_NOT_SET -> return Result.failure(IllegalArgumentException("VoiceElement data is not set"))
|
||||
}
|
||||
|
||||
@ -439,7 +440,10 @@ object NtMsgConvertor {
|
||||
if (EnableOldBDH.get()) {
|
||||
if (!(Transfer with when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(contact.peerUid)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(contact.longPeer().toString())
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(
|
||||
contact.longPeer().toString()
|
||||
)
|
||||
|
||||
MsgConstant.KCHATTYPEGUILD -> Troop(contact.peerUid)
|
||||
else -> return Result.failure(Exception("Not supported chatType(${contact.chatType}) for VoiceMsg"))
|
||||
} trans VoiceResource(file))
|
||||
@ -485,27 +489,31 @@ object NtMsgConvertor {
|
||||
|
||||
private suspend fun videoConvertor(contact: Contact, msgId: Long, sourceVideo: Element): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
val video = VideoElement()
|
||||
val video = com.tencent.qqnt.kernel.nativeinterface.VideoElement()
|
||||
|
||||
val file = when(sourceVideo.video.dataCase!!) {
|
||||
io.kritor.message.VideoElement.DataCase.FILE_NAME -> {
|
||||
val fileMd5 = sourceVideo.video.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "").split(".")[0].lowercase()
|
||||
val file = when (sourceVideo.video.dataCase!!) {
|
||||
VideoElement.DataCase.FILE -> {
|
||||
FileUtils.saveFileToCache(
|
||||
sourceVideo.video.file.toByteArray().inputStream()
|
||||
)
|
||||
}
|
||||
|
||||
VideoElement.DataCase.FILE_NAME -> {
|
||||
val fileMd5 = sourceVideo.video.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "")
|
||||
.split(".")[0].lowercase()
|
||||
FileUtils.getFileByMd5(fileMd5)
|
||||
}
|
||||
io.kritor.message.VideoElement.DataCase.FILE_PATH -> {
|
||||
|
||||
VideoElement.DataCase.FILE_PATH -> {
|
||||
val filePath = sourceVideo.video.filePath
|
||||
File(filePath).inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}
|
||||
}
|
||||
io.kritor.message.VideoElement.DataCase.FILE_BASE64 -> {
|
||||
FileUtils.saveFileToCache(ByteArrayInputStream(
|
||||
Base64.decode(sourceVideo.video.fileBase64, Base64.DEFAULT)
|
||||
))
|
||||
}
|
||||
io.kritor.message.VideoElement.DataCase.URL -> {
|
||||
|
||||
VideoElement.DataCase.FILE_URL -> {
|
||||
val tmp = FileUtils.getTmpFile()
|
||||
if(DownloadUtils.download(sourceVideo.video.url, tmp)) {
|
||||
if (DownloadUtils.download(sourceVideo.video.fileUrl, tmp)) {
|
||||
tmp.inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}.also {
|
||||
@ -513,10 +521,11 @@ object NtMsgConvertor {
|
||||
}
|
||||
} else {
|
||||
tmp.delete()
|
||||
return Result.failure(LogicException("视频资源下载失败: ${sourceVideo.video.url}"))
|
||||
return Result.failure(LogicException("视频资源下载失败: ${sourceVideo.video.fileUrl}"))
|
||||
}
|
||||
}
|
||||
io.kritor.message.VideoElement.DataCase.DATA_NOT_SET -> return Result.failure(IllegalArgumentException("VideoElement data is not set"))
|
||||
|
||||
VideoElement.DataCase.DATA_NOT_SET -> return Result.failure(IllegalArgumentException("VideoElement data is not set"))
|
||||
}
|
||||
|
||||
video.videoMd5 = QQNTWrapperUtil.CppProxy.genFileMd5Hex(file.absolutePath)
|
||||
@ -543,7 +552,10 @@ object NtMsgConvertor {
|
||||
if (EnableOldBDH.get()) {
|
||||
Transfer with when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> Troop(contact.peerUid)
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(contact.longPeer().toString())
|
||||
MsgConstant.KCHATTYPETEMPC2CFROMGROUP, MsgConstant.KCHATTYPEC2C -> Private(
|
||||
contact.longPeer().toString()
|
||||
)
|
||||
|
||||
MsgConstant.KCHATTYPEGUILD -> Troop(contact.peerUid)
|
||||
else -> return Result.failure(Exception("Not supported chatType(${contact.chatType}) for VideoMsg"))
|
||||
} trans VideoResource(file, File(thumbPath.toString()))
|
||||
@ -567,7 +579,11 @@ object NtMsgConvertor {
|
||||
return Result.success(elem)
|
||||
}
|
||||
|
||||
private suspend fun basketballConvertor(contact: Contact, msgId: Long, sourceBasketball: Element): Result<MsgElement> {
|
||||
private suspend fun basketballConvertor(
|
||||
contact: Contact,
|
||||
msgId: Long,
|
||||
sourceBasketball: Element
|
||||
): Result<MsgElement> {
|
||||
val elem = MsgElement()
|
||||
elem.elementType = MsgConstant.KELEMTYPEFACE
|
||||
val face = FaceElement()
|
||||
@ -697,7 +713,11 @@ object NtMsgConvertor {
|
||||
}
|
||||
|
||||
private suspend fun locationConvertor(contact: Contact, msgId: Long, sourceLocation: Element): Result<MsgElement> {
|
||||
LbsHelper.tryShareLocation(contact, sourceLocation.location.lat.toDouble(), sourceLocation.location.lon.toDouble()).onFailure {
|
||||
LbsHelper.tryShareLocation(
|
||||
contact,
|
||||
sourceLocation.location.lat.toDouble(),
|
||||
sourceLocation.location.lon.toDouble()
|
||||
).onFailure {
|
||||
LogCenter.log("无法发送位置分享", Level.ERROR)
|
||||
}
|
||||
return Result.failure(ActionMsgException)
|
||||
@ -801,7 +821,8 @@ object NtMsgConvertor {
|
||||
val action = button.action
|
||||
val permission = action.permission
|
||||
return runCatching {
|
||||
InlineKeyboardButton(button.id, renderData.label, renderData.visitedLabel, renderData.style,
|
||||
InlineKeyboardButton(
|
||||
button.id, renderData.label, renderData.visitedLabel, renderData.style,
|
||||
action.type, 0,
|
||||
action.unsupportedTips,
|
||||
action.data, false,
|
||||
@ -811,7 +832,8 @@ object NtMsgConvertor {
|
||||
false, 0, false, arrayListOf()
|
||||
)
|
||||
}.getOrElse {
|
||||
InlineKeyboardButton(button.id, renderData.label, renderData.visitedLabel, renderData.style,
|
||||
InlineKeyboardButton(
|
||||
button.id, renderData.label, renderData.visitedLabel, renderData.style,
|
||||
action.type, 0,
|
||||
action.unsupportedTips,
|
||||
action.data, false,
|
||||
|
@ -5,7 +5,7 @@ import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgElement
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.kritor.message.*
|
||||
import io.kritor.common.*
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.ActionMsgException
|
||||
@ -135,8 +135,8 @@ private object ReqMsgConvertor {
|
||||
|
||||
val elem = Element.newBuilder()
|
||||
elem.setImage(ImageElement.newBuilder().apply {
|
||||
this.file = md5
|
||||
this.url = when (contact.chatType) {
|
||||
this.fileMd5 = md5
|
||||
this.fileUrl = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEDISC, MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupPicDownUrl(
|
||||
originalUrl = originalUrl,
|
||||
md5 = md5,
|
||||
@ -175,7 +175,7 @@ private object ReqMsgConvertor {
|
||||
else -> throw UnsupportedOperationException("Not supported chat type: ${contact.chatType}")
|
||||
}
|
||||
this.type =
|
||||
if (image.isFlashPic == true) ImageType.FLASH else if (image.original) ImageType.ORIGIN else ImageType.COMMON
|
||||
if (image.isFlashPic == true) ImageElement.ImageType.FLASH else if (image.original) ImageElement.ImageType.ORIGIN else ImageElement.ImageType.COMMON
|
||||
this.subType = image.picSubType
|
||||
})
|
||||
|
||||
@ -191,7 +191,7 @@ private object ReqMsgConvertor {
|
||||
else ptt.md5HexStr
|
||||
|
||||
elem.setVoice(VoiceElement.newBuilder().apply {
|
||||
this.url = when (contact.chatType) {
|
||||
this.fileUrl = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CPttDownUrl("0", ptt.fileUuid)
|
||||
MsgConstant.KCHATTYPEGROUP, MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupPttDownUrl(
|
||||
"0",
|
||||
@ -201,7 +201,7 @@ private object ReqMsgConvertor {
|
||||
|
||||
else -> throw UnsupportedOperationException("Not supported chat type: ${contact.chatType}")
|
||||
}
|
||||
this.file = md5
|
||||
this.fileMd5 = md5
|
||||
this.magic = ptt.voiceChangeType != MsgConstant.KPTTVOICECHANGETYPENONE
|
||||
})
|
||||
|
||||
@ -219,8 +219,8 @@ private object ReqMsgConvertor {
|
||||
}
|
||||
} else video.fileName.split(".")[0].hex2ByteArray()
|
||||
elem.setVideo(VideoElement.newBuilder().apply {
|
||||
this.file = md5.toHexString()
|
||||
this.url = when (contact.chatType) {
|
||||
this.fileMd5 = md5.toHexString()
|
||||
this.fileUrl = when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEC2C -> RichProtoSvc.getC2CVideoDownUrl("0", md5, video.fileUuid)
|
||||
MsgConstant.KCHATTYPEGUILD -> RichProtoSvc.getGroupVideoDownUrl("0", md5, video.fileUuid)
|
||||
@ -233,7 +233,11 @@ private object ReqMsgConvertor {
|
||||
suspend fun convertMarketFace(contact: Contact, element: MsgElement): Result<Element> {
|
||||
val marketFace = element.marketFaceElement
|
||||
val elem = Element.newBuilder()
|
||||
return Result.failure(ActionMsgException)
|
||||
elem.setMarketFace(MarketFaceElement.newBuilder().apply {
|
||||
this.id = marketFace.emojiId
|
||||
})
|
||||
// TODO
|
||||
return Result.success(elem.build())
|
||||
}
|
||||
|
||||
suspend fun convertStructJson(contact: Contact, element: MsgElement): Result<Element> {
|
||||
@ -300,9 +304,9 @@ private object ReqMsgConvertor {
|
||||
}
|
||||
if (sourceRecords.isNullOrEmpty()) {
|
||||
LogCenter.log("无法查询到回复的消息ID: seq = $msgSeq", Level.WARN)
|
||||
this.messageId = reply.replayMsgId
|
||||
this.messageId = reply.replayMsgId.toString()
|
||||
} else {
|
||||
this.messageId = sourceRecords.first().msgId
|
||||
this.messageId = sourceRecords.first().msgId.toString()
|
||||
}
|
||||
})
|
||||
return Result.success(elem.build())
|
||||
@ -393,7 +397,7 @@ private object ReqMsgConvertor {
|
||||
})
|
||||
}.build()
|
||||
})
|
||||
this.applicationId = inlineKeyboard.botAppid
|
||||
this.botAppid = inlineKeyboard.botAppid
|
||||
})
|
||||
return Result.success(elem.build())
|
||||
}
|
||||
|
@ -7,11 +7,8 @@ import com.tencent.mobileqq.qroute.QRoute
|
||||
import com.tencent.qqnt.kernel.nativeinterface.Contact
|
||||
import com.tencent.qqnt.kernel.nativeinterface.MsgConstant
|
||||
import com.tencent.qqnt.msg.api.IMsgService
|
||||
import io.kritor.message.AtElement
|
||||
import io.kritor.message.Element
|
||||
import io.kritor.message.ElementType
|
||||
import io.kritor.message.ImageElement
|
||||
import io.kritor.message.ImageType
|
||||
import io.kritor.common.Element
|
||||
import io.kritor.common.ImageElement
|
||||
import kotlinx.coroutines.suspendCancellableCoroutine
|
||||
import kotlinx.coroutines.withTimeoutOrNull
|
||||
import moe.fuqiuluo.shamrock.helper.Level
|
||||
@ -68,7 +65,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
forEach {
|
||||
try {
|
||||
when(it.type!!) {
|
||||
ElementType.TEXT -> {
|
||||
Element.ElementType.TEXT -> {
|
||||
val text = it.text.text
|
||||
val elem = Elem(
|
||||
text = TextMsg(text)
|
||||
@ -76,13 +73,11 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary.append(text)
|
||||
}
|
||||
ElementType.AT -> {
|
||||
Element.ElementType.AT -> {
|
||||
when (contact.chatType) {
|
||||
MsgConstant.KCHATTYPEGROUP -> {
|
||||
val qq = when (it.at.accountCase) {
|
||||
AtElement.AccountCase.UIN -> it.at.uin.toString()
|
||||
else -> ContactHelper.getUinByUidAsync(it.at.uid)
|
||||
}
|
||||
val qq = ContactHelper.getUinByUidAsync(it.at.uid)
|
||||
|
||||
val type: Int
|
||||
val nick = if (it.at.uid == "all" || it.at.uin == 0L) {
|
||||
type = 1
|
||||
@ -112,10 +107,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
}
|
||||
|
||||
MsgConstant.KCHATTYPEC2C -> {
|
||||
val qq = when (it.at.accountCase) {
|
||||
AtElement.AccountCase.UIN -> it.at.uin.toString()
|
||||
else -> ContactHelper.getUinByUidAsync(it.at.uid)
|
||||
}
|
||||
val qq = ContactHelper.getUinByUidAsync(it.at.uid)
|
||||
val display = "@" + (ContactHelper.getProfileCard(qq.toLong()).onSuccess {
|
||||
it.strNick.ifNullOrEmpty { qq }
|
||||
}.onFailure {
|
||||
@ -130,7 +122,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
else -> throw UnsupportedOperationException("Unsupported chatType($contact) for AtMsg")
|
||||
}
|
||||
}
|
||||
ElementType.FACE -> {
|
||||
Element.ElementType.FACE -> {
|
||||
val faceId = it.face.id
|
||||
val elem = if (it.face.isBig) {
|
||||
Elem(
|
||||
@ -159,12 +151,12 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary.append("[表情]")
|
||||
}
|
||||
ElementType.BUBBLE_FACE -> throw UnsupportedOperationException("Unsupported ElementType.BUBBLE_FACE")
|
||||
ElementType.REPLY -> {
|
||||
Element.ElementType.BUBBLE_FACE -> throw UnsupportedOperationException("Unsupported Element.ElementType.BUBBLE_FACE")
|
||||
Element.ElementType.REPLY -> {
|
||||
val msgId = it.reply.messageId
|
||||
withTimeoutOrNull(3000) {
|
||||
suspendCancellableCoroutine {
|
||||
QRoute.api(IMsgService::class.java).getMsgsByMsgId(contact, arrayListOf(msgId)) { _, _, records ->
|
||||
QRoute.api(IMsgService::class.java).getMsgsByMsgId(contact, arrayListOf(msgId.toLong())) { _, _, records ->
|
||||
it.resume(records)
|
||||
}
|
||||
}
|
||||
@ -191,9 +183,9 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
}
|
||||
summary.append("[回复消息]")
|
||||
}
|
||||
ElementType.IMAGE -> {
|
||||
Element.ElementType.IMAGE -> {
|
||||
val type = it.image.type
|
||||
val isOriginal = type == ImageType.ORIGIN
|
||||
val isOriginal = type == ImageElement.ImageType.ORIGIN
|
||||
val file = when(it.image.dataCase!!) {
|
||||
ImageElement.DataCase.FILE_NAME -> {
|
||||
val fileMd5 = it.image.fileName.replace(regex = "[{}\\-]".toRegex(), replacement = "").split(".")[0].lowercase()
|
||||
@ -205,16 +197,16 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
FileUtils.saveFileToCache(it)
|
||||
}
|
||||
}
|
||||
ImageElement.DataCase.FILE_BASE64 -> {
|
||||
ImageElement.DataCase.FILE -> {
|
||||
FileUtils.saveFileToCache(
|
||||
ByteArrayInputStream(
|
||||
Base64.decode(it.image.fileBase64, Base64.DEFAULT)
|
||||
it.image.file.toByteArray()
|
||||
)
|
||||
)
|
||||
}
|
||||
ImageElement.DataCase.URL -> {
|
||||
ImageElement.DataCase.FILE_URL -> {
|
||||
val tmp = FileUtils.getTmpFile()
|
||||
if(DownloadUtils.download(it.image.url, tmp)) {
|
||||
if(DownloadUtils.download(it.image.fileUrl, tmp)) {
|
||||
tmp.inputStream().use {
|
||||
FileUtils.saveFileToCache(it)
|
||||
}.also {
|
||||
@ -222,7 +214,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
}
|
||||
} else {
|
||||
tmp.delete()
|
||||
throw LogicException("图片资源下载失败: ${it.image.url}")
|
||||
throw LogicException("图片资源下载失败: ${it.image.fileUrl}")
|
||||
}
|
||||
}
|
||||
ImageElement.DataCase.DATA_NOT_SET -> throw IllegalArgumentException("ImageElement data is not set")
|
||||
@ -352,10 +344,10 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
|
||||
summary.append("[图片]")
|
||||
}
|
||||
ElementType.VOICE -> throw UnsupportedOperationException("Unsupported ElementType.VOICE")
|
||||
ElementType.VIDEO -> throw UnsupportedOperationException("Unsupported ElementType.VIDEO")
|
||||
ElementType.BASKETBALL -> throw UnsupportedOperationException("Unsupported ElementType.BASKETBALL")
|
||||
ElementType.DICE -> {
|
||||
Element.ElementType.VOICE -> throw UnsupportedOperationException("Unsupported Element.ElementType.VOICE")
|
||||
Element.ElementType.VIDEO -> throw UnsupportedOperationException("Unsupported Element.ElementType.VIDEO")
|
||||
Element.ElementType.BASKETBALL -> throw UnsupportedOperationException("Unsupported Element.ElementType.BASKETBALL")
|
||||
Element.ElementType.DICE -> {
|
||||
val elem = Elem(
|
||||
commonElem = CommonElem(
|
||||
serviceType = 37,
|
||||
@ -375,7 +367,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary .append( "[骰子]" )
|
||||
}
|
||||
ElementType.RPS -> {
|
||||
Element.ElementType.RPS -> {
|
||||
val elem = Elem(
|
||||
commonElem = CommonElem(
|
||||
serviceType = 37,
|
||||
@ -395,7 +387,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary .append( "[包剪锤]" )
|
||||
}
|
||||
ElementType.POKE -> {
|
||||
Element.ElementType.POKE -> {
|
||||
val elem = Elem(
|
||||
commonElem = CommonElem(
|
||||
serviceType = 2,
|
||||
@ -410,8 +402,8 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary .append( "[戳一戳]" )
|
||||
}
|
||||
ElementType.MUSIC -> throw UnsupportedOperationException("Unsupported ElementType.MUSIC")
|
||||
ElementType.WEATHER -> {
|
||||
Element.ElementType.MUSIC -> throw UnsupportedOperationException("Unsupported Element.ElementType.MUSIC")
|
||||
Element.ElementType.WEATHER -> {
|
||||
var code = it.weather.code.toIntOrNull()
|
||||
if (code == null) {
|
||||
val city = it.weather.city
|
||||
@ -438,11 +430,11 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
throw LogicException("无法获取城市天气")
|
||||
}
|
||||
}
|
||||
ElementType.LOCATION -> throw UnsupportedOperationException("Unsupported ElementType.LOCATION")
|
||||
ElementType.SHARE -> throw UnsupportedOperationException("Unsupported ElementType.SHARE")
|
||||
ElementType.GIFT -> throw UnsupportedOperationException("Unsupported ElementType.GIFT")
|
||||
ElementType.MARKET_FACE -> throw UnsupportedOperationException("Unsupported ElementType.MARKET_FACE")
|
||||
ElementType.FORWARD -> {
|
||||
Element.ElementType.LOCATION -> throw UnsupportedOperationException("Unsupported Element.ElementType.LOCATION")
|
||||
Element.ElementType.SHARE -> throw UnsupportedOperationException("Unsupported Element.ElementType.SHARE")
|
||||
Element.ElementType.GIFT -> throw UnsupportedOperationException("Unsupported Element.ElementType.GIFT")
|
||||
Element.ElementType.MARKET_FACE -> throw UnsupportedOperationException("Unsupported Element.ElementType.MARKET_FACE")
|
||||
Element.ElementType.FORWARD -> {
|
||||
val resId = it.forward.resId
|
||||
val filename = UUID.randomUUID().toString().uppercase()
|
||||
var content = it.forward.summary
|
||||
@ -496,8 +488,8 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary.append( "[聊天记录]" )
|
||||
}
|
||||
ElementType.CONTACT -> throw UnsupportedOperationException("Unsupported ElementType.CONTACT")
|
||||
ElementType.JSON -> {
|
||||
Element.ElementType.CONTACT -> throw UnsupportedOperationException("Unsupported Element.ElementType.CONTACT")
|
||||
Element.ElementType.JSON -> {
|
||||
val elem = Elem(
|
||||
lightApp = LightAppElem(
|
||||
data = byteArrayOf(1) + DeflateTools.compress(it.json.json.toByteArray())
|
||||
@ -506,9 +498,9 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary .append( "[Json消息]" )
|
||||
}
|
||||
ElementType.XML -> throw UnsupportedOperationException("Unsupported ElementType.XML")
|
||||
ElementType.FILE -> throw UnsupportedOperationException("Unsupported ElementType.FILE")
|
||||
ElementType.MARKDOWN -> {
|
||||
Element.ElementType.XML -> throw UnsupportedOperationException("Unsupported Element.ElementType.XML")
|
||||
Element.ElementType.FILE -> throw UnsupportedOperationException("Unsupported Element.ElementType.FILE")
|
||||
Element.ElementType.MARKDOWN -> {
|
||||
val elem = Elem(
|
||||
commonElem = CommonElem(
|
||||
serviceType = 45,
|
||||
@ -519,7 +511,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary.append("[Markdown消息]")
|
||||
}
|
||||
ElementType.BUTTON -> {
|
||||
Element.ElementType.BUTTON -> {
|
||||
val elem = Elem(
|
||||
commonElem = CommonElem(
|
||||
serviceType = 46,
|
||||
@ -552,7 +544,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
)
|
||||
})
|
||||
},
|
||||
appid = it.button.applicationId.toULong()
|
||||
appid = it.button.botAppid.toULong()
|
||||
)
|
||||
).toByteArray(),
|
||||
businessType = 1
|
||||
@ -561,8 +553,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
|
||||
elems.add(elem)
|
||||
summary.append("[Button消息]")
|
||||
}
|
||||
ElementType.NODE -> throw UnsupportedOperationException("Unsupported ElementType.NODE")
|
||||
ElementType.UNRECOGNIZED -> throw UnsupportedOperationException("Unsupported ElementType.UNRECOGNIZED")
|
||||
Element.ElementType.UNRECOGNIZED -> throw UnsupportedOperationException("Unsupported Element.ElementType.UNRECOGNIZED")
|
||||
}
|
||||
} catch (e: Throwable) {
|
||||
LogCenter.log("转换消息失败(Multi): ${e.stackTraceToString()}", Level.ERROR)
|
||||
|
Loading…
x
Reference in New Issue
Block a user