mirror of
https://github.com/mamoe/mirai.git
synced 2025-04-25 04:50:26 +08:00
Fix build
This commit is contained in:
parent
e33fea8a3f
commit
905d4ede9a
mirai-core-qqandroid
build.gradle.kts
src
commonMain/kotlin/net/mamoe/mirai/qqandroid
jvmTest/kotlin
androidPacketTests
net.mamoe.mirai.qqandroid.io.serialization
mirai-core
mirai-demos/mirai-demo-android
@ -93,10 +93,10 @@ kotlin {
|
||||
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
api(kotlin("test", kotlinVersion))
|
||||
api(kotlin("test-junit", kotlinVersion))
|
||||
api(kotlin("test-annotations-common"))
|
||||
api(kotlin("test-common"))
|
||||
implementation(kotlin("test", kotlinVersion))
|
||||
implementation(kotlin("test-junit", kotlinVersion))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation(kotlin("test-common"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -55,6 +55,7 @@ internal abstract class QQAndroidBotBase constructor(
|
||||
|
||||
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
|
||||
|
||||
// internally visible only
|
||||
fun getGroupByUin(uin: Long): Group {
|
||||
return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}")
|
||||
}
|
||||
|
@ -1,301 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.qqandroid.io
|
||||
|
||||
import kotlinx.io.charsets.Charset
|
||||
import kotlinx.io.core.*
|
||||
import kotlin.experimental.or
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
@PublishedApi
|
||||
internal val CharsetGBK = Charset.forName("GBK")
|
||||
@PublishedApi
|
||||
internal val CharsetUTF8 = Charset.forName("UTF8")
|
||||
|
||||
inline fun buildJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit): ByteReadPacket {
|
||||
return JceOutput(stringCharset).apply(block).build()
|
||||
}
|
||||
|
||||
inline fun BytePacketBuilder.writeJcePacket(stringCharset: Charset = CharsetGBK, block: JceOutput.() -> Unit) {
|
||||
return this.writePacket(buildJcePacket(stringCharset, block))
|
||||
}
|
||||
|
||||
fun jceStruct(tag: Int, struct: JceStruct): ByteArray{
|
||||
return buildJcePacket {
|
||||
writeJceStruct(struct, tag)
|
||||
}.readBytes()
|
||||
}
|
||||
|
||||
fun <K, V> jceMap(tag: Int, vararg entries: Pair<K, V>): ByteArray {
|
||||
return buildJcePacket {
|
||||
writeMap(mapOf(*entries), tag)
|
||||
}.readBytes()
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* From: com.qq.taf.jce.JceOutputStream
|
||||
*/
|
||||
@Suppress("unused", "MemberVisibilityCanBePrivate")
|
||||
@UseExperimental(ExperimentalIoApi::class)
|
||||
class JceOutput(
|
||||
private val stringCharset: Charset = CharsetGBK
|
||||
) {
|
||||
private val output: BytePacketBuilder = BytePacketBuilder()
|
||||
|
||||
fun build(): ByteReadPacket = output.build()
|
||||
|
||||
fun close() = output.close()
|
||||
fun flush() = output.flush()
|
||||
|
||||
fun writeByte(v: Byte, tag: Int) {
|
||||
if (v.toInt() == 0) {
|
||||
writeHead(ZERO_TYPE, tag)
|
||||
} else {
|
||||
writeHead(BYTE, tag)
|
||||
output.writeByte(v)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeDouble(v: Double, tag: Int) {
|
||||
writeHead(DOUBLE, tag)
|
||||
output.writeDouble(v)
|
||||
}
|
||||
|
||||
fun writeFloat(v: Float, tag: Int) {
|
||||
writeHead(FLOAT, tag)
|
||||
output.writeFloat(v)
|
||||
}
|
||||
|
||||
fun writeFully(src: ByteArray, tag: Int) {
|
||||
writeHead(SIMPLE_LIST, tag)
|
||||
writeHead(BYTE, 0)
|
||||
writeInt(src.size, 0)
|
||||
output.writeFully(src)
|
||||
}
|
||||
|
||||
fun writeFully(src: DoubleArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeDouble(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFully(src: FloatArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeFloat(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFully(src: IntArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeInt(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFully(src: LongArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeLong(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFully(src: ShortArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeShort(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeFully(src: BooleanArray, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeBoolean(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun <T> writeFully(src: Array<T>, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
writeInt(src.size, 0)
|
||||
src.forEach {
|
||||
writeObject(it, 0)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeInt(v: Int, tag: Int) {
|
||||
if (v in Short.MIN_VALUE..Short.MAX_VALUE) {
|
||||
writeShort(v.toShort(), tag)
|
||||
} else {
|
||||
writeHead(INT, tag)
|
||||
output.writeInt(v)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeLong(v: Long, tag: Int) {
|
||||
if (v in Int.MIN_VALUE..Int.MAX_VALUE) {
|
||||
writeInt(v.toInt(), tag)
|
||||
} else {
|
||||
writeHead(LONG, tag)
|
||||
output.writeLong(v)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeShort(v: Short, tag: Int) {
|
||||
if (v in Byte.MIN_VALUE..Byte.MAX_VALUE) {
|
||||
writeByte(v.toByte(), tag)
|
||||
} else {
|
||||
writeHead(SHORT, tag)
|
||||
output.writeShort(v)
|
||||
}
|
||||
}
|
||||
|
||||
fun writeBoolean(v: Boolean, tag: Int) {
|
||||
this.writeByte(if (v) 1 else 0, tag)
|
||||
}
|
||||
|
||||
fun writeString(v: String, tag: Int) {
|
||||
val array = v.toByteArray(stringCharset)
|
||||
if (array.size > 255) {
|
||||
writeHead(STRING4, tag)
|
||||
output.writeInt(array.size)
|
||||
output.writeFully(array)
|
||||
} else {
|
||||
writeHead(STRING1, tag)
|
||||
output.writeByte(array.size.toByte())
|
||||
output.writeFully(array)
|
||||
}
|
||||
}
|
||||
|
||||
fun <K, V> writeMap(map: Map<K, V>, tag: Int) {
|
||||
writeHead(MAP, tag)
|
||||
if (map.isEmpty()) {
|
||||
writeInt(0, 0)
|
||||
} else {
|
||||
writeInt(map.size, 0)
|
||||
map.forEach { (key, value) ->
|
||||
writeObject(key, 0)
|
||||
writeObject(value, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun writeCollection(collection: Collection<*>?, tag: Int) {
|
||||
writeHead(LIST, tag)
|
||||
if (collection == null || collection.isEmpty()) {
|
||||
writeInt(0, 0)
|
||||
} else {
|
||||
writeInt(collection.size, 0)
|
||||
collection.forEach {
|
||||
writeObject(it, 0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun writeJceStruct(v: JceStruct, tag: Int) {
|
||||
writeHead(STRUCT_BEGIN, tag)
|
||||
v.writeTo(this)
|
||||
writeHead(STRUCT_END, 0)
|
||||
}
|
||||
|
||||
fun <T> writeObject(v: T, tag: Int) {
|
||||
when (v) {
|
||||
is Byte -> writeByte(v, tag)
|
||||
is Short -> writeShort(v, tag)
|
||||
is Int -> writeInt(v, tag)
|
||||
is Long -> writeLong(v, tag)
|
||||
is Float -> writeFloat(v, tag)
|
||||
is Double -> writeDouble(v, tag)
|
||||
is JceStruct -> writeJceStruct(v, tag)
|
||||
is ByteArray -> writeFully(v, tag)
|
||||
is Collection<*> -> writeCollection(v, tag)
|
||||
is Boolean -> writeBoolean(v, tag)
|
||||
is Map<*, *> -> writeMap(v, tag)
|
||||
is IntArray -> writeFully(v, tag)
|
||||
is ShortArray -> writeFully(v, tag)
|
||||
is BooleanArray -> writeFully(v, tag)
|
||||
is LongArray -> writeFully(v, tag)
|
||||
is FloatArray -> writeFully(v, tag)
|
||||
is DoubleArray -> writeFully(v, tag)
|
||||
is Array<*> -> writeFully(v, tag)
|
||||
is String -> writeString(v, tag)
|
||||
|
||||
//
|
||||
// is ByteReadPacket -> ByteArrayPool.useInstance {
|
||||
// v.readAvailable(it)
|
||||
// writeFully(it, tag)
|
||||
// }
|
||||
else -> error("unsupported type: ${v.getClassName()}")
|
||||
}
|
||||
}
|
||||
|
||||
fun write(v: Int, tag: Int) = writeInt(v, tag)
|
||||
fun write(v: Byte, tag: Int) = writeByte(v, tag)
|
||||
fun write(v: Short, tag: Int) = writeShort(v, tag)
|
||||
fun write(v: Long, tag: Int) = writeLong(v, tag)
|
||||
fun write(v: Float, tag: Int) = writeFloat(v, tag)
|
||||
fun write(v: Double, tag: Int) = writeDouble(v, tag)
|
||||
fun write(v: String, tag: Int) = writeString(v, tag)
|
||||
fun write(v: Boolean, tag: Int) = writeBoolean(v, tag)
|
||||
fun write(v: Collection<*>, tag: Int) = writeCollection(v, tag)
|
||||
fun write(v: Map<*, *>, tag: Int) = writeMap(v, tag)
|
||||
fun write(v: ByteArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: IntArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: BooleanArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: LongArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: ShortArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: Array<*>, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: FloatArray, tag: Int) = writeFully(v, tag)
|
||||
fun write(v: DoubleArray, tag: Int) = writeFully(v, tag)
|
||||
|
||||
@PublishedApi
|
||||
internal companion object {
|
||||
const val BYTE: Int = 0
|
||||
const val DOUBLE: Int = 5
|
||||
const val FLOAT: Int = 4
|
||||
const val INT: Int = 2
|
||||
const val JCE_MAX_STRING_LENGTH = 104857600
|
||||
const val LIST: Int = 9
|
||||
const val LONG: Int = 3
|
||||
const val MAP: Int = 8
|
||||
const val SHORT: Int = 1
|
||||
const val SIMPLE_LIST: Int = 13
|
||||
const val STRING1: Int = 6
|
||||
const val STRING4: Int = 7
|
||||
const val STRUCT_BEGIN: Int = 10
|
||||
const val STRUCT_END: Int = 11
|
||||
const val ZERO_TYPE: Int = 12
|
||||
|
||||
private fun Any?.getClassName(): KClass<out Any> = if (this == null) Unit::class else this::class
|
||||
}
|
||||
|
||||
@PublishedApi
|
||||
internal fun writeHead(type: Int, tag: Int) {
|
||||
if (tag < 15) {
|
||||
this.output.writeByte(((tag shl 4) or type).toByte())
|
||||
return
|
||||
}
|
||||
if (tag < 256) {
|
||||
this.output.writeByte((type.toByte() or 0xF0.toByte()))
|
||||
this.output.writeByte(tag.toByte())
|
||||
return
|
||||
}
|
||||
throw JceEncodeException("tag is too large: $tag")
|
||||
}
|
||||
}
|
||||
|
||||
class JceEncodeException(message: String) : RuntimeException(message)
|
@ -9,6 +9,4 @@
|
||||
|
||||
package net.mamoe.mirai.qqandroid.io
|
||||
|
||||
interface JceStruct {
|
||||
fun writeTo(output: JceOutput) = Unit
|
||||
}
|
||||
interface JceStruct
|
@ -16,7 +16,6 @@ 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.Input
|
||||
import kotlinx.io.core.readAvailable
|
||||
import kotlinx.io.core.use
|
||||
@ -64,7 +63,7 @@ internal suspend inline fun HttpClient.postImage(
|
||||
override val contentType: ContentType = ContentType.Image.Any
|
||||
override val contentLength: Long = inputSize
|
||||
|
||||
override suspend fun writeTo(channel: ByteWriteChannel) {
|
||||
override suspend fun writeTo(channel: io.ktor.utils.io.ByteWriteChannel) {
|
||||
ByteArrayPool.useInstance { buffer: ByteArray ->
|
||||
var size: Int
|
||||
while (imageInput.readAvailable(buffer).also { size = it } != 0) {
|
||||
|
@ -1,87 +0,0 @@
|
||||
/*
|
||||
* Copyright 2020 Mamoe Technologies and contributors.
|
||||
*
|
||||
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
|
||||
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
|
||||
*
|
||||
* https://github.com/mamoe/mirai/blob/master/LICENSE
|
||||
*/
|
||||
|
||||
package net.mamoe.mirai.qqandroid.network.http
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.request.get
|
||||
import io.ktor.client.request.headers
|
||||
import io.ktor.client.request.post
|
||||
import io.ktor.client.response.HttpResponse
|
||||
import io.ktor.http.URLProtocol
|
||||
import io.ktor.http.setCookie
|
||||
import io.ktor.http.userAgent
|
||||
import kotlinx.coroutines.io.readRemaining
|
||||
import kotlinx.io.core.readBytes
|
||||
import net.mamoe.mirai.qqandroid.network.QQAndroidClient
|
||||
import net.mamoe.mirai.utils.currentTimeMillis
|
||||
import net.mamoe.mirai.utils.io.toUHexString
|
||||
|
||||
/**
|
||||
* 好像不需要了
|
||||
*/
|
||||
object HttpRequest {
|
||||
private lateinit var cookie: String
|
||||
}
|
||||
|
||||
|
||||
internal suspend fun HttpClient.getPTLoginCookies(
|
||||
client: QQAndroidClient
|
||||
): String {
|
||||
//$"https://ssl.ptlogin2.qq.com/jump?pt_clientver=5593&pt_src=1&keyindex=9&ptlang=2052&clientuin={QQ}&clientkey={Util.ToHex(TXProtocol.BufServiceTicketHttp, "", "{0}")}&u1=https:%2F%2Fuser.qzone.qq.com%2F417085811%3FADUIN=417085811%26ADSESSION={Util.GetTimeMillis(DateTime.Now)}%26ADTAG=CLIENT.QQ.5593_MyTip.0%26ADPUBNO=26841&source=namecardhoverstar"
|
||||
// "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441",
|
||||
val res = post<HttpResponse> {
|
||||
println(client.wLoginSigInfo.userStWebSig.data.toUHexString().replace(" ", "").toLowerCase())
|
||||
url {
|
||||
protocol = URLProtocol.HTTPS
|
||||
host = "ssl.ptlogin2.qq.com"
|
||||
path(
|
||||
"/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin=${client.uin}&clientkey=${client.wLoginSigInfo.userStWebSig.data.toUHexString().replace(
|
||||
" ",
|
||||
""
|
||||
)}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441&FADUIN=417085811&ADSESSION=${currentTimeMillis}&source=namecardhoverstar"
|
||||
)
|
||||
}
|
||||
headers {
|
||||
userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36")
|
||||
}
|
||||
}
|
||||
|
||||
println(res.status)
|
||||
println(res.setCookie())
|
||||
println(res.content.readRemaining().readBytes().toUHexString())
|
||||
return "done";
|
||||
}
|
||||
|
||||
|
||||
internal suspend fun HttpClient.getGroupList(
|
||||
client: QQAndroidClient
|
||||
): String {
|
||||
// "https://ssl.ptlogin2.qq.com/jump?pt_clientver=5509&pt_src=1&keyindex=9&clientuin={0}&clientkey={1}&u1=http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441",
|
||||
val res = get<HttpResponse> {
|
||||
url {
|
||||
protocol = URLProtocol.HTTPS
|
||||
host = "ssl.ptlogin2.qq.com"
|
||||
path("jump")
|
||||
parameters["pt_clientver"] = "5509"
|
||||
parameters["pt_src"] = "1"
|
||||
parameters["keyindex"] = "9"
|
||||
parameters["u1"] = "http%3A%2F%2Fqun.qq.com%2Fmember.html%23gid%3D168209441"
|
||||
parameters["clientuin"] = client.uin.toString()
|
||||
parameters["clientkey"] = client.wLoginSigInfo.userStWebSig.data.toUHexString()
|
||||
}
|
||||
headers {
|
||||
userAgent("Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36")
|
||||
}
|
||||
}
|
||||
|
||||
println(res.status)
|
||||
println(res.setCookie())
|
||||
return "done";
|
||||
}
|
@ -248,6 +248,7 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed
|
||||
|
||||
val encryptedBody = readBytes((remaining - 1).toInt())
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val decrypted = kotlin.runCatching {
|
||||
encryptedBody.decryptBy(encrypt).also { println("first by calculatedShareKey or sessionKey(method=7)") }
|
||||
}.getOrElse {
|
||||
|
@ -75,7 +75,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
|
||||
|
||||
val flag3 = readByte().toInt()
|
||||
|
||||
val uinAccount = readString(readInt() - 4)//uin
|
||||
readString(readInt() - 4)//uin
|
||||
|
||||
//debugPrint("remaining")
|
||||
|
||||
@ -163,17 +163,17 @@ private fun Map<Int, ByteArray>.getOrEmpty(key: Int): ByteArray {
|
||||
|
||||
var randomKey: ByteArray = byteArrayOf()
|
||||
private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) {
|
||||
val qq: Long
|
||||
readIoBuffer(readInt() - 4).withUse {
|
||||
check(readByte().toInt() == 2)
|
||||
this.discardExact(2) // 27 + 2 + body.size
|
||||
this.discardExact(2) // const, =8001
|
||||
this.readUShort() // commandId
|
||||
this.readShort() // const, =0x0001
|
||||
qq = this.readUInt().toLong()
|
||||
this.readUInt().toLong() // qq
|
||||
val encryptionMethod = this.readUShort().toInt()
|
||||
|
||||
this.discardExact(1) // const = 0
|
||||
@Suppress("UNUSED_VARIABLE")
|
||||
val packet = when (encryptionMethod) {
|
||||
4 -> { // peer public key, ECDH
|
||||
var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1)
|
||||
@ -229,7 +229,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori
|
||||
|
||||
commandName = readString(readInt() - 4)
|
||||
DebugLogger.warning("commandName=$commandName")
|
||||
val unknown = readBytes(readInt() - 4)
|
||||
readBytes(readInt() - 4) // unknown, sessionId?
|
||||
//if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
|
||||
|
||||
check(readInt() == 0)
|
||||
@ -278,7 +278,7 @@ private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP
|
||||
|
||||
commandName = readString(readInt() - 4)
|
||||
DebugLogger.warning("commandName=$commandName")
|
||||
val unknown = readBytes(readInt() - 4)
|
||||
readBytes(readInt() - 4) // unknown
|
||||
//if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
|
||||
|
||||
check(readInt() == 0)
|
||||
|
@ -9,6 +9,8 @@
|
||||
|
||||
package net.mamoe.mirai.qqandroid.io.serialization
|
||||
|
||||
/*
|
||||
|
||||
import kotlinx.io.core.readBytes
|
||||
import kotlinx.serialization.SerialId
|
||||
import kotlinx.serialization.Serializable
|
||||
@ -310,4 +312,6 @@ class JceDecoderTest {
|
||||
OuterStruct(listOf(TestSimpleJceStruct(), TestSimpleJceStruct())).contentToString()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
@ -61,13 +61,13 @@ kotlin {
|
||||
languageSettings.useExperimentalAnnotation("kotlin.Experimental")
|
||||
|
||||
dependencies {
|
||||
api(kotlin("stdlib", kotlinVersion))
|
||||
api(kotlin("serialization", kotlinVersion))
|
||||
implementation(kotlin("stdlib", kotlinVersion))
|
||||
implementation(kotlin("serialization", kotlinVersion))
|
||||
|
||||
api("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion")
|
||||
api(kotlinx("io", kotlinXIoVersion))
|
||||
api(kotlinx("coroutines-io", coroutinesIoVersion))
|
||||
api(kotlinx("coroutines-core", coroutinesVersion))
|
||||
implementation("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion")
|
||||
implementation(kotlinx("io", kotlinXIoVersion))
|
||||
implementation(kotlinx("coroutines-io", coroutinesIoVersion))
|
||||
implementation(kotlinx("coroutines-core", coroutinesVersion))
|
||||
}
|
||||
}
|
||||
commonMain {
|
||||
@ -90,8 +90,8 @@ kotlin {
|
||||
}
|
||||
commonTest {
|
||||
dependencies {
|
||||
api(kotlin("test-annotations-common"))
|
||||
api(kotlin("test-common"))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation(kotlin("test-common"))
|
||||
|
||||
//runtimeOnly(files("build/classes/kotlin/metadata/test")) // classpath is not properly set by IDE
|
||||
}
|
||||
@ -102,6 +102,8 @@ kotlin {
|
||||
dependencies {
|
||||
api(kotlin("reflect", kotlinVersion))
|
||||
|
||||
api(kotlinx("io", kotlinXIoVersion))
|
||||
api(kotlinx("io-jvm", kotlinXIoVersion))
|
||||
api(kotlinx("serialization-runtime", serializationVersion))
|
||||
api(kotlinx("coroutines-android", coroutinesVersion))
|
||||
|
||||
@ -111,10 +113,10 @@ kotlin {
|
||||
|
||||
val androidTest by getting {
|
||||
dependencies {
|
||||
api(kotlin("test", kotlinVersion))
|
||||
api(kotlin("test-junit", kotlinVersion))
|
||||
api(kotlin("test-annotations-common"))
|
||||
api(kotlin("test-common"))
|
||||
implementation(kotlin("test", kotlinVersion))
|
||||
implementation(kotlin("test-junit", kotlinVersion))
|
||||
implementation(kotlin("test-annotations-common"))
|
||||
implementation(kotlin("test-common"))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -128,6 +130,9 @@ kotlin {
|
||||
api(ktor("client-core-jvm", ktorVersion))
|
||||
api(kotlinx("io-jvm", kotlinXIoVersion))
|
||||
api(kotlinx("serialization-runtime", serializationVersion))
|
||||
api(kotlinx("coroutines-io", coroutinesIoVersion))
|
||||
api(kotlinx("coroutines-io-jvm", coroutinesIoVersion))
|
||||
api(kotlinx("io-jvm", coroutinesIoVersion))
|
||||
|
||||
api("org.bouncycastle:bcprov-jdk15on:1.64")
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
|
||||
@ -136,8 +141,8 @@ kotlin {
|
||||
|
||||
val jvmTest by getting {
|
||||
dependencies {
|
||||
api(kotlin("test", kotlinVersion))
|
||||
api(kotlin("test-junit", kotlinVersion))
|
||||
implementation(kotlin("test", kotlinVersion))
|
||||
implementation(kotlin("test-junit", kotlinVersion))
|
||||
implementation("org.pcap4j:pcap4j-distribution:1.8.2")
|
||||
|
||||
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
|
||||
|
@ -12,7 +12,6 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import android.graphics.BitmapFactory
|
||||
import io.ktor.util.asStream
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.Input
|
||||
@ -100,7 +99,7 @@ suspend fun InputStream.suspendToExternalImage(): ExternalImage = withContext(IO
|
||||
fun Input.toExternalImage(): ExternalImage {
|
||||
val file = createTempFile().apply { deleteOnExit() }
|
||||
file.outputStream().asOutput().use {
|
||||
this.asStream().asInput().copyTo(it)
|
||||
this.copyTo(it)
|
||||
}
|
||||
return file.toExternalImage()
|
||||
}
|
||||
|
@ -9,11 +9,11 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import io.ktor.util.cio.use
|
||||
import kotlinx.coroutines.CoroutineName
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.GlobalScope
|
||||
import kotlinx.coroutines.io.ByteWriteChannel
|
||||
import kotlinx.coroutines.io.close
|
||||
import kotlinx.coroutines.io.jvm.nio.copyTo
|
||||
import kotlinx.coroutines.io.reader
|
||||
import kotlinx.coroutines.sync.Mutex
|
||||
@ -44,7 +44,7 @@ internal class DefaultLoginSolver : LoginSolver() {
|
||||
tempFile.createNewFile()
|
||||
bot.logger.info("需要图片验证码登录, 验证码为 4 字母")
|
||||
try {
|
||||
tempFile.writeChannel().use { writeFully(data) }
|
||||
tempFile.writeChannel().apply { writeFully(data); close() }
|
||||
bot.logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}")
|
||||
} catch (e: Exception) {
|
||||
bot.logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
|
||||
|
@ -11,7 +11,6 @@
|
||||
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import io.ktor.util.asStream
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.io.core.Input
|
||||
@ -132,7 +131,7 @@ suspend inline fun InputStream.suspendToExternalImage(): ExternalImage = withCon
|
||||
fun Input.toExternalImage(): ExternalImage {
|
||||
val file = createTempFile().apply { deleteOnExit() }
|
||||
file.outputStream().asOutput().use {
|
||||
this.asStream().asInput().copyTo(it)
|
||||
this.copyTo(it)
|
||||
}
|
||||
return file.toExternalImage()
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ android {
|
||||
exclude 'META-INF/ktor-http-cio.kotlin_module'
|
||||
exclude 'META-INF/ktor-client-core.kotlin_module'
|
||||
exclude "META-INF/kotlinx-serialization-runtime.kotlin_module"
|
||||
exclude 'META-INF/ktor-io.kotlin_module'
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user