mirror of
https://github.com/mamoe/mirai.git
synced 2025-01-05 07:30:09 +08:00
Reduce multiplatform functions
This commit is contained in:
parent
71d5dda297
commit
048fe647f0
@ -9,7 +9,7 @@ buildscript {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:3.4.2'
|
||||
classpath 'com.android.tools.build:gradle:3.5.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
classpath "org.jetbrains.kotlinx:atomicfu-gradle-plugin:$atomicfu_version"
|
||||
}
|
||||
@ -25,4 +25,4 @@ allprojects {
|
||||
google()
|
||||
maven { url "https://mirrors.huaweicloud.com/repository/maven/" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,6 @@ package net.mamoe.mirai;
|
||||
* @author NaturalHG
|
||||
*/
|
||||
public final class MiraiMain {
|
||||
private static MiraiServer server;
|
||||
|
||||
public static void main(String[] args) {
|
||||
Runtime.getRuntime().addShutdownHook(new Thread(() -> server.shutdown()));
|
||||
}
|
||||
}
|
@ -1,186 +0,0 @@
|
||||
@file:Suppress("EXPERIMENTAL_API_USAGE")
|
||||
|
||||
package net.mamoe.mirai
|
||||
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.LoginResult
|
||||
import net.mamoe.mirai.utils.LoggerTextFormat
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.config.MiraiConfig
|
||||
import net.mamoe.mirai.utils.setting.MiraiSettings
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.concurrent.ExecutionException
|
||||
|
||||
|
||||
/**
|
||||
* Mirai 服务器.
|
||||
* 管理一些基础的事务
|
||||
*
|
||||
* @author NaturalHG
|
||||
*/
|
||||
object MiraiServer {
|
||||
var isUnix: Boolean = false
|
||||
private set
|
||||
|
||||
var parentFolder: File = File(System.getProperty("user.dir"))
|
||||
|
||||
var logger: MiraiLogger
|
||||
internal set
|
||||
|
||||
internal lateinit var settings: MiraiSettings
|
||||
|
||||
internal lateinit var qqs: MiraiConfig
|
||||
|
||||
private var enabled: Boolean = false
|
||||
|
||||
|
||||
init {
|
||||
this.isUnix = !System.getProperties().getProperty("os.name").toUpperCase().contains("WINDOWS")
|
||||
|
||||
this.logger = MiraiLogger
|
||||
|
||||
logger.logInfo("About to run Mirai (" + Mirai.VERSION + ") under " + if (isUnix) "unix" else "windows")
|
||||
logger.logInfo("Loading data under " + LoggerTextFormat.GREEN + this.parentFolder)
|
||||
|
||||
val setting = File(this.parentFolder, "/Mirai.ini")
|
||||
logger.logInfo("Selecting setting from " + LoggerTextFormat.GREEN + setting)
|
||||
|
||||
/*
|
||||
if (!setting.exists()) {
|
||||
this.initSetting(setting);
|
||||
} else {
|
||||
this.settings = new MiraiSettings(setting);
|
||||
}
|
||||
|
||||
File qqs = new File(this.parentFolder + "/QQ.yml");
|
||||
getLogger().logInfo("Reading QQ accounts from " + LoggerTextFormat.GREEN + qqs);
|
||||
if (!qqs.exists()) {
|
||||
this.initQQConfig(qqs);
|
||||
} else {
|
||||
this.qqs = new MiraiConfig(qqs);
|
||||
}
|
||||
if (this.qqs.isEmpty()) {
|
||||
this.initQQConfig(qqs);
|
||||
}*/
|
||||
|
||||
/*
|
||||
MiraiSettingMapSection qqs = this.setting.getMapSection("qq");
|
||||
qqs.forEach((a,p) -> {
|
||||
this.getLogger().logInfo("Finding available ports between " + "1-65536");
|
||||
try {
|
||||
int port = MiraiNetwork.getAvailablePort();
|
||||
this.getLogger().logInfo("Listening on port " + port);
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
|
||||
this.reload()
|
||||
}
|
||||
|
||||
fun shutdown() {
|
||||
if (this.enabled) {
|
||||
logger.logInfo("About to shutdown Mirai")
|
||||
logger.logInfo("Data have been saved")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun initSetting(setting: File) {
|
||||
logger.logInfo("Thanks for using Mirai")
|
||||
logger.logInfo("initializing Settings")
|
||||
try {
|
||||
if (setting.createNewFile()) {
|
||||
logger.logInfo("Mirai Config Created")
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
this.settings = MiraiSettings(setting)
|
||||
val network = this.settings.getMapSection("network")
|
||||
network["enable_proxy"] = "not supporting yet"
|
||||
|
||||
val proxy = this.settings.getListSection("proxy")
|
||||
proxy.add("1.2.3.4:95")
|
||||
proxy.add("1.2.3.4:100")
|
||||
|
||||
val worker = this.settings.getMapSection("worker")
|
||||
worker["core_task_pool_worker_amount"] = 5
|
||||
|
||||
val plugin = this.settings.getMapSection("plugin")
|
||||
plugin["logDebug"] = false
|
||||
|
||||
this.settings.save()
|
||||
logger.logInfo("initialized; changing can be made in setting file: $setting")
|
||||
}
|
||||
|
||||
private fun initQQConfig(qqConfig: File) {
|
||||
this.qqs = MiraiConfig(qqConfig)
|
||||
MiraiLogger.logInfo("QQ account initialized; changing can be made in Config file: $qqConfig")
|
||||
logger.logInfo("QQ 账户管理初始化完毕")
|
||||
}
|
||||
|
||||
private fun reload() {
|
||||
this.enabled = true
|
||||
MiraiLogger.logInfo(LoggerTextFormat.GREEN.toString() + "Server enabled; Welcome to Mirai")
|
||||
MiraiLogger.logInfo("Mirai Version=" + Mirai.VERSION)
|
||||
|
||||
MiraiLogger.logInfo("Initializing [Bot]s")
|
||||
|
||||
try {
|
||||
availableBot
|
||||
} catch (e: ExecutionException) {
|
||||
e.printStackTrace()
|
||||
} catch (e: InterruptedException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
/*
|
||||
this.qqs.keySet().stream().map(key -> this.qqs.getSection(key)).forEach(section -> {
|
||||
getLogger().logInfo("Initializing [Bot] " + section.getString("account"));
|
||||
try {
|
||||
Bot bot = new Bot(section);
|
||||
var state = bot.network.login$mirai_core().of();
|
||||
//bot.network.login$mirai_core().whenComplete((state, e) -> {
|
||||
if (state == LoginState.REQUIRE_UPLOAD) {
|
||||
Bot.instances.add(bot);
|
||||
getLogger().logGreen(" Login Succeed");
|
||||
} else {
|
||||
getLogger().logError(" Login Failed with logError " + state);
|
||||
bot.close();
|
||||
}
|
||||
// }).of();
|
||||
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
getLogger().logError("Could not load QQ bots config!");
|
||||
System.exit(1);
|
||||
}
|
||||
});*/
|
||||
}
|
||||
|
||||
|
||||
//todo only for test now
|
||||
private var qqList = "1683921395----bb22222\n"
|
||||
|
||||
private val availableBot: Bot
|
||||
@Throws(ExecutionException::class, InterruptedException::class)
|
||||
get() {
|
||||
for (it in qqList.split("\n").dropLastWhile { it.isEmpty() }.toTypedArray()) {
|
||||
val strings = it.split("----").dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
val bot = Bot(BotAccount(strings[0].toUInt(), strings[1]), MiraiLogger)
|
||||
|
||||
if (runBlocking { bot.login() } === LoginResult.SUCCESS) {
|
||||
bot.logger.logGreen("Login succeed")
|
||||
return bot
|
||||
}
|
||||
}
|
||||
|
||||
throw RuntimeException()
|
||||
}
|
||||
}
|
@ -14,7 +14,6 @@ import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.internal.coerceAtLeastOrFail
|
||||
import net.mamoe.mirai.utils.log
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
data class BotAccount(
|
||||
@ -75,11 +74,11 @@ class Bot(val account: BotAccount, val logger: MiraiLogger) {
|
||||
configuration: BotNetworkConfiguration,
|
||||
cause: Throwable? = null
|
||||
): LoginResult {
|
||||
logger.logPurple("Reinitializing BotNetworkHandler")
|
||||
logger.warning("Reinitializing BotNetworkHandler")
|
||||
try {
|
||||
network.close(cause)
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
logger.error(e)
|
||||
}
|
||||
network = TIMBotNetworkHandler(this)
|
||||
return network.login(configuration)
|
||||
|
@ -10,7 +10,6 @@ import net.mamoe.mirai.event.internal.broadcastInternal
|
||||
import net.mamoe.mirai.network.BotNetworkHandler
|
||||
import net.mamoe.mirai.utils.DefaultLogger
|
||||
import net.mamoe.mirai.utils.MiraiLogger
|
||||
import net.mamoe.mirai.utils.log
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
import kotlin.coroutines.EmptyCoroutineContext
|
||||
import kotlin.jvm.JvmOverloads
|
||||
@ -44,7 +43,7 @@ abstract class Event {
|
||||
|
||||
init {
|
||||
if (EventDebuggingFlag) {
|
||||
EventLogger.logDebug(this::class.simpleName + " created")
|
||||
EventLogger.debug(this::class.simpleName + " created")
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -66,20 +65,20 @@ interface Cancellable {
|
||||
|
||||
/**
|
||||
* 广播一个事件的唯一途径.
|
||||
* 若 [context] 不包含 [CoroutineExceptionHandler], 将会使用默认的异常捕获, 即 [log]
|
||||
* 若 [context] 不包含 [CoroutineExceptionHandler], 将会使用默认的异常捕获, 即 [error]
|
||||
* 也就是说, 这个方法不会抛出异常, 只会把异常交由 [context] 捕获
|
||||
*/
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
@JvmOverloads
|
||||
suspend fun <E : Event> E.broadcast(context: CoroutineContext = EmptyCoroutineContext): E {
|
||||
if (EventDebuggingFlag) {
|
||||
EventLogger.logDebug(this::class.simpleName + " pre broadcast")
|
||||
EventLogger.debug(this::class.simpleName + " pre broadcast")
|
||||
}
|
||||
try {
|
||||
return withContext(EventScope.coroutineContext + context) { this@broadcast.broadcastInternal() }
|
||||
} finally {
|
||||
if (EventDebuggingFlag) {
|
||||
EventLogger.logDebug(this::class.simpleName + " after broadcast")
|
||||
EventLogger.debug(this::class.simpleName + " after broadcast")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -13,18 +13,34 @@ import net.mamoe.mirai.utils.ExternalImage
|
||||
* 采用这样的消息模式是因为 QQ 的消息多元化, 一条消息中可包含 [纯文本][PlainText], [图片][Image] 等.
|
||||
*
|
||||
* **在 Kotlin 使用 [Message]**
|
||||
* 这与使用 [String] 的使用非常类似.
|
||||
* 这与使用 [String] 的使用非常类似.
|
||||
*
|
||||
* 比较 [Message] 与 [String] (使用 infix [Message.eq]):
|
||||
* 比较 [Message] 与 [String] (使用 infix [Message.eq]):
|
||||
* `if(event eq "你好") qq.sendMessage(event)`
|
||||
*
|
||||
* 连接 [Message] 与 [Message], [String], (使用 operator [Message.plus]):
|
||||
* ```
|
||||
* 连接 [Message] 与 [Message], [String], (使用 operator [Message.plus]):
|
||||
* ```kotlin
|
||||
* event = PlainText("Hello ")
|
||||
* qq.sendMessage(event + "world")
|
||||
* ```
|
||||
*
|
||||
* 但注意: 不能 `String + Message`. 只能 `Message + String`
|
||||
* `Message1 + Message2 + Message3`, 类似 [String] 的连接:
|
||||
*
|
||||
* +----------+ plus +----------+ plus +----------+
|
||||
* | Message1 | <------ | Message2 | <------ | Message3 |
|
||||
* +----------+ +----------+ +----------+
|
||||
* | | |
|
||||
* +--------------------+--------------------+
|
||||
* |
|
||||
* | 构成
|
||||
* |
|
||||
* V
|
||||
* +--------------+
|
||||
* | MessageChain |
|
||||
* +--------------+
|
||||
*
|
||||
*
|
||||
* 但注意: 不能 `String + Message`. 只能 `Message + String`
|
||||
*
|
||||
* @see PlainText 纯文本
|
||||
* @see Image 图片
|
||||
@ -49,7 +65,7 @@ interface Message {
|
||||
* 除 [MessageChain] 外, 每个 [Message] 类型都拥有一个`伴生对象`(companion object) 来持有一个 Key
|
||||
* 在 [MessageChain.get] 时将会使用到这个 Key 进行判断类型.
|
||||
*
|
||||
* @param M 指代持有它的消息类型
|
||||
* @param M 指代持有这个 Key 的消息类型
|
||||
*/
|
||||
interface Key<M : Message>
|
||||
|
||||
|
@ -33,7 +33,7 @@ internal fun IoBuffer.parseLongText0x19(): PlainText {
|
||||
|
||||
internal fun IoBuffer.parseMessageImage0x06(): Image {
|
||||
discardExact(1)
|
||||
//MiraiLogger.logDebug(this.toUHexString())
|
||||
//MiraiLogger.debug(this.toUHexString())
|
||||
val filenameLength = readShort()
|
||||
|
||||
discardExact(filenameLength.toInt())
|
||||
|
@ -26,7 +26,6 @@ import net.mamoe.mirai.qqAccount
|
||||
import net.mamoe.mirai.utils.BotNetworkConfiguration
|
||||
import net.mamoe.mirai.utils.OnlineStatus
|
||||
import net.mamoe.mirai.utils.io.*
|
||||
import net.mamoe.mirai.utils.log
|
||||
import net.mamoe.mirai.utils.solveCaptcha
|
||||
import kotlin.coroutines.CoroutineContext
|
||||
|
||||
@ -39,7 +38,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
override val coroutineContext: CoroutineContext =
|
||||
Dispatchers.Default + CoroutineExceptionHandler { _, e ->
|
||||
bot.logger.log(e)
|
||||
bot.logger.error(e)
|
||||
} + SupervisorJob()
|
||||
|
||||
|
||||
@ -61,7 +60,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
override suspend fun login(configuration: BotNetworkConfiguration): LoginResult = withContext(this.coroutineContext) {
|
||||
TIMProtocol.SERVER_IP.forEach { ip ->
|
||||
bot.logger.logPurple("Connecting server $ip")
|
||||
bot.logger.warning("Connecting server $ip")
|
||||
socket = BotSocketAdapter(ip, configuration)
|
||||
|
||||
loginResult = CompletableDeferred()
|
||||
@ -69,7 +68,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
socket.resendTouch().takeIf { it != LoginResult.TIMEOUT }?.let { return@withContext it }
|
||||
|
||||
println()
|
||||
bot.logger.logPurple("Timeout. Retrying next server")
|
||||
bot.logger.warning("Timeout. Retrying next server")
|
||||
|
||||
socket.close()
|
||||
}
|
||||
@ -86,7 +85,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
add(EventPacketHandler(session).asNode(EventPacketHandler))
|
||||
add(ActionPacketHandler(session).asNode(ActionPacketHandler))
|
||||
bot.logger.logPurple("Successfully logged in")
|
||||
bot.logger.warning("Successfully logged in")
|
||||
}
|
||||
|
||||
private lateinit var sessionKey: ByteArray
|
||||
@ -134,15 +133,14 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
close()
|
||||
return
|
||||
} catch (e: ReadPacketInternalException) {
|
||||
bot.logger.logError("Socket channel read failed: ${e.message}")
|
||||
bot.logger.error("Socket channel read failed: ${e.message}")
|
||||
continue
|
||||
} catch (e: Throwable) {
|
||||
bot.logger.logError("Caught unexpected exceptions")
|
||||
bot.logger.logError(e)
|
||||
bot.logger.error("Caught unexpected exceptions", e)
|
||||
continue
|
||||
} finally {
|
||||
if (!buffer.canRead() || buffer.readRemaining == 0) {//size==0
|
||||
//bot.logger.logDebug("processReceive: Buffer cannot be read")
|
||||
//bot.logger.debug("processReceive: Buffer cannot be read")
|
||||
buffer.release(IoBuffer.Pool)
|
||||
continue
|
||||
}// sometimes exceptions are thrown without this `if` clause
|
||||
@ -156,7 +154,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
try {
|
||||
distributePacket(it.parseServerPacket(buffer.readRemaining))
|
||||
} catch (e: Exception) {
|
||||
bot.logger.logError(e)
|
||||
bot.logger.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,17 +195,17 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
try {
|
||||
packet.decode()
|
||||
} catch (e: Exception) {
|
||||
e.log()
|
||||
bot.logger.logDebug("Packet=$packet")
|
||||
bot.logger.logDebug("Packet size=" + packet.input.readBytes().size)
|
||||
bot.logger.logDebug("Packet data=" + packet.input.readBytes().toUHexString())
|
||||
bot.logger.error("When distributePacket", e)
|
||||
bot.logger.debug("Packet=$packet")
|
||||
bot.logger.debug("Packet size=" + packet.input.readBytes().size)
|
||||
bot.logger.debug("Packet data=" + packet.input.readBytes().toUHexString())
|
||||
packet.close()
|
||||
throw e
|
||||
}
|
||||
|
||||
packet.use {
|
||||
packet::class.simpleName?.takeIf { !it.endsWith("Encrypted") && !it.endsWith("Raw") }?.let {
|
||||
bot.logger.logCyan("Packet received: $packet")
|
||||
bot.logger.verbose("Packet received: $packet")
|
||||
}
|
||||
|
||||
// Remove first to release the lock
|
||||
@ -284,7 +282,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
val shouldBeSent = buffer.readRemaining
|
||||
check(channel.send(buffer) == shouldBeSent) { "Buffer is not entirely sent. Required sent length=$shouldBeSent, but after channel.send, buffer remains ${buffer.readBytes().toUHexString()}" }//JVM: withContext(IO)
|
||||
} catch (e: SendPacketInternalException) {
|
||||
bot.logger.logError("Caught SendPacketInternalException: ${e.cause?.message}")
|
||||
bot.logger.error("Caught SendPacketInternalException: ${e.cause?.message}")
|
||||
bot.reinitializeNetworkHandler(configuration, e)
|
||||
return@withContext
|
||||
} finally {
|
||||
@ -292,7 +290,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
}
|
||||
}
|
||||
|
||||
bot.logger.logGreen("Packet sent: $packet")
|
||||
bot.logger.info("Packet sent: $packet")
|
||||
|
||||
PacketSentEvent(bot, packet).broadcast()
|
||||
|
||||
@ -340,7 +338,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
if (packet.serverIP != null) {//redirection
|
||||
socket.close()
|
||||
socket = BotSocketAdapter(packet.serverIP!!, socket.configuration)
|
||||
bot.logger.logPurple("Redirecting to ${packet.serverIP}")
|
||||
bot.logger.warning("Redirecting to ${packet.serverIP}")
|
||||
loginResult.complete(socket.resendTouch())
|
||||
} else {//password submission
|
||||
this.loginIP = packet.loginIP
|
||||
@ -406,7 +404,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
is CaptchaTransmissionResponsePacket -> {
|
||||
//packet is ServerCaptchaWrongPacket
|
||||
if (this.captchaSectionId == 0) {
|
||||
bot.logger.logPurple("验证码错误, 请重新输入")
|
||||
bot.logger.warning("验证码错误, 请重新输入")
|
||||
this.captchaSectionId = 1
|
||||
this.captchaCache = null
|
||||
}
|
||||
@ -478,7 +476,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
|
||||
is SessionKeyResponsePacket -> {
|
||||
sessionKey = packet.sessionKey
|
||||
bot.logger.logPurple("sessionKey = ${sessionKey.toUHexString()}")
|
||||
bot.logger.warning("sessionKey = ${sessionKey.toUHexString()}")
|
||||
|
||||
heartbeatJob = launch {
|
||||
while (socket.isOpen) {
|
||||
@ -492,7 +490,7 @@ internal class TIMBotNetworkHandler internal constructor(private val bot: Bot) :
|
||||
sessionKey
|
||||
).sendAndExpect<HeartbeatPacket.Response>().join()
|
||||
} == null) {
|
||||
bot.logger.logPurple("Heartbeat timed out")
|
||||
bot.logger.warning("Heartbeat timed out")
|
||||
bot.reinitializeNetworkHandler(configuration, HeartbeatTimeoutException())
|
||||
return@launch
|
||||
}
|
||||
|
@ -2,9 +2,6 @@
|
||||
|
||||
package net.mamoe.mirai.network.protocol.tim
|
||||
|
||||
import net.mamoe.mirai.utils.solveIpAddress
|
||||
|
||||
|
||||
object TIMProtocol {
|
||||
val SERVER_IP: List<String> = {
|
||||
//add("183.60.56.29")
|
||||
@ -17,7 +14,7 @@ object TIMProtocol {
|
||||
"sz8.tencent.com",
|
||||
"sz9.tencent.com",
|
||||
"sz2.tencent.com"
|
||||
).forEach { list.add(solveIpAddress(it)) }
|
||||
).forEach { list.add(it) }
|
||||
|
||||
list.toList()
|
||||
}()//不使用lazy, 在初始化时就加载.
|
||||
|
@ -14,7 +14,6 @@ import net.mamoe.mirai.network.protocol.tim.packet.ServerPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.event.ServerEventPacket
|
||||
import net.mamoe.mirai.network.protocol.tim.packet.login.RequestSKeyPacket
|
||||
import net.mamoe.mirai.network.qqAccount
|
||||
import net.mamoe.mirai.utils.log
|
||||
|
||||
/**
|
||||
* 动作: 获取好友列表, 点赞, 踢人等.
|
||||
@ -50,7 +49,7 @@ class ActionPacketHandler(session: BotSession) : PacketHandler(session) {
|
||||
try {
|
||||
requestSKey()
|
||||
} catch (e: Throwable) {
|
||||
e.log()
|
||||
bot.logger.error(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class UnknownServerPacket(
|
||||
) : ServerPacket(input) {
|
||||
override fun decode() {
|
||||
val raw = this.input.readBytes()
|
||||
MiraiLogger.logDebug("UnknownServerPacket data: " + raw.toUHexString())
|
||||
MiraiLogger.debug("UnknownServerPacket data: " + raw.toUHexString())
|
||||
}
|
||||
|
||||
class Encrypted(
|
||||
|
@ -50,7 +50,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
|
||||
)
|
||||
discardExact(2)
|
||||
val type = readUShort()
|
||||
//DebugLogger.logPurple("unknown2Byte+byte = ${unknown2Byte.toUHexString()} ${type.toUHexString()}")
|
||||
//DebugLogger.warning("unknown2Byte+byte = ${unknown2Byte.toUHexString()} ${type.toUHexString()}")
|
||||
return when (type.toUInt()) {
|
||||
0x00C4u -> {
|
||||
discardExact(13)
|
||||
@ -90,7 +90,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
|
||||
//"02 10", "00 12" -> ServerUnknownEventPacket(input, eventIdentity)
|
||||
|
||||
else -> {//0x00 79u, 可能是正在输入的包
|
||||
MiraiLogger.logDebug("UnknownEvent type = ${type.toByteArray().toUHexString()}")
|
||||
MiraiLogger.debug("UnknownEvent type = ${type.toByteArray().toUHexString()}")
|
||||
UnknownServerEventPacket(input, eventIdentity)
|
||||
}
|
||||
}.applyId(id).applySequence(sequenceId)
|
||||
@ -126,7 +126,7 @@ abstract class ServerEventPacket(input: ByteReadPacket, val eventIdentity: Event
|
||||
class IgnoredServerEventPacket(val eventId: ByteArray, private val showData: Boolean = false, input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||
override fun decode() {
|
||||
if (showData) {
|
||||
MiraiLogger.logDebug("IgnoredServerEventPacket data: " + this.input.readBytes().toUHexString())
|
||||
MiraiLogger.debug("IgnoredServerEventPacket data: " + this.input.readBytes().toUHexString())
|
||||
} else {
|
||||
this.input.discard()
|
||||
}
|
||||
@ -138,6 +138,6 @@ class IgnoredServerEventPacket(val eventId: ByteArray, private val showData: Boo
|
||||
*/
|
||||
class UnknownServerEventPacket(input: ByteReadPacket, eventIdentity: EventPacketIdentity) : ServerEventPacket(input, eventIdentity) {
|
||||
override fun decode() {
|
||||
MiraiLogger.logDebug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
|
||||
MiraiLogger.debug("UnknownServerEventPacket data: " + this.input.readBytes().toUHexString())
|
||||
}
|
||||
}
|
||||
|
@ -40,8 +40,8 @@ class RequestSKeyPacket(
|
||||
discardExact(4)
|
||||
//debugDiscardExact(2)
|
||||
sKey = this.readString(10)//16??
|
||||
DebugLogger.logPurple("SKey=$sKey")
|
||||
DebugLogger.logPurple("SKey 包后面${this.readRemainingBytes().toUHexString()}")
|
||||
DebugLogger.warning("SKey=$sKey")
|
||||
DebugLogger.warning("SKey 包后面${this.readRemainingBytes().toUHexString()}")
|
||||
}
|
||||
}
|
||||
}
|
@ -3,6 +3,23 @@ package net.mamoe.mirai.utils
|
||||
import net.mamoe.mirai.Bot
|
||||
import kotlin.jvm.JvmOverloads
|
||||
|
||||
|
||||
/**
|
||||
* 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器
|
||||
* 可直接修改这个变量的值来重定向日志输出.
|
||||
*/
|
||||
var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger() }
|
||||
|
||||
/**
|
||||
* 当前平台的默认的日志记录器.
|
||||
* 在 _JVM 控制台_ 端的实现为 [println]
|
||||
* 在 _Android_ 端的实现为 [android.util.Log]
|
||||
*
|
||||
* 不应该直接构造这个类的实例. 请使用 [DefaultLogger]
|
||||
*/
|
||||
expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = null) : MiraiLoggerPlatformBase
|
||||
|
||||
|
||||
/**
|
||||
* 日志记录器. 所有的输出均依赖于它.
|
||||
* 不同的对象可能拥有只属于自己的 logger. 通过 [identity] 来区分.
|
||||
@ -28,38 +45,67 @@ interface MiraiLogger {
|
||||
* val bot = Bot( ... )
|
||||
* bot.follower = MyOwnLogger()
|
||||
*
|
||||
* bot.logInfo("Hi")
|
||||
* bot.info("Hi")
|
||||
* ```
|
||||
* 在这个例子中的 `MyOwnLogger` 将可以记录到 "Hi".
|
||||
*/
|
||||
var follower: MiraiLogger?
|
||||
|
||||
fun logInfo(any: Any?) = log(any)
|
||||
/**
|
||||
* 记录一个 `verbose` 级别的日志.
|
||||
*/
|
||||
fun verbose(any: Any?)
|
||||
|
||||
fun log(e: Throwable)
|
||||
fun verbose(e: Throwable?) = verbose(null, e)
|
||||
fun verbose(message: String?, e: Throwable?)
|
||||
|
||||
fun log(any: Any?)
|
||||
/**
|
||||
* 记录一个 `debug` 级别的日志.
|
||||
*/
|
||||
fun debug(any: Any?)
|
||||
|
||||
fun logError(any: Any?)
|
||||
fun debug(e: Throwable?) = debug(null, e)
|
||||
fun debug(message: String?, e: Throwable?)
|
||||
|
||||
fun logError(e: Throwable) = log(e)
|
||||
|
||||
fun logDebug(any: Any?)
|
||||
/**
|
||||
* 记录一个 `info` 级别的日志.
|
||||
*/
|
||||
fun info(any: Any?)
|
||||
|
||||
fun logCyan(any: Any?)
|
||||
fun info(e: Throwable?) = info(null, e)
|
||||
fun info(message: String?, e: Throwable?)
|
||||
|
||||
fun logPurple(any: Any?)
|
||||
|
||||
fun logGreen(any: Any?)
|
||||
/**
|
||||
* 记录一个 `warning` 级别的日志.
|
||||
*/
|
||||
fun warning(any: Any?)
|
||||
|
||||
fun warning(e: Throwable?) = warning(null, e)
|
||||
fun warning(message: String?, e: Throwable?)
|
||||
|
||||
|
||||
/**
|
||||
* 记录一个 `error` 级别的日志.
|
||||
*/
|
||||
fun error(e: Any?)
|
||||
|
||||
fun error(e: Throwable?) = error(null, e)
|
||||
fun error(message: String?, e: Throwable?)
|
||||
|
||||
fun logBlue(any: Any?)
|
||||
|
||||
/**
|
||||
* 添加一个 [follower], 返回 [follower]
|
||||
* 它只会把 `this` 的属性 [MiraiLogger.follower] 修改为这个函数的参数 [follower], 然后返回这个参数.
|
||||
* 若 [MiraiLogger.follower] 已经有值, 则会替换掉这个值.
|
||||
*
|
||||
* +------+ +----------+ +----------+ +----------+
|
||||
* | base | <-- | follower | <-- | follower | <-- | follower |
|
||||
* +------+ +----------+ +----------+ +----------+
|
||||
*
|
||||
* @see follower
|
||||
* @return [follower]
|
||||
*/
|
||||
operator fun plus(follower: MiraiLogger): MiraiLogger
|
||||
|
||||
@ -72,6 +118,29 @@ interface MiraiLogger {
|
||||
operator fun plusAssign(follower: MiraiLogger)
|
||||
}
|
||||
|
||||
/**
|
||||
* 不做任何事情的 logger, keep silent.
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object Silent : PlatformLogger() {
|
||||
override val identity: String? = null
|
||||
|
||||
override fun error0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun debug0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun warning0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun verbose0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun info0(any: Any?) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 平台基类.
|
||||
* 实现了 [follower] 的调用传递.
|
||||
@ -80,58 +149,66 @@ interface MiraiLogger {
|
||||
abstract class MiraiLoggerPlatformBase : MiraiLogger {
|
||||
final override var follower: MiraiLogger? = null
|
||||
|
||||
final override fun logInfo(any: Any?) = log(any)
|
||||
|
||||
final override fun log(e: Throwable) {
|
||||
log0(e)
|
||||
follower?.log(e)
|
||||
final override fun verbose(any: Any?) {
|
||||
follower?.verbose(any)
|
||||
verbose0(any)
|
||||
}
|
||||
|
||||
final override fun log(any: Any?) {
|
||||
log0(any)
|
||||
follower?.log(any)
|
||||
final override fun verbose(message: String?, e: Throwable?) {
|
||||
follower?.verbose(message, e)
|
||||
verbose0(message, e)
|
||||
}
|
||||
|
||||
final override fun logError(any: Any?) {
|
||||
logError0(any)
|
||||
follower?.logError(any)
|
||||
final override fun debug(any: Any?) {
|
||||
follower?.debug(any)
|
||||
debug0(any)
|
||||
}
|
||||
|
||||
override fun logError(e: Throwable) = log(e)
|
||||
|
||||
final override fun logDebug(any: Any?) {
|
||||
logDebug0(any)
|
||||
follower?.logDebug(any)
|
||||
final override fun debug(message: String?, e: Throwable?) {
|
||||
follower?.debug(message, e)
|
||||
debug0(message, e)
|
||||
}
|
||||
|
||||
final override fun logCyan(any: Any?) {
|
||||
logCyan0(any)
|
||||
follower?.logCyan(any)
|
||||
final override fun info(any: Any?) {
|
||||
follower?.info(any)
|
||||
info0(any)
|
||||
}
|
||||
|
||||
final override fun logPurple(any: Any?) {
|
||||
logPurple0(any)
|
||||
follower?.logPurple(any)
|
||||
final override fun info(message: String?, e: Throwable?) {
|
||||
follower?.info(message, e)
|
||||
info0(message, e)
|
||||
}
|
||||
|
||||
final override fun logGreen(any: Any?) {
|
||||
logGreen0(any)
|
||||
follower?.logGreen(any)
|
||||
final override fun warning(any: Any?) {
|
||||
follower?.warning(any)
|
||||
warning0(any)
|
||||
}
|
||||
|
||||
final override fun logBlue(any: Any?) {
|
||||
logBlue0(any)
|
||||
follower?.logBlue(any)
|
||||
final override fun warning(message: String?, e: Throwable?) {
|
||||
follower?.warning(message, e)
|
||||
warning0(message, e)
|
||||
}
|
||||
|
||||
protected abstract fun log0(e: Throwable)
|
||||
protected abstract fun log0(any: Any?)
|
||||
protected abstract fun logError0(any: Any?)
|
||||
protected abstract fun logDebug0(any: Any?)
|
||||
protected abstract fun logCyan0(any: Any?)
|
||||
protected abstract fun logPurple0(any: Any?)
|
||||
protected abstract fun logGreen0(any: Any?)
|
||||
protected abstract fun logBlue0(any: Any?)
|
||||
final override fun error(e: Any?) {
|
||||
follower?.error(e)
|
||||
error0(e)
|
||||
}
|
||||
|
||||
final override fun error(message: String?, e: Throwable?) {
|
||||
follower?.error(message, e)
|
||||
error0(message, e)
|
||||
}
|
||||
|
||||
protected abstract fun verbose0(any: Any?)
|
||||
protected abstract fun verbose0(message: String?, e: Throwable?)
|
||||
protected abstract fun debug0(any: Any?)
|
||||
protected abstract fun debug0(message: String?, e: Throwable?)
|
||||
protected abstract fun info0(any: Any?)
|
||||
protected abstract fun info0(message: String?, e: Throwable?)
|
||||
protected abstract fun warning0(any: Any?)
|
||||
protected abstract fun warning0(message: String?, e: Throwable?)
|
||||
protected abstract fun error0(any: Any?)
|
||||
protected abstract fun error0(message: String?, e: Throwable?)
|
||||
|
||||
override fun plus(follower: MiraiLogger): MiraiLogger {
|
||||
this.follower = follower
|
||||
@ -142,53 +219,3 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger {
|
||||
if (this.follower == null) this.follower = follower
|
||||
else this.follower!! += follower
|
||||
}
|
||||
|
||||
/**
|
||||
* 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器
|
||||
*/
|
||||
var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger() }
|
||||
|
||||
/**
|
||||
* 当前平台的默认的日志记录器.
|
||||
* 在 _JVM 控制台_ 端的实现为 [println]
|
||||
*
|
||||
* 不应该直接构造这个类的实例. 需使用 [DefaultLogger]
|
||||
*/
|
||||
expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = null) : MiraiLoggerPlatformBase
|
||||
|
||||
/**
|
||||
* 不作任何事情的 logger
|
||||
*/
|
||||
@Suppress("unused")
|
||||
object NoLogger : PlatformLogger() {
|
||||
override val identity: String? = null
|
||||
|
||||
override fun log0(e: Throwable) {
|
||||
}
|
||||
|
||||
override fun log0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logError0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logDebug0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logCyan0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logPurple0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logGreen0(any: Any?) {
|
||||
}
|
||||
|
||||
override fun logBlue0(any: Any?) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 在顶层日志记录这个异常
|
||||
*/
|
||||
fun Throwable.log() = MiraiLogger.log(this)
|
@ -0,0 +1,2 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
@ -30,11 +30,6 @@ expect fun crc32(key: ByteArray): Int
|
||||
*/
|
||||
expect fun md5(byteArray: ByteArray): ByteArray
|
||||
|
||||
/**
|
||||
* Hostname 解析 IP 地址
|
||||
*/
|
||||
expect fun solveIpAddress(hostname: String): String // TODO: 2019/10/28 是否有必要?
|
||||
|
||||
/**
|
||||
* Localhost 解析
|
||||
*/
|
||||
|
@ -7,29 +7,29 @@ import net.mamoe.mirai.utils.MiraiLogger
|
||||
|
||||
internal object DebugLogger : MiraiLogger by DefaultLogger("Packet Debug")
|
||||
|
||||
internal fun debugPrintln(any: Any?) = DebugLogger.logPurple(any)
|
||||
internal fun debugPrintln(any: Any?) = DebugLogger.warning(any)
|
||||
|
||||
internal fun ByteArray.debugPrint(name: String): ByteArray {
|
||||
DebugLogger.logPurple(name + "=" + this.toUHexString())
|
||||
DebugLogger.warning(name + "=" + this.toUHexString())
|
||||
return this
|
||||
}
|
||||
|
||||
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
|
||||
internal fun IoBuffer.debugPrint(name: String): IoBuffer {
|
||||
val readBytes = this.readBytes()
|
||||
DebugLogger.logPurple(name + "=" + readBytes.toUHexString())
|
||||
DebugLogger.warning(name + "=" + readBytes.toUHexString())
|
||||
return readBytes.toIoBuffer()
|
||||
}
|
||||
|
||||
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("discardExact(n)"))
|
||||
internal fun Input.debugDiscardExact(n: Number, name: String = "") {
|
||||
DebugLogger.logPurple("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
|
||||
DebugLogger.warning("Discarded($n) $name=" + this.readBytes(n.toInt()).toUHexString())
|
||||
}
|
||||
|
||||
@Deprecated("Low efficiency, only for debug purpose", ReplaceWith("this"))
|
||||
internal fun ByteReadPacket.debugPrint(name: String = ""): ByteReadPacket {
|
||||
val bytes = this.readBytes()
|
||||
DebugLogger.logPurple("ByteReadPacket $name=" + bytes.toUHexString())
|
||||
DebugLogger.warning("ByteReadPacket $name=" + bytes.toUHexString())
|
||||
return bytes.toReadPacket()
|
||||
}
|
||||
|
||||
@ -74,10 +74,4 @@ internal fun ByteArray.printColorizedHex(name: String = "", ignoreUntilFirstCons
|
||||
println(toUHexString().printColorize(ignoreUntilFirstConst))
|
||||
}
|
||||
println()
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO 这两个方法不应该 MPP
|
||||
*/
|
||||
expect fun printCompareHex(hex1s: String, hex2s: String): String
|
||||
expect fun String.printColorize(ignoreUntilFirstConst: Boolean = false): String
|
||||
}
|
@ -1,11 +1,79 @@
|
||||
@file:Suppress("ObjectPropertyName", "MayBeConstant", "NonAsciiCharacters", "SpellCheckingInspection")
|
||||
@file:Suppress("ObjectPropertyName", "MayBeConstant", "NonAsciiCharacters", "SpellCheckingInspection", "unused")
|
||||
|
||||
package net.mamoe.mirai.utils.io
|
||||
|
||||
import kotlinx.io.core.toByteArray
|
||||
import net.mamoe.mirai.network.protocol.tim.TIMProtocol
|
||||
import java.lang.reflect.Field
|
||||
import java.util.*
|
||||
import kotlin.math.max
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
/**
|
||||
* 匹配已知 hex 常量并格式化后打印到控制台.
|
||||
*
|
||||
* 低效率, 仅调试使用.
|
||||
*/
|
||||
internal fun String.printColorize(ignoreUntilFirstConst: Boolean): String = with(HexComparator) { colorize(ignoreUntilFirstConst) }
|
||||
|
||||
/**
|
||||
* 比较两个 hex 并格式化后打印到控制台.
|
||||
*
|
||||
* 低效率, 仅调试使用.
|
||||
*/
|
||||
internal fun printCompareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s, hex2s) }
|
||||
|
||||
data class NamedHexElement(
|
||||
val name: String,
|
||||
val value: String
|
||||
)
|
||||
|
||||
/**
|
||||
* 初始化用于匹配的 Hex 列表
|
||||
*/
|
||||
private fun LinkedHashSet<NamedHexElement>.initConstFileds() {
|
||||
listOf(
|
||||
TestConsts,
|
||||
TIMProtocol,
|
||||
PacketIds
|
||||
).forEach { obj ->
|
||||
obj::class.members.filterIsInstance<KProperty<*>>().forEach { property ->
|
||||
add(NamedHexElement(property.name, property.getter.call().toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private object TestConsts {
|
||||
val NIU_BI = "牛逼".toByteArray().toUHexString()
|
||||
val _1994701021 = 1994701021.toUHexString(" ")
|
||||
val _1040400290 = 1040400290.toUHexString(" ")
|
||||
val _580266363 = 580266363.toUHexString(" ")
|
||||
|
||||
val _1040400290_ = "3E 03 3F A2"
|
||||
val _1994701021_ = "76 E4 B8 DD"
|
||||
val _jiahua_ = "B1 89 BE 09"
|
||||
val _Him188moe_ = "Him188moe".toByteArray().toUHexString()
|
||||
val 发图片2 = "发图片2".toByteArray().toUHexString()
|
||||
val 发图片群 = "发图片群".toByteArray().toUHexString()
|
||||
val 发图片 = "发图片".toByteArray().toUHexString()
|
||||
val 群 = "群".toByteArray().toUHexString()
|
||||
val 你好 = "你好".toByteArray().toUHexString()
|
||||
|
||||
val MESSAGE_TAIL_10404 =
|
||||
"0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"
|
||||
.replace(" ", " ")
|
||||
|
||||
val FONT_10404 = "E5 BE AE E8 BD AF E9 9B 85 E9 BB 91"
|
||||
|
||||
val varint580266363 = "FB D2 D8 94 02"
|
||||
val varint1040400290 = "A2 FF 8C F0 03"
|
||||
var varint1994701021 = "DD F1 92 B7 07"
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
private object PacketIds {
|
||||
val heartbeat = "00 58"
|
||||
val friendmsgsend = "00 CD"
|
||||
val friendmsgevent = "00 CE"
|
||||
}
|
||||
|
||||
/**
|
||||
* Hex 比较器, 并着色已知常量
|
||||
@ -16,7 +84,7 @@ import kotlin.math.max
|
||||
* @author NaturalHG
|
||||
* @author Him188moe
|
||||
*/
|
||||
internal object HexComparator {
|
||||
private object HexComparator {
|
||||
|
||||
private val RED = "\u001b[31m"
|
||||
private val GREEN = "\u001b[33m"
|
||||
@ -24,49 +92,8 @@ internal object HexComparator {
|
||||
private val BLUE = "\u001b[34m"
|
||||
|
||||
@Suppress("unused")
|
||||
class ConstMatcher constructor(hex: String) {
|
||||
private val matches = LinkedList<Match>()
|
||||
|
||||
object TestConsts {
|
||||
val NIU_BI = "牛逼".toByteArray().toUHexString()
|
||||
val _1994701021 = 1994701021.toUHexString(" ")
|
||||
val _1040400290 = 1040400290.toUHexString(" ")
|
||||
val _580266363 = 580266363.toUHexString(" ")
|
||||
|
||||
val _1040400290_ = "3E 03 3F A2"
|
||||
val _1994701021_ = "76 E4 B8 DD"
|
||||
val _jiahua_ = "B1 89 BE 09"
|
||||
val _Him188moe_ = "Him188moe".toByteArray().toUHexString()
|
||||
val 发图片2 = "发图片2".toByteArray().toUHexString()
|
||||
val 发图片群 = "发图片群".toByteArray().toUHexString()
|
||||
val 发图片 = "发图片".toByteArray().toUHexString()
|
||||
val 群 = "群".toByteArray().toUHexString()
|
||||
val 你好 = "你好".toByteArray().toUHexString()
|
||||
|
||||
val MESSAGE_TAIL_10404 = "0E 00 07 01 00 04 00 00 00 09 19 00 18 01 00 15 AA 02 12 9A 01 0F 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00"
|
||||
.replace(" ", " ")
|
||||
|
||||
val FONT_10404 = "E5 BE AE E8 BD AF E9 9B 85 E9 BB 91"
|
||||
|
||||
val varint580266363 = "FB D2 D8 94 02"
|
||||
val varint1040400290 = "A2 FF 8C F0 03"
|
||||
var varint1994701021 = "DD F1 92 B7 07"
|
||||
}
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
object PacketIds {
|
||||
val heartbeat = "00 58"
|
||||
val friendmsgsend = "00 CD"
|
||||
val friendmsgevent = "00 CE"
|
||||
}
|
||||
|
||||
init {
|
||||
CONST_FIELDS.forEach { field ->
|
||||
for (match in match(hex, field)) {
|
||||
matches.add(Match(match, field.name))
|
||||
}
|
||||
}
|
||||
}
|
||||
private class ConstMatcher constructor(hex: String) {
|
||||
private val matches = linkedSetOf<Match>()
|
||||
|
||||
fun getMatchedConstName(hexNumber: Int): String? {
|
||||
for (match in this.matches) {
|
||||
@ -79,41 +106,36 @@ internal object HexComparator {
|
||||
|
||||
private class Match internal constructor(val range: IntRange, val constName: String)
|
||||
|
||||
companion object {
|
||||
private val CONST_FIELDS: List<Field> = listOf(
|
||||
TestConsts::class.java,
|
||||
TIMProtocol::class.java,
|
||||
PacketIds::class.java
|
||||
).map { it.declaredFields }.flatMap { fields ->
|
||||
fields.map { field ->
|
||||
field.trySetAccessible()
|
||||
field
|
||||
init {
|
||||
TIMProtocol::class.members.filterIsInstance<KProperty<*>>().forEach {
|
||||
for (match in match(hex, it.getter.call().toString())) {
|
||||
matches.add(Match(match, it.getter.call().toString()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun match(hex: String, field: Field): List<IntRange> {
|
||||
companion object {
|
||||
val CONST_FIELDS: Set<NamedHexElement> = linkedSetOf<NamedHexElement>().apply { initConstFileds() }
|
||||
}
|
||||
|
||||
private fun match(hex: String, field: String): Set<IntRange> {
|
||||
val constValue: String
|
||||
try {
|
||||
constValue = (field.get(null) as String).trim { it <= ' ' }
|
||||
constValue = field.trim { it <= ' ' }
|
||||
if (constValue.length / 3 <= 3) {//Minimum numbers of const hex bytes
|
||||
return LinkedList()
|
||||
return linkedSetOf()
|
||||
}
|
||||
} catch (e: IllegalAccessException) {
|
||||
throw RuntimeException(e)
|
||||
} catch (ignored: ClassCastException) {
|
||||
return LinkedList()
|
||||
return linkedSetOf()
|
||||
}
|
||||
|
||||
return object : LinkedList<IntRange>() {
|
||||
init {
|
||||
var index = -1
|
||||
index = hex.indexOf(constValue, index + 1)
|
||||
while (index != -1) {
|
||||
add(IntRange(index / 3, (index + constValue.length) / 3))
|
||||
return mutableSetOf<IntRange>().apply {
|
||||
var index = -1
|
||||
index = hex.indexOf(constValue, index + 1)
|
||||
while (index != -1) {
|
||||
add(IntRange(index / 3, (index + constValue.length) / 3))
|
||||
|
||||
index = hex.indexOf(constValue, index + 1)
|
||||
}
|
||||
index = hex.indexOf(constValue, index + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -222,12 +244,12 @@ internal object HexComparator {
|
||||
}
|
||||
|
||||
return builder.append(" ").append(dif).append(" 个不同").append("\n")
|
||||
.append(numberLine).append("\n")
|
||||
.append(hex1ConstName).append("\n")
|
||||
.append(hex1b).append("\n")
|
||||
.append(hex2b).append("\n")
|
||||
.append(hex2ConstName).append("\n")
|
||||
.toString()
|
||||
.append(numberLine).append("\n")
|
||||
.append(hex1ConstName).append("\n")
|
||||
.append(hex1b).append("\n")
|
||||
.append(hex2b).append("\n")
|
||||
.append(hex2ConstName).append("\n")
|
||||
.toString()
|
||||
|
||||
|
||||
}
|
||||
@ -267,15 +289,15 @@ internal object HexComparator {
|
||||
}
|
||||
|
||||
return builder.append("\n")
|
||||
.append(numberLine).append("\n")
|
||||
.append(if (firstConst == null) hex1ConstName else {
|
||||
with(hex1ConstName) {
|
||||
val index = indexOf(firstConst)
|
||||
if (index == -1) toString() else " " + substring(index, length)
|
||||
}
|
||||
}).append("\n")
|
||||
.append(hex1b).append("\n")
|
||||
.toString()
|
||||
.append(numberLine).append("\n")
|
||||
.append(if (firstConst == null) hex1ConstName else {
|
||||
with(hex1ConstName) {
|
||||
val index = indexOf(firstConst)
|
||||
if (index == -1) toString() else " " + substring(index, length)
|
||||
}
|
||||
}).append("\n")
|
||||
.append(hex1b).append("\n")
|
||||
.toString()
|
||||
}
|
||||
|
||||
|
||||
@ -288,7 +310,4 @@ internal object HexComparator {
|
||||
} else number.toString()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
actual fun String.printColorize(ignoreUntilFirstConst: Boolean): String = with(HexComparator) { colorize(ignoreUntilFirstConst) }
|
||||
actual fun printCompareHex(hex1s: String, hex2s: String): String = with(HexComparator) { compare(hex1s, hex2s) }
|
||||
}
|
@ -47,7 +47,7 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
|
||||
135 -> {//包数据错误. 目前怀疑是 tlv0006
|
||||
this.readRemainingBytes().cutTail(1).decryptBy(TIMProtocol.shareKey).read {
|
||||
discardExact(51)
|
||||
MiraiLogger.logError("Internal logError: " + readLVString())//抱歉,请重新输入密码。
|
||||
MiraiLogger.error("Internal error: " + readLVString())//抱歉,请重新输入密码。
|
||||
}
|
||||
|
||||
LoginResult.INTERNAL_ERROR
|
||||
@ -63,8 +63,8 @@ fun ByteReadPacket.parseServerPacket(size: Int): ServerPacket {
|
||||
else -> LoginResult.UNKNOWN
|
||||
/*
|
||||
//unknown
|
||||
63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown logError)")
|
||||
351 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown logError)")
|
||||
63 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
|
||||
351 -> throw IllegalArgumentException(bytes.size.toString() + " (Unknown error)")
|
||||
|
||||
else -> throw IllegalArgumentException(bytes.size.toString())*/
|
||||
}, this).applySequence(sequenceId)
|
||||
|
@ -22,17 +22,17 @@ import kotlin.math.min
|
||||
internal actual suspend fun solveCaptcha(captchaBuffer: IoBuffer): String? = captchaLock.withLock {
|
||||
val captcha = captchaBuffer.readBytes()
|
||||
withContext(Dispatchers.IO) {
|
||||
MiraiLogger.logCyan(ImageIO.read(captcha.inputStream()).createCharImg())
|
||||
MiraiLogger.verbose(ImageIO.read(captcha.inputStream()).createCharImg())
|
||||
}
|
||||
MiraiLogger.logCyan("需要验证码登录, 验证码为 4 字母")
|
||||
MiraiLogger.verbose("需要验证码登录, 验证码为 4 字母")
|
||||
try {
|
||||
File(System.getProperty("user.dir") + "/temp/Captcha.png")
|
||||
.let { withContext(Dispatchers.IO) { it.createNewFile(); it.writeBytes(captcha) } }
|
||||
MiraiLogger.logCyan("若看不清字符图片, 请查看 Mirai 目录下 /temp/Captcha.png")
|
||||
MiraiLogger.verbose("若看不清字符图片, 请查看 Mirai 目录下 /temp/Captcha.png")
|
||||
} catch (e: Exception) {
|
||||
MiraiLogger.logCyan("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
|
||||
MiraiLogger.verbose("无法写出验证码文件(${e.message}), 请尝试查看以上字符图片")
|
||||
}
|
||||
MiraiLogger.logCyan("若要更换验证码, 请直接回车")
|
||||
MiraiLogger.verbose("若要更换验证码, 请直接回车")
|
||||
readLine()?.takeUnless { it.isEmpty() || it.length != 4 }
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
package net.mamoe.mirai.utils
|
||||
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.PrintStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
@ -11,21 +13,41 @@ actual typealias PlatformLogger = Console
|
||||
open class Console @JvmOverloads internal constructor(
|
||||
override val identity: String? = null
|
||||
) : MiraiLoggerPlatformBase() {
|
||||
override fun logGreen0(any: Any?) = println(any.toString(), LoggerTextFormat.GREEN)
|
||||
override fun logPurple0(any: Any?) = println(any.toString(), LoggerTextFormat.LIGHT_PURPLE)
|
||||
override fun logBlue0(any: Any?) = println(any.toString(), LoggerTextFormat.BLUE)
|
||||
override fun logCyan0(any: Any?) = println(any.toString(), LoggerTextFormat.LIGHT_CYAN)
|
||||
override fun logError0(any: Any?) = println(any.toString(), LoggerTextFormat.RED)
|
||||
override fun log0(e: Throwable) = e.printStackTrace()
|
||||
override fun log0(any: Any?) = println(any.toString(), LoggerTextFormat.WHITE)
|
||||
override fun logDebug0(any: Any?) {
|
||||
if (DEBUGGING) {
|
||||
println(any.toString(), LoggerTextFormat.YELLOW)
|
||||
}
|
||||
override fun verbose0(any: Any?) = println(any.toString(), LoggerTextFormat.LIGHT_GRAY)
|
||||
override fun verbose0(message: String?, e: Throwable?) {
|
||||
verbose(message.toString())
|
||||
e?.printStackTrace()
|
||||
}
|
||||
|
||||
override fun info0(any: Any?) = println(any.toString(), LoggerTextFormat.GREEN)
|
||||
override fun info0(message: String?, e: Throwable?) {
|
||||
info(message.toString())
|
||||
e?.printStackTrace()
|
||||
}
|
||||
|
||||
override fun warning0(any: Any?) = println(any.toString(), LoggerTextFormat.YELLOW)
|
||||
override fun warning0(message: String?, e: Throwable?) {
|
||||
warning(message.toString())
|
||||
e?.printStackTrace()
|
||||
}
|
||||
|
||||
override fun error0(any: Any?) = println(any.toString(), LoggerTextFormat.RED)
|
||||
override fun error0(message: String?, e: Throwable?) {
|
||||
error(message.toString())
|
||||
e?.printStackTrace()
|
||||
}
|
||||
|
||||
override fun debug0(any: Any?) {
|
||||
println(any.toString(), LoggerTextFormat.CYAN)
|
||||
}
|
||||
|
||||
override fun debug0(message: String?, e: Throwable?) {
|
||||
debug(message.toString())
|
||||
e?.printStackTrace()
|
||||
}
|
||||
|
||||
private fun println(value: String?, color: LoggerTextFormat) {
|
||||
val time = SimpleDateFormat("HH:mm:ss").format(Date())
|
||||
val time = SimpleDateFormat("HH:mm:ss", Locale.SIMPLIFIED_CHINESE).format(Date())
|
||||
|
||||
if (identity == null) {
|
||||
println("$color$time : $value")
|
||||
@ -35,8 +57,6 @@ open class Console @JvmOverloads internal constructor(
|
||||
}
|
||||
}
|
||||
|
||||
private val DEBUGGING: Boolean by lazy {
|
||||
//todo 添加环境变量检测
|
||||
//avoid inspections
|
||||
true
|
||||
}
|
||||
@Suppress("unused")
|
||||
val Throwable.stacktraceString: String
|
||||
get() = ByteArrayOutputStream().also { printStackTrace(PrintStream(it)) }.toString()
|
@ -19,10 +19,6 @@ import java.util.zip.CRC32
|
||||
|
||||
actual val deviceName: String = InetAddress.getLocalHost().hostName
|
||||
|
||||
/*
|
||||
* TODO: we may use libraries that provide these functions
|
||||
*/
|
||||
|
||||
actual fun crc32(key: ByteArray): Int = CRC32().let { it.update(key); it.value.toInt() }
|
||||
|
||||
actual fun md5(byteArray: ByteArray): ByteArray = MessageDigest.getInstance("MD5").digest(byteArray)
|
||||
@ -55,7 +51,7 @@ fun DataInput.md5(): ByteArray {
|
||||
return digest.digest()
|
||||
}
|
||||
|
||||
actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(hostname).hostAddress
|
||||
//actual fun solveIpAddress(hostname: String): String = InetAddress.getByName(hostname).hostAddress
|
||||
|
||||
actual fun localIpAddress(): String = InetAddress.getLocalHost().hostAddress
|
||||
|
||||
|
0
mirai-core/src/jvmTest/kotlin/Run.kt
Normal file
0
mirai-core/src/jvmTest/kotlin/Run.kt
Normal file
Loading…
Reference in New Issue
Block a user