5 Commits

Author SHA1 Message Date
7baf459b2a Shamrock: fix scene and group code 2024-04-10 21:09:10 +08:00
36a09ca088 update kritor 2024-04-08 20:00:44 +08:00
926c4659f6 Shamrock: add kritor metadata 2024-04-07 16:51:21 +08:00
cb7c68f36c fix: build error 2024-04-07 16:27:35 +08:00
72af39208c update kritor 2024-04-07 16:08:33 +08:00
12 changed files with 86 additions and 33 deletions

View File

@ -2,8 +2,15 @@
package kritor.client package kritor.client
import com.google.protobuf.ByteString import com.google.protobuf.ByteString
import io.grpc.CallOptions
import io.grpc.Channel
import io.grpc.ClientCall
import io.grpc.ClientInterceptor
import io.grpc.ForwardingClientCall
import io.grpc.Metadata
import io.grpc.ManagedChannel import io.grpc.ManagedChannel
import io.grpc.ManagedChannelBuilder import io.grpc.ManagedChannelBuilder
import io.grpc.MethodDescriptor
import io.kritor.common.Request import io.kritor.common.Request
import io.kritor.common.Response import io.kritor.common.Response
import io.kritor.event.EventServiceGrpcKt import io.kritor.event.EventServiceGrpcKt
@ -23,6 +30,8 @@ import kritor.handlers.handleGrpc
import moe.fuqiuluo.shamrock.helper.Level import moe.fuqiuluo.shamrock.helper.Level
import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.internals.GlobalEventTransmitter import moe.fuqiuluo.shamrock.internals.GlobalEventTransmitter
import moe.fuqiuluo.shamrock.tools.ShamrockVersion
import qq.service.ticket.TicketHelper
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
internal class KritorClient( internal class KritorClient(
@ -39,11 +48,26 @@ internal class KritorClient(
if (::channel.isInitialized && isActive()){ if (::channel.isInitialized && isActive()){
channel.shutdown() channel.shutdown()
} }
val interceptor = object : ClientInterceptor {
override fun <ReqT, RespT> interceptCall(method: MethodDescriptor<ReqT, RespT>, callOptions: CallOptions, next: Channel): ClientCall<ReqT, RespT> {
return object : ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
override fun start(responseListener: Listener<RespT>, headers: Metadata) {
headers.merge(Metadata().apply {
put(Metadata.Key.of("kritor-self-uin", Metadata.ASCII_STRING_MARSHALLER), TicketHelper.getUin())
put(Metadata.Key.of("kritor-self-uid", Metadata.ASCII_STRING_MARSHALLER), TicketHelper.getUid())
put(Metadata.Key.of("kritor-self-version", Metadata.ASCII_STRING_MARSHALLER), "OpenShamrock-$ShamrockVersion")
})
super.start(responseListener, headers)
}
}
}
}
channel = ManagedChannelBuilder channel = ManagedChannelBuilder
.forAddress(host, port) .forAddress(host, port)
.usePlaintext() .usePlaintext()
.enableRetry() // 允许尝试 .enableRetry() // 允许尝试
.executor(Dispatchers.IO.asExecutor()) // 使用协程的调度器 .executor(Dispatchers.IO.asExecutor()) // 使用协程的调度器
.intercept(interceptor)
.build() .build()
}.onFailure { }.onFailure {
LogCenter.log("KritorClient start failed: ${it.stackTraceToString()}", Level.ERROR) LogCenter.log("KritorClient start failed: ${it.stackTraceToString()}", Level.ERROR)

View File

@ -2,7 +2,12 @@
package kritor.server package kritor.server
import io.grpc.Grpc import io.grpc.Grpc
import io.grpc.Metadata
import io.grpc.InsecureServerCredentials import io.grpc.InsecureServerCredentials
import io.grpc.ServerCall
import io.grpc.ServerCallHandler
import io.grpc.ServerInterceptor
import io.grpc.ForwardingServerCall.SimpleForwardingServerCall;
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.ExperimentalCoroutinesApi
@ -10,14 +15,35 @@ import kotlinx.coroutines.asExecutor
import kritor.auth.AuthInterceptor import kritor.auth.AuthInterceptor
import kritor.service.* import kritor.service.*
import moe.fuqiuluo.shamrock.helper.LogCenter import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.tools.ShamrockVersion
import qq.service.ticket.TicketHelper
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class KritorServer( class KritorServer(
private val port: Int private val port: Int
): CoroutineScope { ): CoroutineScope {
private val serverInterceptor = object : ServerInterceptor {
override fun <ReqT, RespT> interceptCall(
call: ServerCall<ReqT, RespT>, headers: Metadata, next: ServerCallHandler<ReqT, RespT>
): ServerCall.Listener<ReqT> {
return next.startCall(object : SimpleForwardingServerCall<ReqT, RespT>(call) {
override fun sendHeaders(headers: Metadata?) {
headers?.apply {
put(Metadata.Key.of("kritor-self-uin", Metadata.ASCII_STRING_MARSHALLER), TicketHelper.getUin())
put(Metadata.Key.of("kritor-self-uid", Metadata.ASCII_STRING_MARSHALLER), TicketHelper.getUid())
put(Metadata.Key.of("kritor-self-version", Metadata.ASCII_STRING_MARSHALLER), "OpenShamrock-$ShamrockVersion")
}
super.sendHeaders(headers)
}
}, headers)
}
}
private val server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create()) private val server = Grpc.newServerBuilderForPort(port, InsecureServerCredentials.create())
.executor(Dispatchers.IO.asExecutor()) .executor(Dispatchers.IO.asExecutor())
.intercept(AuthInterceptor) .intercept(AuthInterceptor)
.intercept(serverInterceptor)
.addService(AuthenticationService) .addService(AuthenticationService)
.addService(CoreService) .addService(CoreService)
.addService(FriendService) .addService(FriendService)

View File

@ -225,8 +225,8 @@ internal object FriendService : FriendServiceGrpcKt.FriendServiceCoroutineImplBa
} }
@Grpc("FriendService", "GetUidByUin") @Grpc("FriendService", "GetUidByUin")
override suspend fun getUidByUin(request: GetUidRequest): GetUidResponse { override suspend fun getUidByUin(request: GetUidByUinRequest): GetUidByUinResponse {
return GetUidResponse.newBuilder().apply { return GetUidByUinResponse.newBuilder().apply {
request.targetUinsList.forEach { request.targetUinsList.forEach {
putUidMap(it, ContactHelper.getUidByUinAsync(it)) putUidMap(it, ContactHelper.getUidByUinAsync(it))
} }

View File

@ -3,6 +3,7 @@ package kritor.service
import io.grpc.Status import io.grpc.Status
import io.grpc.StatusRuntimeException import io.grpc.StatusRuntimeException
import io.kritor.group.* import io.kritor.group.*
import moe.fuqiuluo.shamrock.helper.LogCenter
import moe.fuqiuluo.shamrock.helper.TroopHonorHelper.decodeHonor import moe.fuqiuluo.shamrock.helper.TroopHonorHelper.decodeHonor
import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty import moe.fuqiuluo.shamrock.tools.ifNullOrEmpty
import qq.service.contact.ContactHelper import qq.service.contact.ContactHelper
@ -213,9 +214,10 @@ internal object GroupService : GroupServiceGrpcKt.GroupServiceCoroutineImplBase(
return GetGroupListResponse.newBuilder().apply { return GetGroupListResponse.newBuilder().apply {
groupList.forEach { groupInfo -> groupList.forEach { groupInfo ->
this.addGroupsInfo(GroupInfo.newBuilder().apply { this.addGroupsInfo(GroupInfo.newBuilder().apply {
groupId = groupInfo.troopcode.toLong() groupId = groupInfo.troopcode.ifNullOrEmpty { groupInfo.uin }.ifNullOrEmpty { groupInfo.troopuin }?.toLong() ?: 0
groupName = groupInfo.troopname.ifNullOrEmpty { groupInfo.troopRemark } groupName = groupInfo.troopname.ifNullOrEmpty { groupInfo.troopRemark }
.ifNullOrEmpty { groupInfo.newTroopName } ?: "" .ifNullOrEmpty { groupInfo.newTroopName }
?: ""
groupRemark = groupInfo.troopRemark ?: "" groupRemark = groupInfo.troopRemark ?: ""
owner = groupInfo.troopowneruin?.toLong() ?: 0 owner = groupInfo.troopowneruin?.toLong() ?: 0
addAllAdmins(GroupHelper.getAdminList(groupId)) addAllAdmins(GroupHelper.getAdminList(groupId))

View File

@ -463,7 +463,7 @@ internal object MessageService : MessageServiceGrpcKt.MessageServiceCoroutineImp
request.contact.longPeer(), request.contact.longPeer(),
msg.msgSeq.toULong(), msg.msgSeq.toULong(),
request.faceId.toString(), request.faceId.toString(),
request.isComment request.isSet
) )
return ReactMessageWithEmojiResponse.newBuilder().build() return ReactMessageWithEmojiResponse.newBuilder().build()
} }

View File

@ -7,6 +7,7 @@ import com.tencent.qqnt.kernel.nativeinterface.MsgRecord
import io.kritor.event.* import io.kritor.event.*
import io.kritor.common.PushMessageBody import io.kritor.common.PushMessageBody
import io.kritor.common.Contact import io.kritor.common.Contact
import io.kritor.common.Scene
import io.kritor.common.Sender import io.kritor.common.Sender
import kotlinx.coroutines.DelicateCoroutinesApi import kotlinx.coroutines.DelicateCoroutinesApi
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
@ -24,12 +25,12 @@ internal object GlobalEventTransmitter : QQInterfaces() {
MutableSharedFlow<NoticeEvent>() MutableSharedFlow<NoticeEvent>()
} }
private val requestEventFlow by lazy { private val requestEventFlow by lazy {
MutableSharedFlow<RequestsEvent>() MutableSharedFlow<RequestEvent>()
} }
private suspend fun pushNotice(noticeEvent: NoticeEvent) = noticeEventFlow.emit(noticeEvent) private suspend fun pushNotice(noticeEvent: NoticeEvent) = noticeEventFlow.emit(noticeEvent)
private suspend fun pushRequest(requestEvent: RequestsEvent) = requestEventFlow.emit(requestEvent) private suspend fun pushRequest(requestEvent: RequestEvent) = requestEventFlow.emit(requestEvent)
private suspend fun transMessageEvent(record: MsgRecord, message: PushMessageBody) = private suspend fun transMessageEvent(record: MsgRecord, message: PushMessageBody) =
MessageEventFlow.emit(record to message) MessageEventFlow.emit(record to message)
@ -44,7 +45,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
this.messageId = record.msgId.toString() this.messageId = record.msgId.toString()
this.messageSeq = record.msgSeq this.messageSeq = record.msgSeq
this.contact = Contact.newBuilder().apply { this.contact = Contact.newBuilder().apply {
this.scene = scene this.scene = Scene.GROUP
this.peer = record.peerUin.toString() this.peer = record.peerUin.toString()
this.subPeer = record.peerUid this.subPeer = record.peerUid
}.build() }.build()
@ -67,7 +68,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
this.messageId = record.msgId.toString() this.messageId = record.msgId.toString()
this.messageSeq = record.msgSeq this.messageSeq = record.msgSeq
this.contact = Contact.newBuilder().apply { this.contact = Contact.newBuilder().apply {
this.scene = scene this.scene = Scene.FRIEND
this.peer = record.senderUin.toString() this.peer = record.senderUin.toString()
this.subPeer = record.senderUid this.subPeer = record.senderUid
}.build() }.build()
@ -92,7 +93,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
this.messageId = record.msgId.toString() this.messageId = record.msgId.toString()
this.messageSeq = record.msgSeq this.messageSeq = record.msgSeq
this.contact = Contact.newBuilder().apply { this.contact = Contact.newBuilder().apply {
this.scene = scene this.scene = if (groupCode > 0) Scene.STRANGER_FROM_GROUP else Scene.STRANGER
this.peer = record.senderUin.toString() this.peer = record.senderUin.toString()
this.subPeer = groupCode.toString() this.subPeer = groupCode.toString()
}.build() }.build()
@ -115,7 +116,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
this.messageId = record.msgId.toString() this.messageId = record.msgId.toString()
this.messageSeq = record.msgSeq this.messageSeq = record.msgSeq
this.contact = Contact.newBuilder().apply { this.contact = Contact.newBuilder().apply {
this.scene = scene this.scene = Scene.GUILD
this.peer = record.guildId ?: "" this.peer = record.guildId ?: ""
this.subPeer = record.channelId ?: "" this.subPeer = record.channelId ?: ""
}.build() }.build()
@ -484,13 +485,13 @@ internal object GlobalEventTransmitter : QQInterfaces() {
*/ */
object RequestTransmitter { object RequestTransmitter {
suspend fun transFriendApp(time: Long, operator: Long, tipText: String, flag: String): Boolean { suspend fun transFriendApp(time: Long, operator: Long, tipText: String, flag: String): Boolean {
pushRequest(RequestsEvent.newBuilder().apply { pushRequest(RequestEvent.newBuilder().apply {
this.type = RequestsEvent.RequestType.FRIEND_APPLY this.type = RequestEvent.RequestType.FRIEND_APPLY
this.time = time.toInt() this.time = time.toInt()
this.requestId = flag
this.friendApply = FriendApplyRequest.newBuilder().apply { this.friendApply = FriendApplyRequest.newBuilder().apply {
this.applierUin = operator this.applierUin = operator
this.message = tipText this.message = tipText
this.flag = flag
}.build() }.build()
}.build()) }.build())
return true return true
@ -504,15 +505,15 @@ internal object GlobalEventTransmitter : QQInterfaces() {
groupCode: Long, groupCode: Long,
flag: String flag: String
): Boolean { ): Boolean {
pushRequest(RequestsEvent.newBuilder().apply { pushRequest(RequestEvent.newBuilder().apply {
this.type = RequestsEvent.RequestType.GROUP_APPLY this.type = RequestEvent.RequestType.GROUP_APPLY
this.time = time.toInt() this.time = time.toInt()
this.requestId = flag
this.groupApply = GroupApplyRequest.newBuilder().apply { this.groupApply = GroupApplyRequest.newBuilder().apply {
this.applierUid = applierUid this.applierUid = applierUid
this.applierUin = applierUin this.applierUin = applierUin
this.groupId = groupCode this.groupId = groupCode
this.reason = reason this.reason = reason
this.flag = flag
}.build() }.build()
}.build()) }.build())
return true return true
@ -535,7 +536,7 @@ internal object GlobalEventTransmitter : QQInterfaces() {
} }
} }
suspend inline fun onRequestEvent(collector: FlowCollector<RequestsEvent>) { suspend inline fun onRequestEvent(collector: FlowCollector<RequestEvent>) {
requestEventFlow.collect { requestEventFlow.collect {
GlobalScope.launch { GlobalScope.launch {
collector.emit(it) collector.emit(it)

View File

@ -401,10 +401,10 @@ private object MsgConvertor {
suspend fun convertInlineKeyboard(record: MsgRecord, element: MsgElement): Result<Element> { suspend fun convertInlineKeyboard(record: MsgRecord, element: MsgElement): Result<Element> {
val inlineKeyboard = element.inlineKeyboardElement val inlineKeyboard = element.inlineKeyboardElement
val elem = Element.newBuilder() val elem = Element.newBuilder()
elem.type = ElementType.BUTTON elem.type = ElementType.KEYBOARD
elem.setButton(ButtonElement.newBuilder().apply { elem.setKeyboard(KeyboardElement.newBuilder().apply {
inlineKeyboard.rows.forEach { row -> inlineKeyboard.rows.forEach { row ->
this.addRows(ButtonRow.newBuilder().apply { this.addRows(KeyboardRow.newBuilder().apply {
row.buttons.forEach buttonsLoop@{ button -> row.buttons.forEach buttonsLoop@{ button ->
if (button == null) return@buttonsLoop if (button == null) return@buttonsLoop
this.addButtons(Button.newBuilder().apply { this.addButtons(Button.newBuilder().apply {

View File

@ -227,9 +227,9 @@ suspend fun List<Elem>.toKritorResponseMessages(contact: Contact): ArrayList<Ele
46 -> { 46 -> {
val buttonExtra = commonElem.elem!!.decodeProtobuf<ButtonExtra>() val buttonExtra = commonElem.elem!!.decodeProtobuf<ButtonExtra>()
kritorMessages.add( kritorMessages.add(
Element.newBuilder().setButton(ButtonElement.newBuilder().apply { Element.newBuilder().setKeyboard(KeyboardElement.newBuilder().apply {
this.addAllRows(buttonExtra.field1!!.rows!!.map { row -> this.addAllRows(buttonExtra.field1!!.rows!!.map { row ->
ButtonRow.newBuilder().apply { KeyboardRow.newBuilder().apply {
this.addAllButtons(row.buttons!!.map { button -> this.addAllButtons(row.buttons!!.map { button ->
Button.newBuilder().apply { Button.newBuilder().apply {
this.id = button.id this.id = button.id

View File

@ -97,7 +97,7 @@ object NtMsgConvertor {
ElementType.JSON to ::jsonConvertor, ElementType.JSON to ::jsonConvertor,
ElementType.FORWARD to ::forwardConvertor, ElementType.FORWARD to ::forwardConvertor,
ElementType.MARKDOWN to ::markdownConvertor, ElementType.MARKDOWN to ::markdownConvertor,
ElementType.BUTTON to ::buttonConvertor, ElementType.KEYBOARD to ::buttonConvertor,
) )
suspend fun convertToNtMsgs(contact: Contact, msgId: Long, msgs: Messages): ArrayList<MsgElement> { suspend fun convertToNtMsgs(contact: Contact, msgId: Long, msgs: Messages): ArrayList<MsgElement> {
@ -663,14 +663,14 @@ object NtMsgConvertor {
} }
} }
MusicPlatform.NetEase -> { MusicPlatform.NETEASE -> {
val id = sourceMusic.music.id val id = sourceMusic.music.id
if (!MusicHelper.tryShare163MusicById(contact, msgId, id)) { if (!MusicHelper.tryShare163MusicById(contact, msgId, id)) {
LogCenter.log("无法发送网易云音乐分享", Level.ERROR) LogCenter.log("无法发送网易云音乐分享", Level.ERROR)
} }
} }
MusicPlatform.Custom -> { MusicPlatform.CUSTOM -> {
val data = sourceMusic.music.custom val data = sourceMusic.music.custom
ArkMsgHelper.tryShareMusic( ArkMsgHelper.tryShareMusic(
contact, contact,
@ -848,7 +848,7 @@ object NtMsgConvertor {
elem.elementType = MsgConstant.KELEMTYPEINLINEKEYBOARD elem.elementType = MsgConstant.KELEMTYPEINLINEKEYBOARD
val rows = arrayListOf<InlineKeyboardRow>() val rows = arrayListOf<InlineKeyboardRow>()
val keyboard = sourceButton.button val keyboard = sourceButton.keyboard
keyboard.rowsList.forEach { row -> keyboard.rowsList.forEach { row ->
val buttons = arrayListOf<InlineKeyboardButton>() val buttons = arrayListOf<InlineKeyboardButton>()
row.buttonsList.forEach { button -> row.buttonsList.forEach { button ->

View File

@ -366,9 +366,9 @@ private object ReqMsgConvertor {
suspend fun convertInlineKeyboard(contact: Contact, element: MsgElement): Result<Element> { suspend fun convertInlineKeyboard(contact: Contact, element: MsgElement): Result<Element> {
val inlineKeyboard = element.inlineKeyboardElement val inlineKeyboard = element.inlineKeyboardElement
val elem = Element.newBuilder() val elem = Element.newBuilder()
elem.setButton(ButtonElement.newBuilder().apply { elem.setKeyboard(KeyboardElement.newBuilder().apply {
this.addAllRows(inlineKeyboard.rows.map { row -> this.addAllRows(inlineKeyboard.rows.map { row ->
ButtonRow.newBuilder().apply { KeyboardRow.newBuilder().apply {
this.addAllButtons(row.buttons.map { button -> this.addAllButtons(row.buttons.map { button ->
Button.newBuilder().apply { Button.newBuilder().apply {
this.id = button.id this.id = button.id

View File

@ -511,13 +511,13 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
elems.add(elem) elems.add(elem)
summary.append("[Markdown消息]") summary.append("[Markdown消息]")
} }
Element.ElementType.BUTTON -> { Element.ElementType.KEYBOARD -> {
val elem = Elem( val elem = Elem(
commonElem = CommonElem( commonElem = CommonElem(
serviceType = 46, serviceType = 46,
elem = ButtonExtra( elem = ButtonExtra(
field1 = Object1( field1 = Object1(
rows = it.button.rowsList.map { row -> rows = it.keyboard.rowsList.map { row ->
Row(buttons = row.buttonsList.map { button -> Row(buttons = row.buttonsList.map { button ->
val renderData = button.renderData val renderData = button.renderData
val action = button.action val action = button.action
@ -544,7 +544,7 @@ suspend fun List<Element>.toRichText(contact: Contact): Result<Pair<String, Rich
) )
}) })
}, },
appid = it.button.botAppid.toULong() appid = it.keyboard.botAppid.toULong()
) )
).toByteArray(), ).toByteArray(),
businessType = 1 businessType = 1