mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-21 16:12:25 +08:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
a776b25b27
@ -1,15 +1,26 @@
|
||||
package net.mamoe.mirai.qqandroid
|
||||
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.contact.*
|
||||
import net.mamoe.mirai.data.FriendNameRemark
|
||||
import net.mamoe.mirai.data.PreviousNameList
|
||||
import net.mamoe.mirai.data.Profile
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.MessageChain
|
||||
import net.mamoe.mirai.message.data.NotOnlineImageFromFile
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.network.highway.Highway
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.CSDataHighwayHead
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.withUse
|
||||
import net.mamoe.mirai.qqandroid.utils.toIpV4AddressString
|
||||
import net.mamoe.mirai.utils.ExternalImage
|
||||
import net.mamoe.mirai.utils.MiraiInternalAPI
|
||||
import net.mamoe.mirai.utils.cryptor.contentToString
|
||||
import net.mamoe.mirai.utils.getValue
|
||||
import net.mamoe.mirai.utils.io.PlatformSocket
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
import net.mamoe.mirai.utils.unsafeWeakRef
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@ -116,7 +127,73 @@ internal class GroupImpl(
|
||||
}
|
||||
|
||||
override suspend fun uploadImage(image: ExternalImage): Image {
|
||||
TODO("not implemented")
|
||||
}
|
||||
bot.network.run {
|
||||
val response: ImgStore.GroupPicUp.Response = ImgStore.GroupPicUp(
|
||||
bot.client,
|
||||
uin = bot.uin,
|
||||
groupCode = id,
|
||||
md5 = image.md5,
|
||||
size = image.inputSize,
|
||||
picWidth = image.width,
|
||||
picHeight = image.height,
|
||||
picType = image.imageType,
|
||||
filename = image.filename
|
||||
).sendAndExpect()
|
||||
|
||||
when (response) {
|
||||
is ImgStore.GroupPicUp.Response.Failed -> error("upload group image failed with reason ${response.message}")
|
||||
is ImgStore.GroupPicUp.Response.FileExists -> {
|
||||
val resourceId = image.calculateImageResourceId()
|
||||
return NotOnlineImageFromFile(
|
||||
resourceId = resourceId,
|
||||
md5 = response.fileInfo.fileMd5,
|
||||
filepath = resourceId,
|
||||
fileLength = response.fileInfo.fileSize.toInt(),
|
||||
height = response.fileInfo.fileHeight,
|
||||
width = response.fileInfo.fileWidth,
|
||||
imageType = response.fileInfo.fileType
|
||||
)
|
||||
}
|
||||
is ImgStore.GroupPicUp.Response.RequireUpload -> {
|
||||
|
||||
val socket = PlatformSocket()
|
||||
socket.connect(response.uploadIpList.first().toIpV4AddressString().also { println("serverIp=$it") }, response.uploadPortList.first())
|
||||
// socket.use {
|
||||
socket.send(
|
||||
Highway.RequestDataTrans(
|
||||
uin = bot.uin,
|
||||
command = "PicUp.DataUp",
|
||||
buildVer = bot.client.buildVer,
|
||||
uKey = response.uKey,
|
||||
data = image.input,
|
||||
dataSize = image.inputSize.toInt(),
|
||||
md5 = image.md5,
|
||||
sequenceId = bot.client.nextHighwayDataTransSequenceId()
|
||||
)
|
||||
)
|
||||
// }
|
||||
|
||||
//0A 3C 08 01 12 0A 31 39 39 34 37 30 31 30 32 31 1A 0C 50 69 63 55 70 2E 44 61 74 61 55 70 20 E9 A7 05 28 00 30 BD DB 8B 80 02 38 80 20 40 02 4A 0A 38 2E 32 2E 30 2E 31 32 39 36 50 84 10 12 3D 08 00 10 FD 08 18 00 20 FD 08 28 C6 01 38 00 42 10 D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E 4A 10 D4 1D 8C D9 8F 00 B2 04 E9 80 09 98 EC F8 42 7E 50 89 92 A2 FB 06 58 00 60 00 18 53 20 01 28 00 30 04 3A 00 40 E6 B7 F7 D9 80 2E 48 00 50 00
|
||||
socket.read().withUse {
|
||||
readByte()
|
||||
val headLength = readInt()
|
||||
val bodyLength = readInt()
|
||||
val proto = readProtoBuf(CSDataHighwayHead.RspDataHighwayHead.serializer(), length = headLength)
|
||||
println(proto.contentToString())
|
||||
println(readBytes(bodyLength).toUHexString())
|
||||
}
|
||||
val resourceId = image.calculateImageResourceId()
|
||||
return NotOnlineImageFromFile(
|
||||
resourceId = resourceId,
|
||||
md5 = image.md5,
|
||||
filepath = resourceId,
|
||||
fileLength = image.inputSize.toInt(),
|
||||
height = image.height,
|
||||
width = image.width,
|
||||
imageType = image.imageType
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -95,7 +95,8 @@ internal open class QQAndroidClient(
|
||||
|
||||
var openAppId: Long = 715019303L
|
||||
|
||||
val apkVersionName: ByteArray = "8.2.0".toByteArray()
|
||||
val apkVersionName: ByteArray get() = "8.2.0".toByteArray()
|
||||
val buildVer: String get() = "8.2.0.1296"
|
||||
|
||||
private val messageSequenceId: AtomicInt = atomic(0)
|
||||
internal fun atomicNextMessageSequenceId(): Int = messageSequenceId.getAndAdd(2)
|
||||
@ -103,6 +104,9 @@ 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)
|
||||
|
||||
val appClientVersion: Int = 0
|
||||
|
||||
var networkType: NetworkType = NetworkType.WIFI
|
||||
|
@ -0,0 +1,129 @@
|
||||
package net.mamoe.mirai.qqandroid.network.highway
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.http.ContentType
|
||||
import io.ktor.http.HttpStatusCode
|
||||
import io.ktor.http.URLProtocol
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.userAgent
|
||||
import kotlinx.coroutines.io.ByteWriteChannel
|
||||
import kotlinx.io.core.*
|
||||
import kotlinx.io.pool.useInstance
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.toByteArray
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.CSDataHighwayHead
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
import net.mamoe.mirai.utils.io.ByteArrayPool
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
internal suspend inline fun HttpClient.postImage(
|
||||
htcmd: String,
|
||||
uin: Long,
|
||||
groupcode: Long?,
|
||||
imageInput: Input,
|
||||
inputSize: Long,
|
||||
uKeyHex: String
|
||||
): Boolean = try {
|
||||
post<HttpStatusCode> {
|
||||
url {
|
||||
protocol = URLProtocol.HTTP
|
||||
host = "htdata2.qq.com"
|
||||
path("cgi-bin/httpconn")
|
||||
|
||||
parameters["htcmd"] = htcmd
|
||||
parameters["uin"] = uin.toString()
|
||||
|
||||
if (groupcode != null) parameters["groupcode"] = groupcode.toString()
|
||||
|
||||
parameters["term"] = "pc"
|
||||
parameters["ver"] = "5603"
|
||||
parameters["filesize"] = inputSize.toString()
|
||||
parameters["range"] = 0.toString()
|
||||
parameters["ukey"] = uKeyHex
|
||||
|
||||
userAgent("QQClient")
|
||||
}
|
||||
|
||||
body = object : OutgoingContent.WriteChannelContent() {
|
||||
override val contentType: ContentType = ContentType.Image.Any
|
||||
override val contentLength: Long = inputSize
|
||||
|
||||
override suspend fun writeTo(channel: ByteWriteChannel) {
|
||||
ByteArrayPool.useInstance { buffer: ByteArray ->
|
||||
var size: Int
|
||||
while (imageInput.readAvailable(buffer).also { size = it } != 0) {
|
||||
channel.writeFully(buffer, 0, size)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} == HttpStatusCode.OK
|
||||
} finally {
|
||||
imageInput.close()
|
||||
}
|
||||
|
||||
object Highway {
|
||||
fun RequestDataTrans(
|
||||
uin: Long,
|
||||
command: String,
|
||||
sequenceId: Int,
|
||||
buildVer: String,
|
||||
appId: Int = 537062845,
|
||||
dataFlag: Int = 4096,
|
||||
commandId: Int = 2,
|
||||
localId: Int = 2052,
|
||||
|
||||
uKey: ByteArray,
|
||||
data: Input,
|
||||
dataSize: Int,
|
||||
md5: ByteArray
|
||||
): ByteReadPacket {
|
||||
val dataHighwayHead = CSDataHighwayHead.DataHighwayHead(
|
||||
version = 1,
|
||||
uin = uin.toString(),
|
||||
command = command,
|
||||
seq = sequenceId,
|
||||
retryTimes = 0,
|
||||
appid = appId,
|
||||
dataflag = dataFlag,
|
||||
commandId = commandId,
|
||||
buildVer = buildVer,
|
||||
localeId = localId
|
||||
)
|
||||
val segHead = CSDataHighwayHead.SegHead(
|
||||
datalength = dataSize,
|
||||
filesize = dataSize.toLong() and 0xFFffFFff,
|
||||
serviceticket = uKey,
|
||||
md5 = md5,
|
||||
fileMd5 = md5
|
||||
)
|
||||
return Codec.buildC2SData(dataHighwayHead, segHead, EMPTY_BYTE_ARRAY, null, data, dataSize)
|
||||
}
|
||||
|
||||
private object Codec {
|
||||
fun buildC2SData(
|
||||
dataHighwayHead: CSDataHighwayHead.DataHighwayHead,
|
||||
segHead: CSDataHighwayHead.SegHead,
|
||||
extendInfo: ByteArray,
|
||||
loginSigHead: CSDataHighwayHead.LoginSigHead?,
|
||||
body: Input,
|
||||
bodySize: Int
|
||||
): ByteReadPacket {
|
||||
val head = CSDataHighwayHead.ReqDataHighwayHead(
|
||||
msgBasehead = dataHighwayHead,
|
||||
msgSeghead = segHead,
|
||||
reqExtendinfo = extendInfo,
|
||||
msgLoginSigHead = loginSigHead
|
||||
).toByteArray(CSDataHighwayHead.ReqDataHighwayHead.serializer())
|
||||
|
||||
return buildPacket {
|
||||
writeByte(40)
|
||||
writeInt(head.size)
|
||||
writeInt(bodySize)
|
||||
writeFully(head)
|
||||
body.copyTo(this)
|
||||
writeByte(41)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,279 @@
|
||||
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 net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
|
||||
@Serializable
|
||||
class Cmd0x388 : ProtoBuf {
|
||||
@Serializable
|
||||
class DelImgReq(
|
||||
@SerialId(1) val srcUin: Long = 0L,
|
||||
@SerialId(2) val dstUin: Long = 0L,
|
||||
@SerialId(3) val reqTerm: Int = 0,
|
||||
@SerialId(4) val reqPlatformType: Int = 0,
|
||||
@SerialId(5) val buType: Int = 0,
|
||||
@SerialId(6) val buildVer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(7) val fileResid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(8) val picWidth: Int = 0,
|
||||
@SerialId(9) val picHeight: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class DelImgRsp(
|
||||
@SerialId(1) val result: Int = 0,
|
||||
@SerialId(2) val failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val fileResid: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ExpRoamExtendInfo(
|
||||
@SerialId(1) val resid: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ExpRoamPicInfo(
|
||||
@SerialId(1) val shopFlag: Int = 0,
|
||||
@SerialId(2) val pkgId: Int = 0,
|
||||
@SerialId(3) val picId: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ExtensionCommPicTryUp(
|
||||
@SerialId(1) val bytesExtinfo: List<ByteArray>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ExtensionExpRoamTryUp(
|
||||
@SerialId(1) val msgExproamPicInfo: List<ExpRoamPicInfo>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class GetImgUrlReq(
|
||||
@SerialId(1) val groupCode: Long = 0L,
|
||||
@SerialId(2) val dstUin: Long = 0L,
|
||||
@SerialId(3) val fileid: Long = 0L,
|
||||
@SerialId(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val urlFlag: Int = 0,
|
||||
@SerialId(6) val urlType: Int = 0,
|
||||
@SerialId(7) val reqTerm: Int = 0,
|
||||
@SerialId(8) val reqPlatformType: Int = 0,
|
||||
@SerialId(9) val innerIp: Int = 0,
|
||||
@SerialId(10) val buType: Int = 0,
|
||||
@SerialId(11) val buildVer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(12) val fileId: Long = 0L,
|
||||
@SerialId(13) val fileSize: Long = 0L,
|
||||
@SerialId(14) val originalPic: Int = 0,
|
||||
@SerialId(15) val retryReq: Int = 0,
|
||||
@SerialId(16) val fileHeight: Int = 0,
|
||||
@SerialId(17) val fileWidth: Int = 0,
|
||||
@SerialId(18) val picType: Int = 0,
|
||||
@SerialId(19) val picUpTimestamp: Int = 0,
|
||||
@SerialId(20) val reqTransferType: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class GetImgUrlRsp(
|
||||
@SerialId(1) val fileid: Long = 0L,
|
||||
@SerialId(2) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val result: Int = 0,
|
||||
@SerialId(4) val failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val msgImgInfo: ImgInfo? = null,
|
||||
@SerialId(6) val bytesThumbDownUrl: List<ByteArray>? = null,
|
||||
@SerialId(7) val bytesOriginalDownUrl: List<ByteArray>? = null,
|
||||
@SerialId(8) val bytesBigDownUrl: List<ByteArray>? = null,
|
||||
@SerialId(9) val uint32DownIp: List<Int>? = null,
|
||||
@SerialId(10) val uint32DownPort: List<Int>? = null,
|
||||
@SerialId(11) val downDomain: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(12) val thumbDownPara: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(13) val originalDownPara: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(14) val bigDownPara: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(15) val fileId: Long = 0L,
|
||||
@SerialId(16) val autoDownType: Int = 0,
|
||||
@SerialId(17) val uint32OrderDownType: List<Int>? = null,
|
||||
@SerialId(19) val bigThumbDownPara: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(20) val httpsUrlFlag: Int = 0,
|
||||
@SerialId(26) val msgDownIp6: List<IPv6Info>? = null,
|
||||
@SerialId(27) val clientIp6: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class GetPttUrlReq(
|
||||
@SerialId(1) val groupCode: Long = 0L,
|
||||
@SerialId(2) val dstUin: Long = 0L,
|
||||
@SerialId(3) val fileid: Long = 0L,
|
||||
@SerialId(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val reqTerm: Int = 0,
|
||||
@SerialId(6) val reqPlatformType: Int = 0,
|
||||
@SerialId(7) val innerIp: Int = 0,
|
||||
@SerialId(8) val buType: Int = 0,
|
||||
@SerialId(9) val buildVer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(10) val fileId: Long = 0L,
|
||||
@SerialId(11) val fileKey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(12) val codec: Int = 0,
|
||||
@SerialId(13) val buId: Int = 0,
|
||||
@SerialId(14) val reqTransferType: Int = 0,
|
||||
@SerialId(15) val isAuto: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class GetPttUrlRsp(
|
||||
@SerialId(1) val fileid: Long = 0L,
|
||||
@SerialId(2) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val result: Int = 0,
|
||||
@SerialId(4) val failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val bytesDownUrl: List<ByteArray>? = null,
|
||||
@SerialId(6) val uint32DownIp: List<Int>? = null,
|
||||
@SerialId(7) val uint32DownPort: List<Int>? = null,
|
||||
@SerialId(8) val downDomain: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(9) val downPara: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(10) val fileId: Long = 0L,
|
||||
@SerialId(11) val transferType: Int = 0,
|
||||
@SerialId(12) val allowRetry: Int = 0,
|
||||
@SerialId(26) val msgDownIp6: List<IPv6Info>? = null,
|
||||
@SerialId(27) val clientIp6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(28) val strDomain: String = ""
|
||||
) : ProtoBuf
|
||||
|
||||
@Suppress("ArrayInDataClass")
|
||||
@Serializable
|
||||
data class ImgInfo(
|
||||
@SerialId(1) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val fileType: Int = 0,
|
||||
@SerialId(3) val fileSize: Long = 0L,
|
||||
@SerialId(4) val fileWidth: Int = 0,
|
||||
@SerialId(5) val fileHeight: Int = 0
|
||||
) : ProtoBuf {
|
||||
override fun toString(): String {
|
||||
return "ImgInfo(fileMd5=${fileMd5.contentToString()}, fileType=$fileType, fileSize=$fileSize, fileWidth=$fileWidth, fileHeight=$fileHeight)"
|
||||
}
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class IPv6Info(
|
||||
@SerialId(1) val ip6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val port: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class PicSize(
|
||||
@SerialId(1) val original: Int = 0,
|
||||
@SerialId(2) val thumb: Int = 0,
|
||||
@SerialId(3) val high: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ReqBody(
|
||||
@SerialId(1) val netType: Int = 0,
|
||||
@SerialId(2) val subcmd: Int = 0,
|
||||
@SerialId(3) val msgTryupImgReq: List<TryUpImgReq>? = null,
|
||||
@SerialId(4) val msgGetimgUrlReq: List<GetImgUrlReq>? = null,
|
||||
@SerialId(5) val msgTryupPttReq: List<TryUpPttReq>? = null,
|
||||
@SerialId(6) val msgGetpttUrlReq: List<GetPttUrlReq>? = null,
|
||||
@SerialId(7) val commandId: Int = 0,
|
||||
@SerialId(8) val msgDelImgReq: List<DelImgReq>? = null,
|
||||
@SerialId(1001) val extension: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class RspBody(
|
||||
@SerialId(1) val clientIp: Int = 0,
|
||||
@SerialId(2) val subcmd: Int = 0,
|
||||
@SerialId(3) val msgTryupImgRsp: List<TryUpImgRsp>? = null,
|
||||
@SerialId(4) val msgGetimgUrlRsp: List<GetImgUrlRsp>? = null,
|
||||
@SerialId(5) val msgTryupPttRsp: List<TryUpPttRsp>? = null,
|
||||
@SerialId(6) val msgGetpttUrlRsp: List<GetPttUrlRsp>? = null,
|
||||
@SerialId(7) val msgDelImgRsp: List<DelImgRsp>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class TryUpImgReq(
|
||||
@SerialId(1) val groupCode: Long = 0L,
|
||||
@SerialId(2) val srcUin: Long = 0L,
|
||||
@SerialId(3) val fileId: Long = 0L,
|
||||
@SerialId(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val fileSize: Long = 0L,
|
||||
@SerialId(6) val fileName: String ="",
|
||||
@SerialId(7) val srcTerm: Int = 0,
|
||||
@SerialId(8) val platformType: Int = 0,
|
||||
@SerialId(9) val buType: Int = 0,
|
||||
@SerialId(10) val picWidth: Int = 0,
|
||||
@SerialId(11) val picHeight: Int = 0,
|
||||
@SerialId(12) val picType: Int = 0,
|
||||
@SerialId(13) val buildVer: String = "",
|
||||
@SerialId(14) val innerIp: Int = 0,
|
||||
@SerialId(15) val appPicType: Int = 0,
|
||||
@SerialId(16) val originalPic: Int = 0,
|
||||
@SerialId(17) val fileIndex: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(18) val dstUin: Long = 0L,
|
||||
@SerialId(19) val srvUpload: Int = 0,
|
||||
@SerialId(20) val transferUrl: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class TryUpImgRsp(
|
||||
@SerialId(1) val fileId: Long = 0L,
|
||||
@SerialId(2) val result: Int = 0,
|
||||
@SerialId(3) val failMsg: String = "",
|
||||
@SerialId(4) val boolFileExit: Boolean = false,
|
||||
@SerialId(5) val msgImgInfo: ImgInfo? = null,
|
||||
@SerialId(6) val uint32UpIp: List<Int>? = null,
|
||||
@SerialId(7) val uint32UpPort: List<Int>? = null,
|
||||
@SerialId(8) val upUkey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(9) val fileid: Long = 0L,
|
||||
@SerialId(10) val upOffset: Long = 0L,
|
||||
@SerialId(11) val blockSize: Long = 0L,
|
||||
@SerialId(12) val boolNewBigChan: Boolean = false,
|
||||
@SerialId(26) val msgUpIp6: List<IPv6Info>? = null,
|
||||
@SerialId(27) val clientIp6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(1001) val msgInfo4busi: TryUpInfo4Busi? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class TryUpInfo4Busi(
|
||||
@SerialId(1) val downDomain: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val thumbDownUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val originalDownUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val bigDownUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val fileResid: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class TryUpPttReq(
|
||||
@SerialId(1) val groupCode: Long = 0L,
|
||||
@SerialId(2) val srcUin: Long = 0L,
|
||||
@SerialId(3) val fileId: Long = 0L,
|
||||
@SerialId(4) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val fileSize: Long = 0L,
|
||||
@SerialId(6) val fileName: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(7) val srcTerm: Int = 0,
|
||||
@SerialId(8) val platformType: Int = 0,
|
||||
@SerialId(9) val buType: Int = 0,
|
||||
@SerialId(10) val buildVer: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(11) val innerIp: Int = 0,
|
||||
@SerialId(12) val voiceLength: Int = 0,
|
||||
@SerialId(13) val boolNewUpChan: Boolean = false,
|
||||
@SerialId(14) val codec: Int = 0,
|
||||
@SerialId(15) val voiceType: Int = 0,
|
||||
@SerialId(16) val buId: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class TryUpPttRsp(
|
||||
@SerialId(1) val fileId: Long = 0L,
|
||||
@SerialId(2) val result: Int = 0,
|
||||
@SerialId(3) val failMsg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val boolFileExit: Boolean = false,
|
||||
@SerialId(5) val uint32UpIp: List<Int>? = null,
|
||||
@SerialId(6) val uint32UpPort: List<Int>? = null,
|
||||
@SerialId(7) val upUkey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(8) val fileid: Long = 0L,
|
||||
@SerialId(9) val upOffset: Long = 0L,
|
||||
@SerialId(10) val blockSize: Long = 0L,
|
||||
@SerialId(11) val fileKey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(12) val channelType: Int = 0,
|
||||
@SerialId(26) val msgUpIp6: List<IPv6Info>? = null,
|
||||
@SerialId(27) val clientIp6: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
}
|
@ -0,0 +1,454 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.data.proto
|
||||
|
||||
import kotlinx.serialization.SerialId
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.protobuf.ProtoNumberType
|
||||
import kotlinx.serialization.protobuf.ProtoType
|
||||
import net.mamoe.mirai.qqandroid.io.ProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
|
||||
|
||||
@Serializable
|
||||
class BdhExtinfo : ProtoBuf {
|
||||
@Serializable
|
||||
class CommFileExtReq(
|
||||
@SerialId(1) val actionType: Int = 0,
|
||||
@SerialId(2) val uuid: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class CommFileExtRsp(
|
||||
@SerialId(1) val int32Retcode: Int = 0,
|
||||
@SerialId(2) val downloadUrl: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class PicInfo(
|
||||
@SerialId(1) val idx: Int = 0,
|
||||
@SerialId(2) val size: Int = 0,
|
||||
@SerialId(3) val binMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val type: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class QQVoiceExtReq(
|
||||
@SerialId(1) val qid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val fmt: Int = 0,
|
||||
@SerialId(3) val rate: Int = 0,
|
||||
@SerialId(4) val bits: Int = 0,
|
||||
@SerialId(5) val channel: Int = 0,
|
||||
@SerialId(6) val pinyin: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class QQVoiceExtRsp(
|
||||
@SerialId(1) val qid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val int32Retcode: Int = 0,
|
||||
@SerialId(3) val msgResult: List<QQVoiceResult>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class QQVoiceResult(
|
||||
@SerialId(1) val text: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val pinyin: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val source: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ShortVideoReqExtInfo(
|
||||
@SerialId(1) val cmd: Int = 0,
|
||||
@SerialId(2) val sessionId: Long = 0L,
|
||||
@SerialId(3) val msgThumbinfo: PicInfo? = null,
|
||||
@SerialId(4) val msgVideoinfo: VideoInfo? = null,
|
||||
@SerialId(5) val msgShortvideoSureReq: ShortVideoSureReqInfo? = null,
|
||||
@SerialId(6) val boolIsMergeCmdBeforeData: Boolean = false
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ShortVideoRspExtInfo(
|
||||
@SerialId(1) val cmd: Int = 0,
|
||||
@SerialId(2) val sessionId: Long = 0L,
|
||||
@SerialId(3) val int32Retcode: Int = 0,
|
||||
@SerialId(4) val errinfo: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val msgThumbinfo: PicInfo? = null,
|
||||
@SerialId(6) val msgVideoinfo: VideoInfo? = null,
|
||||
@SerialId(7) val msgShortvideoSureRsp: ShortVideoSureRspInfo? = null,
|
||||
@SerialId(8) val retryFlag: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ShortVideoSureReqInfo(
|
||||
@SerialId(1) val fromuin: Long = 0L,
|
||||
@SerialId(2) val chatType: Int = 0,
|
||||
@SerialId(3) val touin: Long = 0L,
|
||||
@SerialId(4) val groupCode: Long = 0L,
|
||||
@SerialId(5) val clientType: Int = 0,
|
||||
@SerialId(6) val msgThumbinfo: PicInfo? = null,
|
||||
@SerialId(7) val msgMergeVideoinfo: List<VideoInfo>? = null,
|
||||
@SerialId(8) val msgDropVideoinfo: List<VideoInfo>? = null,
|
||||
@SerialId(9) val businessType: Int = 0,
|
||||
@SerialId(10) val subBusinessType: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ShortVideoSureRspInfo(
|
||||
@SerialId(1) val fileid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val ukey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val msgVideoinfo: VideoInfo? = null,
|
||||
@SerialId(4) val mergeCost: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class StoryVideoExtReq : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class StoryVideoExtRsp(
|
||||
@SerialId(1) val int32Retcode: Int = 0,
|
||||
@SerialId(2) val msg: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val cdnUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val fileKey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(5) val fileId: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class UploadPicExtInfo(
|
||||
@SerialId(1) val fileResid: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val downloadUrl: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val thumbDownloadUrl: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class VideoInfo(
|
||||
@SerialId(1) val idx: Int = 0,
|
||||
@SerialId(2) val size: Int = 0,
|
||||
@SerialId(3) val binMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val format: Int = 0,
|
||||
@SerialId(5) val resLen: Int = 0,
|
||||
@SerialId(6) val resWidth: Int = 0,
|
||||
@SerialId(7) val time: Int = 0,
|
||||
@SerialId(8) val starttime: Long = 0L,
|
||||
@SerialId(9) val isAudio: Int = 0
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class CSDataHighwayHead : ProtoBuf {
|
||||
@Serializable
|
||||
class C2CCommonExtendinfo(
|
||||
@SerialId(1) val infoId: Int = 0,
|
||||
@SerialId(2) val msgFilterExtendinfo: FilterExtendinfo? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class DataHighwayHead(
|
||||
@SerialId(1) val version: Int = 0,
|
||||
@SerialId(2) val uin: String = "",
|
||||
@SerialId(3) val command: String = "",
|
||||
@SerialId(4) val seq: Int = 0,
|
||||
@SerialId(5) val retryTimes: Int = 0,
|
||||
@SerialId(6) val appid: Int = 0,
|
||||
@SerialId(7) val dataflag: Int = 0,
|
||||
@SerialId(8) val commandId: Int = 0,
|
||||
@SerialId(9) val buildVer: String = "",
|
||||
@SerialId(10) val localeId: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class DataHole(
|
||||
@SerialId(1) val begin: Long = 0L,
|
||||
@SerialId(2) val end: Long = 0L
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class FilterExtendinfo(
|
||||
@SerialId(1) val filterFlag: Int = 0,
|
||||
@SerialId(2) val msgImageFilterRequest: ImageFilterRequest? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class FilterStyle(
|
||||
@SerialId(1) val styleId: Int = 0,
|
||||
@SerialId(2) val styleName: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ImageFilterRequest(
|
||||
@SerialId(1) val sessionId: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val clientIp: Int = 0,
|
||||
@SerialId(3) val uin: Long = 0L,
|
||||
@SerialId(4) val style: FilterStyle? = null,
|
||||
@SerialId(5) val width: Int = 0,
|
||||
@SerialId(6) val height: Int = 0,
|
||||
@SerialId(7) val imageData: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ImageFilterResponse(
|
||||
@SerialId(1) val retCode: Int = 0,
|
||||
@SerialId(2) val imageData: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val costTime: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class LoginSigHead(
|
||||
@SerialId(1) val loginsigType: Int = 0,
|
||||
@SerialId(2) val loginsig: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class NewServiceTicket(
|
||||
@SerialId(1) val signature: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val ukey: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class PicInfoExt(
|
||||
@SerialId(1) val picWidth: Int = 0,
|
||||
@SerialId(2) val picHeight: Int = 0,
|
||||
@SerialId(3) val picFlag: Int = 0,
|
||||
@SerialId(4) val busiType: Int = 0,
|
||||
@SerialId(5) val srcTerm: Int = 0,
|
||||
@SerialId(6) val platType: Int = 0,
|
||||
@SerialId(7) val netType: Int = 0,
|
||||
@SerialId(8) val imgType: Int = 0,
|
||||
@SerialId(9) val appPicType: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class PicRspExtInfo(
|
||||
@SerialId(1) val skey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val clientIp: Int = 0,
|
||||
@SerialId(3) val upOffset: Long = 0L,
|
||||
@SerialId(4) val blockSize: Long = 0L
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class QueryHoleRsp(
|
||||
@SerialId(1) val result: Int = 0,
|
||||
@SerialId(2) val dataHole: List<DataHole>? = null,
|
||||
@SerialId(3) val boolCompFlag: Boolean = false
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ReqDataHighwayHead(
|
||||
@SerialId(1) val msgBasehead: DataHighwayHead? = null,
|
||||
@SerialId(2) val msgSeghead: SegHead? = null,
|
||||
@SerialId(3) val reqExtendinfo: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(4) val timestamp: Long = 0L,
|
||||
@SerialId(5) val msgLoginSigHead: LoginSigHead? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class RspBody(
|
||||
@SerialId(1) val msgQueryHoleRsp: QueryHoleRsp? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class RspDataHighwayHead(
|
||||
@SerialId(1) val msgBasehead: DataHighwayHead? = null,
|
||||
@SerialId(2) val msgSeghead: SegHead? = null,
|
||||
@SerialId(3) val errorCode: Int = 0,
|
||||
@SerialId(4) val allowRetry: Int = 0,
|
||||
@SerialId(5) val cachecost: Int = 0,
|
||||
@SerialId(6) val htcost: Int = 0,
|
||||
@SerialId(7) val rspExtendinfo: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(8) val timestamp: Long = 0L,
|
||||
@SerialId(9) val range: Long = 0L,
|
||||
@SerialId(10) val isReset: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class SegHead(
|
||||
@SerialId(1) val serviceid: Int = 0,
|
||||
@SerialId(2) val filesize: Long = 0L,
|
||||
@SerialId(3) val dataoffset: Long = 0L,
|
||||
@SerialId(4) val datalength: Int = 0,
|
||||
@SerialId(5) val rtcode: Int = 0,
|
||||
@SerialId(6) val serviceticket: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(7) val flag: Int = 0,
|
||||
@SerialId(8) val md5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(9) val fileMd5: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(10) val cacheAddr: Int = 0,
|
||||
@SerialId(11) val queryTimes: Int = 0,
|
||||
@SerialId(12) val updateCacheip: Int = 0
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class HwConfigPersistentPB : ProtoBuf {
|
||||
@Serializable
|
||||
class HwConfigItemPB(
|
||||
@SerialId(1) val ingKey: String = "",
|
||||
@SerialId(2) val endPointList: List<HwEndPointPB>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class HwConfigPB(
|
||||
@SerialId(1) val configItemList: List<HwConfigItemPB>? = null,
|
||||
@SerialId(2) val netSegConfList: List<HwNetSegConfPB>? = null,
|
||||
@SerialId(3) val shortVideoNetConf: List<HwNetSegConfPB>? = null,
|
||||
@SerialId(4) val configItemListIp6: List<HwConfigItemPB>? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class HwEndPointPB(
|
||||
@SerialId(1) val ingHost: String = "",
|
||||
@SerialId(2) val int32Port: Int = 0,
|
||||
@SerialId(3) val int64Timestampe: Long = 0L
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class HwNetSegConfPB(
|
||||
@SerialId(1) val int64NetType: Long = 0L,
|
||||
@SerialId(2) val int64SegSize: Long = 0L,
|
||||
@SerialId(3) val int64SegNum: Long = 0L,
|
||||
@SerialId(4) val int64CurConnNum: Long = 0L
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class HwSessionInfoPersistentPB : ProtoBuf {
|
||||
@Serializable
|
||||
class HwSessionInfoPB(
|
||||
@SerialId(1) val httpconnSigSession: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val sessionKey: ByteArray = EMPTY_BYTE_ARRAY
|
||||
) : ProtoBuf
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class Subcmd0x501 : ProtoBuf {
|
||||
@Serializable
|
||||
class ReqBody(
|
||||
@SerialId(1281) val msgSubcmd0x501ReqBody: SubCmd0x501ReqBody? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class RspBody(
|
||||
@SerialId(1281) val msgSubcmd0x501RspBody: SubCmd0x501Rspbody? = null
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class SubCmd0x501ReqBody(
|
||||
@SerialId(1) val uin: Long = 0L,
|
||||
@SerialId(2) val idcId: Int = 0,
|
||||
@SerialId(3) val appid: Int = 0,
|
||||
@SerialId(4) val loginSigType: Int = 0,
|
||||
@SerialId(5) val loginSigTicket: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(6) val requestFlag: Int = 0,
|
||||
@SerialId(7) val uint32ServiceTypes: List<Int>? = null,
|
||||
@SerialId(8) val bid: Int = 0,
|
||||
@SerialId(9) val term: Int = 0,
|
||||
@SerialId(10) val plat: Int = 0,
|
||||
@SerialId(11) val net: Int = 0,
|
||||
@SerialId(12) val caller: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class SubCmd0x501Rspbody(
|
||||
@SerialId(1) val httpconnSigSession: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(2) val sessionKey: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val msgHttpconnAddrs: List<SrvAddrs>? = null,
|
||||
@SerialId(4) val preConnection: Int = 0,
|
||||
@SerialId(5) val csConn: Int = 0,
|
||||
@SerialId(6) val msgIpLearnConf: IpLearnConf? = null,
|
||||
@SerialId(7) val msgDynTimeoutConf: DynTimeOutConf? = null,
|
||||
@SerialId(8) val msgOpenUpConf: OpenUpConf? = null,
|
||||
@SerialId(9) val msgDownloadEncryptConf: DownloadEncryptConf? = null,
|
||||
@SerialId(10) val msgShortVideoConf: ShortVideoConf? = null,
|
||||
@SerialId(11) val msgPtvConf: PTVConf? = null
|
||||
) : ProtoBuf {
|
||||
@Serializable
|
||||
class DownloadEncryptConf(
|
||||
@SerialId(1) val boolEnableEncryptRequest: Boolean = false,
|
||||
@SerialId(2) val boolEnableEncryptedPic: Boolean = false,
|
||||
@SerialId(3) val ctrlFlag: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class DynTimeOutConf(
|
||||
@SerialId(1) val tbase2g: Int = 0,
|
||||
@SerialId(2) val tbase3g: Int = 0,
|
||||
@SerialId(3) val tbase4g: Int = 0,
|
||||
@SerialId(4) val tbaseWifi: Int = 0,
|
||||
@SerialId(5) val torg2g: Int = 0,
|
||||
@SerialId(6) val torg3g: Int = 0,
|
||||
@SerialId(7) val torg4g: Int = 0,
|
||||
@SerialId(8) val torgWifi: Int = 0,
|
||||
@SerialId(9) val maxTimeout: Int = 0,
|
||||
@SerialId(10) val enableDynTimeout: Int = 0,
|
||||
@SerialId(11) val maxTimeout2g: Int = 0,
|
||||
@SerialId(12) val maxTimeout3g: Int = 0,
|
||||
@SerialId(13) val maxTimeout4g: Int = 0,
|
||||
@SerialId(14) val maxTimeoutWifi: Int = 0,
|
||||
@SerialId(15) val hbTimeout2g: Int = 0,
|
||||
@SerialId(16) val hbTimeout3g: Int = 0,
|
||||
@SerialId(17) val hbTimeout4g: Int = 0,
|
||||
@SerialId(18) val hbTimeoutWifi: Int = 0,
|
||||
@SerialId(19) val hbTimeoutDefault: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class Ip6Addr(
|
||||
@SerialId(1) val type: Int = 0,
|
||||
@SerialId(2) val ip6: ByteArray = EMPTY_BYTE_ARRAY,
|
||||
@SerialId(3) val port: Int = 0,
|
||||
@SerialId(4) val area: Int = 0,
|
||||
@SerialId(5) val sameIsp: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class IpAddr(
|
||||
@SerialId(1) val type: Int = 0,
|
||||
@ProtoType(ProtoNumberType.FIXED) @SerialId(2) val ip: Int = 0,
|
||||
@SerialId(3) val port: Int = 0,
|
||||
@SerialId(4) val area: Int = 0,
|
||||
@SerialId(5) val sameIsp: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class IpLearnConf(
|
||||
@SerialId(1) val refreshCachedIp: Int = 0,
|
||||
@SerialId(2) val enableIpLearn: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class NetSegConf(
|
||||
@SerialId(1) val netType: Int = 0,
|
||||
@SerialId(2) val segsize: Int = 0,
|
||||
@SerialId(3) val segnum: Int = 0,
|
||||
@SerialId(4) val curconnnum: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class OpenUpConf(
|
||||
@SerialId(1) val boolEnableOpenup: Boolean = false,
|
||||
@SerialId(2) val preSendSegnum: Int = 0,
|
||||
@SerialId(3) val preSendSegnum3g: Int = 0,
|
||||
@SerialId(4) val preSendSegnum4g: Int = 0,
|
||||
@SerialId(5) val preSendSegnumWifi: Int = 0
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class PTVConf(
|
||||
@SerialId(1) val channelType: Int = 0,
|
||||
@SerialId(2) val msgNetsegconf: List<NetSegConf>? = null,
|
||||
@SerialId(3) val boolOpenHardwareCodec: Boolean = false
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class ShortVideoConf(
|
||||
@SerialId(1) val channelType: Int = 0,
|
||||
@SerialId(2) val msgNetsegconf: List<NetSegConf>? = null,
|
||||
@SerialId(3) val boolOpenHardwareCodec: Boolean = false,
|
||||
@SerialId(4) val boolSendAheadSignal: Boolean = false
|
||||
) : ProtoBuf
|
||||
|
||||
@Serializable
|
||||
class SrvAddrs(
|
||||
@SerialId(1) val serviceType: Int = 0,
|
||||
@SerialId(2) val msgAddrs: List<IpAddr>? = null,
|
||||
@SerialId(3) val fragmentSize: Int = 0,
|
||||
@SerialId(4) val msgNetsegconf: List<NetSegConf>? = null,
|
||||
@SerialId(5) val msgAddrsV6: List<Ip6Addr>? = null
|
||||
) : ProtoBuf
|
||||
}
|
||||
}
|
@ -5,7 +5,9 @@ import kotlinx.io.pool.useInstance
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.event.Subscribable
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.TroopManagement
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImageUpPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.ImgStore
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image.LongConn
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.MessageSvc
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.chat.receive.OnlinePush
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.list.FriendList
|
||||
@ -119,6 +121,9 @@ internal object KnownPacketFactories {
|
||||
FriendList.GetFriendGroupList,
|
||||
FriendList.GetTroopListSimplify,
|
||||
FriendList.GetTroopMemberList,
|
||||
ImgStore.GroupPicUp,
|
||||
ImageUpPacket,
|
||||
LongConn.OffPicDown,
|
||||
TroopManagement.EditNametag,
|
||||
TroopManagement.Mute,
|
||||
TroopManagement.MuteAll
|
||||
|
@ -1,42 +0,0 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.writeFully
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
|
||||
|
||||
internal object ImageDownPacket : OutgoingPacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") {
|
||||
|
||||
operator fun invoke(client: QQAndroidClient, req: GetImgUrlReq): OutgoingPacket {
|
||||
// TODO: 2020/1/24 测试: bodyType, subAppId
|
||||
return buildLoginOutgoingPacket(client, key = client.wLoginSigInfo.d2Key, bodyType = 1) {
|
||||
writeSsoPacket(client, subAppId = 0, commandName = commandName, sequenceId = it) {
|
||||
val data = ProtoBufWithNullableSupport.dump(
|
||||
Cmd0x352Packet.serializer(),
|
||||
Cmd0x352Packet.createByImageRequest(req)
|
||||
)
|
||||
writeInt(data.size + 4)
|
||||
writeFully(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ImageDownPacketResponse {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
||||
sealed class ImageDownPacketResponse : Packet {
|
||||
object Success : ImageDownPacketResponse()
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -10,15 +10,13 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.UploadImgReq
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
|
||||
internal object ImageUpPacket : OutgoingPacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") {
|
||||
|
||||
operator fun invoke(client: QQAndroidClient, req: UploadImgReq): OutgoingPacket {
|
||||
// TODO: 2020/1/24 测试: bodyType, subAppId
|
||||
return buildLoginOutgoingPacket(client, key = client.wLoginSigInfo.d2Key, bodyType = 1) {
|
||||
writeSsoPacket(client, subAppId = 0, commandName = commandName, sequenceId = it) {
|
||||
return buildOutgoingUniPacket(client) {
|
||||
val data = ProtoBufWithNullableSupport.dump(
|
||||
Cmd0x352Packet.serializer(),
|
||||
Cmd0x352Packet.createByImageRequest(req)
|
||||
@ -27,7 +25,6 @@ internal object ImageUpPacket : OutgoingPacketFactory<ImageUpPacket.ImageUpPacke
|
||||
writeFully(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ImageUpPacketResponse {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
|
@ -0,0 +1,101 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.readProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.writeProtoBuf
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x388
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
|
||||
|
||||
internal class ImgStore {
|
||||
object GroupPicUp : OutgoingPacketFactory<GroupPicUp.Response>("ImgStore.GroupPicUp") {
|
||||
|
||||
operator fun invoke(
|
||||
client: QQAndroidClient,
|
||||
uin: Long,
|
||||
groupCode: Long,
|
||||
md5: ByteArray,
|
||||
size: Long,
|
||||
picWidth: Int,
|
||||
picHeight: Int,
|
||||
picType: Int = 1000,
|
||||
fileId: Long = 0,
|
||||
filename: String,
|
||||
srcTerm: Int = 5,
|
||||
platformType: Int = 9,
|
||||
buType: Int = 1,
|
||||
appPicType: Int = 1006,
|
||||
originalPic: Int = 0
|
||||
): OutgoingPacket = buildOutgoingUniPacket(client) {
|
||||
writeProtoBuf(
|
||||
Cmd0x388.ReqBody.serializer(),
|
||||
Cmd0x388.ReqBody(
|
||||
netType = 3, // wifi
|
||||
subcmd = 1,
|
||||
msgTryupImgReq = listOf(
|
||||
Cmd0x388.TryUpImgReq(
|
||||
groupCode = groupCode,
|
||||
srcUin = uin,
|
||||
fileMd5 = md5,
|
||||
fileSize = size,
|
||||
fileId = fileId,
|
||||
fileName = filename,
|
||||
picWidth = picWidth,
|
||||
picHeight = picHeight,
|
||||
picType = picType,
|
||||
appPicType = appPicType,
|
||||
buildVer = client.buildVer,
|
||||
srcTerm = srcTerm,
|
||||
platformType = platformType,
|
||||
originalPic = originalPic,
|
||||
buType = buType
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
sealed class Response : Packet {
|
||||
class FileExists(
|
||||
val fileId: Long,
|
||||
val fileInfo: Cmd0x388.ImgInfo
|
||||
) : Response() {
|
||||
override fun toString(): String {
|
||||
return "FileExists(fileId=$fileId, fileInfo=$fileInfo)"
|
||||
}
|
||||
}
|
||||
|
||||
class RequireUpload(
|
||||
val fileId: Long,
|
||||
val uKey: ByteArray,
|
||||
val uploadIpList: List<Int>,
|
||||
val uploadPortList: List<Int>
|
||||
) : Response() {
|
||||
override fun toString(): String {
|
||||
return "RequireUpload(fileId=$fileId, uKey=${uKey.contentToString()})"
|
||||
}
|
||||
}
|
||||
|
||||
data class Failed(
|
||||
val resultCode: Int,
|
||||
val message: String
|
||||
) : Response()
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response {
|
||||
val resp0 = readProtoBuf(Cmd0x388.RspBody.serializer())
|
||||
resp0.msgTryupImgRsp ?: error("cannot find `msgTryupImgRsp` from `Cmd0x388.RspBody`")
|
||||
val resp = resp0.msgTryupImgRsp.first()
|
||||
return when {
|
||||
resp.result != 0 -> Response.Failed(resultCode = resp.result, message = resp.failMsg)
|
||||
resp.boolFileExit -> Response.FileExists(fileId = resp.fileid, fileInfo = resp.msgImgInfo!!)
|
||||
else -> Response.RequireUpload(fileId = resp.fileid, uKey = resp.upUkey, uploadIpList = resp.uint32UpIp!!, uploadPortList = resp.uint32UpPort!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
|
||||
|
||||
import kotlinx.io.core.ByteReadPacket
|
||||
import kotlinx.io.core.writeFully
|
||||
import net.mamoe.mirai.data.Packet
|
||||
import net.mamoe.mirai.qqandroid.QQAndroidBot
|
||||
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
|
||||
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
|
||||
|
||||
internal class LongConn {
|
||||
|
||||
object OffPicDown : OutgoingPacketFactory<OffPicDown.ImageDownPacketResponse>("LongConn.OffPicDown"){
|
||||
operator fun invoke(client: QQAndroidClient, req: GetImgUrlReq): OutgoingPacket {
|
||||
// TODO: 2020/1/24 测试: bodyType, subAppId
|
||||
return buildLoginOutgoingPacket(client, key = client.wLoginSigInfo.d2Key, bodyType = 1) {
|
||||
writeSsoPacket(client, subAppId = 0, commandName = commandName, sequenceId = it) {
|
||||
val data = ProtoBufWithNullableSupport.dump(
|
||||
Cmd0x352Packet.serializer(),
|
||||
Cmd0x352Packet.createByImageRequest(req)
|
||||
)
|
||||
writeInt(data.size + 4)
|
||||
writeFully(data)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ImageDownPacketResponse {
|
||||
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||
}
|
||||
|
||||
|
||||
sealed class ImageDownPacketResponse : Packet {
|
||||
object Success : ImageDownPacketResponse()
|
||||
}
|
||||
}
|
||||
}
|
@ -6,7 +6,7 @@ import java.io.File
|
||||
|
||||
fun main() {
|
||||
println(
|
||||
File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/group/group_label/""")
|
||||
File("""/Users/jiahua.liu/Desktop/QQAndroid-F/app/src/main/java/tencent/im/s2c/msgtype0x210/submsgtype0xc7/bussinfo/mutualmark""")
|
||||
.generateUnarrangedClasses().toMutableList().arrangeClasses().joinToString("\n\n")
|
||||
)
|
||||
}
|
||||
|
@ -31,8 +31,6 @@ interface Group : Contact, CoroutineScope {
|
||||
|
||||
/**
|
||||
* 在 [Group] 实例创建的时候查询一次. 并与事件同步事件更新
|
||||
*
|
||||
* **注意**: 获得的列表仅为这一时刻的成员列表的镜像. 它将不会被更新
|
||||
*/
|
||||
val members: ContactList<Member>
|
||||
|
||||
|
@ -5,6 +5,7 @@ package net.mamoe.mirai.message.data
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
sealed class Image : Message {
|
||||
abstract val filepath: String
|
||||
abstract val md5: ByteArray
|
||||
|
||||
abstract override fun toString(): String
|
||||
@ -15,7 +16,7 @@ sealed class Image : Message {
|
||||
}
|
||||
|
||||
abstract class CustomFace : Image() {
|
||||
abstract val filepath: String
|
||||
abstract override val filepath: String
|
||||
abstract val fileId: Int
|
||||
abstract val serverIp: Int
|
||||
abstract val serverPort: Int
|
||||
@ -106,7 +107,7 @@ data class CustomFaceFromFile(
|
||||
abstract class NotOnlineImage : Image() {
|
||||
abstract val resourceId: String
|
||||
abstract override val md5: ByteArray
|
||||
abstract val filepath: String
|
||||
abstract override val filepath: String
|
||||
abstract val fileLength: Int
|
||||
abstract val height: Int
|
||||
abstract val width: Int
|
||||
|
@ -7,18 +7,10 @@ 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.data.*
|
||||
import net.mamoe.mirai.message.data.Image
|
||||
import net.mamoe.mirai.message.data.sendTo
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
|
||||
@Suppress("FunctionName")
|
||||
fun ExternalImage(
|
||||
width: Int,
|
||||
height: Int,
|
||||
md5: ByteArray,
|
||||
format: String,
|
||||
data: ByteReadPacket
|
||||
): ExternalImage = ExternalImage(width, height, md5, format, data, data.remaining)
|
||||
|
||||
/**
|
||||
* 外部图片. 图片数据还没有读取到内存.
|
||||
*
|
||||
@ -33,19 +25,53 @@ class ExternalImage(
|
||||
val md5: ByteArray,
|
||||
imageFormat: String,
|
||||
val input: Input,
|
||||
val inputSize: Long
|
||||
val inputSize: Long,
|
||||
val filename: String
|
||||
) {
|
||||
private val format: String
|
||||
|
||||
init {
|
||||
if (imageFormat == "JPEG" || imageFormat == "jpeg") {//必须转换
|
||||
this.format = "jpg"
|
||||
} else {
|
||||
this.format = imageFormat
|
||||
companion object {
|
||||
operator fun invoke(
|
||||
width: Int,
|
||||
height: Int,
|
||||
md5: ByteArray,
|
||||
format: String,
|
||||
data: ByteReadPacket,
|
||||
filename: String
|
||||
): ExternalImage = ExternalImage(width, height, md5, format, data, data.remaining, filename)
|
||||
}
|
||||
|
||||
private val format: String = when (val it =imageFormat.toLowerCase()) {
|
||||
"jpeg" -> "jpg" //必须转换
|
||||
else -> it
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* ImgType:
|
||||
* JPG: 1000
|
||||
* PNG: 1001
|
||||
* WEBP: 1002
|
||||
* BMP: 1005
|
||||
* GIG: 2000
|
||||
* APNG: 2001
|
||||
* SHARPP: 1004
|
||||
*/
|
||||
val imageType: Int
|
||||
get() = when (format){
|
||||
"jpg" -> 1000
|
||||
"png" -> 1001
|
||||
"webp" -> 1002
|
||||
"bmp" -> 1005
|
||||
"gig" -> 2000
|
||||
"apng" -> 2001
|
||||
"sharpp" -> 1004
|
||||
else -> 1000 // unsupported, just make it jpg
|
||||
}
|
||||
|
||||
override fun toString(): String = "[ExternalImage(${width}x$height $format)]"
|
||||
|
||||
fun calculateImageResourceId(): String {
|
||||
return "{${md5[0..3]}-${md5[4..5]}-${md5[6..7]}-${md5[8..9]}-${md5[10..15]}}.$format"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -12,6 +12,7 @@ import kotlinx.io.core.copyTo
|
||||
import kotlinx.io.errors.IOException
|
||||
import kotlinx.io.streams.asInput
|
||||
import kotlinx.io.streams.asOutput
|
||||
import net.mamoe.mirai.utils.io.getRandomString
|
||||
import java.awt.image.BufferedImage
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
@ -44,7 +45,7 @@ fun BufferedImage.toExternalImage(formatName: String = "gif"): ExternalImage {
|
||||
})
|
||||
}
|
||||
|
||||
return ExternalImage(width, height, digest.digest(), formatName, buffer)
|
||||
return ExternalImage(width, height, digest.digest(), formatName, buffer, getRandomString(10) + "." + formatName)
|
||||
}
|
||||
|
||||
suspend inline fun BufferedImage.suspendToExternalImage(): ExternalImage = withContext(IO) { toExternalImage() }
|
||||
@ -66,7 +67,8 @@ fun File.toExternalImage(): ExternalImage {
|
||||
md5 = this.inputStream().use { it.md5() },
|
||||
imageFormat = image.formatName,
|
||||
input = this.inputStream().asInput(IoBuffer.Pool),
|
||||
inputSize = this.length()
|
||||
inputSize = this.length(),
|
||||
filename = this.name
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,10 @@ dependencies {
|
||||
implementation 'org.jsoup:jsoup:1.12.1'
|
||||
}
|
||||
|
||||
mainClassName = "demo.gentleman.MainKt"
|
||||
run{
|
||||
standardInput = System.in
|
||||
mainClassName = "demo.gentleman.MainKt"
|
||||
}
|
||||
compileKotlin {
|
||||
kotlinOptions {
|
||||
freeCompilerArgs = ["-XXLanguage:+InlineClasses"]
|
||||
|
Loading…
Reference in New Issue
Block a user