diff --git a/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt b/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt index 088725e25..c6bcf25c7 100644 --- a/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt +++ b/mirai-api-http/src/main/kotlin/net.mamoe.mirai.api.http/MiraiHttpApplication.kt @@ -71,7 +71,7 @@ fun Application.mirai() { routing { mirai("/sendFriendMessage") { // TODO: 2019/11/21 解析图片消息等为 Message - Bot.instanceWhose(qq = param("bot")).getQQ(param("qq")).sendMessage(param<String>("message")) + Bot.instanceWhose(qq = param("bot")).getFriend(param("qq")).sendMessage(param<String>("message")) call.ok() } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index fc460a2ef..bbf097f45 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -33,12 +33,8 @@ internal abstract class QQAndroidBotBase constructor( val selfQQ: QQ by lazy { QQ(uin) } - override fun getQQ(id: Long): QQ { - return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this as QQAndroidBot, coroutineContext, id) }) - } - - fun getQQOrAdd(id: Long): QQ { - return qqs.delegate.filteringGetOrAdd({ it.id == id }, { QQImpl(this as QQAndroidBot, coroutineContext, id) }) + override fun getFriend(id: Long): QQ { + return qqs.delegate[id] } override fun QQ(id: Long): QQ { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 48d4cbffb..14b249287 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -115,7 +115,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler //val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>() //println(msg.contentToString()) - + bot.qqs.delegate.clear() + bot.groups.delegate.clear() val startTime = currentTimeMillis try { @@ -134,7 +135,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler totalFriendCount = data.totalFriendCount data.friendList.forEach { // atomic add - bot.qqs.delegate.addLast(bot.getQQ(it.friendUin).also { + bot.qqs.delegate.addLast(bot.getFriend(it.friendUin).also { currentFriendCount++ }) } @@ -475,12 +476,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler /** * 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms) */ - suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 1): E { + suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 0): E { require(timeoutMillis > 0) { "timeoutMillis must > 0" } require(retry >= 0) { "retry must >= 0" } var lastException: Exception? = null - repeat(retry + 1) { + if (retry == 0) { val handler = PacketListener(commandName = commandName, sequenceId = sequenceId) packetListeners.addLast(handler) try { @@ -495,13 +496,33 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } ?: net.mamoe.mirai.qqandroid.utils.inline { error("timeout when receiving response of $commandName") } - } catch (e: Exception) { - lastException = e } finally { packetListeners.remove(handler) } + } else this.delegate.useBytes { data, length -> + repeat(retry + 1) { + val handler = PacketListener(commandName = commandName, sequenceId = sequenceId) + packetListeners.addLast(handler) + try { + withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) { + channel.send(data, 0, length) + } + bot.logger.info("Send: ${this.commandName}") + return withTimeoutOrNull(timeoutMillis) { + @Suppress("UNCHECKED_CAST") + handler.await() as E + // 不要 `withTimeout`. timeout 的异常会不知道去哪了. + } ?: net.mamoe.mirai.qqandroid.utils.inline { + error("timeout when receiving response of $commandName") + } + } catch (e: Exception) { + lastException = e + } finally { + packetListeners.remove(handler) + } + } + throw lastException!! } - throw lastException!! } @PublishedApi diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 8c0ad5763..978af6ccd 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -123,14 +123,11 @@ internal class MessageSvc { val messages = resp.uinPairMsgs.asSequence().filterNot { it.msg == null }.flatMap { it.msg!!.asSequence() }.mapNotNull { when (it.msgHead.msgType) { - 166 -> { - FriendMessage( - bot, - false, // TODO: 2020/1/29 PREVIOUS?? - bot.getQQ(it.msgHead.fromUin), - it.msgBody.richText.toMessageChain() - ) - } + 166 -> FriendMessage( + bot, + bot.getFriend(it.msgHead.fromUin), + it.msgBody.richText.toMessageChain() + ) else -> null } }.toMutableList() @@ -176,7 +173,7 @@ internal class MessageSvc { } data class Failed(val errorCode: Int, val errorMessage: String) : Response() { - override fun toString(): String = "MessageSvc.PbSendMsg.Response.FAILED(errorCode=$errorCode, errorMessage=$errorMessage" + override fun toString(): String = "MessageSvc.PbSendMsg.Response.Failed(errorCode=$errorCode, errorMessage=$errorMessage" } } @@ -224,7 +221,7 @@ internal class MessageSvc { ///return@buildOutgoingUniPacket writeProtoBuf( MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq( - routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)), // TODO: 2020/1/30 确认这里是 id 还是 internalId + routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupCode)), contentHead = MsgComm.ContentHead(pkgNum = 1, divSeq = seq), msgBody = ImMsgBody.MsgBody( richText = ImMsgBody.RichText( diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index 718a2ec10..f702bb57b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -58,9 +58,15 @@ abstract class Bot : CoroutineScope { abstract val qqs: ContactList<QQ> /** - * 获取一个好友对象. 若没有这个好友, 则会抛出异常[NoSuchElementException] + * 获取一个好友对象. 若没有这个好友, 则会抛出异常 [NoSuchElementException] */ - abstract fun getQQ(id: Long): QQ + @Deprecated(message = "这个函数有歧义. 它获取的是好友, 却名为 getQQ", replaceWith = ReplaceWith("getFriend(id)")) + fun getQQ(id: Long): QQ = getFriend(id) + + /** + * 获取一个好友对象. 若没有这个好友, 则会抛出异常 [NoSuchElementException] + */ + abstract fun getFriend(id: Long): QQ /** * 构造一个 [QQ] 对象. 它持有对 [Bot] 的弱引用([WeakRef]). @@ -133,8 +139,8 @@ abstract class Bot : CoroutineScope { // region extensions - fun Int.qq(): QQ = getQQ(this.toLong()) - fun Long.qq(): QQ = getQQ(this) + fun Int.qq(): QQ = getFriend(this.toLong()) + fun Long.qq(): QQ = getFriend(this) /** diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt index 289dcef79..8bfd19824 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/QQ.kt @@ -11,7 +11,7 @@ import net.mamoe.mirai.data.Profile /** * QQ 对象. * 注意: 一个 [QQ] 实例并不是独立的, 它属于一个 [Bot]. - * 它不能被直接构造. 任何时候都应从 [Bot.getQQ] 或事件中获取. + * 它不能被直接构造. 任何时候都应从 [Bot.getFriend] 或事件中获取. * * 对于同一个 [Bot] 任何一个人的 [QQ] 实例都是单一的. * diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt index c93ecbe6b..065bff68c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt @@ -8,20 +8,9 @@ import net.mamoe.mirai.utils.MiraiInternalAPI class FriendMessage( bot: Bot, - /** - * 是否是在这次登录之前的消息, 即消息记录 - */ - val previous: Boolean, override val sender: QQ, override val message: MessageChain ) : MessagePacket<QQ, QQ>(bot), BroadcastControllable { - /** - * 是否应被自动广播. 此为内部 API - */ - @MiraiInternalAPI - override val shouldBroadcast: Boolean - get() = !previous - override val subject: QQ get() = sender override fun toString(): String = "FriendMessage(sender=${sender.id}, message=$message)" diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt index 8745f1564..be4a6b6e4 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt @@ -4,7 +4,9 @@ package net.mamoe.mirai.message import kotlinx.io.core.ByteReadPacket import net.mamoe.mirai.Bot -import net.mamoe.mirai.contact.* +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.data.EventPacket import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.data.* @@ -71,12 +73,19 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) : // region Image download suspend inline fun Image.downloadAsByteArray(): ByteArray = bot.run { downloadAsByteArray() } + suspend inline fun Image.download(): ByteReadPacket = bot.run { download() } // endregion - fun At.qq(): QQ = bot.getQQ(this.target) + @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this.target)")) + fun At.qq(): QQ = bot.getFriend(this.target) - fun Int.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0).toLong()) - fun Long.qq(): QQ = bot.getQQ(this.coerceAtLeastOrFail(0)) + @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this.toLong())")) + fun Int.qq(): QQ = bot.getFriend(this.coerceAtLeastOrFail(0).toLong()) + @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getFriend(this)")) + fun Long.qq(): QQ = bot.getFriend(this.coerceAtLeastOrFail(0)) + + @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("bot.getGroup(this)")) + fun Long.group(): Group = bot.getGroup(this) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt index 1a0527a9f..4cde854c4 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt @@ -34,7 +34,7 @@ fun ByteReadPacket.transferTo(outputStream: OutputStream) { } } -fun <R> ByteReadPacket.useBytes( +inline fun <R> ByteReadPacket.useBytes( n: Int = remaining.toInt(),//not that safe but adequate block: (data: ByteArray, length: Int) -> R ): R = ByteArrayPool.useInstance { diff --git a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt index 0af6a97c7..a49eec53b 100644 --- a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt +++ b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt @@ -23,7 +23,7 @@ internal class BlockingBotImpl(private val bot: Bot) : BlockingBot { @UseExperimental(MiraiInternalAPI::class) override fun getQQs(): List<BlockingQQ> = bot.qqs.delegate.toList().map { it.blocking() } - override fun getQQ(id: Long): BlockingQQ = bot.getQQ(id).blocking() + override fun getQQ(id: Long): BlockingQQ = bot.getFriend(id).blocking() @UseExperimental(MiraiInternalAPI::class) override fun getGroups(): List<BlockingGroup> = bot.groups.delegate.toList().map { it.blocking() }