mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-06 08:00:10 +08:00
C2C message send support
This commit is contained in:
parent
6ac9acc640
commit
5d46d1c4be
@ -3,8 +3,11 @@ package net.mamoe.mirai.qqandroid
|
||||
import net.mamoe.mirai.BotAccount
|
||||
import net.mamoe.mirai.utils.BotConfiguration
|
||||
import net.mamoe.mirai.utils.Context
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
|
||||
internal actual class QQAndroidBot actual constructor(
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
internal actual class QQAndroidBot
|
||||
actual constructor(
|
||||
context: Context,
|
||||
account: BotAccount,
|
||||
configuration: BotConfiguration
|
||||
|
@ -18,16 +18,15 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.QQImpl
|
||||
import net.mamoe.mirai.qqandroid.event.ForceOfflineEvent
|
||||
import net.mamoe.mirai.qqandroid.event.PacketReceivedEvent
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.LoginPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc
|
||||
import net.mamoe.mirai.utils.LockFreeLinkedList
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.getValue
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.jvm.Volatile
|
||||
@ -107,6 +106,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
|
||||
|
||||
override suspend fun init() {
|
||||
// delay(5000)
|
||||
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
|
||||
|
||||
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
|
||||
if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
|
||||
|
@ -145,7 +145,7 @@ internal class MsgComm : ProtoBuf {
|
||||
@SerialId(1) val lastReadTime: Int = 0,
|
||||
@SerialId(2) val peerUin: Long = 0L,
|
||||
@SerialId(3) val msgCompleted: Int = 0,
|
||||
@SerialId(4) val msg: List<Msg>,
|
||||
@SerialId(4) val msg: List<Msg>? = null,
|
||||
@SerialId(5) val unreadMsgNum: Int = 0,
|
||||
@SerialId(8) val c2cType: Int = 0,
|
||||
@SerialId(9) val serviceType: Int = 0,
|
||||
|
@ -3,14 +3,15 @@ package net.mamoe.mirai.qqandroid.network.protocol.data.proto
|
||||
import kotlinx.serialization.SerialId
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.mamoe.mirai.qqandroid.io.ProtoBuf
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.random.Random
|
||||
|
||||
@Serializable
|
||||
class SyncCookie(
|
||||
@SerialId(1) val time1: Long? = null, // 1580277992
|
||||
@SerialId(2) val time: Long, // 1580277992
|
||||
@SerialId(3) val unknown1: Long = Random.nextLong(),// 678328038
|
||||
@SerialId(4) val unknown2: Long = Random.nextLong(), // 1687142153
|
||||
@SerialId(3) val unknown1: Long = Random.nextLong().absoluteValue,// 678328038
|
||||
@SerialId(4) val unknown2: Long = Random.nextLong().absoluteValue, // 1687142153
|
||||
@SerialId(5) val const1: Long = const1_, // 1458467940
|
||||
@SerialId(11) val const2: Long = const2_, // 2683038258
|
||||
@SerialId(12) val unknown3: Long = 0x1d,
|
||||
@ -18,8 +19,8 @@ class SyncCookie(
|
||||
@SerialId(14) val unknown4: Long = 0
|
||||
) : ProtoBuf
|
||||
|
||||
private val const1_: Long = Random.nextLong()
|
||||
private val const2_: Long = Random.nextLong()
|
||||
private val const1_: Long = Random.nextLong().absoluteValue
|
||||
private val const2_: Long = Random.nextLong().absoluteValue
|
||||
/*
|
||||
|
||||
@Serializable
|
||||
|
@ -4,6 +4,7 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import net.mamoe.mirai.data.MultiPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.message.FriendMessage
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
@ -29,7 +30,6 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.currentTimeSeconds
|
||||
import net.mamoe.mirai.utils.io.hexToBytes
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.math.absoluteValue
|
||||
import kotlin.random.Random
|
||||
|
||||
@ -39,14 +39,14 @@ internal class MessageSvc {
|
||||
*/
|
||||
internal object PushNotify : IncomingPacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify {
|
||||
discardExact(4)
|
||||
discardExact(4) // don't remove
|
||||
|
||||
return decodeUniPacket(RequestPushNotify.serializer())
|
||||
}
|
||||
|
||||
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
|
||||
network.run {
|
||||
return PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0)
|
||||
return PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: currentTimeSeconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -57,9 +57,6 @@ internal class MessageSvc {
|
||||
*/
|
||||
@UseExperimental(MiraiInternalAPI::class)
|
||||
internal object PbGetMsg : OutgoingPacketFactory<PbGetMsg.Response>("MessageSvc.PbGetMsg") {
|
||||
val EXTRA_DATA =
|
||||
"08 00 12 33 6D 6F 64 65 6C 3A 78 69 67 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
syncFlag: MsgSvc.SyncFlag = MsgSvc.SyncFlag.START,
|
||||
@ -67,7 +64,7 @@ internal class MessageSvc {
|
||||
): OutgoingPacket = buildOutgoingUniPacket(
|
||||
client
|
||||
) {
|
||||
println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}")
|
||||
//println("syncCookie=${client.c2cMessageSync.syncCookie?.toUHexString()}")
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbGetMsgReq.serializer(),
|
||||
MsgSvc.PbGetMsgReq(
|
||||
@ -96,7 +93,11 @@ internal class MessageSvc {
|
||||
* 不要直接 expect 这个 class. 它可能
|
||||
*/
|
||||
@MiraiInternalAPI
|
||||
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: MutableList<FriendMessage>) : MultiPacket<FriendMessage>(delegate) {
|
||||
open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: MutableList<FriendMessage>) : MultiPacket<FriendMessage>(delegate),
|
||||
BroadcastControllable {
|
||||
override val shouldBroadcast: Boolean
|
||||
get() = syncFlagFromServer == MsgSvc.SyncFlag.STOP
|
||||
|
||||
override fun toString(): String {
|
||||
return "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=List(size=${this.size}))"
|
||||
}
|
||||
@ -120,7 +121,7 @@ internal class MessageSvc {
|
||||
return GetMsgSuccess(mutableListOf())
|
||||
}
|
||||
|
||||
val messages = resp.uinPairMsgs.asSequence().flatMap { it.msg.asSequence() }.mapNotNull {
|
||||
val messages = resp.uinPairMsgs.asSequence().filterNot { it.msg == null }.flatMap { it.msg!!.asSequence() }.mapNotNull {
|
||||
when (it.msgHead.msgType) {
|
||||
166 -> {
|
||||
FriendMessage(
|
||||
@ -134,7 +135,7 @@ internal class MessageSvc {
|
||||
}
|
||||
}.toMutableList()
|
||||
if (resp.syncFlag == MsgSvc.SyncFlag.STOP) {
|
||||
return GetMsgSuccess(messages)
|
||||
return GetMsgSuccess(mutableListOf(messages.last()))
|
||||
}
|
||||
return Response(resp.syncFlag, messages)
|
||||
}
|
||||
@ -146,7 +147,7 @@ internal class MessageSvc {
|
||||
|
||||
MsgSvc.SyncFlag.CONTINUE -> {
|
||||
network.run {
|
||||
PbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds)
|
||||
PbGetMsg(client, MsgSvc.SyncFlag.CONTINUE, currentTimeSeconds).sendWithoutExpect()
|
||||
}
|
||||
return
|
||||
}
|
||||
@ -199,8 +200,7 @@ internal class MessageSvc {
|
||||
),
|
||||
msgSeq = client.atomicNextMessageSequenceId(),
|
||||
msgRand = Random.nextInt().absoluteValue,
|
||||
syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() }
|
||||
?: SyncCookie(time = currentTimeSeconds).toByteArray(SyncCookie.serializer())
|
||||
syncCookie = SyncCookie(time = currentTimeSeconds).toByteArray(SyncCookie.serializer())
|
||||
// msgVia = 1
|
||||
)
|
||||
)
|
||||
@ -217,21 +217,22 @@ internal class MessageSvc {
|
||||
|
||||
///writeFully("0A 08 0A 06 08 89 FC A6 8C 0B 12 06 08 01 10 00 18 00 1A 1F 0A 1D 12 08 0A 06 0A 04 F0 9F 92 A9 12 11 AA 02 0E 88 01 00 9A 01 08 78 00 F8 01 00 C8 02 00 20 9B 7A 28 F4 CA 9B B8 03 32 34 08 92 C2 C4 F1 05 10 92 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 89 84 F9 A2 06 48 DE 8C EA E5 0E 58 D9 BD BB A0 09 60 1D 68 92 C2 C4 F1 05 70 00 40 01".hexToBytes())
|
||||
|
||||
val seq = client.atomicNextMessageSequenceId()
|
||||
///return@buildOutgoingUniPacket
|
||||
writeProtoBuf(
|
||||
MsgSvc.PbSendMsgReq.serializer(), MsgSvc.PbSendMsgReq(
|
||||
routingHead = MsgSvc.RoutingHead(grp = MsgSvc.Grp(groupCode = groupId)), // TODO: 2020/1/30 确认这里是 id 还是 internalId
|
||||
contentHead = MsgComm.ContentHead(pkgNum = 1),
|
||||
contentHead = MsgComm.ContentHead(pkgNum = 1, divSeq = seq),
|
||||
msgBody = ImMsgBody.MsgBody(
|
||||
richText = ImMsgBody.RichText(
|
||||
elems = message.toRichTextElems()
|
||||
)
|
||||
),
|
||||
msgSeq = client.atomicNextMessageSequenceId(),
|
||||
//msgRand = Random.nextInt() and 0x7FFF,
|
||||
syncCookie = SyncCookie(time = currentTimeSeconds).toByteArray(SyncCookie.serializer())
|
||||
//SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer())
|
||||
// msgVia = 1
|
||||
msgSeq = seq,
|
||||
msgRand = Random.nextInt().absoluteValue,
|
||||
syncCookie = "08 A0 C2 C4 F1 05 10 A0 C2 C4 F1 05 18 E6 ED B9 C3 02 20 89 FE BE A4 06 28 E4 C2 B1 95 03 48 A1 9F E0 C7 08 58 D3 C2 8F A0 09 60 1D 68 A0 C2 C4 F1 05 70 00".hexToBytes()
|
||||
?: SyncCookie(time = currentTimeSeconds + client.timeDifference).toByteArray(SyncCookie.serializer()),
|
||||
msgVia = 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
@ -3,11 +3,10 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.message.GroupMessage
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
|
||||
@ -22,7 +21,7 @@ internal class OnlinePush {
|
||||
@UseExperimental(ExperimentalStdlibApi::class)
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): GroupMessage {
|
||||
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
|
||||
val pbPushMsg = ProtoBufWithNullableSupport.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes())
|
||||
val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer())
|
||||
|
||||
val extraInfo: ImMsgBody.ExtraInfo? = pbPushMsg.msg.msgBody.richText.elems.firstOrNull { it.extraInfo != null }?.extraInfo
|
||||
|
||||
|
@ -5,62 +5,123 @@ import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
|
||||
import net.mamoe.mirai.utils.io.hexToBytes
|
||||
|
||||
internal fun NotOnlineImageFromFile.toJceData(): ImMsgBody.NotOnlineImage {
|
||||
return ImMsgBody.NotOnlineImage(
|
||||
filePath = this.filepath,
|
||||
resId = this.resourceId,
|
||||
oldPicMd5 = false,
|
||||
picMd5 = this.md5,
|
||||
fileLen = this.fileLength,
|
||||
picHeight = this.height,
|
||||
picWidth = this.width,
|
||||
bizType = this.bizType,
|
||||
imgType = this.imageType,
|
||||
downloadPath = this.downloadPath
|
||||
)
|
||||
}
|
||||
|
||||
/*
|
||||
notOnlineImage=NotOnlineImage#2050019814 {
|
||||
filePath=41AEF2D4B5BD24CF3791EFC5FEB67D60.jpg
|
||||
fileLen=0x00000350(848)
|
||||
downloadPath=/f2b7e5c0-acb3-4e83-aa5c-c8383840cc91
|
||||
oldVerSendFile=<Empty ByteArray>
|
||||
imgType=0x000003E8(1000)
|
||||
previewsImage=<Empty ByteArray>
|
||||
picMd5=41 AE F2 D4 B5 BD 24 CF 37 91 EF C5 FE B6 7D 60
|
||||
picHeight=0x00000032(50)
|
||||
picWidth=0x00000033(51)
|
||||
resId=/f2b7e5c0-acb3-4e83-aa5c-c8383840cc91
|
||||
flag=<Empty ByteArray>
|
||||
thumbUrl=
|
||||
original=0x00000000(0)
|
||||
bigUrl=
|
||||
origUrl=
|
||||
bizType=0x00000005(5)
|
||||
result=0x00000000(0)
|
||||
index=0x00000000(0)
|
||||
opFaceBuf=<Empty ByteArray>
|
||||
oldPicMd5=false
|
||||
thumbWidth=0x00000000(0)
|
||||
thumbHeight=0x00000000(0)
|
||||
fileId=0x00000000(0)
|
||||
showLen=0x00000000(0)
|
||||
downloadLen=0x00000000(0)
|
||||
_400Url=
|
||||
_400Width=0x00000000(0)
|
||||
_400Height=0x00000000(0)
|
||||
pbReserve=08 01 10 00 32 00 42 0E 5B E5 8A A8 E7 94 BB E8 A1 A8 E6 83 85 5D 50 00 78 05
|
||||
}
|
||||
*/
|
||||
internal fun MessageChain.toRichTextElems(): MutableList<ImMsgBody.Elem> {
|
||||
val elems = mutableListOf<ImMsgBody.Elem>()
|
||||
val elements = mutableListOf<ImMsgBody.Elem>()
|
||||
|
||||
this.forEach {
|
||||
when (it) {
|
||||
is PlainText -> {
|
||||
elems.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
|
||||
elements.add(ImMsgBody.Elem(text = ImMsgBody.Text(str = it.stringValue)))
|
||||
}
|
||||
is At -> {
|
||||
|
||||
}
|
||||
is Image -> {
|
||||
elems.add(
|
||||
ImMsgBody.Elem(
|
||||
notOnlineImage = ImMsgBody.NotOnlineImage(
|
||||
filePath = it.id.value, // 错了, 应该是 2B23D705CAD1F2CF3710FE582692FCC4.jpg
|
||||
fileLen = 1149, // 假的
|
||||
downloadPath = it.id.value,
|
||||
imgType = 1000, // 不确定
|
||||
picMd5 = "2B 23 D7 05 CA D1 F2 CF 37 10 FE 58 26 92 FC C4".hexToBytes(),
|
||||
picHeight = 66,
|
||||
picWidth = 66,
|
||||
resId = it.id.value,
|
||||
bizType = 5,
|
||||
pbReserve = ImMsgBody.PbReserve.DEFAULT // 可能还可以改变 `[动画表情]`
|
||||
)
|
||||
)
|
||||
)
|
||||
is NotOnlineImageFromServer -> {
|
||||
elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate))
|
||||
elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "78 00 90 01 01 F8 01 00 A0 02 00 C8 02 00".hexToBytes())))
|
||||
}
|
||||
is NotOnlineImageFromFile -> {
|
||||
elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData()))
|
||||
elements.add(ImMsgBody.Elem(generalFlags = ImMsgBody.GeneralFlags(pbReserve = "78 00 90 01 01 F8 01 00 A0 02 00 C8 02 00".hexToBytes())))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return elems
|
||||
return elements
|
||||
}
|
||||
|
||||
|
||||
internal class NotOnlineImageFromServer(
|
||||
internal val delegate: ImMsgBody.NotOnlineImage
|
||||
) : NotOnlineImage() {
|
||||
override val resourceId: String
|
||||
get() = delegate.resId
|
||||
override val md5: ByteArray
|
||||
get() = delegate.picMd5
|
||||
override val filepath: String
|
||||
get() = delegate.filePath
|
||||
override val fileLength: Int
|
||||
get() = delegate.fileLen
|
||||
override val height: Int
|
||||
get() = delegate.picHeight
|
||||
override val width: Int
|
||||
get() = delegate.picWidth
|
||||
override val bizType: Int
|
||||
get() = delegate.bizType
|
||||
override val imageType: Int
|
||||
get() = delegate.imgType
|
||||
override val downloadPath: String
|
||||
get() = delegate.downloadPath
|
||||
|
||||
}
|
||||
|
||||
internal fun ImMsgBody.RichText.toMessageChain(): MessageChain {
|
||||
val message = MessageChain(initialCapacity = elems.size)
|
||||
|
||||
elems.forEach {
|
||||
when {
|
||||
it.notOnlineImage != null -> message.add(
|
||||
Image(
|
||||
ImageIdQQA(
|
||||
it.notOnlineImage.resId,
|
||||
it.notOnlineImage.origUrl
|
||||
)
|
||||
)
|
||||
NotOnlineImageFromServer(it.notOnlineImage)
|
||||
)
|
||||
it.customFace != null -> message.add(
|
||||
Image(
|
||||
ImageIdQQA(
|
||||
it.customFace.filePath,
|
||||
it.customFace.origUrl
|
||||
)
|
||||
NotOnlineImageFromFile(
|
||||
it.customFace.filePath,
|
||||
it.customFace.md5,
|
||||
it.customFace.origUrl,
|
||||
it.customFace.downloadLen,
|
||||
it.customFace.height,
|
||||
it.customFace.width,
|
||||
it.customFace.bizType,
|
||||
it.customFace.imageType,
|
||||
it.customFace.filePath
|
||||
)
|
||||
)
|
||||
it.text != null -> message.add(it.text.str.toMessage())
|
||||
@ -70,12 +131,5 @@ internal fun ImMsgBody.RichText.toMessageChain(): MessageChain {
|
||||
return message
|
||||
}
|
||||
|
||||
internal class ImageIdQQA(
|
||||
override val value: String,
|
||||
originalLink: String
|
||||
) : ImageId {
|
||||
val link: ImageLink =
|
||||
ImageLinkQQA("http://gchat.qpic.cn$originalLink")
|
||||
}
|
||||
|
||||
internal inline class ImageLinkQQA(override val original: String) : ImageLink
|
@ -8,7 +8,6 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.use
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.AddFriendResult
|
||||
import net.mamoe.mirai.data.ImageLink
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.utils.GroupNotFoundException
|
||||
@ -104,11 +103,9 @@ abstract class Bot : CoroutineScope {
|
||||
|
||||
// region actions
|
||||
|
||||
abstract suspend fun Image.getLink(): ImageLink
|
||||
abstract suspend fun Image.downloadAsByteArray(): ByteArray
|
||||
|
||||
suspend fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
|
||||
|
||||
suspend fun Image.download(): ByteReadPacket = getLink().download()
|
||||
abstract suspend fun Image.download(): ByteReadPacket
|
||||
|
||||
/**
|
||||
* 添加一个好友
|
||||
|
@ -36,7 +36,7 @@ interface Contact : CoroutineScope {
|
||||
*/
|
||||
suspend fun sendMessage(message: MessageChain)
|
||||
|
||||
suspend fun uploadImage(image: ExternalImage): ImageId
|
||||
suspend fun uploadImage(image: ExternalImage): Image
|
||||
}
|
||||
|
||||
suspend inline fun Contact.sendMessage(message: Message) = sendMessage(message.toChain())
|
||||
|
@ -37,7 +37,7 @@ class ContactList<C : Contact>(@MiraiInternalAPI val delegate: LockFreeLinkedLis
|
||||
|
||||
operator fun <C : Contact> LockFreeLinkedList<C>.get(id: Long): C {
|
||||
forEach { if (it.id == id) return it }
|
||||
throw NoSuchElementException()
|
||||
throw NoSuchElementException("No such contact with id $id")
|
||||
}
|
||||
|
||||
fun <C : Contact> LockFreeLinkedList<C>.getOrNull(id: Long): C? {
|
||||
|
@ -6,7 +6,6 @@ import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.EventPacket
|
||||
import net.mamoe.mirai.data.ImageLink
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.message.data.*
|
||||
import net.mamoe.mirai.utils.*
|
||||
@ -65,17 +64,14 @@ abstract class MessagePacketBase<TSender : QQ, TSubject : Contact>(_bot: Bot) :
|
||||
|
||||
suspend inline fun ExternalImage.upload(): Image = this.upload(subject)
|
||||
suspend inline fun Image.send() = this.sendTo(subject)
|
||||
suspend inline fun ImageId.send() = this.sendTo(subject)
|
||||
suspend inline fun Message.send() = this.sendTo(subject)
|
||||
suspend inline fun String.send() = this.toMessage().sendTo(subject)
|
||||
|
||||
// endregion
|
||||
|
||||
// region Image download
|
||||
suspend inline fun Image.getLink(): ImageLink = with(bot) { getLink() }
|
||||
|
||||
suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
|
||||
suspend inline fun Image.download(): ByteReadPacket = getLink().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)
|
||||
|
Loading…
Reference in New Issue
Block a user