mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-10 02:20:14 +08:00
GroupImageDownload supports
This commit is contained in:
parent
44a6ba160e
commit
1294441716
@ -2,11 +2,11 @@
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import io.ktor.client.request.get
|
||||
import kotlinx.io.charsets.Charsets
|
||||
import kotlinx.io.core.*
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.message.ImageId0x06
|
||||
import net.mamoe.mirai.message.requireLength
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
@ -59,11 +59,8 @@ interface FriendImageResponse : EventPacket
|
||||
* 图片数据地址.
|
||||
*/
|
||||
// TODO: 2019/11/15 应该为 inline class, 但 kotlin 有 bug
|
||||
data class FriendImageLink(inline val value: String) : FriendImageResponse {
|
||||
suspend fun downloadAsByteArray(): ByteArray = download().readBytes()
|
||||
suspend fun download(): ByteReadPacket = Http.get(value)
|
||||
|
||||
override fun toString(): String = "FriendImageLink($value)"
|
||||
data class FriendImageLink(override inline val original: String) : FriendImageResponse, ImageLink {
|
||||
override fun toString(): String = "FriendImageLink($original)"
|
||||
}
|
||||
|
||||
/**
|
||||
@ -199,7 +196,7 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
writeUByte(0x1Au)
|
||||
writeUByte(0x47u)
|
||||
writeTUVarint(0x08u, bot)
|
||||
writeTUVarint(0x10u, bot)
|
||||
writeTUVarint(0x10u, bot) // 这里实际上应该是这张图片来自哪个 QQ 号. 但传 bot 也没事.
|
||||
writeTLV(0x1Au, imageId.value.toByteArray(Charsets.ISO_8859_1))
|
||||
writeHex("20 02 30 04 38 20 40 FF 01 50 00 6A 05 32 36 39 33 33 78 01")
|
||||
}
|
||||
@ -276,7 +273,7 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
while (readUByte().toUInt() != 0x4Au) readUVarLong()
|
||||
val uKey = readBytes(readUVarInt().toInt())//128
|
||||
while (readUByte().toUInt() != 0x52u) readUVarLong()
|
||||
val imageId = ImageId(readString(readUVarInt().toInt()))//37
|
||||
val imageId = ImageId0x06(readString(readUVarInt().toInt()))//37
|
||||
return FriendImageUKey(imageId, uKey)
|
||||
} catch (e: EOFException) {
|
||||
val toDiscard = readUByte().toInt() - 37
|
||||
@ -285,7 +282,7 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
FriendImageOverFileSizeMax
|
||||
} else {
|
||||
discardExact(toDiscard)
|
||||
val imageId = ImageId(readString(37))
|
||||
val imageId = ImageId0x06(readString(37))
|
||||
FriendImageAlreadyExists(imageId)
|
||||
}
|
||||
}
|
||||
@ -302,6 +299,7 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
// 3A 00 80 01 00
|
||||
|
||||
|
||||
|
||||
//00 00 00 08 00 00
|
||||
// [02 29]
|
||||
// 12 [06] 98 01 02 A0 01 00
|
||||
@ -315,7 +313,7 @@ object FriendImagePacket : SessionPacketFactory<FriendImageResponse>() {
|
||||
discardExact(1)
|
||||
discardExact(2)// [A4 04] 后文长度
|
||||
check(readUByte().toUInt() == 0x0Au) { "Illegal identity. Required 0x0Au" }
|
||||
/* val imageId = */ImageId(readString(readUByte().toInt()))
|
||||
/* val imageId = */ImageId0x06(readString(readUByte().toInt()))
|
||||
|
||||
check(readUByte().toUInt() == 0x18u) { "Illegal identity. Required 0x18u" }
|
||||
check(readUShort().toUInt() == 0x0032u) { "Illegal identity. Required 0x0032u" }
|
||||
|
@ -3,8 +3,9 @@
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.charsets.Charsets
|
||||
import kotlinx.io.core.*
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readBytes
|
||||
import kotlinx.serialization.SerialId
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoBuf
|
||||
@ -13,16 +14,17 @@ import net.mamoe.mirai.contact.GroupId
|
||||
import net.mamoe.mirai.contact.GroupInternalId
|
||||
import net.mamoe.mirai.contact.withSession
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.message.ImageId0x03
|
||||
import net.mamoe.mirai.message.requireLength
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.EventPacket
|
||||
import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.Http
|
||||
import net.mamoe.mirai.utils.assertUnreachable
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.io.debugPrintln
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import kotlin.coroutines.coroutineContext
|
||||
|
||||
|
||||
@ -64,14 +66,32 @@ interface GroupImageResponse : EventPacket
|
||||
|
||||
// endregion
|
||||
|
||||
@Suppress("unused")
|
||||
@Serializable
|
||||
data class ImageDownloadInfo(
|
||||
@SerialId(11) val host: String,
|
||||
class ImageDownloadInfo(
|
||||
@SerialId(3) val errorCode: Int = 0, // 0 for success
|
||||
@SerialId(4) val errorMessage: String? = null, // 感动中国
|
||||
|
||||
@SerialId(12) val thumbnail: String,
|
||||
@SerialId(13) val original: String,
|
||||
@SerialId(14) val compressed: String
|
||||
) : GroupImageResponse
|
||||
@SerialId(10) private val _port: List<Byte>? = null,
|
||||
@SerialId(11) private val _host: String? = null,
|
||||
|
||||
@SerialId(12) private val _thumbnail: String? = null,
|
||||
@SerialId(13) private val _original: String? = null,
|
||||
@SerialId(14) private val _compressed: String? = null
|
||||
) : GroupImageResponse, ImageLink {
|
||||
private val port: List<Byte> get() = _port!!
|
||||
private val host: String get() = "http://" + _host!!
|
||||
|
||||
val thumbnail: String get() = host + ":" + port.first() + _thumbnail!!
|
||||
override val original: String get() = host + ":" + port.first() + _original!!
|
||||
val compressed: String get() = host + ":" + port.first() + _compressed!!
|
||||
override fun toString(): String = "ImageDownloadInfo(${_original?.let { original } ?: errorMessage ?: "unknown"}"
|
||||
}
|
||||
|
||||
fun ImageDownloadInfo.requireSuccess(): ImageDownloadInfo {
|
||||
require(this.errorCode == 0) { this.errorMessage ?: "null" }
|
||||
return this
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ImageUploadInfo(
|
||||
@ -86,126 +106,162 @@ class ImageUploadInfo(
|
||||
@AnnotatedId(KnownPacketId.GROUP_IMAGE_ID)
|
||||
@PacketVersion(date = "2019.10.26", timVersion = "2.3.2 (21173)")
|
||||
object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
|
||||
/*
|
||||
请求上传图片
|
||||
ProtoMap(
|
||||
varint 0=0x5D(UVarInt(data=93))
|
||||
varint 1=0x01(UVarInt(data=1))
|
||||
delimi 2=98 01 01
|
||||
varint 2=0x01(UVarInt(data=1))
|
||||
delimi 3=08 A0 89 F7 B6 03 10 A2 FF 8C F0 03 18 00 22 10 2C F2 65 98 12 EA 9C 88 60 BD 7A 29 8E 6F 9B 4D 28 F0 0B 32 1A 43 00 4D 00 45 00 35 00 44 00 53 00 5A 00 43 00 4C 00 52 00 51 00 29 00 28 00 38 01 48 01 50 8B 02 58 BE 03 60 02 6A 05 32 36 39 33 33 70 00 78 03 80 01 00
|
||||
)
|
||||
*/
|
||||
private val RequestImageIdUnknownByteArray = ubyteArrayOf(0x98u, 0x01u, 0x01u).toByteArray()
|
||||
private val constValue3 = byteArrayOf(
|
||||
0x28, 0x00, 0x5A, 0x00, 0x53, 0x00, 0x41, 0x00, 0x58, 0x00, 0x40, 0x00, 0x57,
|
||||
0x00, 0x4B, 0x00, 0x52, 0x00, 0x4A, 0x00, 0x5A, 0x00, 0x31, 0x00, 0x7E, 0x00
|
||||
)
|
||||
|
||||
@Suppress("unused")
|
||||
@Serializable
|
||||
private class RequestIdProto(
|
||||
@SerialId(2) val unknown4: Byte = 1,
|
||||
@SerialId(3) var body: Body
|
||||
) {
|
||||
@Serializable
|
||||
class Body(
|
||||
@SerialId(1) val group: Int,
|
||||
@SerialId(2) val bot: Int,
|
||||
@SerialId(3) val const1: Byte = 0,
|
||||
@SerialId(4) val md5: ByteArray,
|
||||
@SerialId(5) val const2: Short = 0x0E2D,
|
||||
@SerialId(6) val const3: ByteArray = constValue3,
|
||||
@SerialId(7) val const4: Byte = 1,
|
||||
@SerialId(9) val const5: Byte = 1,
|
||||
@SerialId(10) val width: Int,
|
||||
@SerialId(11) val height: Int,
|
||||
@SerialId(12) val const6: Byte = 4,
|
||||
@SerialId(13) val const7: ByteArray = constValue7,
|
||||
@SerialId(14) val const8: Byte = 0,
|
||||
@SerialId(15) val const9: Byte = 3,
|
||||
@SerialId(16) val const10: Byte = 0
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@Serializable
|
||||
private class RequestLinkProto(
|
||||
@SerialId(2) val unknown4: Byte = 2,
|
||||
@SerialId(4) var body: Body
|
||||
) {
|
||||
/*
|
||||
ProtoMap(
|
||||
varint 1=0x8E87C28403(UVarInt(data=814777230))
|
||||
varint 2=0xA2FF8CF003(UVarInt(data=1040400290))
|
||||
varint 3=0xFBECB9A9A(UVarInt(data=2771285627))
|
||||
delimi 4=66 3C 60 FB 31 67 85 84 1A 18 00 52 2C D6 C8 7E
|
||||
varint 5=0x04(UVarInt(data=4))
|
||||
varint 6=0x02(UVarInt(data=2))
|
||||
varint 7=0x20(UVarInt(data=32))
|
||||
varint 8=0xFF01(UVarInt(data=255))
|
||||
varint 9=0x00(UVarInt(data=0))
|
||||
varint 10=0x01(UVarInt(data=1))
|
||||
delimi 11=32 36 39 33 33
|
||||
varint 12=0x00(UVarInt(data=0))
|
||||
varint 13=0x00(UVarInt(data=0))
|
||||
varint 14=0x01(UVarInt(data=1))
|
||||
varint 15=0x00(UVarInt(data=0))
|
||||
varint 16=0xA412(UVarInt(data=2340))
|
||||
varint 17=0xB808(UVarInt(data=1080))
|
||||
varint 18=0xE807(UVarInt(data=1000))
|
||||
varint 20=0x01(UVarInt(data=1))
|
||||
)
|
||||
*/
|
||||
@Serializable
|
||||
class Body(
|
||||
@SerialId(1) val group: Int,
|
||||
@SerialId(2) val bot: Int,
|
||||
@SerialId(3) val uniqueId: Int,
|
||||
@SerialId(4) val md5: ByteArray,
|
||||
@SerialId(5) val const2: Byte = 4,
|
||||
@SerialId(6) val const3: Byte = 2,
|
||||
@SerialId(7) val const4: Byte = 32,
|
||||
@SerialId(8) val const14: Int = 255,
|
||||
@SerialId(9) val const5: Byte = 0,
|
||||
@SerialId(10) val unknown5: Int = 1,
|
||||
@SerialId(11) val const7: ByteArray = constValue7,
|
||||
@SerialId(12) val unknown6: Byte = 0,
|
||||
@SerialId(13) val const6: Byte = 0,
|
||||
@SerialId(14) val const8: Byte = 0,
|
||||
@SerialId(15) val const9: Byte = 0,
|
||||
@SerialId(16) val height: Int,
|
||||
@SerialId(17) val width: Int,
|
||||
@SerialId(18) val const12: Int = 1003, //?? 有时候还是1000, 1004
|
||||
@SerialId(20) val const13: Byte = 1
|
||||
)
|
||||
}
|
||||
|
||||
private val constValue7: ByteArray = byteArrayOf(0x32, 0x36, 0x39, 0x33, 0x33)
|
||||
|
||||
private val requestImageIdHead = ubyteArrayOf(0x12u, 0x03u, 0x98u, 0x01u, 0x01u)
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun RequestImageId(
|
||||
bot: UInt,
|
||||
groupInternalId: GroupInternalId,
|
||||
image: ExternalImage,
|
||||
sessionKey: SessionKey
|
||||
): OutgoingPacket = buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x04) {
|
||||
writeHex("00 00 00 07 00 00")
|
||||
|
||||
writeShortLVPacket(lengthOffset = { it - 7 }) {
|
||||
writeByte(0x08)
|
||||
writeHex("01 12 03 98 01 01 10 01 1A")
|
||||
// 02 10 02 22
|
||||
|
||||
writeUVarIntLVPacket(lengthOffset = { it }) {
|
||||
writeTUVarint(0x08u, groupInternalId.value)
|
||||
writeTUVarint(0x10u, bot)
|
||||
writeTV(0x1800u)
|
||||
|
||||
writeUByte(0x22u)
|
||||
writeUByte(0x10u)
|
||||
writeFully(image.md5)
|
||||
|
||||
writeTUVarint(0x28u, image.inputSize.toUInt())
|
||||
writeUVarIntLVPacket(tag = 0x32u) {
|
||||
writeTV(0x5B_00u)
|
||||
writeTV(0x40_00u)
|
||||
writeTV(0x33_00u)
|
||||
writeTV(0x48_00u)
|
||||
writeTV(0x5F_00u)
|
||||
writeTV(0x58_00u)
|
||||
writeTV(0x46_00u)
|
||||
writeTV(0x51_00u)
|
||||
writeTV(0x45_00u)
|
||||
writeTV(0x51_00u)
|
||||
writeTV(0x40_00u)
|
||||
writeTV(0x24_00u)
|
||||
writeTV(0x4F_00u)
|
||||
}
|
||||
writeTV(0x38_01u)
|
||||
writeTV(0x48_01u)
|
||||
writeTUVarint(0x50u, image.width.toUInt())
|
||||
writeTUVarint(0x58u, image.height.toUInt())
|
||||
writeTV(0x60_04u)//这个似乎会变 有时候是02, 有时候是03
|
||||
writeTByteArray(0x6Au, value0x6A)
|
||||
|
||||
writeTV(0x70_00u)
|
||||
writeTV(0x78_03u)
|
||||
writeTV(0x80_01u)
|
||||
writeUByte(0u)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
): OutgoingPacket = buildSessionProtoPacket(
|
||||
bot, sessionKey, name = "GroupImagePacket.RequestImageId",
|
||||
head = requestImageIdHead,
|
||||
serializer = RequestIdProto.serializer(),
|
||||
protoObj = RequestIdProto(
|
||||
body = RequestIdProto.Body(
|
||||
bot = bot.toInt(),
|
||||
group = groupInternalId.value.toInt(),
|
||||
md5 = image.md5,
|
||||
height = image.height,
|
||||
width = image.width
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
private val requestImageLinkHead = ubyteArrayOf(0x08u, 0x01u, 0x12u, 0x03u, 0x98u, 0x01u, 0x2u)
|
||||
@Suppress("FunctionName")
|
||||
fun RequestImageLink(
|
||||
bot: UInt,
|
||||
sessionKey: SessionKey,
|
||||
imageId: ImageId
|
||||
imageId: ImageId0x03
|
||||
): OutgoingPacket {
|
||||
imageId.requireLength()
|
||||
require(imageId.value.length == 37) { "ImageId.value.length must == 37" }
|
||||
|
||||
// 00 00 00 07 00 00 00
|
||||
// [4B]
|
||||
// 08
|
||||
// 01 12
|
||||
// 03 98
|
||||
// 01 02
|
||||
// 08 02
|
||||
//
|
||||
// 1A [47]
|
||||
// 08 [A2 FF 8C F0 03] UVarInt
|
||||
// 10 [DD F1 92 B7 07] UVarInt
|
||||
// 1A [25] 2F 38 65 32 63 32 38 62 64 2D 35 38 61 31 2D 34 66 37 30 2D 38 39 61 31 2D 65 37 31 39 66 63 33 30 37 65 65 66
|
||||
// 20 02 30 04 38 20 40 FF 01 50 00 6A 05 32 36 39 33 33 78 01
|
||||
|
||||
|
||||
// 00 00 00 07 00 00 00
|
||||
// [4B]
|
||||
// 08 01
|
||||
// 12 03
|
||||
// 98 01 02
|
||||
// 08 02
|
||||
//
|
||||
// 1A
|
||||
// [47]
|
||||
// 08 [A2 FF 8C F0 03]
|
||||
// 10 [A6 A7 F1 EA 02]
|
||||
// 1A [25] 2F 39 61 31 66 37 31 36 32 2D 38 37 30 38 2D 34 39 30 38 2D 38 31 63 30 2D 66 34 63 64 66 33 35 63 38 64 37 65
|
||||
// 20 02 30 04 38 20 40 FF 01 50 00 6A 05 32 36 39 33 33 78 01
|
||||
|
||||
return buildSessionPacket(bot, sessionKey, version = TIMProtocol.version0x04) {
|
||||
writeHex("00 00 00 07 00 00")
|
||||
|
||||
writeUShort(0x004Bu)
|
||||
|
||||
writeUByte(0x08u)
|
||||
writeTV(0x01_12u)
|
||||
writeTV(0x03_98u)
|
||||
writeTV(0x01_02u)
|
||||
writeTV(0x08_02u)
|
||||
|
||||
writeUByte(0x1Au)
|
||||
writeUByte(0x47u)
|
||||
writeTUVarint(0x08u, bot)
|
||||
writeTUVarint(0x10u, bot)
|
||||
writeTLV(0x1Au, imageId.value.toByteArray(Charsets.ISO_8859_1))
|
||||
writeHex("20 02 30 04 38 20 40 FF 01 50 00 6A 05 32 36 39 33 33 78 01")
|
||||
}
|
||||
//require(imageId.value.length == 37) { "ImageId.value.length must == 37" }
|
||||
//[00 00 00 07] [00 00 00 52] (08 01 12 03 98 01 02) 10 02 22 4E 08 A0 89 F7 B6 03 10 A2 FF 8C F0 03 18 BB 92 94 BF 08 22 10 64 CF BB 65 00 13 8D B5 58 E2 45 1E EA 65 88 E1 28 04 30 02 38 20 40 FF 01 48 00 50 01 5A 05 32 36 39 33 33 60 00 68 00 70 00 78 00 80 01 97 04 88 01 ED 03 90 01 04 A0 01 01
|
||||
// head 长度 proto 长度 head proto
|
||||
return buildSessionProtoPacket(
|
||||
bot,
|
||||
sessionKey,
|
||||
name = "GroupImagePacket.RequestImageLink",
|
||||
head = requestImageLinkHead,
|
||||
serializer = RequestLinkProto.serializer(),
|
||||
protoObj = RequestLinkProto(
|
||||
body = RequestLinkProto.Body(
|
||||
bot = bot.toInt(), // same bin representation, so will be decoded correctly as a unsigned value in the server
|
||||
group = bot.toInt(), // TODO 似乎是必须要填group ??
|
||||
uniqueId = imageId.uniqueId.toInt(),
|
||||
md5 = imageId.md5,
|
||||
height = imageId.height,
|
||||
width = imageId.width
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val value0x6A: UByteArray = ubyteArrayOf(0x05u, 0x32u, 0x36u, 0x36u, 0x35u, 0x36u)
|
||||
|
||||
override suspend fun ByteReadPacket.decode(id: PacketId, sequenceId: UShort, handler: BotNetworkHandler<*>): GroupImageResponse {
|
||||
discardExact(6)//00 00 00 05 00 00
|
||||
|
||||
discardExact(2) // 是 protobuf 的长度, 但是是错的
|
||||
val bytes = readBytes()
|
||||
val headLength = readInt()
|
||||
val protoLength = readInt()
|
||||
discardExact(headLength)
|
||||
val bytes = readBytes(protoLength)
|
||||
// println(ByteReadPacket(bytes).readProtoMap())
|
||||
|
||||
@Serializable
|
||||
@ -214,6 +270,7 @@ object GroupImagePacket : SessionPacketFactory<GroupImageResponse>() {
|
||||
@SerialId(4) val imageDownloadInfo: ImageDownloadInfo? = null
|
||||
)
|
||||
|
||||
debugPrintln("收到返回=" + bytes.toUHexString())
|
||||
val proto = ProtoBuf.load(GroupImageResponseProto.serializer(), bytes)
|
||||
return when {
|
||||
proto.imageUploadInfoPacket != null -> proto.imageUploadInfoPacket
|
||||
|
@ -0,0 +1,78 @@
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS", "unused", "NO_REFLECTION_IN_CLASS_PATH")
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim.packet.action
|
||||
|
||||
import io.ktor.client.request.get
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.utils.Http
|
||||
|
||||
/**
|
||||
* 图片文件过大
|
||||
*/
|
||||
class OverFileSizeMaxException : IllegalStateException()
|
||||
|
||||
interface ImageLink {
|
||||
/**
|
||||
* 原图
|
||||
*/
|
||||
val original: String
|
||||
|
||||
suspend fun downloadAsByteArray(): ByteArray = download().readBytes()
|
||||
|
||||
suspend fun download(): ByteReadPacket = Http.get(original)
|
||||
}
|
||||
|
||||
/*
|
||||
/**
|
||||
* 似乎没有必要. 服务器的返回永远都是 01 00 00 00 02 00 00
|
||||
*/
|
||||
@Deprecated("Useless packet")
|
||||
@AnnotatedId(KnownPacketId.SUBMIT_IMAGE_FILE_NAME)
|
||||
@PacketVersion(date = "2019.10.26", timVersion = "2.3.2 (21173)")
|
||||
object SubmitImageFilenamePacket : PacketFactory {
|
||||
operator fun invoke(
|
||||
bot: UInt,
|
||||
target: UInt,
|
||||
filename: String,
|
||||
sessionKey: SessionKey
|
||||
): OutgoingPacket = buildOutgoingPacket {
|
||||
writeQQ(bot)
|
||||
writeFully(TIMProtocol.fixVer2)//?
|
||||
//writeHex("04 00 00 00 01 2E 01 00 00 69 35")
|
||||
|
||||
encryptAndWrite(sessionKey) {
|
||||
writeByte(0x01)
|
||||
writeQQ(bot)
|
||||
writeQQ(target)
|
||||
writeZero(2)
|
||||
writeUByte(0x02u)
|
||||
writeRandom(1)
|
||||
writeHex("00 0A 00 01 00 01")
|
||||
val name = "UserDataImage:$filename"
|
||||
writeShort(name.length.toShort())
|
||||
writeStringUtf8(name)
|
||||
writeHex("00 00")
|
||||
writeRandom(2)//这个也与是哪个好友有关?
|
||||
writeHex("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2E 01")//35 02? 最后这个值是与是哪个好友有关
|
||||
|
||||
//this.debugPrintThis("SubmitImageFilenamePacket")
|
||||
}
|
||||
|
||||
//解密body=01 3E 03 3F A2 7C BC D3 C1 00 00 27 1A 00 0A 00 01 00 01 00 30 55 73 65 72 44 61 74 61 43 75 73 74 6F 6D 46 61 63 65 3A 31 5C 28 5A 53 41 58 40 57 4B 52 4A 5A 31 7E 33 59 4F 53 53 4C 4D 32 4B 49 2E 6A 70 67 00 00 06 E2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2F 02
|
||||
//解密body=01 3E 03 3F A2 7C BC D3 C1 00 00 27 1B 00 0A 00 01 00 01 00 30 55 73 65 72 44 61 74 61 43 75 73 74 6F 6D 46 61 63 65 3A 31 5C 28 5A 53 41 58 40 57 4B 52 4A 5A 31 7E 33 59 4F 53 53 4C 4D 32 4B 49 2E 6A 70 67 00 00 06 E2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2F 02
|
||||
//解密body=01 3E 03 3F A2 7C BC D3 C1 00 00 27 1C 00 0A 00 01 00 01 00 30 55 73 65 72 44 61 74 61 43 75 73 74 6F 6D 46 61 63 65 3A 31 5C 29 37 42 53 4B 48 32 44 35 54 51 28 5A 35 7D 35 24 56 5D 32 35 49 4E 2E 6A 70 67 00 00 03 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 2F 02
|
||||
}
|
||||
|
||||
@PacketVersion(date = "2019.10.19", timVersion = "2.3.2 (21173)")
|
||||
class Response {
|
||||
override fun decode() = with(input) {
|
||||
require(readBytes().contentEquals(expecting))
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val expecting = byteArrayOf(0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00)
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// regiion GroupImageResponse
|
@ -5,24 +5,25 @@ package net.mamoe.mirai.network.protocol.tim.packet.event
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.discardExact
|
||||
import kotlinx.io.core.readUInt
|
||||
import net.mamoe.mirai.*
|
||||
import net.mamoe.mirai.Bot
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.MemberPermission
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.event.BroadcastControllable
|
||||
import net.mamoe.mirai.event.events.BotEvent
|
||||
import net.mamoe.mirai.getGroup
|
||||
import net.mamoe.mirai.getQQ
|
||||
import net.mamoe.mirai.message.*
|
||||
import net.mamoe.mirai.message.internal.readMessageChain
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.PacketVersion
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImageLink
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.FriendImagePacket
|
||||
import net.mamoe.mirai.network.sessionKey
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.ImageLink
|
||||
import net.mamoe.mirai.utils.*
|
||||
import net.mamoe.mirai.utils.io.printTLVMap
|
||||
import net.mamoe.mirai.utils.io.read
|
||||
import net.mamoe.mirai.utils.io.readTLVMap
|
||||
import net.mamoe.mirai.utils.io.readUShortLVByteArray
|
||||
import net.mamoe.mirai.withSession
|
||||
import kotlin.jvm.JvmName
|
||||
|
||||
/**
|
||||
@ -87,8 +88,8 @@ abstract class MessagePacketBase<TSubject : Contact> : EventPacket, BotEvent() {
|
||||
// endregion
|
||||
|
||||
// region Image download
|
||||
suspend inline fun Image.getLink(): ImageLink = bot.withSession { getLink() }
|
||||
|
||||
suspend fun Image.getLink(): FriendImageLink = bot.withSession { FriendImagePacket.RequestImageLink(bot.qqAccount, bot.sessionKey, id).sendAndExpect() }
|
||||
suspend inline fun Image.downloadAsByteArray(): ByteArray = getLink().downloadAsByteArray()
|
||||
suspend inline fun Image.download(): ByteReadPacket = getLink().download()
|
||||
// endregion
|
||||
@ -106,6 +107,7 @@ data class GroupMessage(
|
||||
override val sender: QQ,
|
||||
override val message: MessageChain = NullMessageChain
|
||||
) : MessagePacket<Group>() {
|
||||
|
||||
override val subject: Group get() = group
|
||||
}
|
||||
|
||||
|
@ -7,10 +7,7 @@ import kotlinx.io.core.Input
|
||||
import net.mamoe.mirai.contact.Contact
|
||||
import net.mamoe.mirai.contact.Group
|
||||
import net.mamoe.mirai.contact.QQ
|
||||
import net.mamoe.mirai.message.Image
|
||||
import net.mamoe.mirai.message.ImageId
|
||||
import net.mamoe.mirai.message.image
|
||||
import net.mamoe.mirai.message.sendTo
|
||||
import net.mamoe.mirai.message.*
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.action.uploadImage
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
|
||||
@ -52,7 +49,8 @@ class ExternalImage(
|
||||
/**
|
||||
* 用于发送消息的 [ImageId]
|
||||
*/
|
||||
val groupImageId: ImageId by lazy { ImageId("{${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}}.$format") }
|
||||
@Suppress("EXPERIMENTAL_UNSIGNED_LITERALS")
|
||||
val groupImageId: ImageId by lazy { ImageId0x03("{${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}}.$format", 0u, height, width) }
|
||||
|
||||
override fun toString(): String = "[ExternalImage(${width}x$height $format)]"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user