diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index e13db5f34..c5e4fd723 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -51,7 +51,7 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin } } - override suspend fun uploadImage(image: ExternalImage): Image { + override suspend fun uploadImage(image: ExternalImage): Image = try { bot.network.run { val response = LongConn.OffPicUp( bot.client, Cmd0x352.TryUpImgReq( @@ -60,12 +60,11 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin fileId = 0, fileMd5 = image.md5, fileSize = image.inputSize.toInt(), - fileName = image.md5.toUHexString("") + ".jpg", + fileName = image.md5.toUHexString("") + "." + image.format, imgOriginal = 1, imgWidth = image.width, imgHeight = image.height, - imgType = image.imageType, - buType = 0 + imgType = image.imageType ) ).sendAndExpect<LongConn.OffPicUp.Response>() @@ -81,7 +80,6 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin is LongConn.OffPicUp.Response.RequireUpload -> { HighwayHelper.uploadImage( client = bot.client, - uin = bot.uin, serverIp = response.serverIp[0].toIpV4AddressString(), serverPort = response.serverPort[0], imageInput = image.input, @@ -103,6 +101,8 @@ internal class QQImpl(bot: QQAndroidBot, override val coroutineContext: Coroutin is LongConn.OffPicUp.Response.Failed -> error(response.message) } } + } finally { + image.input.close() } override suspend fun queryProfile(): Profile { @@ -355,7 +355,7 @@ internal class GroupImpl( } } - override suspend fun uploadImage(image: ExternalImage): Image { + override suspend fun uploadImage(image: ExternalImage): Image = try { bot.network.run { val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp( bot.client, @@ -393,7 +393,6 @@ internal class GroupImpl( HighwayHelper.uploadImage( client = bot.client, - uin = bot.uin, serverIp = response.uploadIpList.first().toIpV4AddressString(), serverPort = response.uploadPortList.first(), imageInput = image.input, @@ -436,6 +435,8 @@ internal class GroupImpl( } } } + } finally { + image.input.close() } override fun equals(other: Any?): Boolean { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt index 074118e57..28bbc4527 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidClient.kt @@ -104,8 +104,11 @@ internal open class QQAndroidClient( private val requestPacketRequestId: AtomicInt = atomic(1921334513) internal fun nextRequestPacketRequestId(): Int = requestPacketRequestId.getAndAdd(2) - private val highwayDataTransSequenceId: AtomicInt = atomic(87017) - internal fun nextHighwayDataTransSequenceId(): Int = highwayDataTransSequenceId.getAndAdd(2) + private val highwayDataTransSequenceIdForGroup: AtomicInt = atomic(87017) + internal fun nextHighwayDataTransSequenceIdForGroup(): Int = highwayDataTransSequenceIdForGroup.getAndAdd(2) + + private val highwayDataTransSequenceIdForFriend: AtomicInt = atomic(40717) + internal fun nextHighwayDataTransSequenceIdForFriend(): Int = highwayDataTransSequenceIdForFriend.getAndAdd(2) val appClientVersion: Int = 0 diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/Codec.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/Codec.kt index 9478d2721..2e0649d07 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/Codec.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/Codec.kt @@ -78,6 +78,9 @@ object Highway { md5: ByteArray ): ByteReadPacket { require(uKey.size == 128) { "bad uKey. Required size=128, got ${uKey.size}" } + require(data !is ByteReadPacket || data.remaining.toInt() == dataSize) { "bad input. given dataSize=$dataSize, but actual readRemaining=${(data as ByteReadPacket).remaining}" } + require(data !is IoBuffer || data.readRemaining == dataSize) { "bad input. given dataSize=$dataSize, but actual readRemaining=${(data as IoBuffer).readRemaining}" } + val dataHighwayHead = CSDataHighwayHead.DataHighwayHead( version = 1, uin = uin.toString(), @@ -91,7 +94,7 @@ object Highway { ) val segHead = CSDataHighwayHead.SegHead( datalength = dataSize, - filesize = dataSize.toLong() and 0xFFffFFff, + filesize = dataSize.toLong(), serviceticket = uKey, md5 = md5, fileMd5 = md5, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt index 55b52992a..bcd7fe054 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/highway/HighwayHelper.kt @@ -15,7 +15,6 @@ internal object HighwayHelper { suspend fun uploadImage( client: QQAndroidClient, - uin: Long, serverIp: String, serverPort: Int, uKey: ByteArray, @@ -26,14 +25,18 @@ internal object HighwayHelper { ) { require(md5.size == 16) { "bad md5. Required size=16, got ${md5.size}" } require(uKey.size == 128) { "bad uKey. Required size=128, got ${uKey.size}" } + require(commandId == 2 || commandId == 1) { "bad commandId. Must be 1 or 2" } + val socket = PlatformSocket() socket.connect(serverIp, serverPort) socket.use { socket.send( Highway.RequestDataTrans( - uin = uin, + uin = client.uin, command = "PicUp.DataUp", - sequenceId = client.nextHighwayDataTransSequenceId(), + sequenceId = + if (commandId == 2) client.nextHighwayDataTransSequenceIdForGroup() + else client.nextHighwayDataTransSequenceIdForFriend(), uKey = uKey, data = imageInput, dataSize = inputSize, diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352.kt index a45c6cd3e..a313b3942 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/proto/Cmd0x352.kt @@ -91,7 +91,7 @@ internal class Cmd0x352 : ProtoBuf { @SerialId(2) val msgTryupImgReq: List<TryUpImgReq>? = null,// optional @SerialId(3) val msgGetimgUrlReq: List<GetImgUrlReq>? = null,// optional @SerialId(4) val msgDelImgReq: List<DelImgReq>? = null, - @SerialId(10) val netType: Int = 0// 数据网络=5 + @SerialId(10) val netType: Int = 3// 数据网络=5 ) : ProtoBuf @Serializable @@ -117,11 +117,10 @@ internal class Cmd0x352 : ProtoBuf { @SerialId(9) val innerIP: Int = 0, @SerialId(10) val addressBook: Int = 0,//chatType == 1006为1 我觉得发0没问题 @SerialId(11) val retry: Int = 0,//default - @SerialId(12) val buType: Int,//1或96 不确定 + @SerialId(12) val buType: Int = 1,//1或96 不确定 @SerialId(13) val imgOriginal: Int,//是否为原图 @SerialId(14) val imgWidth: Int, @SerialId(15) val imgHeight: Int, - @SerialId(16) val imgType: Int = 1000, /** * ImgType: * JPG: 1000 @@ -131,7 +130,8 @@ internal class Cmd0x352 : ProtoBuf { * GIG: 2000 * APNG: 2001 * SHARPP: 1004 - * */ + */ + @SerialId(16) val imgType: Int = 1000, @SerialId(17) val buildVer: String = "8.2.0.1296",//版本号 @SerialId(18) val fileIndex: ByteArray = EMPTY_BYTE_ARRAY,//default @SerialId(19) val fileStoreDays: Int = 0,//default diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index 22b20102d..b8b22ddbb 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -85,7 +85,7 @@ kotlin { api(ktor("network", ktorVersion)) //implementation("io.ktor:ktor-io:1.3.0-beta-1") - runtimeOnly(files("build/classes/kotlin/metadata/main")) // classpath is not properly set by IDE + //runtimeOnly(files("build/classes/kotlin/metadata/main")) // classpath is not properly set by IDE } } commonTest { @@ -93,7 +93,7 @@ kotlin { api(kotlin("test-annotations-common")) api(kotlin("test-common")) - runtimeOnly(files("build/classes/kotlin/metadata/test")) // classpath is not properly set by IDE + //runtimeOnly(files("build/classes/kotlin/metadata/test")) // classpath is not properly set by IDE } } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt index 8cbbea0a7..7a0e2d5f3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/ExternalImage.kt @@ -43,13 +43,13 @@ class ExternalImage( ): ExternalImage = ExternalImage(width, height, md5, format, data, data.remaining, filename) } - private val format: String = when (val it = imageFormat.toLowerCase()) { - "jpeg" -> "jpg" //必须转换 - else -> it - } + val format: String = + when (val it = imageFormat.toLowerCase()) { + "jpeg" -> "jpg" //必须转换 + else -> it + } /** - * * ImgType: * JPG: 1000 * PNG: 1001