Commit 388e1a5b authored by Him188's avatar Him188

Cleanup

parent 9aa1d7d3
#Thu Oct 03 14:28:43 CST 2019 #Thu Oct 03 14:28:43 CST 2019
distributionUrl=https\://services.gradle.org/distributions/gradle-6.0.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
......
...@@ -41,7 +41,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -41,7 +41,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
override val supervisor: CompletableJob = SupervisorJob(bot.coroutineContext[Job]) override val supervisor: CompletableJob = SupervisorJob(bot.coroutineContext[Job])
override val coroutineContext: CoroutineContext = bot.coroutineContext + CoroutineExceptionHandler { _, throwable -> override val coroutineContext: CoroutineContext = bot.coroutineContext + CoroutineExceptionHandler { _, throwable ->
throwable.logStacktrace("Exception in NetworkHandler") bot.logger.error("Exception in NetworkHandler", throwable)
} }
private lateinit var channel: PlatformSocket private lateinit var channel: PlatformSocket
...@@ -106,6 +106,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -106,6 +106,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow
} }
@UseExperimental(MiraiExperimentalAPI::class)
override suspend fun init() { override suspend fun init() {
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> { this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
if (this@QQAndroidBotNetworkHandler.bot == this.bot) { if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
...@@ -113,6 +114,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -113,6 +114,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
} }
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect()
//val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>() //val msg = MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect<MessageSvc.PbGetMsg.Response>()
//println(msg.contentToString()) //println(msg.contentToString())
bot.qqs.delegate.clear() bot.qqs.delegate.clear()
...@@ -199,16 +202,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -199,16 +202,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} catch (e: Exception) { } catch (e: Exception) {
groupInfo[it.groupCode] = -1 groupInfo[it.groupCode] = -1
bot.logger.info("群${it.groupCode}的列表拉取失败, 将采用动态加入") bot.logger.info("群${it.groupCode}的列表拉取失败, 将采用动态加入")
println(e.message) bot.logger.error(e)
println(e.logStacktrace())
} }
} }
} }
bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个") bot.logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个")
} catch (e: Exception) { } catch (e: Exception) {
bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") bot.logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
println(e.message) bot.logger.error(e)
println(e.logStacktrace())
} }
//===log===// //===log===//
...@@ -239,8 +240,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -239,8 +240,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
} }
bot.logger.info("====================Mirai Bot List初始化完毕====================") bot.logger.info("====================Mirai Bot List初始化完毕====================")
return
MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() bot.firstLoginSucceed = true
} }
...@@ -483,7 +484,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -483,7 +484,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
private val packetReceiveLock: Mutex = Mutex() private val packetReceiveLock: Mutex = Mutex()
/** /**
* 发送一个包, 但不期待任何返回.- * 发送一个包, 但不期待任何返回.
*/ */
suspend fun OutgoingPacket.sendWithoutExpect() { suspend fun OutgoingPacket.sendWithoutExpect() {
bot.logger.info("Send: ${this.commandName}") bot.logger.info("Send: ${this.commandName}")
...@@ -494,6 +495,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -494,6 +495,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
/** /**
* 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms) * 发送一个包, 并挂起直到接收到指定的返回包或超时(3000ms)
*
* @param retry 当不为 0 时将使用 [ByteArrayPool] 缓存. 因此若非必要, 请不要允许 retry
*/ */
suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 0): E { suspend fun <E : Packet> OutgoingPacket.sendAndExpect(timeoutMillis: Long = 3000, retry: Int = 0): E {
require(timeoutMillis > 0) { "timeoutMillis must > 0" } require(timeoutMillis > 0) { "timeoutMillis must > 0" }
......
package net.mamoe.mirai.qqandroid.network.http package net.mamoe.mirai.qqandroid.network.http
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.request.* 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.client.response.HttpResponse
import io.ktor.http.ContentType
import io.ktor.http.URLProtocol import io.ktor.http.URLProtocol
import io.ktor.http.setCookie import io.ktor.http.setCookie
import io.ktor.http.userAgent import io.ktor.http.userAgent
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.io.readRemaining import kotlinx.coroutines.io.readRemaining
import kotlinx.coroutines.withContext import kotlinx.io.core.readBytes
import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.utils.cryptor.contentToString
import net.mamoe.mirai.utils.currentTimeMillis import net.mamoe.mirai.utils.currentTimeMillis
import net.mamoe.mirai.utils.io.readRemainingBytes
import net.mamoe.mirai.utils.io.toUHexString import net.mamoe.mirai.utils.io.toUHexString
/** /**
...@@ -49,7 +46,7 @@ internal suspend fun HttpClient.getPTLoginCookies( ...@@ -49,7 +46,7 @@ internal suspend fun HttpClient.getPTLoginCookies(
println(res.status) println(res.status)
println(res.setCookie()) println(res.setCookie())
println(res.content.readRemaining().readRemainingBytes().toUHexString()) println(res.content.readRemaining().readBytes().toUHexString())
return "done"; return "done";
} }
......
...@@ -10,7 +10,6 @@ import net.mamoe.mirai.utils.MiraiInternalAPI ...@@ -10,7 +10,6 @@ import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.encryptAndWrite import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.writeHex import net.mamoe.mirai.utils.io.writeHex
import net.mamoe.mirai.utils.io.writeIntLVPacket import net.mamoe.mirai.utils.io.writeIntLVPacket
import net.mamoe.mirai.utils.io.writeQQ
internal class OutgoingPacket constructor( internal class OutgoingPacket constructor(
name: String?, name: String?,
...@@ -250,7 +249,7 @@ internal fun BytePacketBuilder.writeOicqRequestPacket( ...@@ -250,7 +249,7 @@ internal fun BytePacketBuilder.writeOicqRequestPacket(
writeShort(client.protocolVersion) writeShort(client.protocolVersion)
writeShort(commandId.toShort()) writeShort(commandId.toShort())
writeShort(1) // const?? writeShort(1) // const??
writeQQ(client.uin) writeInt(client.uin.toInt())
writeByte(3) // originally const writeByte(3) // originally const
writeByte(encryptMethod.id.toByte()) writeByte(encryptMethod.id.toByte())
writeByte(0) // const8_always_0 writeByte(0) // const8_always_0
......
...@@ -23,7 +23,7 @@ fun BytePacketBuilder.t1(uin: Long, ip: ByteArray) { ...@@ -23,7 +23,7 @@ fun BytePacketBuilder.t1(uin: Long, ip: ByteArray) {
writeShort(1) // _ip_ver writeShort(1) // _ip_ver
writeInt(Random.nextInt()) writeInt(Random.nextInt())
writeInt(uin.toInt()) writeInt(uin.toInt())
writeTime() writeInt(currentTimeMillis.toInt())
writeFully(ip) writeFully(ip)
writeShort(0) writeShort(0)
} shouldEqualsTo 20 } shouldEqualsTo 20
...@@ -100,7 +100,7 @@ fun BytePacketBuilder.t106( ...@@ -100,7 +100,7 @@ fun BytePacketBuilder.t106(
writeLong(uin) writeLong(uin)
} }
writeTime() writeInt(currentTimeMillis.toInt())
writeFully(ByteArray(4)) // ip // no need to write actual ip writeFully(ByteArray(4)) // ip // no need to write actual ip
writeByte(n5_always_1.toByte()) writeByte(n5_always_1.toByte())
writeFully(passwordMd5) writeFully(passwordMd5)
......
package net.mamoe.mirai.qqandroid.network.protocol.packet.chat package net.mamoe.mirai.qqandroid.network.protocol.packet.chat
import kotlinx.io.charsets.Charset import kotlinx.io.core.ByteReadPacket
import kotlinx.io.charsets.encode import kotlinx.io.core.buildPacket
import kotlinx.io.core.* import kotlinx.io.core.readBytes
import kotlinx.io.core.toByteArray
import kotlinx.serialization.toUtf8Bytes import kotlinx.serialization.toUtf8Bytes
import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.Member
import net.mamoe.mirai.data.Packet import net.mamoe.mirai.data.Packet
import net.mamoe.mirai.qqandroid.QQAndroidBot import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.io.serialization.* import net.mamoe.mirai.qqandroid.io.serialization.*
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.GetTroopListReqV2Simplify
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq import net.mamoe.mirai.qqandroid.network.protocol.data.jce.ModifyGroupCardReq
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo import net.mamoe.mirai.qqandroid.network.protocol.data.jce.stUinInfo
...@@ -22,7 +22,6 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket ...@@ -22,7 +22,6 @@ 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.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.utils.daysToSeconds import net.mamoe.mirai.utils.daysToSeconds
import net.mamoe.mirai.utils.io.encodeToGBKString
import net.mamoe.mirai.utils.io.encodeToString import net.mamoe.mirai.utils.io.encodeToString
internal object TroopManagement { internal object TroopManagement {
...@@ -355,7 +354,7 @@ internal object TroopManagement { ...@@ -355,7 +354,7 @@ internal object TroopManagement {
gender = 0, gender = 0,
dwuin = member.id, dwuin = member.id,
dwFlag = 31, dwFlag = 31,
sName = newName.toUtf8Bytes().encodeToGBKString(), sName = newName.toUtf8Bytes().encodeToString(charset = CharsetGBK),
sPhone = "", sPhone = "",
sEmail = "", sEmail = "",
sRemark = "" sRemark = ""
......
...@@ -22,15 +22,15 @@ import net.mamoe.mirai.utils.md5 ...@@ -22,15 +22,15 @@ import net.mamoe.mirai.utils.md5
/** /**
* OicqRequest * OicqRequest
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class) @Suppress("FunctionName")
@UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class)
internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login") { internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login") {
private const val subAppId = 537062845L
/** /**
* 提交验证码 * 提交验证码
*/ */
object SubCommand2 { object SubCommand2 {
private const val appId = 16L
private const val subAppId = 537062845L
fun SubmitSliderCaptcha( fun SubmitSliderCaptcha(
client: QQAndroidClient, client: QQAndroidClient,
ticket: String ticket: String
...@@ -66,10 +66,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -66,10 +66,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
} }
object SubCommand20 { object SubCommand20 {
private const val appId = 16L
private const val subAppId = 537062845L
@UseExperimental(MiraiInternalAPI::class)
operator fun invoke( operator fun invoke(
client: QQAndroidClient, client: QQAndroidClient,
t402: ByteArray t402: ByteArray
...@@ -91,9 +88,6 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -91,9 +88,6 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
* 提交 SMS * 提交 SMS
*/ */
object SubCommand7 { object SubCommand7 {
private const val appId = 16L
private const val subAppId = 537062845L
@UseExperimental(MiraiInternalAPI::class)
operator fun invoke( operator fun invoke(
client: QQAndroidClient client: QQAndroidClient
): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId ->
...@@ -297,7 +291,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -297,7 +291,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
} }
} }
class DeviceLockLogin(val t402: ByteArray, val t403: ByteArray) : LoginPacketResponse() { class DeviceLockLogin(val t402: ByteArray) : LoginPacketResponse() {
override fun toString(): String = "LoginPacket.LoginPacketResponse.DeviceLockLogin" override fun toString(): String = "LoginPacket.LoginPacketResponse.DeviceLockLogin"
} }
} }
...@@ -320,7 +314,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -320,7 +314,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
2 -> onSolveLoginCaptcha(tlvMap, bot) 2 -> onSolveLoginCaptcha(tlvMap, bot)
160 /*-96*/ -> onUnsafeDeviceLogin(tlvMap) 160 /*-96*/ -> onUnsafeDeviceLogin(tlvMap)
204 /*-52*/ -> onSMSVerifyNeeded(tlvMap, bot) 204 /*-52*/ -> onSMSVerifyNeeded(tlvMap, bot)
else -> tlvMap[0x149]?.let { bot.client.analysisTlv149(it) } ?: error("unknown login result type: $type") else -> tlvMap[0x149]?.let { analysisTlv149(it) } ?: error("unknown login result type: $type")
} }
} }
...@@ -331,11 +325,11 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -331,11 +325,11 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
): LoginPacketResponse.DeviceLockLogin { ): LoginPacketResponse.DeviceLockLogin {
bot.client.t104 = tlvMap.getOrFail(0x104) bot.client.t104 = tlvMap.getOrFail(0x104)
// println("403: " + tlvMap[0x403]?.toUHexString()) // println("403: " + tlvMap[0x403]?.toUHexString())
return LoginPacketResponse.DeviceLockLogin(tlvMap[0x402]!!, tlvMap.getOrFail(0x403)) return LoginPacketResponse.DeviceLockLogin(tlvMap.getOrFail(0x402))
} }
private fun onUnsafeDeviceLogin(tlvMap: TlvMap): LoginPacketResponse.UnsafeLogin { private fun onUnsafeDeviceLogin(tlvMap: TlvMap): LoginPacketResponse.UnsafeLogin {
return LoginPacketResponse.UnsafeLogin(tlvMap.getOrFail(0x204).toReadPacket().readRemainingBytes().encodeToString()) return LoginPacketResponse.UnsafeLogin(tlvMap.getOrFail(0x204).toReadPacket().readBytes().encodeToString())
} }
private fun onErrorMessage(tlvMap: TlvMap): LoginPacketResponse.Error { private fun onErrorMessage(tlvMap: TlvMap): LoginPacketResponse.Error {
...@@ -369,7 +363,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -369,7 +363,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
imageData.discardExact(2)//image Length imageData.discardExact(2)//image Length
val sign = imageData.readBytes(signInfoLength.toInt()) val sign = imageData.readBytes(signInfoLength.toInt())
return LoginPacketResponse.Captcha.Picture( return LoginPacketResponse.Captcha.Picture(
data = imageData.readRemainingBytes().toIoBuffer(), data = imageData.readBytes().toIoBuffer(),
sign = sign sign = sign
) )
} else error("UNKNOWN CAPTCHA QUESTION: $question") } else error("UNKNOWN CAPTCHA QUESTION: $question")
...@@ -652,11 +646,6 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -652,11 +646,6 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
pwdFlag = readByte().toInt() == 1 pwdFlag = readByte().toInt() == 1
} }
/**
*/
private fun QQAndroidClient.analysisTlv528(t528: ByteArray) = t528.read {
}
/** /**
* 设置 [QQAndroidClient.uin] * 设置 [QQAndroidClient.uin]
*/ */
...@@ -696,7 +685,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo ...@@ -696,7 +685,7 @@ internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketRespo
/** /**
* 错误消息 * 错误消息
*/ */
private fun QQAndroidClient.analysisTlv149(t149: ByteArray): LoginPacketResponse.Error { private fun analysisTlv149(t149: ByteArray): LoginPacketResponse.Error {
return t149.read { return t149.read {
discardExact(2) //type discardExact(2) //type
......
...@@ -114,6 +114,16 @@ fun ByteReadPacket.decodeMultiClientToServerPackets() { ...@@ -114,6 +114,16 @@ fun ByteReadPacket.decodeMultiClientToServerPackets() {
println() println()
} }
fun Map<Int, ByteArray>.printTLVMap(name: String = "", keyLength: Int = 2) =
debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() }.mapKeys {
when (keyLength) {
1 -> it.key.toUByte().contentToString()
2 -> it.key.toUShort().contentToString()
4 -> it.key.toUInt().contentToString()
else -> error("Expecting 1, 2 or 4 for keyLength")
}
}.entries.joinToString(prefix = "{", postfix = "}", separator = "\n"))
fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed", { buildPacket { writeInt(it.size + 4); writeFully(it) } }) { fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed", { buildPacket { writeInt(it.size + 4); writeFully(it) } }) {
val flag1 = readInt() val flag1 = readInt()
println("flag1=" + flag1.contentToString()) println("flag1=" + flag1.contentToString())
...@@ -139,7 +149,7 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed ...@@ -139,7 +149,7 @@ fun ByteReadPacket.analysisOneFullPacket(): ByteReadPacket = debugIfFail("Failed
println("uin=" + readString(readInt() - 4)) println("uin=" + readString(readInt() - 4))
println("// 解密 body") println("// 解密 body")
val encrypted = readRemainingBytes() val encrypted = readBytes()
val decrypted = encrypted.tryDecryptOrNull() val decrypted = encrypted.tryDecryptOrNull()
if (decrypted == null) { if (decrypted == null) {
......
...@@ -198,6 +198,10 @@ private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) { ...@@ -198,6 +198,10 @@ private fun ByteReadPacket.parseOicqResponse(body: ByteReadPacket.() -> Unit) {
} }
} }
fun ByteReadPacket.readIoBuffer(
n: Int = remaining.toInt()//not that safe but adequate
): IoBuffer = IoBuffer.Pool.borrow().also { this.readFully(it, n) }
/** /**
* 解析 SSO 层包装 * 解析 SSO 层包装
*/ */
......
package net.mamoe.mirai.utils.cryptor package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.MiraiDebugAPI
import java.lang.reflect.Field import java.lang.reflect.Field
import kotlin.reflect.full.allSuperclasses import kotlin.reflect.full.allSuperclasses
@MiraiDebugAPI
actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String { actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String {
val newPrefix = prefix
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" + return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") } this.allFieldsFromSuperClassesMatching { it.name.startsWith("net.mamoe.mirai") }
.distinctBy { it.name } .distinctBy { it.name }
.filterNot { it.name.contains("$") || it.name == "Companion" || it.isSynthetic || it.name == "serialVersionUID" } .filterNot { it.name.contains("$") || it.name == "Companion" || it.isSynthetic || it.name == "serialVersionUID" }
.joinToStringPrefixed( .joinToStringPrefixed(
prefix = newPrefix prefix = prefix
) { ) {
it.isAccessible = true it.isAccessible = true
if (filter != null) { if (filter != null) {
...@@ -22,7 +23,7 @@ actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: Strin ...@@ -22,7 +23,7 @@ actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: Strin
it.name + "=" + kotlin.runCatching { it.name + "=" + kotlin.runCatching {
val value = it.get(this) val value = it.get(this)
if (value == this) "<this>" if (value == this) "<this>"
else value.contentToString(newPrefix) else value.contentToString(prefix)
}.getOrElse { "<!>" } }.getOrElse { "<!>" }
} + "\n$prefix}" } + "\n$prefix}"
} }
......
...@@ -134,8 +134,6 @@ abstract class Bot : CoroutineScope { ...@@ -134,8 +134,6 @@ abstract class Bot : CoroutineScope {
* 不建议调用这个函数. * 不建议调用这个函数.
* *
* 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login] * 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login]
*
* @throws LoginFailedException
*/ */
abstract suspend fun login() abstract suspend fun login()
// endregion // endregion
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
package net.mamoe.mirai package net.mamoe.mirai
import net.mamoe.mirai.utils.LoginFailedException
import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
...@@ -15,8 +14,6 @@ import kotlin.jvm.JvmName ...@@ -15,8 +14,6 @@ import kotlin.jvm.JvmName
//Contacts //Contacts
/** /**
* 登录, 返回 [this] * 登录, 返回 [this]
*
* @throws LoginFailedException
*/ */
suspend inline fun <B: Bot> B.alsoLogin(): B = also { login() } suspend inline fun <B: Bot> B.alsoLogin(): B = also { login() }
......
...@@ -7,6 +7,7 @@ import kotlin.coroutines.EmptyCoroutineContext ...@@ -7,6 +7,7 @@ import kotlin.coroutines.EmptyCoroutineContext
import kotlin.jvm.JvmStatic import kotlin.jvm.JvmStatic
/** /**
* 验证码, 设备锁解决器
*/ */
abstract class LoginSolver { abstract class LoginSolver {
abstract suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? abstract suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String?
......
package net.mamoe.mirai.utils
import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.toByteArray
import kotlinx.io.core.writeFully
import net.mamoe.mirai.utils.io.getRandomByteArray
fun md5(str: String): ByteArray = md5(str.toByteArray())
\ No newline at end of file
...@@ -80,7 +80,7 @@ class ExternalImage( ...@@ -80,7 +80,7 @@ class ExternalImage(
suspend fun ExternalImage.sendTo(contact: Contact) = when (contact) { suspend fun ExternalImage.sendTo(contact: Contact) = when (contact) {
is Group -> contact.uploadImage(this).sendTo(contact) is Group -> contact.uploadImage(this).sendTo(contact)
is QQ -> contact.uploadImage(this).sendTo(contact) is QQ -> contact.uploadImage(this).sendTo(contact)
else -> assertUnreachable() else -> error("unreachable")
} }
/** /**
...@@ -92,7 +92,7 @@ suspend fun ExternalImage.sendTo(contact: Contact) = when (contact) { ...@@ -92,7 +92,7 @@ suspend fun ExternalImage.sendTo(contact: Contact) = when (contact) {
suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) { suspend fun ExternalImage.upload(contact: Contact): Image = when (contact) {
is Group -> contact.uploadImage(this) is Group -> contact.uploadImage(this)
is QQ -> contact.uploadImage(this) is QQ -> contact.uploadImage(this)
else -> assertUnreachable() else -> error("unreachable")
} }
/** /**
......
package net.mamoe.mirai.utils
import net.mamoe.mirai.data.LoginResult
class LoginFailedException(
val result: LoginResult,
message: String = "Login failed with reason $result"
) : RuntimeException(message)
\ No newline at end of file
@file:Suppress("unused")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
...@@ -139,7 +141,7 @@ interface MiraiLogger { ...@@ -139,7 +141,7 @@ interface MiraiLogger {
/** /**
* 当前平台的默认的日志记录器. * 当前平台的默认的日志记录器.
* 在 _JVM 控制台_ 端的实现为 [println] * 在 _JVM 控制台_ 端的实现为 [println]
* 在 _Android_ 端的实现为 [android.util.Log] * 在 _Android_ 端的实现为 `android.util.Log`
* *
* 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion] * 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion]
*/ */
......
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/** /**
* 要求 [this] 最小为 [min]. * 要求 [this] 最小为 [min].
*/ */
......
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
/** /**
* 图片文件过大 * 图片文件过大
*/ */
......
@file:Suppress("EXPERIMENTAL_API_USAGE") @file:Suppress("EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.util.date.GMTDate import io.ktor.util.date.GMTDate
import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.io.core.toByteArray
/** /**
* 时间戳 * 时间戳
...@@ -36,6 +37,8 @@ expect fun ByteArray.unzip(offset: Int = 0, length: Int = this.size - offset): B ...@@ -36,6 +37,8 @@ expect fun ByteArray.unzip(offset: Int = 0, length: Int = this.size - offset): B
*/ */
expect fun md5(byteArray: ByteArray): ByteArray expect fun md5(byteArray: ByteArray): ByteArray
inline fun md5(str: String): ByteArray = md5(str.toByteArray())
/** /**
* hostname 解析 ipv4 * hostname 解析 ipv4
*/ */
...@@ -53,7 +56,7 @@ expect val Http: HttpClient ...@@ -53,7 +56,7 @@ expect val Http: HttpClient
expect fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher expect fun newCoroutineDispatcher(threadCount: Int): CoroutineDispatcher
internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int){ internal fun ByteArray.checkOffsetAndLength(offset: Int, length: Int) {
require(offset >= 0) { "offset shouldn't be negative: $offset" } require(offset >= 0) { "offset shouldn't be negative: $offset" }
require(length >= 0) { "length shouldn't be negative: $length" } require(length >= 0) { "length shouldn't be negative: $length" }
require(offset + length <= this.size) { "offset ($offset) + length ($length) > array.size (${this.size})" } require(offset + length <= this.size) { "offset ($offset) + length ($length) > array.size (${this.size})" }
......
@file:Suppress("unused", "FunctionName") @file:Suppress("unused", "FunctionName", "NOTHING_TO_INLINE")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
...@@ -16,7 +16,7 @@ import kotlin.coroutines.EmptyCoroutineContext ...@@ -16,7 +16,7 @@ import kotlin.coroutines.EmptyCoroutineContext
* val image: Deferred<Image> by suspendLazy{ /* intializer */ } * val image: Deferred<Image> by suspendLazy{ /* intializer */ }
* ``` * ```
*/ */
fun <R> CoroutineScope.suspendLazy(context: CoroutineContext = EmptyCoroutineContext, initializer: suspend () -> R): Lazy<Deferred<R>> = inline fun <R> CoroutineScope.suspendLazy(context: CoroutineContext = EmptyCoroutineContext, noinline initializer: suspend () -> R): Lazy<Deferred<R>> =
SuspendLazy(this, context, initializer) SuspendLazy(this, context, initializer)
/** /**
......
package net.mamoe.mirai.utils
/**
* 仅用于测试时标记, 未来会删除
*
* @author Him188moe
*/
@Suppress("unused")
internal annotation class Tested(val date: String = "")
\ No newline at end of file
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.time.seconds import kotlin.time.seconds
// 临时使用, 待 Kotlin Duration 稳定后使用 Duration. // 临时使用, 待 Kotlin Duration 稳定后使用 Duration.
......
package net.mamoe.mirai.utils
/**
* 表示这里是不可到达的位置.
*/
@Suppress("NOTHING_TO_INLINE")
internal inline fun assertUnreachable(): Nothing = error("This clause should not be reached")
package net.mamoe.mirai.utils.cryptor
import kotlinx.io.core.BytePacketBuilder
import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.IoBuffer
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.io.ByteArrayPool
import net.mamoe.mirai.utils.io.encryptAndWrite
import net.mamoe.mirai.utils.io.toReadPacket
/**
* [ByteArray] 解密器
*/
interface DecrypterByteArray : Decrypter {
val value: ByteArray
override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket = input.decryptBy(value, offset, length)
}
/**
* [IoBuffer] 解密器
*/
interface DecrypterIoBuffer : Decrypter {
val value: IoBuffer
override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket = input.decryptBy(value, offset, length)
}
/**
* 连接在一起的解密器
*/
inline class LinkedDecrypter(inline val block: (input: ByteReadPacket, offset: Int, length: Int) -> ByteReadPacket) : Decrypter {
override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket = block(input, offset, length)
}
object NoDecrypter : Decrypter, DecrypterType<NoDecrypter> {
override fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket {
if (offset == 0 && length == input.remaining.toInt()) {
return input
}
ByteArrayPool.useInstance { buffer ->
input.readFully(buffer, offset, length)
return buffer.toReadPacket()
}
}
}
fun Decrypter.decrypt(input: ByteReadPacket): ByteReadPacket = this.decrypt(input, 0, input.remaining.toInt())
/**
* 解密器
*/
interface Decrypter {
// do not write with default args. NoSuchMethodError when inline classes override this function
fun decrypt(input: ByteReadPacket, offset: Int, length: Int): ByteReadPacket
/**
* 连接后将会先用 this 解密, 再用 [another] 解密
*/
operator fun plus(another: Decrypter): Decrypter =
LinkedDecrypter { input: ByteReadPacket, offset: Int, length: Int -> another.decrypt(this.decrypt(input, offset, length)) }
}
interface DecrypterType<D : Decrypter>
inline fun BytePacketBuilder.encryptAndWrite(key: DecrypterByteArray, encoder: BytePacketBuilder.() -> Unit) =
this.encryptAndWrite(key.value, encoder)
...@@ -6,6 +6,9 @@ import kotlinx.io.core.ByteReadPacket ...@@ -6,6 +6,9 @@ import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.readBytes import kotlinx.io.core.readBytes
import kotlinx.io.core.readUInt import kotlinx.io.core.readUInt
import kotlinx.io.core.readULong import kotlinx.io.core.readULong
import net.mamoe.mirai.utils.MiraiDebugAPI
import net.mamoe.mirai.utils.MiraiExperimentalAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import kotlin.jvm.JvmStatic import kotlin.jvm.JvmStatic
...@@ -24,12 +27,14 @@ import kotlin.jvm.JvmStatic ...@@ -24,12 +27,14 @@ import kotlin.jvm.JvmStatic
* *
* https://www.jianshu.com/p/f888907adaeb * https://www.jianshu.com/p/f888907adaeb
*/ */
@MiraiDebugAPI
fun ProtoFieldId(serializedId: UInt): ProtoFieldId = fun ProtoFieldId(serializedId: UInt): ProtoFieldId =
ProtoFieldId( ProtoFieldId(
protoFieldNumber(serializedId), protoFieldNumber(serializedId),
protoType(serializedId) protoType(serializedId)
) )
@MiraiDebugAPI
data class ProtoFieldId( data class ProtoFieldId(
val fieldNumber: Int, val fieldNumber: Int,
val type: ProtoType val type: ProtoType
...@@ -38,6 +43,7 @@ data class ProtoFieldId( ...@@ -38,6 +43,7 @@ data class ProtoFieldId(
} }
@Suppress("SpellCheckingInspection") @Suppress("SpellCheckingInspection")
@MiraiDebugAPI
enum class ProtoType(val value: Byte, private val typeName: String) { enum class ProtoType(val value: Byte, private val typeName: String) {
/** /**
* int32, int64, uint32, uint64, sint32, sint64, bool, enum * int32, int64, uint32, uint64, sint32, sint64, bool, enum
...@@ -82,6 +88,7 @@ enum class ProtoType(val value: Byte, private val typeName: String) { ...@@ -82,6 +88,7 @@ enum class ProtoType(val value: Byte, private val typeName: String) {
* *
* serializedId = (fieldNumber << 3) | wireType * serializedId = (fieldNumber << 3) | wireType
*/ */
@MiraiDebugAPI
fun protoType(number: UInt): ProtoType = fun protoType(number: UInt): ProtoType =
ProtoType.valueOf(number.toInt().shl(29).ushr(29).toByte()) ProtoType.valueOf(number.toInt().shl(29).ushr(29).toByte())
...@@ -90,9 +97,10 @@ fun protoType(number: UInt): ProtoType = ...@@ -90,9 +97,10 @@ fun protoType(number: UInt): ProtoType =
* *
* serializedId = (fieldNumber << 3) | wireType * serializedId = (fieldNumber << 3) | wireType
*/ */
@MiraiDebugAPI
fun protoFieldNumber(number: UInt): Int = number.toInt().ushr(3) fun protoFieldNumber(number: UInt): Int = number.toInt().ushr(3)
@MiraiDebugAPI
class ProtoMap(map: MutableMap<ProtoFieldId, Any>) : MutableMap<ProtoFieldId, Any> by map { class ProtoMap(map: MutableMap<ProtoFieldId, Any>) : MutableMap<ProtoFieldId, Any> by map {
companion object { companion object {
@JvmStatic @JvmStatic
...@@ -120,6 +128,7 @@ class ProtoMap(map: MutableMap<ProtoFieldId, Any>) : MutableMap<ProtoFieldId, An ...@@ -120,6 +128,7 @@ class ProtoMap(map: MutableMap<ProtoFieldId, Any>) : MutableMap<ProtoFieldId, An
/** /**
* 将所有元素加入转换为多行的字符串表示. * 将所有元素加入转换为多行的字符串表示.
*/ */
@MiraiDebugAPI
fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharSequence): String { fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharSequence): String {
return this.joinToString(prefix = "$prefix${ProtoMap.indent}", separator = "\n$prefix${ProtoMap.indent}", transform = transform) return this.joinToString(prefix = "$prefix${ProtoMap.indent}", separator = "\n$prefix${ProtoMap.indent}", transform = transform)
} }
...@@ -135,6 +144,7 @@ fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharS ...@@ -135,6 +144,7 @@ fun <T> Sequence<T>.joinToStringPrefixed(prefix: String, transform: (T) -> CharS
* `data class`: 调用其 [toString] * `data class`: 调用其 [toString]
* 其他类型: 反射获取它和它的所有来自 Mirai 的 super 类型的所有自有属性并递归调用 [contentToString]. 嵌套结构将会以缩进表示 * 其他类型: 反射获取它和它的所有来自 Mirai 的 super 类型的所有自有属性并递归调用 [contentToString]. 嵌套结构将会以缩进表示
*/ */
@MiraiDebugAPI("Extremely slow")
fun Any?.contentToString(prefix: String = ""): String = when (this) { fun Any?.contentToString(prefix: String = ""): String = when (this) {
is Unit -> "Unit" is Unit -> "Unit"
is UInt -> "0x" + this.toUHexString("") + "($this)" is UInt -> "0x" + this.toUHexString("") + "($this)"
...@@ -222,8 +232,11 @@ fun Any?.contentToString(prefix: String = ""): String = when (this) { ...@@ -222,8 +232,11 @@ fun Any?.contentToString(prefix: String = ""): String = when (this) {
} }
} }
@MiraiExperimentalAPI("Extremely slow")
@MiraiDebugAPI("Extremely slow")
expect fun Any.contentToStringReflectively(prefix: String = "", filter: ((String, Any?) -> Boolean)? = null): String expect fun Any.contentToStringReflectively(prefix: String = "", filter: ((String, Any?) -> Boolean)? = null): String
@MiraiDebugAPI
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap { fun ByteReadPacket.readProtoMap(length: Long = this.remaining): ProtoMap {
val map = ProtoMap(mutableMapOf()) val map = ProtoMap(mutableMapOf())
......
@file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS") @file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils.io package net.mamoe.mirai.utils.io
import kotlinx.io.charsets.Charset import kotlinx.io.charsets.Charset
import kotlinx.io.charsets.Charsets
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.String import kotlinx.io.core.String
import kotlinx.io.core.use import kotlinx.io.core.use
...@@ -10,6 +13,8 @@ import net.mamoe.mirai.utils.checkOffsetAndLength ...@@ -10,6 +13,8 @@ import net.mamoe.mirai.utils.checkOffsetAndLength
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
import kotlin.jvm.JvmOverloads import kotlin.jvm.JvmOverloads
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
...@@ -80,12 +85,9 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In ...@@ -80,12 +85,9 @@ fun UByteArray.toUHexString(separator: String = " ", offset: Int = 0, length: In
} }
@Suppress("NOTHING_TO_INLINE") @Suppress("NOTHING_TO_INLINE")
inline fun ByteArray.encodeToString(): String = String(this) inline fun ByteArray.encodeToString(charset: Charset = Charsets.UTF_8): String = String(this, charset = charset)
fun ByteArray.encodeToGBKString(): String = String(this, 0, this.size, Charset.forName("GBK")) inline fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) =
fun ByteArray.toReadPacket(offset: Int = 0, length: Int = this.size - offset) =
ByteReadPacket(this, offset = offset, length = length) ByteReadPacket(this, offset = offset, length = length)
@UseExperimental(ExperimentalContracts::class) @UseExperimental(ExperimentalContracts::class)
...@@ -94,6 +96,4 @@ inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R { ...@@ -94,6 +96,4 @@ inline fun <R> ByteArray.read(t: ByteReadPacket.() -> R): R {
callsInPlace(t, InvocationKind.EXACTLY_ONCE) callsInPlace(t, InvocationKind.EXACTLY_ONCE)
} }
return this.toReadPacket().use(t) return this.toReadPacket().use(t)
} }
\ No newline at end of file
fun ByteArray.cutTail(length: Int): ByteArray = this.copyOfRange(0, this.size - length)
\ No newline at end of file
@file:Suppress("NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils.io package net.mamoe.mirai.utils.io
import kotlinx.io.core.* import kotlinx.io.core.*
...@@ -9,29 +13,34 @@ import net.mamoe.mirai.utils.withSwitch ...@@ -9,29 +13,34 @@ import net.mamoe.mirai.utils.withSwitch
import kotlin.contracts.ExperimentalContracts import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.InvocationKind import kotlin.contracts.InvocationKind
import kotlin.contracts.contract import kotlin.contracts.contract
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
@MiraiDebugAPI("Unsatble")
object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug").withSwitch() object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug").withSwitch()
fun Throwable.logStacktrace(message: String? = null) = DebugLogger.error(message, this) @MiraiDebugAPI("Unstable")
inline fun Throwable.logStacktrace(message: String? = null) = DebugLogger.error(message, this)
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun debugPrintln(any: Any?) = DebugLogger.debug(any) inline fun debugPrintln(any: Any?) = DebugLogger.debug(any)
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun String.debugPrintThis(name: String): String { inline fun String.debugPrintThis(name: String): String {
DebugLogger.debug("$name=$this") DebugLogger.debug("$name=$this")
return this return this
} }
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun ByteArray.debugPrintThis(name: String): ByteArray { inline fun ByteArray.debugPrintThis(name: String): ByteArray {
DebugLogger.debug(name + "=" + this.toUHexString()) DebugLogger.debug(name + "=" + this.toUHexString())
return this return this
} }
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun IoBuffer.debugPrintThis(name: String): IoBuffer { inline fun IoBuffer.debugPrintThis(name: String): IoBuffer {
ByteArrayPool.useInstance { ByteArrayPool.useInstance {
val count = this.readAvailable(it) val count = this.readAvailable(it)
DebugLogger.debug(name + "=" + it.toUHexString(offset = 0, length = count)) DebugLogger.debug(name + "=" + it.toUHexString(offset = 0, length = count))
...@@ -49,12 +58,12 @@ inline fun IoBuffer.debugCopyUse(block: IoBuffer.() -> Unit): IoBuffer { ...@@ -49,12 +58,12 @@ inline fun IoBuffer.debugCopyUse(block: IoBuffer.() -> Unit): IoBuffer {
} }
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun Input.debugDiscardExact(n: Number, name: String = "") { inline fun Input.debugDiscardExact(n: Number, name: String = "") {
DebugLogger.debug("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString()) DebugLogger.debug("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
} }
@MiraiDebugAPI("Low efficiency.") @MiraiDebugAPI("Low efficiency.")
fun ByteReadPacket.debugPrintThis(name: String = ""): ByteReadPacket { inline fun ByteReadPacket.debugPrintThis(name: String = ""): ByteReadPacket {
ByteArrayPool.useInstance { ByteArrayPool.useInstance {
val count = this.readAvailable(it) val count = this.readAvailable(it)
DebugLogger.debug("ByteReadPacket $name=" + it.toUHexString(offset = 0, length = count)) DebugLogger.debug("ByteReadPacket $name=" + it.toUHexString(offset = 0, length = count))
......
@file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS", "NOTHING_TO_INLINE") @file:Suppress("EXPERIMENTAL_API_USAGE", "EXPERIMENTAL_UNSIGNED_LITERALS", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils.io package net.mamoe.mirai.utils.io
...@@ -7,8 +9,10 @@ import kotlinx.io.charsets.Charset ...@@ -7,8 +9,10 @@ import kotlinx.io.charsets.Charset
import kotlinx.io.charsets.Charsets import kotlinx.io.charsets.Charsets
import kotlinx.io.core.* import kotlinx.io.core.*
import kotlinx.io.pool.useInstance import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.assertUnreachable import net.mamoe.mirai.utils.MiraiDebugAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.contentToString import net.mamoe.mirai.utils.cryptor.contentToString
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
import kotlin.jvm.JvmSynthetic import kotlin.jvm.JvmSynthetic
...@@ -34,6 +38,7 @@ fun ByteReadPacket.transferTo(outputStream: OutputStream) { ...@@ -34,6 +38,7 @@ fun ByteReadPacket.transferTo(outputStream: OutputStream) {
} }
} }
@MiraiInternalAPI
inline fun <R> ByteReadPacket.useBytes( inline fun <R> ByteReadPacket.useBytes(
n: Int = remaining.toInt(),//not that safe but adequate n: Int = remaining.toInt(),//not that safe but adequate
block: (data: ByteArray, length: Int) -> R block: (data: ByteArray, length: Int) -> R
...@@ -42,51 +47,24 @@ inline fun <R> ByteReadPacket.useBytes( ...@@ -42,51 +47,24 @@ inline fun <R> ByteReadPacket.useBytes(
block(it, n) block(it, n)
} }
fun ByteReadPacket.readRemainingBytes( inline fun ByteReadPacket.readPacket(
n: Int = remaining.toInt()//not that safe but adequate
): ByteArray = ByteArray(n).also { readAvailable(it, 0, n) }
fun ByteReadPacket.readIoBuffer(
n: Int = remaining.toInt()//not that safe but adequate
): IoBuffer = IoBuffer.Pool.borrow().also { this.readFully(it, n) }
fun ByteReadPacket.readPacket(
n: Int = remaining.toInt()//not that safe but adequate n: Int = remaining.toInt()//not that safe but adequate
): ByteReadPacket = this.readBytes(n).toReadPacket() ): ByteReadPacket = this.readBytes(n).toReadPacket()
fun ByteReadPacket.readIoBuffer(n: Short) = this.readIoBuffer(n.toInt()) inline fun Input.readUByteLVString(): String = String(this.readUByteLVByteArray())
fun Input.readIP(): String = buildString(4 + 3) {
repeat(4) {
val byte = readUByte()
this.append(byte.toString())
if (it != 3) this.append(".")
}
}
fun Input.readQQ(): Long = this.readUInt().toLong()
fun Input.readGroup(): Long = this.readUInt().toLong()
fun Input.readGroupId(): Long = this.readUInt().toLong()
fun Input.readGroupCode(): Long = this.readUInt().toLong()
fun Input.readUVarIntLVString(): String = String(this.readUVarIntByteArray())
fun Input.readUByteLVString(): String = String(this.readUByteLVByteArray()) inline fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray())
fun Input.readUShortLVString(): String = String(this.readUShortLVByteArray()) inline fun Input.readUByteLVByteArray(): ByteArray = this.readBytes(this.readUByte().toInt())
fun Input.readUVarIntByteArray(): ByteArray = this.readBytes(this.readUVarInt().toInt()) inline fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
fun Input.readUByteLVByteArray(): ByteArray = this.readBytes(this.readUByte().toInt())
fun Input.readUShortLVByteArray(): ByteArray = this.readBytes(this.readUShort().toInt())
private inline fun <R> inline(block: () -> R): R = block() private inline fun <R> inline(block: () -> R): R = block()
typealias TlvMap = MutableMap<Int, ByteArray> typealias TlvMap = MutableMap<Int, ByteArray>
fun TlvMap.getOrFail(tag: Int): ByteArray { inline fun TlvMap.getOrFail(tag: Int): ByteArray {
return this[tag] ?: error("cannot find tlv 0x${tag.toUHexString("")}($tag)") return this[tag] ?: error("cannot find tlv 0x${tag.toUHexString("")}($tag)")
} }
...@@ -94,10 +72,12 @@ inline fun TlvMap.getOrFail(tag: Int, lazyMessage: (tag: Int) -> String): ByteAr ...@@ -94,10 +72,12 @@ inline fun TlvMap.getOrFail(tag: Int, lazyMessage: (tag: Int) -> String): ByteAr
return this[tag] ?: error(lazyMessage(tag)) return this[tag] ?: error(lazyMessage(tag))
} }
fun Input.readTLVMap(tagSize: Int = 2): TlvMap = readTLVMap(true, tagSize) @MiraiDebugAPI
inline fun Input.readTLVMap(tagSize: Int = 2, suppressDuplication: Boolean = true): TlvMap = readTLVMap(true, tagSize, suppressDuplication)
@MiraiDebugAPI
@Suppress("DuplicatedCode") @Suppress("DuplicatedCode")
fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int): TlvMap { fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int, suppressDuplication: Boolean = true): TlvMap {
val map = mutableMapOf<Int, ByteArray>() val map = mutableMapOf<Int, ByteArray>()
var key = 0 var key = 0
...@@ -119,20 +99,22 @@ fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int): TlvMap { ...@@ -119,20 +99,22 @@ fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int): TlvMap {
}.toUByte() != UByte.MAX_VALUE) { }.toUByte() != UByte.MAX_VALUE) {
if (map.containsKey(key)) { if (map.containsKey(key)) {
DebugLogger.error( if (!suppressDuplication) {
@Suppress("IMPLICIT_CAST_TO_ANY") DebugLogger.error(
""" @Suppress("IMPLICIT_CAST_TO_ANY")
"""
Error readTLVMap: Error readTLVMap:
duplicated key ${when (tagSize) { duplicated key ${when (tagSize) {
1 -> key.toByte() 1 -> key.toByte()
2 -> key.toShort() 2 -> key.toShort()
4 -> key 4 -> key
else -> assertUnreachable() else -> error("unreachable")
}.contentToString()} }.contentToString()}
map=${map.contentToString()} map=${map.contentToString()}
duplicating value=${this.readUShortLVByteArray().toUHexString()} duplicating value=${this.readUShortLVByteArray().toUHexString()}
""".trimIndent() """.trimIndent()
) )
}
} else { } else {
try { try {
map[key] = this.readUShortLVByteArray() map[key] = this.readUShortLVByteArray()
...@@ -147,98 +129,10 @@ fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int): TlvMap { ...@@ -147,98 +129,10 @@ fun Input.readTLVMap(expectingEOF: Boolean = true, tagSize: Int): TlvMap {
return map return map
} }
/** inline fun Input.readString(length: Int, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length), charset = charset)
* 读扁平的 tag-UVarInt map. 重复的 tag 将只保留最后一个 inline fun Input.readString(length: Long, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
* inline fun Input.readString(length: Short, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
* tag: UByte
* value: UVarint
*/
@Suppress("DuplicatedCode")
fun Input.readFlatTUVarIntMap(expectingEOF: Boolean = false, tagSize: Int = 1): MutableMap<UInt, UInt> {
val map = mutableMapOf<UInt, UInt>()
var type: UShort = 0u
while (inline {
try {
type = when (tagSize) {
1 -> readUByte().toUShort()
2 -> readUShort()
else -> error("Unsupported tag size: $tagSize")
}
} catch (e: EOFException) {
if (expectingEOF) {
return map
}
throw e
}
type
}.toUByte() != UByte.MAX_VALUE) {
if (map.containsKey(type.toUInt())) {
map[type.toUInt()] = this.readUVarInt()
} else {
map[type.toUInt()] = this.readUVarInt()
}
}
return map
}
fun Map<Int, ByteArray>.printTLVMap(name: String = "", keyLength: Int = 2) =
debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() }.mapKeys {
when (keyLength) {
1 -> it.key.toUByte().contentToString()
2 -> it.key.toUShort().contentToString()
4 -> it.key.toUInt().contentToString()
else -> illegalArgument("Expecting 1, 2 or 4 for keyLength")
}
}.entries.joinToString(prefix = "{", postfix = "}", separator = "\n"))
internal inline fun unsupported(message: String? = null): Nothing = error(message ?: "Unsupported")
internal inline fun illegalArgument(message: String? = null): Nothing = error(message ?: "Illegal argument passed")
@JvmName("printTLVStringMap")
fun Map<Int, String>.printTLVMap(name: String = "") =
debugPrintln("TLVMap $name= " + this.mapKeys { it.key.toInt().toUShort().toUHexString() })
fun Input.readString(length: Int, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length), charset = charset)
fun Input.readString(length: Long, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
fun Input.readString(length: Short, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
@JvmSynthetic @JvmSynthetic
fun Input.readString(length: UShort, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset) inline fun Input.readString(length: UShort, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
fun Input.readString(length: Byte, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset) inline fun Input.readString(length: Byte, charset: Charset = Charsets.UTF_8): String = String(this.readBytes(length.toInt()), charset = charset)
\ No newline at end of file
@JvmSynthetic
fun Input.readStringUntil(stopSignalExclude: UByte, expectingEOF: Boolean = false): String = readStringUntil(stopSignalExclude.toByte(), expectingEOF)
@JvmName("readStringUntil0")
fun Input.readStringUntil(stopSignalExclude: Byte, expectingEOF: Boolean = false): String {
ByteArrayPool.useInstance {
var count = 0
val buffer = byteArrayOf(1)
while (readAvailable(buffer, 1) == 1) {
if (buffer[0] == stopSignalExclude) {
return buffer.encodeToString()
}
it[count++] = buffer[0]
}
if (!expectingEOF) {
throw EOFException("Early EOF")
}
return buffer.encodeToString()
}
}
private const val TRUE_BYTE_VALUE: Byte = 1
fun Input.readBoolean(): Boolean = this.readByte() == TRUE_BYTE_VALUE
fun Input.readLVNumber(): Number {
return when (this.readShort().toInt()) {
1 -> this.readByte()
2 -> this.readShort()
4 -> this.readInt()
8 -> this.readLong()
else -> throw UnsupportedOperationException()
}
}
\ No newline at end of file
@file:Suppress("EXPERIMENTAL_API_USAGE") @file:Suppress("EXPERIMENTAL_API_USAGE", "NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils.io package net.mamoe.mirai.utils.io
import kotlinx.io.core.* import kotlinx.io.core.*
import kotlinx.io.pool.useInstance
import net.mamoe.mirai.utils.Tested
import net.mamoe.mirai.utils.coerceAtMostOrFail import net.mamoe.mirai.utils.coerceAtMostOrFail
import net.mamoe.mirai.utils.cryptor.encryptBy import net.mamoe.mirai.utils.cryptor.encryptBy
import net.mamoe.mirai.utils.currentTimeMillis import kotlin.jvm.JvmMultifileClass
import net.mamoe.mirai.utils.deviceName import kotlin.jvm.JvmName
import kotlin.random.Random
import kotlin.random.nextInt
fun BytePacketBuilder.writeZero(count: Int) {
require(count != 0) { "Trying to write zero with count 0, you made a mistake?" }
require(count > 0) { "writeZero: count must > 0" }
repeat(count) { this.writeByte(0) }
}
fun BytePacketBuilder.writeRandom(length: Int) = repeat(length) { this.writeByte(Random.Default.nextInt(255).toByte()) }
fun BytePacketBuilder.writeQQ(qq: Long) = this.writeUInt(qq.toUInt()) // same bit rep.
fun BytePacketBuilder.writeGroup(groupId: Long) = this.writeUInt(groupId.toUInt())
fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLength: Int) { fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLength: Int) {
if (array.size <= maxLength) { if (array.size <= maxLength) {
...@@ -35,7 +22,7 @@ fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLe ...@@ -35,7 +22,7 @@ fun BytePacketBuilder.writeShortLVByteArrayLimitedLength(array: ByteArray, maxLe
} }
} }
fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray): Int { inline fun BytePacketBuilder.writeShortLVByteArray(byteArray: ByteArray): Int {
this.writeShort(byteArray.size.toShort()) this.writeShort(byteArray.size.toShort())
this.writeFully(byteArray) this.writeFully(byteArray)
return byteArray.size return byteArray.size
...@@ -59,18 +46,7 @@ inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset ...@@ -59,18 +46,7 @@ inline fun BytePacketBuilder.writeShortLVPacket(tag: UByte? = null, lengthOffset
return length.toInt() return length.toInt()
} }
inline fun BytePacketBuilder.writeUVarIntLVPacket(tag: UByte? = null, lengthOffset: ((Long) -> Long) = {it}, builder: BytePacketBuilder.() -> Unit) = inline fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
BytePacketBuilder().apply(builder).build().use {
if (tag != null) writeUByte(tag)
writeUVarInt(lengthOffset.invoke(it.remaining).coerceAtMostOrFail(0xFFFFL))
writePacket(it)
}
fun BytePacketBuilder.writeShortLVString(str: String) = writeShortLVByteArray(str.toByteArray())
fun BytePacketBuilder.writeIP(ip: String) = writeFully(ip.trim().split(".").map { it.toUByte() }.toUByteArray())
fun BytePacketBuilder.writeTime() = this.writeInt(currentTimeMillis.toInt())
fun BytePacketBuilder.writeHex(uHex: String) { fun BytePacketBuilder.writeHex(uHex: String) {
uHex.split(" ").forEach { uHex.split(" ").forEach {
...@@ -79,76 +55,8 @@ fun BytePacketBuilder.writeHex(uHex: String) { ...@@ -79,76 +55,8 @@ fun BytePacketBuilder.writeHex(uHex: String) {
} }
} }
} }
fun BytePacketBuilder.writeTLV(tag: UByte, values: UByteArray) {
writeUByte(tag)
writeUVarInt(values.size.toUInt())
writeFully(values)
}
fun BytePacketBuilder.writeTLV(tag: UByte, values: ByteArray) {
writeUByte(tag)
writeUVarInt(values.size.toUInt())
writeFully(values)
}
fun BytePacketBuilder.writeTHex(tag: UByte, uHex: String) {
this.writeUByte(tag)
this.writeFully(uHex.hexToUBytes())
}
fun BytePacketBuilder.writeTV(tagValue: UShort) = writeUShort(tagValue)
fun BytePacketBuilder.writeTV(tag: UByte, value: UByte) {
writeUByte(tag)
writeUByte(value)
}
fun BytePacketBuilder.writeTUbyte(tag: UByte, value: UByte) {
this.writeUByte(tag)
this.writeUByte(value)
}
fun BytePacketBuilder.writeTUVarint(tag: UByte, value: UInt) {
this.writeUByte(tag)
this.writeUVarInt(value)
}
fun BytePacketBuilder.writeTByteArray(tag: UByte, value: ByteArray) {
this.writeUByte(tag)
this.writeFully(value)
}
fun BytePacketBuilder.writeTByteArray(tag: UByte, value: UByteArray) {
this.writeUByte(tag)
this.writeFully(value)
}
/** /**
* 会使用 [ByteArrayPool] 缓存 * 会使用 [ByteArrayPool] 缓存
*/ */
inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) = inline fun BytePacketBuilder.encryptAndWrite(key: ByteArray, encoder: BytePacketBuilder.() -> Unit) =
BytePacketBuilder().apply(encoder).build().encryptBy(key) { decrypted -> writeFully(decrypted) } BytePacketBuilder().apply(encoder).build().encryptBy(key) { decrypted -> writeFully(decrypted) }
\ No newline at end of file
inline fun BytePacketBuilder.encryptAndWrite(key: IoBuffer, encoder: BytePacketBuilder.() -> Unit) = ByteArrayPool.useInstance {
key.readFully(it, 0, key.readRemaining)
encryptAndWrite(it, encoder)
}
inline fun BytePacketBuilder.encryptAndWrite(keyHex: String, encoder: BytePacketBuilder.() -> Unit) = encryptAndWrite(keyHex.hexToBytes(), encoder)
@Tested
fun BytePacketBuilder.writeDeviceName(random: Boolean) {
val deviceName: String = if (random) {
"DESKTOP-" + String(ByteArray(7) {
(if (Random.nextBoolean()) Random.nextInt('A'.toInt()..'Z'.toInt())
else Random.nextInt('1'.toInt()..'9'.toInt())).toByte()
})
} else {
deviceName
}
this.writeShort((deviceName.length + 2).toShort())
this.writeShort(deviceName.length.toShort())
this.writeStringUtf8(deviceName)
}
\ No newline at end of file
...@@ -16,8 +16,8 @@ import kotlin.jvm.JvmSynthetic ...@@ -16,8 +16,8 @@ import kotlin.jvm.JvmSynthetic
* *
* Source project: [Nukkit](http://github.com/nukkit/nukkit) * Source project: [Nukkit](http://github.com/nukkit/nukkit)
* *
* @author MagicDroidX of Nukkit Project * @author MagicDroidX from Nukkit Project
* @author lmlstarqaq of Nukkit Project * @author lmlstarqaq from Nukkit Project
*/ */
internal fun encodeZigZag32(signedInt: Int): Long { internal fun encodeZigZag32(signedInt: Int): Long {
...@@ -42,10 +42,6 @@ internal fun decodeZigZag64(signedLong: Long): Long { ...@@ -42,10 +42,6 @@ internal fun decodeZigZag64(signedLong: Long): Long {
} }
fun Input.readVarInt(): Int {
return decodeZigZag32(this.readUVarInt())
}
inline class UVarInt( inline class UVarInt(
val data: UInt val data: UInt
) )
......
@file:Suppress("NOTHING_TO_INLINE")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils package net.mamoe.mirai.utils
fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName
inline fun <K, V> Map<K, V>.firstValue(): V = this.entries.first().value
fun <K, V> Map<K, V>.firstValueOrNull(): V? = this.entries.firstOrNull()?.value inline fun <K, V> Map<K, V>.firstValueOrNull(): V? = this.entries.firstOrNull()?.value
fun <K, V> Map<K, V>.firstKey(): K = this.entries.first().key inline fun <K, V> Map<K, V>.firstKey(): K = this.entries.first().key
fun <K, V> Map<K, V>.firstKeyOrNull(): K? = this.entries.firstOrNull()?.key inline fun <K, V> Map<K, V>.firstKeyOrNull(): K? = this.entries.firstOrNull()?.key
\ No newline at end of file \ No newline at end of file
...@@ -28,7 +28,7 @@ import kotlin.coroutines.CoroutineContext ...@@ -28,7 +28,7 @@ import kotlin.coroutines.CoroutineContext
actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver() actual var defaultLoginSolver: LoginSolver = DefaultLoginSolver()
class DefaultLoginSolver : LoginSolver() { internal class DefaultLoginSolver : LoginSolver() {
override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? = loginSolverLock.withLock { override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? = loginSolverLock.withLock {
val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() } val tempFile: File = createTempFile(suffix = ".png").apply { deleteOnExit() }
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
......
package net.mamoe.mirai.utils.cryptor package net.mamoe.mirai.utils.cryptor
import net.mamoe.mirai.utils.MiraiDebugAPI
import java.lang.reflect.Field import java.lang.reflect.Field
import kotlin.reflect.full.allSuperclasses import kotlin.reflect.full.allSuperclasses
val FIELD_TRY_SET_ACCESSIBLE = Field::class.java.declaredMethods.firstOrNull { it.name == "trySetAccessible" } val FIELD_TRY_SET_ACCESSIBLE = Field::class.java.declaredMethods.firstOrNull { it.name == "trySetAccessible" }
@MiraiDebugAPI
actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String { actual fun Any.contentToStringReflectively(prefix: String, filter: ((name: String, value: Any?) -> Boolean)?): String {
val newPrefix = prefix + ProtoMap.indent val newPrefix = prefix + ProtoMap.indent
return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" + return (this::class.simpleName ?: "<UnnamedClass>") + "#" + this::class.hashCode() + " {\n" +
......
...@@ -16,7 +16,6 @@ import kotlinx.io.core.readBytes ...@@ -16,7 +16,6 @@ import kotlinx.io.core.readBytes
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.event.subscribeMessages
import net.mamoe.mirai.qqandroid.QQAndroid import net.mamoe.mirai.qqandroid.QQAndroid
import net.mamoe.mirai.utils.LoginFailedException
import net.mamoe.mirai.utils.LoginSolver import net.mamoe.mirai.utils.LoginSolver
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
...@@ -67,7 +66,7 @@ class MiraiService : Service() { ...@@ -67,7 +66,7 @@ class MiraiService : Service() {
try { try {
login() login()
mCallback?.get()?.onSuccess() mCallback?.get()?.onSuccess()
} catch (e: LoginFailedException) { } catch (e: Exception) {
mCallback?.get()?.onFailed() mCallback?.get()?.onFailed()
} }
} }
......
...@@ -77,10 +77,7 @@ public interface BlockingBot { ...@@ -77,10 +77,7 @@ public interface BlockingBot {
* 登录. * 登录.
* <p> * <p>
* 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login] * 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login]
*
* @throws net.mamoe.mirai.utils.LoginFailedException
*/ */
@SuppressWarnings("JavaDoc")
void login(); void login();
// endregion // endregion
......
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