Commit 905d4ede authored by Him188's avatar Him188

Fix build

parent e33fea8a
...@@ -93,10 +93,10 @@ kotlin { ...@@ -93,10 +93,10 @@ kotlin {
val androidTest by getting { val androidTest by getting {
dependencies { dependencies {
api(kotlin("test", kotlinVersion)) implementation(kotlin("test", kotlinVersion))
api(kotlin("test-junit", kotlinVersion)) implementation(kotlin("test-junit", kotlinVersion))
api(kotlin("test-annotations-common")) implementation(kotlin("test-annotations-common"))
api(kotlin("test-common")) implementation(kotlin("test-common"))
} }
} }
} }
......
...@@ -55,6 +55,7 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -55,6 +55,7 @@ internal abstract class QQAndroidBotBase constructor(
override val groups: ContactList<Group> = ContactList(LockFreeLinkedList()) override val groups: ContactList<Group> = ContactList(LockFreeLinkedList())
// internally visible only
fun getGroupByUin(uin: Long): Group { fun getGroupByUin(uin: Long): Group {
return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}") return groups.delegate.filteringGetOrNull { (it as GroupImpl).uin == uin } ?: throw NoSuchElementException("Can not found group with ID=${uin}")
} }
......
/*
* 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)
\ No newline at end of file
...@@ -9,6 +9,4 @@ ...@@ -9,6 +9,4 @@
package net.mamoe.mirai.qqandroid.io package net.mamoe.mirai.qqandroid.io
interface JceStruct { interface JceStruct
fun writeTo(output: JceOutput) = Unit \ No newline at end of file
}
\ No newline at end of file
...@@ -16,7 +16,6 @@ import io.ktor.http.HttpStatusCode ...@@ -16,7 +16,6 @@ import io.ktor.http.HttpStatusCode
import io.ktor.http.URLProtocol import io.ktor.http.URLProtocol
import io.ktor.http.content.OutgoingContent import io.ktor.http.content.OutgoingContent
import io.ktor.http.userAgent import io.ktor.http.userAgent
import kotlinx.coroutines.io.ByteWriteChannel
import kotlinx.io.core.Input import kotlinx.io.core.Input
import kotlinx.io.core.readAvailable import kotlinx.io.core.readAvailable
import kotlinx.io.core.use import kotlinx.io.core.use
...@@ -64,7 +63,7 @@ internal suspend inline fun HttpClient.postImage( ...@@ -64,7 +63,7 @@ internal suspend inline fun HttpClient.postImage(
override val contentType: ContentType = ContentType.Image.Any override val contentType: ContentType = ContentType.Image.Any
override val contentLength: Long = inputSize 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 -> ByteArrayPool.useInstance { buffer: ByteArray ->
var size: Int var size: Int
while (imageInput.readAvailable(buffer).also { size = it } != 0) { while (imageInput.readAvailable(buffer).also { size = it } != 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 ...@@ -248,6 +248,7 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed
val encryptedBody = readBytes((remaining - 1).toInt()) val encryptedBody = readBytes((remaining - 1).toInt())
@Suppress("NAME_SHADOWING")
val decrypted = kotlin.runCatching { val decrypted = kotlin.runCatching {
encryptedBody.decryptBy(encrypt).also { println("first by calculatedShareKey or sessionKey(method=7)") } encryptedBody.decryptBy(encrypt).also { println("first by calculatedShareKey or sessionKey(method=7)") }
}.getOrElse { }.getOrElse {
......
...@@ -75,7 +75,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) { ...@@ -75,7 +75,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
val flag3 = readByte().toInt() val flag3 = readByte().toInt()
val uinAccount = readString(readInt() - 4)//uin readString(readInt() - 4)//uin
//debugPrint("remaining") //debugPrint("remaining")
...@@ -163,17 +163,17 @@ private fun Map<Int, ByteArray>.getOrEmpty(key: Int): ByteArray { ...@@ -163,17 +163,17 @@ private fun Map<Int, ByteArray>.getOrEmpty(key: Int): ByteArray {
var randomKey: ByteArray = byteArrayOf() var randomKey: ByteArray = byteArrayOf()
private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) { private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) {
val qq: Long
readIoBuffer(readInt() - 4).withUse { readIoBuffer(readInt() - 4).withUse {
check(readByte().toInt() == 2) check(readByte().toInt() == 2)
this.discardExact(2) // 27 + 2 + body.size this.discardExact(2) // 27 + 2 + body.size
this.discardExact(2) // const, =8001 this.discardExact(2) // const, =8001
this.readUShort() // commandId this.readUShort() // commandId
this.readShort() // const, =0x0001 this.readShort() // const, =0x0001
qq = this.readUInt().toLong() this.readUInt().toLong() // qq
val encryptionMethod = this.readUShort().toInt() val encryptionMethod = this.readUShort().toInt()
this.discardExact(1) // const = 0 this.discardExact(1) // const = 0
@Suppress("UNUSED_VARIABLE")
val packet = when (encryptionMethod) { val packet = when (encryptionMethod) {
4 -> { // peer public key, ECDH 4 -> { // peer public key, ECDH
var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1) var data = this.decryptBy(shareKeyCalculatedByConstPubKey, 0, this.readRemaining - 1)
...@@ -229,7 +229,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori ...@@ -229,7 +229,7 @@ private fun parseSsoFrame(flag3: Int, input: ByteReadPacket): KnownPacketFactori
commandName = readString(readInt() - 4) commandName = readString(readInt() - 4)
DebugLogger.warning("commandName=$commandName") 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()}") //if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
check(readInt() == 0) check(readInt() == 0)
...@@ -278,7 +278,7 @@ private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP ...@@ -278,7 +278,7 @@ private fun parseUniFrame(input: ByteReadPacket): KnownPacketFactories.IncomingP
commandName = readString(readInt() - 4) commandName = readString(readInt() - 4)
DebugLogger.warning("commandName=$commandName") DebugLogger.warning("commandName=$commandName")
val unknown = readBytes(readInt() - 4) readBytes(readInt() - 4) // unknown
//if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}") //if (unknown.toInt() != 0x02B05B8B) DebugLogger.debug("got new unknown: ${unknown.toUHexString()}")
check(readInt() == 0) check(readInt() == 0)
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
package net.mamoe.mirai.qqandroid.io.serialization package net.mamoe.mirai.qqandroid.io.serialization
/*
import kotlinx.io.core.readBytes import kotlinx.io.core.readBytes
import kotlinx.serialization.SerialId import kotlinx.serialization.SerialId
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
...@@ -310,4 +312,6 @@ class JceDecoderTest { ...@@ -310,4 +312,6 @@ class JceDecoderTest {
OuterStruct(listOf(TestSimpleJceStruct(), TestSimpleJceStruct())).contentToString() OuterStruct(listOf(TestSimpleJceStruct(), TestSimpleJceStruct())).contentToString()
) )
} }
} }
\ No newline at end of file
*/
\ No newline at end of file
...@@ -61,13 +61,13 @@ kotlin { ...@@ -61,13 +61,13 @@ kotlin {
languageSettings.useExperimentalAnnotation("kotlin.Experimental") languageSettings.useExperimentalAnnotation("kotlin.Experimental")
dependencies { dependencies {
api(kotlin("stdlib", kotlinVersion)) implementation(kotlin("stdlib", kotlinVersion))
api(kotlin("serialization", kotlinVersion)) implementation(kotlin("serialization", kotlinVersion))
api("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion") implementation("org.jetbrains.kotlinx:atomicfu:$atomicFuVersion")
api(kotlinx("io", kotlinXIoVersion)) implementation(kotlinx("io", kotlinXIoVersion))
api(kotlinx("coroutines-io", coroutinesIoVersion)) implementation(kotlinx("coroutines-io", coroutinesIoVersion))
api(kotlinx("coroutines-core", coroutinesVersion)) implementation(kotlinx("coroutines-core", coroutinesVersion))
} }
} }
commonMain { commonMain {
...@@ -90,8 +90,8 @@ kotlin { ...@@ -90,8 +90,8 @@ kotlin {
} }
commonTest { commonTest {
dependencies { dependencies {
api(kotlin("test-annotations-common")) implementation(kotlin("test-annotations-common"))
api(kotlin("test-common")) implementation(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
} }
...@@ -102,6 +102,8 @@ kotlin { ...@@ -102,6 +102,8 @@ kotlin {
dependencies { dependencies {
api(kotlin("reflect", kotlinVersion)) api(kotlin("reflect", kotlinVersion))
api(kotlinx("io", kotlinXIoVersion))
api(kotlinx("io-jvm", kotlinXIoVersion))
api(kotlinx("serialization-runtime", serializationVersion)) api(kotlinx("serialization-runtime", serializationVersion))
api(kotlinx("coroutines-android", coroutinesVersion)) api(kotlinx("coroutines-android", coroutinesVersion))
...@@ -111,10 +113,10 @@ kotlin { ...@@ -111,10 +113,10 @@ kotlin {
val androidTest by getting { val androidTest by getting {
dependencies { dependencies {
api(kotlin("test", kotlinVersion)) implementation(kotlin("test", kotlinVersion))
api(kotlin("test-junit", kotlinVersion)) implementation(kotlin("test-junit", kotlinVersion))
api(kotlin("test-annotations-common")) implementation(kotlin("test-annotations-common"))
api(kotlin("test-common")) implementation(kotlin("test-common"))
} }
} }
} }
...@@ -128,6 +130,9 @@ kotlin { ...@@ -128,6 +130,9 @@ kotlin {
api(ktor("client-core-jvm", ktorVersion)) api(ktor("client-core-jvm", ktorVersion))
api(kotlinx("io-jvm", kotlinXIoVersion)) api(kotlinx("io-jvm", kotlinXIoVersion))
api(kotlinx("serialization-runtime", serializationVersion)) 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") api("org.bouncycastle:bcprov-jdk15on:1.64")
runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE runtimeOnly(files("build/classes/kotlin/jvm/main")) // classpath is not properly set by IDE
...@@ -136,8 +141,8 @@ kotlin { ...@@ -136,8 +141,8 @@ kotlin {
val jvmTest by getting { val jvmTest by getting {
dependencies { dependencies {
api(kotlin("test", kotlinVersion)) implementation(kotlin("test", kotlinVersion))
api(kotlin("test-junit", kotlinVersion)) implementation(kotlin("test-junit", kotlinVersion))
implementation("org.pcap4j:pcap4j-distribution:1.8.2") implementation("org.pcap4j:pcap4j-distribution:1.8.2")
runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE runtimeOnly(files("build/classes/kotlin/jvm/test")) // classpath is not properly set by IDE
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import io.ktor.util.asStream
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.io.core.Input import kotlinx.io.core.Input
...@@ -100,7 +99,7 @@ suspend fun InputStream.suspendToExternalImage(): ExternalImage = withContext(IO ...@@ -100,7 +99,7 @@ suspend fun InputStream.suspendToExternalImage(): ExternalImage = withContext(IO
fun Input.toExternalImage(): ExternalImage { fun Input.toExternalImage(): ExternalImage {
val file = createTempFile().apply { deleteOnExit() } val file = createTempFile().apply { deleteOnExit() }
file.outputStream().asOutput().use { file.outputStream().asOutput().use {
this.asStream().asInput().copyTo(it) this.copyTo(it)
} }
return file.toExternalImage() return file.toExternalImage()
} }
......
...@@ -9,11 +9,11 @@ ...@@ -9,11 +9,11 @@
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import io.ktor.util.cio.use
import kotlinx.coroutines.CoroutineName import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.io.ByteWriteChannel import kotlinx.coroutines.io.ByteWriteChannel
import kotlinx.coroutines.io.close
import kotlinx.coroutines.io.jvm.nio.copyTo import kotlinx.coroutines.io.jvm.nio.copyTo
import kotlinx.coroutines.io.reader import kotlinx.coroutines.io.reader
import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.Mutex
...@@ -44,7 +44,7 @@ internal class DefaultLoginSolver : LoginSolver() { ...@@ -44,7 +44,7 @@ internal class DefaultLoginSolver : LoginSolver() {
tempFile.createNewFile() tempFile.createNewFile()
bot.logger.info("需要图片验证码登录, 验证码为 4 字母") bot.logger.info("需要图片验证码登录, 验证码为 4 字母")
try { try {
tempFile.writeChannel().use { writeFully(data) } tempFile.writeChannel().apply { writeFully(data); close() }
bot.logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}") bot.logger.info("将会显示字符图片. 若看不清字符图片, 请查看文件 ${tempFile.absolutePath}")
} catch (e: Exception) { } catch (e: Exception) {
bot.logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片") bot.logger.info("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
......
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import io.ktor.util.asStream
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.io.core.Input import kotlinx.io.core.Input
...@@ -132,7 +131,7 @@ suspend inline fun InputStream.suspendToExternalImage(): ExternalImage = withCon ...@@ -132,7 +131,7 @@ suspend inline fun InputStream.suspendToExternalImage(): ExternalImage = withCon
fun Input.toExternalImage(): ExternalImage { fun Input.toExternalImage(): ExternalImage {
val file = createTempFile().apply { deleteOnExit() } val file = createTempFile().apply { deleteOnExit() }
file.outputStream().asOutput().use { file.outputStream().asOutput().use {
this.asStream().asInput().copyTo(it) this.copyTo(it)
} }
return file.toExternalImage() return file.toExternalImage()
} }
......
...@@ -31,6 +31,7 @@ android { ...@@ -31,6 +31,7 @@ android {
exclude 'META-INF/ktor-http-cio.kotlin_module' exclude 'META-INF/ktor-http-cio.kotlin_module'
exclude 'META-INF/ktor-client-core.kotlin_module' exclude 'META-INF/ktor-client-core.kotlin_module'
exclude "META-INF/kotlinx-serialization-runtime.kotlin_module" exclude "META-INF/kotlinx-serialization-runtime.kotlin_module"
exclude 'META-INF/ktor-io.kotlin_module'
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment