Skip to content

Commit

Permalink
Redesign MultiMsg; Support nested ForwardMessage sending; close #1198
Browse files Browse the repository at this point in the history
  • Loading branch information
Karlatemp committed Nov 16, 2021
1 parent b42a577 commit b5d8c70
Show file tree
Hide file tree
Showing 6 changed files with 284 additions and 80 deletions.
1 change: 1 addition & 0 deletions mirai-core-utils/src/commonMain/kotlin/Numbers.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,4 @@ package net.mamoe.mirai.utils
public fun Int.toLongUnsigned(): Long = this.toLong().and(0xFFFF_FFFF)
public fun Short.toIntUnsigned(): Int = this.toUShort().toInt()
public fun Byte.toIntUnsigned(): Int = toInt() and 0xFF
public fun Int.concatAsLong(i2: Int): Long = this.toLongUnsigned().shl(Int.SIZE_BITS) or i2.toLongUnsigned()
83 changes: 16 additions & 67 deletions mirai-core/src/commonMain/kotlin/MiraiImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import io.ktor.client.features.*
import io.ktor.client.request.*
import io.ktor.client.request.forms.*
import io.ktor.util.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.currentCoroutineContext
import kotlinx.io.core.discardExact
import kotlinx.io.core.readBytes
Expand All @@ -38,13 +37,19 @@ import net.mamoe.mirai.internal.message.*
import net.mamoe.mirai.internal.message.DeepMessageRefiner.refineDeep
import net.mamoe.mirai.internal.network.components.EventDispatcher
import net.mamoe.mirai.internal.network.components.EventDispatcherScopeFlag
import net.mamoe.mirai.internal.network.highway.*
import net.mamoe.mirai.internal.network.highway.ChannelKind
import net.mamoe.mirai.internal.network.highway.ResourceKind
import net.mamoe.mirai.internal.network.highway.tryDownload
import net.mamoe.mirai.internal.network.highway.tryServersDownload
import net.mamoe.mirai.internal.network.protocol.data.jce.SvcDevLoginInfo
import net.mamoe.mirai.internal.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.internal.network.protocol.data.proto.LongMsg
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.internal.network.protocol.data.proto.MsgTransmit
import net.mamoe.mirai.internal.network.protocol.packet.chat.*
import net.mamoe.mirai.internal.network.protocol.packet.chat.MultiMsg
import net.mamoe.mirai.internal.network.protocol.packet.chat.NewContact
import net.mamoe.mirai.internal.network.protocol.packet.chat.NudgePacket
import net.mamoe.mirai.internal.network.protocol.packet.chat.PbMessageSvc
import net.mamoe.mirai.internal.network.protocol.packet.chat.voice.PttStore
import net.mamoe.mirai.internal.network.protocol.packet.list.FriendList
import net.mamoe.mirai.internal.network.protocol.packet.login.StatSvc
Expand All @@ -55,17 +60,13 @@ import net.mamoe.mirai.internal.network.sKey
import net.mamoe.mirai.internal.utils.MiraiProtocolInternal
import net.mamoe.mirai.internal.utils.crypto.TEA
import net.mamoe.mirai.internal.utils.io.serialization.loadAs
import net.mamoe.mirai.internal.utils.io.serialization.toByteArray
import net.mamoe.mirai.message.MessageSerializers
import net.mamoe.mirai.message.action.Nudge
import net.mamoe.mirai.message.data.*
import net.mamoe.mirai.message.data.Image.Key.IMAGE_ID_REGEX
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_1
import net.mamoe.mirai.message.data.Image.Key.IMAGE_RESOURCE_ID_REGEX_2
import net.mamoe.mirai.utils.*
import net.mamoe.mirai.utils.ExternalResource.Companion.toExternalResource
import kotlin.math.absoluteValue
import kotlin.random.Random

internal fun getMiraiImpl() = Mirai as MiraiImpl

Expand Down Expand Up @@ -632,70 +633,18 @@ internal open class MiraiImpl : IMirai, LowLevelApiAccessor {
sendMessageHandler: SendMessageHandler<*>,
message: Collection<ForwardMessage.INode>,
isLong: Boolean,
): String = with(bot.asQQAndroidBot()) {
): String {
bot.asQQAndroidBot()
message.forEach {
it.messageChain.ensureSequenceIdAvailable()
}
val uploader = MultiMsgUploader(
client = bot.client,
isLong = isLong,
handler = sendMessageHandler,
).also { it.emitMain(message) }


val data = message.calculateValidationData(
client = client,
random = Random.nextInt().absoluteValue,
sendMessageHandler,
isLong,
)

val response = network.run {
MultiMsg.ApplyUp.createForGroup(
buType = if (isLong) 1 else 2,
client = bot.client,
messageData = data,
dstUin = sendMessageHandler.targetUin
).sendAndExpect()
}

val resId: String
when (response) {
is MultiMsg.ApplyUp.Response.MessageTooLarge ->
error(
"Internal error: message is too large, but this should be handled before sending. "
)
is MultiMsg.ApplyUp.Response.RequireUpload -> {
resId = response.proto.msgResid

val body = LongMsg.ReqBody(
subcmd = 1,
platformType = 9,
termType = 5,
msgUpReq = listOf(
LongMsg.MsgUpReq(
msgType = 3, // group
dstUin = sendMessageHandler.targetUin,
msgId = 0,
msgUkey = response.proto.msgUkey,
needCache = 0,
storeType = 2,
msgContent = data.data
)
)
).toByteArray(LongMsg.ReqBody.serializer())

body.toExternalResource().use { resource ->
Highway.uploadResourceBdh(
bot = bot,
resource = resource,
kind = when (isLong) {
true -> ResourceKind.LONG_MESSAGE
false -> ResourceKind.FORWARD_MESSAGE
},
commandId = 27,
initialTicket = response.proto.msgSig
)
}
}
}

return resId
return uploader.uploadAndReturnResId()
}

override suspend fun solveNewFriendRequestEvent(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ internal suspend fun <C : Contact> SendMessageHandler<C>.transformSpecialMessage
)
return RichMessage.forwardMessage(
resId = resId,
timeSeconds = currentTimeSeconds(),
fileName = currentTimeSeconds().toString(),
forwardMessage = forward,
)
}
Expand Down
23 changes: 15 additions & 8 deletions mirai-core/src/commonMain/kotlin/message/LongMessageInternal.kt
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ internal data class ForwardMessageInternal(
val preview = titles
val source = xmlFoot.findField("name")

if (fileName != null) { // nested
val transmits = refineContext.getNotNull(MsgTransmits)[fileName]
?: return SimpleServiceMessage(serviceId, content) // Refine failed
val resId = resId?.takeIf { it.isNotEmpty() }

if (fileName != null) kotlin.run nested@{ // nested
val transmits = refineContext[MsgTransmits]?.get(fileName)
?: return@nested // Refine failed
return MessageOrigin(
SimpleServiceMessage(serviceId, content),
null, // Nested don't have resource id
resId,
MessageOriginKind.FORWARD,
) + ForwardMessage(
preview = preview,
Expand All @@ -97,6 +99,11 @@ internal data class ForwardMessageInternal(
)
}

// No id and no fileName
if (resId == null) {
return SimpleServiceMessage(serviceId, content)
}

return MessageOrigin(
SimpleServiceMessage(serviceId, content),
resId,
Expand All @@ -107,7 +114,7 @@ internal data class ForwardMessageInternal(
brief = brief,
source = source,
summary = summary.trim(),
nodeList = Mirai.downloadForwardMessage(bot, resId!!),
nodeList = Mirai.downloadForwardMessage(bot, resId),
)
}

Expand Down Expand Up @@ -157,19 +164,19 @@ internal fun RichMessage.Key.longMessage(brief: String, resId: String, timeSecon
}


private fun String.xmlEnc():String {
private fun String.xmlEnc(): String {
return this.replace("&", "&amp;")
}

internal fun RichMessage.Key.forwardMessage(
resId: String,
timeSeconds: Long,
fileName: String,
forwardMessage: ForwardMessage,
): ForwardMessageInternal = with(forwardMessage) {
val template = """
<?xml version="1.0" encoding="utf-8"?>
<msg serviceID="35" templateID="1" action="viewMultiMsg" brief="${brief.take(30).xmlEnc()}"
m_resid="$resId" m_fileName="$timeSeconds"
m_resid="$resId" m_fileName="$fileName"
tSum="3" sourceMsgId="0" url="" flag="3" adverSign="0" multiMsgFlag="0">
<item layout="1" advertiser_id="0" aid="0">
<title size="34" maxLines="2" lineSpace="12">${title.take(50).xmlEnc()}</title>
Expand Down

0 comments on commit b5d8c70

Please sign in to comment.