Commit ae9d2bca authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

# Conflicts:
#	mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt
parents 4ae589bb 63a4d5f3
...@@ -104,7 +104,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -104,7 +104,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
} }
override suspend fun init() { override suspend fun init() {
delay(5000) // delay(5000)
this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> { this@QQAndroidBotNetworkHandler.subscribeAlways<ForceOfflineEvent> {
if (this@QQAndroidBotNetworkHandler.bot == this.bot) { if (this@QQAndroidBotNetworkHandler.bot == this.bot) {
...@@ -126,10 +126,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -126,10 +126,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
20, 20,
0, 0,
0 0
).sendAndExpect<FriendList.GetFriendGroupList.Response>( ).sendAndExpect<FriendList.GetFriendGroupList.Response>(timeoutMillis = 1000)
timeoutMillis = 8000,
retry = 5
)
totalFriendCount = data.totalFriendCount totalFriendCount = data.totalFriendCount
data.friendList.forEach { data.friendList.forEach {
...@@ -153,10 +150,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -153,10 +150,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
bot.logger.info("开始加载组列表") bot.logger.info("开始加载组列表")
val troopData = FriendList.GetTroopListSimplify( val troopData = FriendList.GetTroopListSimplify(
bot.client bot.client
).sendAndExpect<FriendList.GetTroopListSimplify.Response>(10000) ).sendAndExpect<FriendList.GetTroopListSimplify.Response>(timeoutMillis = 1000)
println(troopData.groups.contentToString()) println(troopData.contentToString())
bot.logger.info("加载组列表成功")
} catch (e: Exception) { } catch (e: Exception) {
bot.logger.info("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") bot.logger.info("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表")
} }
...@@ -240,7 +235,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -240,7 +235,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
bot.logger.info("Received packet: $packet") bot.logger.info("Received packet: $packet")
packetFactory?.run { packetFactory?.run {
bot.handle(packet) when (this) {
is OutgoingPacketFactory<P> -> bot.handle(packet)
is IncomingPacketFactory<P> -> bot.handle(packet, sequenceId)?.sendWithoutExpect()
}
} }
} }
......
# QQAndroid Protocol
## Overview
Note: `head` and `body` functions do nothing. They just work as
notations
PseudoCode:
```
OutgoingPacket {
int head.size + body.size + 4
head {
int 0x0A
byte 0x02
int extra data size + 4
byte[] extra data // initially={}
byte 0
int uinAccount.length + 4
byte[] uinAccount // =qqNumber.toString()
}
body { // encrypted by `ByteArray(16)` when login, after which by sessionKey
SSOPacket {
int head.size + 4
head {
int sequenceId
int subAppId
int subAppId
hex "01 00 00 00 00 00 00 00 00 00 01 00" // unknown values
int extraData.size + 4
byte[] extraData // empty when login
int commandName.length + 4
byte[] commandName // e.g. wtlogin.login
int 4 + 4
int 0x02B05B8B
int imei.length + 4
byte[] imei
int 0 + 4
short ksid.length + 2
byte[] ksid
int 0 + 4
}
int body.size + 4
body {
OicqRequestPacket {
head {
byte 2 // head flag
short 27 + 2 + remaining.length
ushort client.protocolVersion // const 8001
ushort commandId // e.g. 0x0810
ushort 0x0001
uint client.uin
byte 3 // const
ubyte encryptMethod.value // [EncryptMethod]
byte 0 // const
int 2 // const
int client.appClientVersion
int 0 // const
}
body {
// only write one of the following two structures!!
// if encryption method is ECDH
EncryptionMethodECDH {
head {
byte 1
byte 1
byte[] privateKey // random key
short 258
short [ECDH.publicKey].size // always 49
byte[] [ECDH.publicKey]
}
body {
// real body
}
}
// if encryption method is SessionKey
EncryptionMethodSessionKey {
head {
byte 1
byte if (currentLoginState == 2) 3 else 2
fully key
short 258 // const
short 0
}
body {
// real body
}
}
}
tail {
byte 3 // tail flag
}
}
}
}
}
}
```
## Packet bodies
### LoginPacket - SubCommand 9
**TO BE UPDATED**
PseudoCode:
```
short 9 // subCommand
tlvList {
}
```
...@@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image ...@@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.writeFully import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
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.ProtoBufWithNullableSupport
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq import net.mamoe.mirai.qqandroid.network.protocol.data.proto.GetImgUrlReq
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
internal object ImageDownPacket : PacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") { internal object ImageDownPacket : OutgoingPacketFactory<ImageDownPacket.ImageDownPacketResponse>("LongConn.OffPicDown") {
operator fun invoke(client: QQAndroidClient, req: GetImgUrlReq): OutgoingPacket { operator fun invoke(client: QQAndroidClient, req: GetImgUrlReq): OutgoingPacket {
// TODO: 2020/1/24 测试: bodyType, subAppId // TODO: 2020/1/24 测试: bodyType, subAppId
......
...@@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image ...@@ -2,18 +2,18 @@ package net.mamoe.mirai.qqandroid.network.protocol.packet.chat.image
import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.ByteReadPacket
import kotlinx.io.core.writeFully import kotlinx.io.core.writeFully
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
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.ProtoBufWithNullableSupport
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Cmd0x352Packet
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.UploadImgReq import net.mamoe.mirai.qqandroid.network.protocol.data.proto.UploadImgReq
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
internal object ImageUpPacket : PacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") { internal object ImageUpPacket : OutgoingPacketFactory<ImageUpPacket.ImageUpPacketResponse>("LongConn.OffPicUp") {
operator fun invoke(client: QQAndroidClient, req: UploadImgReq): OutgoingPacket { operator fun invoke(client: QQAndroidClient, req: UploadImgReq): OutgoingPacket {
// TODO: 2020/1/24 测试: bodyType, subAppId // TODO: 2020/1/24 测试: bodyType, subAppId
......
...@@ -19,9 +19,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody ...@@ -19,9 +19,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgComm
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgSvc
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SyncCookie import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SyncCookie
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket
import net.mamoe.mirai.qqandroid.utils.toMessageChain import net.mamoe.mirai.qqandroid.utils.toMessageChain
import net.mamoe.mirai.qqandroid.utils.toRichTextElems import net.mamoe.mirai.qqandroid.utils.toRichTextElems
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
...@@ -36,19 +34,18 @@ internal class MessageSvc { ...@@ -36,19 +34,18 @@ internal class MessageSvc {
/** /**
* 告知要刷新好友消息 * 告知要刷新好友消息
*/ */
internal object PushNotify : PacketFactory<RequestPushNotify>("MessageSvc.PushNotify") { internal object PushNotify : IncomingPacketFactory<RequestPushNotify>("MessageSvc.PushNotify") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): RequestPushNotify { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): RequestPushNotify {
discardExact(8) discardExact(8)
return decodeUniPacket(RequestPushNotify.serializer()) return decodeUniPacket(RequestPushNotify.serializer())
} }
override suspend fun QQAndroidBot.handle(packet: RequestPushNotify) { override suspend fun QQAndroidBot.handle(packet: RequestPushNotify, sequenceId: Int): OutgoingPacket? {
network.run { network.run {
PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0).sendAndExpect<MultiPacket<FriendMessage>>() return PbGetMsg(client, MsgSvc.SyncFlag.START, packet.stMsgInfo?.uMsgTime ?: 0)
} }
} }
} }
...@@ -56,7 +53,7 @@ internal class MessageSvc { ...@@ -56,7 +53,7 @@ internal class MessageSvc {
* 获取好友消息和消息记录 * 获取好友消息和消息记录
*/ */
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
internal object PbGetMsg : PacketFactory<PbGetMsg.Response>("MessageSvc.PbGetMsg") { internal object PbGetMsg : OutgoingPacketFactory<PbGetMsg.Response>("MessageSvc.PbGetMsg") {
val EXTRA_DATA = val EXTRA_DATA =
"08 00 12 33 6D 6F 64 65 6C 3A 78 69 67 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes() "08 00 12 33 6D 6F 64 65 6C 3A 78 69 67 6F 6D 69 20 36 3B 6F 73 3A 32 32 3B 76 65 72 73 69 6F 6E 3A 76 32 6D 61 6E 3A 78 69 61 6F 6D 69 73 79 73 3A 4C 4D 59 34 38 5A 18 E4 E1 A4 FF FE 2D 20 E9 E1 A4 FF FE 2D 28 A8 E1 A4 FF FE 2D 30 99 E1 A4 FF FE 2D".hexToBytes()
...@@ -81,7 +78,7 @@ internal class MessageSvc { ...@@ -81,7 +78,7 @@ internal class MessageSvc {
syncFlag = syncFlag, syncFlag = syncFlag,
// serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY, // serverBuf = from.serverBuf ?: EMPTY_BYTE_ARRAY,
syncCookie = client.c2cMessageSync.syncCookie syncCookie = client.c2cMessageSync.syncCookie
?: SyncCookie(time = Random.nextLong()).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it }, ?: SyncCookie(time = msgTime + client.timeDifference).toByteArray(SyncCookie.serializer())//.also { client.c2cMessageSync.syncCookie = it },
// syncFlag = client.c2cMessageSync.syncFlag, // syncFlag = client.c2cMessageSync.syncFlag,
//msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf, //msgCtrlBuf = client.c2cMessageSync.msgCtrlBuf,
//pubaccountCookie = client.c2cMessageSync.pubAccountCookie //pubaccountCookie = client.c2cMessageSync.pubAccountCookie
...@@ -160,7 +157,7 @@ internal class MessageSvc { ...@@ -160,7 +157,7 @@ internal class MessageSvc {
/** /**
* 被挤下线 * 被挤下线
*/ */
internal object PushForceOffline : PacketFactory<ForceOfflineEvent>("MessageSvc.PushForceOffline") { internal object PushForceOffline : OutgoingPacketFactory<ForceOfflineEvent>("MessageSvc.PushForceOffline") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ForceOfflineEvent { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): ForceOfflineEvent {
discardExact(4) discardExact(4)
val struct = this.decodeUniPacket(RequestPushForceOffline.serializer()) val struct = this.decodeUniPacket(RequestPushForceOffline.serializer())
...@@ -168,7 +165,7 @@ internal class MessageSvc { ...@@ -168,7 +165,7 @@ internal class MessageSvc {
} }
} }
internal object PbSendMsg : PacketFactory<PbSendMsg.Response>("MessageSvc.PbSendMsg") { internal object PbSendMsg : OutgoingPacketFactory<PbSendMsg.Response>("MessageSvc.PbSendMsg") {
sealed class Response : Packet { sealed class Response : Packet {
object SUCCESS : Response() { object SUCCESS : Response() {
override fun toString(): String = "MessageSvc.PbSendMsg.Response.SUCCESS" override fun toString(): String = "MessageSvc.PbSendMsg.Response.SUCCESS"
...@@ -230,9 +227,9 @@ internal class MessageSvc { ...@@ -230,9 +227,9 @@ internal class MessageSvc {
elems = message.toRichTextElems() elems = message.toRichTextElems()
) )
), ),
msgSeq = client.atomicNextMessageSequenceId() msgSeq = client.atomicNextMessageSequenceId(),
// msgRand = 123 //msgRand = Random.nextInt() and 0x7FFF,
//syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: syncCookie = client.c2cMessageSync.syncCookie?.takeIf { it.isNotEmpty() } ?: EMPTY_BYTE_ARRAY
//SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer()) //SyncCookie(currentTimeSeconds, Random.nextLong().absoluteValue, Random.nextLong().absoluteValue).toByteArray(SyncCookie.serializer())
// msgVia = 1 // msgVia = 1
) )
......
...@@ -11,7 +11,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot ...@@ -11,7 +11,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport import net.mamoe.mirai.qqandroid.io.serialization.ProtoBufWithNullableSupport
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush import net.mamoe.mirai.qqandroid.network.protocol.data.proto.MsgOnlinePush
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.utils.toMessageChain import net.mamoe.mirai.qqandroid.utils.toMessageChain
...@@ -19,9 +19,9 @@ internal class OnlinePush { ...@@ -19,9 +19,9 @@ internal class OnlinePush {
/** /**
* 接受群消息 * 接受群消息
*/ */
internal object PbPushGroupMsg : PacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") { internal object PbPushGroupMsg : IncomingPacketFactory<GroupMessage>("OnlinePush.PbPushGroupMsg") {
@UseExperimental(ExperimentalStdlibApi::class) @UseExperimental(ExperimentalStdlibApi::class)
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GroupMessage { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): GroupMessage {
// 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00 // 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00
discardExact(4) discardExact(4)
val pbPushMsg = ProtoBufWithNullableSupport.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes()) val pbPushMsg = ProtoBufWithNullableSupport.load(MsgOnlinePush.PbPushMsg.serializer(), readBytes())
...@@ -48,9 +48,5 @@ internal class OnlinePush { ...@@ -48,9 +48,5 @@ internal class OnlinePush {
} }
) )
} }
override suspend fun QQAndroidBot.handle(packet: GroupMessage) {
}
} }
} }
\ No newline at end of file
...@@ -14,7 +14,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.* ...@@ -14,7 +14,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.*
import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Vec0xd50 import net.mamoe.mirai.qqandroid.network.protocol.data.proto.Vec0xd50
import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY import net.mamoe.mirai.qqandroid.network.protocol.packet.EMPTY_BYTE_ARRAY
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory 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.io.discardExact import net.mamoe.mirai.utils.io.discardExact
...@@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.discardExact ...@@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.discardExact
internal class FriendList { internal class FriendList {
internal object GetTroopMemberList : internal object GetTroopMemberList :
PacketFactory<GetTroopMemberList.Response>("friendlist.GetTroopMemberListReq") { OutgoingPacketFactory<GetTroopMemberList.Response>("friendlist.GetTroopMemberListReq") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopMemberList.Response { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopMemberList.Response {
TODO() TODO()
} }
...@@ -65,7 +65,7 @@ internal class FriendList { ...@@ -65,7 +65,7 @@ internal class FriendList {
} }
internal object GetTroopListSimplify : internal object GetTroopListSimplify :
PacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") { OutgoingPacketFactory<GetTroopListSimplify.Response>("friendlist.GetTroopListReqV2") {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopListSimplify.Response { override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): GetTroopListSimplify.Response {
val res = this.decodeUniPacket(GetTroopListRespV2.serializer()) val res = this.decodeUniPacket(GetTroopListRespV2.serializer())
return Response(res.vecTroopList.orEmpty()) return Response(res.vecTroopList.orEmpty())
...@@ -109,7 +109,8 @@ internal class FriendList { ...@@ -109,7 +109,8 @@ internal class FriendList {
} }
} }
} }
internal object GetFriendGroupList : PacketFactory<GetFriendGroupList.Response>("friendlist.getFriendGroupList") {
internal object GetFriendGroupList : OutgoingPacketFactory<GetFriendGroupList.Response>("friendlist.getFriendGroupList") {
class Response( class Response(
val totalFriendCount: Short, val totalFriendCount: Short,
......
...@@ -9,27 +9,27 @@ import net.mamoe.mirai.qqandroid.io.serialization.jceRequestSBuffer ...@@ -9,27 +9,27 @@ import net.mamoe.mirai.qqandroid.io.serialization.jceRequestSBuffer
import net.mamoe.mirai.qqandroid.io.serialization.writeJceStruct import net.mamoe.mirai.qqandroid.io.serialization.writeJceStruct
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushResp import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushResp
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.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildOutgoingUniPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.utils.cryptor.contentToString import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket
import net.mamoe.mirai.utils.io.debugPrintThis
import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushReq as PushReqJceStruct import net.mamoe.mirai.qqandroid.network.protocol.data.jce.PushReq as PushReqJceStruct
internal class ConfigPushSvc { internal class ConfigPushSvc {
object PushReq : PacketFactory<PushReqJceStruct>("ConfigPushSvc.PushReq") { object PushReq : IncomingPacketFactory<PushReqJceStruct>(
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): PushReqJceStruct { receivingCommandName = "ConfigPushSvc.PushReq",
responseCommandName = "ConfigPushSvc.PushResp"
) {
override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): PushReqJceStruct {
discardExact(4) discardExact(4)
val pushReq = decodeUniPacket(PushReqJceStruct.serializer()) return decodeUniPacket(PushReqJceStruct.serializer())
println(pushReq.contentToString())
return pushReq
} }
override suspend fun QQAndroidBot.handle(packet: PushReqJceStruct) { override suspend fun QQAndroidBot.handle(packet: PushReqJceStruct, sequenceId: Int): OutgoingPacket? {
network.run { return network.run {
buildOutgoingUniPacket( buildResponseUniPacket(
client, client,
sequenceId = client.configPushSvcPushReqSequenceId.also { println("configPushSvcPushReqSequenceId=${client.configPushSvcPushReqSequenceId}") }, sequenceId = client.configPushSvcPushReqSequenceId,
commandName = "ConfigPushSvc.PushResp", commandName = "ConfigPushSvc.PushResp",
name = "ConfigPushSvc.PushResp" name = "ConfigPushSvc.PushResp"
) { ) {
...@@ -52,8 +52,8 @@ internal class ConfigPushSvc { ...@@ -52,8 +52,8 @@ internal class ConfigPushSvc {
), ),
charset = JceCharset.UTF8 charset = JceCharset.UTF8
) )
writePacket(this.build().debugPrintThis()) // writePacket(this.build().debugPrintThis())
}.sendWithoutExpect() }
} }
} }
} }
......
...@@ -11,16 +11,19 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.* ...@@ -11,16 +11,19 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.utils.GuidSource import net.mamoe.mirai.qqandroid.utils.GuidSource
import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag import net.mamoe.mirai.qqandroid.utils.MacOrAndroidIdChangeFlag
import net.mamoe.mirai.qqandroid.utils.guidFlag import net.mamoe.mirai.qqandroid.utils.guidFlag
import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.MiraiDebugAPI
import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.cryptor.decryptBy import net.mamoe.mirai.utils.cryptor.decryptBy
import net.mamoe.mirai.utils.currentTimeSeconds
import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.*
import net.mamoe.mirai.utils.io.discardExact import net.mamoe.mirai.utils.io.discardExact
import net.mamoe.mirai.utils.md5
/** /**
* OicqRequest * OicqRequest
*/ */
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login") { internal object LoginPacket : OutgoingPacketFactory<LoginPacket.LoginPacketResponse>("wtlogin.login") {
/** /**
* 提交验证码 * 提交验证码
...@@ -686,7 +689,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt ...@@ -686,7 +689,7 @@ internal object LoginPacket : PacketFactory<LoginPacket.LoginPacketResponse>("wt
*/ */
private fun QQAndroidClient.analysisTlv130(t130: ByteArray) = t130.read { private fun QQAndroidClient.analysisTlv130(t130: ByteArray) = t130.read {
discardExact(2) discardExact(2)
timeDifference = readUInt().toLong() - currentTimeMillis timeDifference = readUInt().toLong() - currentTimeSeconds
ipFromT149 = readBytes(4) ipFromT149 = readBytes(4)
} }
......
...@@ -10,7 +10,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient ...@@ -10,7 +10,7 @@ import net.mamoe.mirai.qqandroid.network.QQAndroidClient
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.SvcReqRegister import net.mamoe.mirai.qqandroid.network.protocol.data.jce.SvcReqRegister
import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacketFactory
import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildLoginOutgoingPacket
import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769 import net.mamoe.mirai.qqandroid.network.protocol.packet.oidb.oidb0x769.Oidb0x769
import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.writeSsoPacket
...@@ -33,7 +33,7 @@ internal enum class RegPushReason { ...@@ -33,7 +33,7 @@ internal enum class RegPushReason {
} }
internal class StatSvc { internal class StatSvc {
internal object Register : PacketFactory<Register.Response>("StatSvc.register") { internal object Register : OutgoingPacketFactory<Register.Response>("StatSvc.register") {
internal object Response : Packet { internal object Response : Packet {
override fun toString(): String = "Response(StatSvc.register)" override fun toString(): String = "Response(StatSvc.register)"
......
...@@ -7,7 +7,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot ...@@ -7,7 +7,7 @@ import net.mamoe.mirai.qqandroid.QQAndroidBot
import net.mamoe.mirai.qqandroid.network.QQAndroidClient import net.mamoe.mirai.qqandroid.network.QQAndroidClient
import net.mamoe.mirai.qqandroid.network.protocol.packet.* import net.mamoe.mirai.qqandroid.network.protocol.packet.*
internal object TransEmpPacket : PacketFactory<TransEmpPacket.Response>("wtlogin.trans_emp") { internal object TransEmpPacket : OutgoingPacketFactory<TransEmpPacket.Response>("wtlogin.trans_emp") {
private const val appId = 16L private const val appId = 16L
private const val subAppId = 537062845L private const val subAppId = 537062845L
......
...@@ -4,10 +4,7 @@ package androidPacketTests ...@@ -4,10 +4,7 @@ package androidPacketTests
import kotlinx.io.core.* import kotlinx.io.core.*
import kotlinx.io.pool.useInstance import kotlinx.io.pool.useInstance
import net.mamoe.mirai.qqandroid.network.protocol.packet.DECRYPTER_16_ZERO import net.mamoe.mirai.qqandroid.network.protocol.packet.*
import net.mamoe.mirai.qqandroid.network.protocol.packet.KnownPacketFactories
import net.mamoe.mirai.qqandroid.network.protocol.packet.PacketLogger
import net.mamoe.mirai.qqandroid.network.protocol.packet.withUse
import net.mamoe.mirai.utils.cryptor.ECDH import net.mamoe.mirai.utils.cryptor.ECDH
import net.mamoe.mirai.utils.cryptor.adjustToPublicKey import net.mamoe.mirai.utils.cryptor.adjustToPublicKey
import net.mamoe.mirai.utils.cryptor.decryptBy import net.mamoe.mirai.utils.cryptor.decryptBy
...@@ -99,7 +96,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) { ...@@ -99,7 +96,7 @@ private fun processFullPacketWithoutLength(packet: ByteReadPacket) {
try { try {
bytes.toReadPacket().parseOicqResponse { bytes.toReadPacket().parseOicqResponse {
debugIfFail { debugIfFail {
if (it.packetFactory.commandName == "wtlogin.login") { if ((it.packetFactory as? OutgoingPacketFactory<*>)?.commandName == "wtlogin.login") {
DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key") DebugLogger.info("服务器发来了 wtlogin.login. 正在解析 key")
try { try {
val subCommand = readUShort().toInt() val subCommand = readUShort().toInt()
......
...@@ -5,59 +5,73 @@ import kotlin.jvm.JvmOverloads ...@@ -5,59 +5,73 @@ import kotlin.jvm.JvmOverloads
/** /**
* 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器 * 用于创建默认的日志记录器. 在一些需要使用日志的 Mirai 的组件, 如 [Bot], 都会通过这个函数构造日志记录器.
* 可直接修改这个变量的值来重定向日志输出. * 可直接修改这个变量的值来重定向日志输出.
*/
var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger(it) }
/**
* 当前平台的默认的日志记录器.
* 在 _JVM 控制台_ 端的实现为 [println]
* 在 _Android_ 端的实现为 [android.util.Log]
* *
* 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion] * **注意:** 请务必将所有的输出定向到日志记录系统, 否则在某些情况下 (如 web 控制台中) 将无法接收到输出
*
* **注意:** 请为日志做好分类, 即不同的模块使用不同的 [MiraiLogger].
* 如, [Bot] 中使用 identity 为 "Bot(qqId)" 的 [MiraiLogger]
* 而 [Bot] 的网络处理中使用 identity 为 "BotNetworkHandler" 的.
*/ */
expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = "Mirai") : MiraiLoggerPlatformBase var DefaultLogger: (identity: String?) -> MiraiLogger = { PlatformLogger(it) }
/** /**
* 给这个 logger 添加一个开关, 用于控制是否记录 log * 给这个 logger 添加一个开关, 用于控制是否记录 log
*
*/ */
@JvmOverloads @JvmOverloads
fun MiraiLogger.withSwitch(default: Boolean = true): MiraiLoggerWithSwitch = MiraiLoggerWithSwitch(this, default) fun MiraiLogger.withSwitch(default: Boolean = true): MiraiLoggerWithSwitch = MiraiLoggerWithSwitch(this, default)
/** /**
* 日志记录器. 所有的输出均依赖于它. * 日志记录器. 所有的输出均依赖于它.
* 不同的对象可能拥有只属于自己的 logger. 通过 [identity] 来区分. * 不同的对象可拥有只属于自己的 logger. 通过 [identity] 来区分.
*
* 注意: 如果你需要重新实现日志, 请不要直接实现这个接口, 请继承 [MiraiLoggerPlatformBase]
* *
* 注意: 请不要直接实现这个接口, 请继承 [MiraiLoggerPlatformBase] * 在定义 logger 变量时, 请一直使用 [MiraiLogger] 或者 [MiraiLoggerWithSwitch].
* *
* @see MiraiLoggerPlatformBase 平台通用基础实现 * @see SimpleLogger 简易 logger, 它将所有的日志记录操作都转移给 lambda `(String?, Throwable?) -> Unit`
* @see PlatformLogger 各个平台下的默认日志记录实现.
* @see SilentLogger 忽略任何日志记录操作的 logger 实例.
*
* @see MiraiLoggerPlatformBase 平台通用基础实现. 若
*/ */
interface MiraiLogger { interface MiraiLogger {
/** /**
* 顶层日志记录器. * 顶层日志记录器.
*
* 顶层日志会导致混乱并难以定位问题. 请自行构造 logger 实例并使用.
* 请参考使用 [DefaultLogger]
*/ */
@Deprecated(message = "顶层日志会导致混乱并难以定位问题. 请自行构造 logger 实例并使用.", level = DeprecationLevel.WARNING)
companion object : MiraiLogger by DefaultLogger("Mirai") companion object : MiraiLogger by DefaultLogger("Mirai")
/**
* 日志的标记. 在 Mirai 中, identity 可为
* - "Bot"
* - "BotNetworkHandler"
* 等.
*
* 它只用于帮助调试或统计. 十分建议清晰定义 identity
*/
val identity: String? val identity: String?
/** /**
* 随从. 在 this 中调用所有方法后都应继续往 [follower] 传递调用. * 随从. 在 this 中调用所有方法后都应继续往 [follower] 传递调用.
* [follower] 的存在可以让一次日志被多个日志记录器记录. * [follower] 的存在可以让一次日志被多个日志记录器记录.
* *
* 例: * 一般不建议直接修改这个属性. 请通过 [plus] 来连接两个日志记录器.
* ```kotlin * 如: `val logger = bot.logger + MyOwnLogger()`
* val bot = Bot( ... ) * 这样, 当调用 `logger.info()` 时, bot.logger 会首先记录, MyOwnLogger 会随后记录.
* bot.follower = MyOwnLogger()
* *
* bot.info("Hi") * 当然, 多个 logger 也可以加在一起: `val logger = bot.logger + MyOwnLogger() + MyOwnLogger2()`
* ```
* 在这个例子中的 `MyOwnLogger` 将可以记录到 "Hi".
*/ */
var follower: MiraiLogger? var follower: MiraiLogger?
/** /**
* 记录一个 `verbose` 级别的日志. * 记录一个 `verbose` 级别的日志.
* 无关紧要的, 经常大量输出的日志应使用它.
*/ */
fun verbose(any: Any?) fun verbose(any: Any?)
...@@ -65,7 +79,7 @@ interface MiraiLogger { ...@@ -65,7 +79,7 @@ interface MiraiLogger {
fun verbose(message: String?, e: Throwable?) fun verbose(message: String?, e: Throwable?)
/** /**
* 记录一个 `debug` 级别的日志. * 记录一个 _调试_ 级别的日志.
*/ */
fun debug(any: Any?) fun debug(any: Any?)
...@@ -74,7 +88,7 @@ interface MiraiLogger { ...@@ -74,7 +88,7 @@ interface MiraiLogger {
/** /**
* 记录一个 `info` 级别的日志. * 记录一个 _信息_ 级别的日志.
*/ */
fun info(any: Any?) fun info(any: Any?)
...@@ -83,7 +97,7 @@ interface MiraiLogger { ...@@ -83,7 +97,7 @@ interface MiraiLogger {
/** /**
* 记录一个 `warning` 级别的日志. * 记录一个 _警告_ 级别的日志.
*/ */
fun warning(any: Any?) fun warning(any: Any?)
...@@ -92,7 +106,7 @@ interface MiraiLogger { ...@@ -92,7 +106,7 @@ interface MiraiLogger {
/** /**
* 记录一个 `error` 级别的日志. * 记录一个 _错误_ 级别的日志.
*/ */
fun error(e: Any?) fun error(e: Any?)
...@@ -109,10 +123,9 @@ interface MiraiLogger { ...@@ -109,10 +123,9 @@ interface MiraiLogger {
* | base | <-- | follower | <-- | follower | <-- | follower | * | base | <-- | follower | <-- | follower | <-- | follower |
* +------+ +----------+ +----------+ +----------+ * +------+ +----------+ +----------+ +----------+
* *
* @see follower
* @return [follower] * @return [follower]
*/ */
operator fun plus(follower: MiraiLogger): MiraiLogger operator fun <T : MiraiLogger> plus(follower: T): T
/** /**
* 添加一个 [follower] * 添加一个 [follower]
...@@ -123,6 +136,15 @@ interface MiraiLogger { ...@@ -123,6 +136,15 @@ interface MiraiLogger {
operator fun plusAssign(follower: MiraiLogger) operator fun plusAssign(follower: MiraiLogger)
} }
/**
* 当前平台的默认的日志记录器.
* 在 _JVM 控制台_ 端的实现为 [println]
* 在 _Android_ 端的实现为 [android.util.Log]
*
* 不应该直接构造这个类的实例. 请使用 [DefaultLogger], 或使用默认的顶层日志记录 [MiraiLogger.Companion]
*/
expect open class PlatformLogger @JvmOverloads internal constructor(identity: String? = "Mirai") : MiraiLoggerPlatformBase
/** /**
* 不做任何事情的 logger, keep silent. * 不做任何事情的 logger, keep silent.
*/ */
...@@ -167,7 +189,11 @@ class SimpleLogger(override val identity: String?, private val logger: (String?, ...@@ -167,7 +189,11 @@ class SimpleLogger(override val identity: String?, private val logger: (String?,
class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogger, default: Boolean) : MiraiLoggerPlatformBase() { class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogger, default: Boolean) : MiraiLoggerPlatformBase() {
override val identity: String? get() = delegate.identity override val identity: String? get() = delegate.identity
private var switch: Boolean = default /**
* true 为开启.
*/
@PublishedApi
internal var switch: Boolean = default
fun enable() { fun enable() {
switch = true switch = true
...@@ -188,15 +214,53 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg ...@@ -188,15 +214,53 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg
override fun error0(any: Any?) = if (switch) delegate.error(any) else Unit override fun error0(any: Any?) = if (switch) delegate.error(any) else Unit
override fun error0(message: String?, e: Throwable?) = if (switch) delegate.error(message, e) else Unit override fun error0(message: String?, e: Throwable?) = if (switch) delegate.error(message, e) else Unit
inline fun verbose(lazyMessage: () -> String) {
if (switch) verbose(lazyMessage())
}
inline fun verbose(lazyMessage: () -> String, e: Throwable?) {
if (switch) verbose(lazyMessage(), e)
}
inline fun debug(lazyMessage: () -> Any?) {
if (switch) debug(lazyMessage())
}
inline fun debug(lazyMessage: () -> String?, e: Throwable?) {
if (switch) debug(lazyMessage(), e)
}
inline fun info(lazyMessage: () -> Any?) {
if (switch) info(lazyMessage())
}
inline fun info(lazyMessage: () -> String?, e: Throwable?) {
if (switch) info(lazyMessage(), e)
}
inline fun warning(lazyMessage: () -> Any?) {
if (switch) warning(lazyMessage())
}
inline fun warning(lazyMessage: () -> String?, e: Throwable?) {
if (switch) warning(lazyMessage(), e)
}
inline fun error(lazyMessage: () -> Any?) {
if (switch) error(lazyMessage())
}
inline fun error(lazyMessage: () -> String?, e: Throwable?) {
if (switch) error(lazyMessage(), e)
}
} }
/** /**
* 平台日志基类. * 日志基类. 实现了 [follower] 的调用传递.
* 实现了 [follower] 的调用传递. * 若 Mirai 自带的日志系统无法满足需求, 请继承这个类并实现其抽象函数.
*
* 若要自行实现日志记录, 请优先考虑继承 [PlatformLogger].
* *
* 它不应该被用作变量的类型定义. 只应被继承 * 这个类不应该被用作变量的类型定义. 只应被作为继承对象.
* 在定义 logger 变量时, 请一直使用 [MiraiLogger] 或者 [MiraiLoggerWithSwitch].
*/ */
abstract class MiraiLoggerPlatformBase : MiraiLogger { abstract class MiraiLoggerPlatformBase : MiraiLogger {
final override var follower: MiraiLogger? = null final override var follower: MiraiLogger? = null
...@@ -262,7 +326,7 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { ...@@ -262,7 +326,7 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger {
protected abstract fun error0(any: Any?) protected abstract fun error0(any: Any?)
protected abstract fun error0(message: String?, e: Throwable?) protected abstract fun error0(message: String?, e: Throwable?)
override fun plus(follower: MiraiLogger): MiraiLogger { override operator fun <T : MiraiLogger> plus(follower: T): T {
this.follower = follower this.follower = follower
return follower return follower
} }
......
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