diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 0216f73f6..8fd0da5f1 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -220,6 +220,44 @@ fun main() { +### 发送引用回复消息(仅支持群消息) + +``` +[POST] /sendQuoteMessage +``` + +使用此方法向指定的消息进行引用回复 + +#### 请求 + +```json5 +{ + "sessionKey": "YourSession", + "target": 987654321, + "messageChain": [ + { "type": "Plain", "text":"hello\n" }, + { "type": "Plain", "text":"world" } + ] +} +``` + +| 名字 | 类型 | 可选 | 举例 | 说明 | +| ------------ | ------ | ----- | ----------- | -------------------------------- | +| sessionKey | String | false | YourSession | 已经激活的Session | +| target | Long | false | 987654321 | 引用消息的Message Source的Uid | +| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 | + +#### 响应: 返回统一状态码 + +```json5 +{ + "code": 0, + "msg": "success" +} +``` + + + ### 发送图片消息(通过URL) ``` @@ -308,6 +346,9 @@ Content-Type:multipart/form-data [{ "type": "GroupMessage", // 消息类型:GroupMessage或FriendMessage "messageChain": [{ // 消息链,是一个消息对象构成的数组 + "type": "Source", + "uid": 123456 + },{ "type": "Plain", "text": "Miral牛逼" }], @@ -350,6 +391,19 @@ Content-Type:multipart/form-data + [ ] Xml,Xml卡片消息 + [ ] 敬请期待 +#### Source + +```json5 +{ + "type": "Source", + "uid": 123456 +} +``` + +| 名字 | 类型 | 说明 | +| ---- | ---- | ------------------------------------------------------------ | +| uid | Long | 消息的识别号,用于引用回复(Source类型只在群消息中返回,且永远为chain的第一个元素) | + #### At ```json5 diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt index ccd6d2440..f50f00e11 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt @@ -36,6 +36,9 @@ data class UnKnownMessagePacketDTO(val msg: String) : MessagePacketDTO() // Message @Serializable +@SerialName("Source") +data class MessageSourceDTO(val uid: Long) : MessageDTO() +@Serializable @SerialName("At") data class AtDTO(val target: Long, val display: String) : MessageDTO() @Serializable @@ -85,6 +88,7 @@ fun MessageChainDTO.toMessageChain() = @UseExperimental(ExperimentalUnsignedTypes::class) fun Message.toDTO() = when (this) { + is MessageSource -> MessageSourceDTO(messageUid) is At -> AtDTO(target, display) is AtAll -> AtAllDTO(0L) is Face -> FaceDTO(id.value.toInt()) @@ -102,7 +106,7 @@ fun MessageDTO.toMessage() = when (this) { is PlainDTO -> PlainText(text) is ImageDTO -> Image(imageId) is XmlDTO -> XMLMessage(xml) - is UnknownMessageDTO -> PlainText("assert cannot reach") + is MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach") } diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt index 28a79f184..e3a1637ef 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt @@ -9,17 +9,32 @@ package net.mamoe.mirai.api.http.queue +import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket +import net.mamoe.mirai.message.data.MessageSource +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedDeque class MessageQueue : ConcurrentLinkedDeque>() { + val quoteCache = ConcurrentHashMap() + fun fetch(size: Int): List> { var count = size + quoteCache.clear() val ret = ArrayList>(count) while (!this.isEmpty() && count-- > 0) { - ret.add(this.pop()) + val packet = pop() + ret.add(packet) + + if (packet is GroupMessage) { + addCache(packet) + } } return ret } + + private fun addCache(msg: GroupMessage) { + quoteCache[msg.message[MessageSource].messageUid] = msg + } } \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt index 6a41fe76c..aa2beb5b8 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt @@ -52,6 +52,12 @@ fun Application.messageModule() { call.respondStateCode(StateCode.Success) } + miraiVerify("/quoteMessage") { + it.session.messageQueue.quoteCache[it.target]?.quoteReply(it.messageChain.toMessageChain()) + ?: throw NoSuchElementException() + call.respondStateCode(StateCode.Success) + } + miraiVerify("sendImageMessage") { val bot = it.session.bot val contact = when { @@ -72,12 +78,14 @@ fun Application.messageModule() { if (!SessionManager.containSession(sessionKey)) throw IllegalSessionException val session = try { SessionManager[sessionKey] as AuthedSession - } catch (e: TypeCastException) { throw NotVerifiedSessionException } + } catch (e: TypeCastException) { + throw NotVerifiedSessionException + } val type = parts.value("type") parts.file("img")?.apply { val image = streamProvider().use { - when(type) { + when (type) { "group" -> session.bot.groups.toList().random().uploadImage(it) "friend" -> session.bot.qqs.toList().random().uploadImage(it) else -> null diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt index 8b37ebd80..e46fbb1f5 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt @@ -13,6 +13,7 @@ import kotlinx.serialization.* import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import net.mamoe.mirai.api.http.data.common.* +import net.mamoe.mirai.message.data.MessageSource // 解析失败时直接返回null,由路由判断响应400状态 @UseExperimental(ImplicitReflectionSerializer::class) @@ -50,6 +51,7 @@ object MiraiJson { UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer() } polymorphic(MessageDTO.serializer()) { + MessageSourceDTO::class with MessageSourceDTO.serializer() AtDTO::class with AtDTO.serializer() AtAllDTO::class with AtAllDTO.serializer() FaceDTO::class with FaceDTO.serializer()