From 7c69bd038df6b866798888cfe1790319abc735b4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 13 Feb 2020 13:34:22 +0800 Subject: [PATCH 01/43] Replace println with network.logger.debug --- .../network/protocol/packet/chat/receive/OnlinePush.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 0e9cee6be..91880a4d3 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -215,7 +215,7 @@ internal class OnlinePush { 4096 -> { val dataBytes = this.readBytes(26) val message = this.readString(this.readByte().toInt()) - println(dataBytes.toUHexString()) + // println(dataBytes.toUHexString()) if (dataBytes[0].toInt() != 59) { return GroupNameChangeEvent( @@ -244,7 +244,7 @@ internal class OnlinePush { ) } else -> { - println("Unknown server messages $message") + bot.network.logger.debug{"Unknown server messages $message"} return NoPacket } } @@ -255,17 +255,17 @@ internal class OnlinePush { // println(msgInfo.vMsg.toUHexString()) // } else -> { - println("unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " ") + bot.network.logger.debug { "unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " " } } } } msgInfo.shMsgType.toInt() == 528 -> { - println("unknown shtype ${msgInfo.shMsgType.toInt()}") + bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } // val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer()) // println(content.contentToString()) } else -> { - println("unknown shtype ${msgInfo.shMsgType.toInt()}") + bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } } } } From 33c75c824ef9b75c8968e35e42d13779d229c49a Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 13 Feb 2020 13:38:19 +0800 Subject: [PATCH 02/43] Make OnlinePushPack internal --- .../mirai/qqandroid/network/protocol/data/jce/OnlinePushPack.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/OnlinePushPack.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/OnlinePushPack.kt index 9578bd4de..7fc67599d 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/OnlinePushPack.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/data/jce/OnlinePushPack.kt @@ -13,7 +13,7 @@ import kotlinx.serialization.SerialId import kotlinx.serialization.Serializable import net.mamoe.mirai.qqandroid.io.JceStruct -class OnlinePushPack { +internal class OnlinePushPack { @Serializable internal class DelMsgInfo( @SerialId(0) val fromUin: Long, From a3945924a4b7431ac478d64a9957647cab2f87a4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 13 Feb 2020 13:42:32 +0800 Subject: [PATCH 03/43] Add docs --- .../commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt index eff2e9535..b14880475 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt @@ -30,7 +30,7 @@ annotation class MiraiInternalAPI( ) /** - * 标记这个类, 类型, 函数, 属性, 字段, 或构造器为实验性的. + * 标记这个类, 类型, 函数, 属性, 字段, 或构造器为实验性的 API. * * 这些 API 不具有稳定性, 且可能会在任意时刻更改. * 不建议在发行版本中使用这些 API. @@ -56,7 +56,7 @@ annotation class MiraiDebugAPI( ) /** - * 标记这个 API 是自 Mirai 某个版本起才受支持. + * 标记一个自 Mirai 某个版本起才支持的 API. */ @Target(CLASS, PROPERTY, FIELD, CONSTRUCTOR, FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, TYPEALIAS) @Retention(AnnotationRetention.BINARY) From 8f03d44df1cfc19618c0423a9940783b4183a710 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 13 Feb 2020 16:09:10 +0800 Subject: [PATCH 04/43] Add shortcut --- .../src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt index acd50e64b..2e8f9b859 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt @@ -98,4 +98,6 @@ suspend inline fun Member.mute(duration: Duration): Boolean { require(duration.inDays <= 30) { "duration must be at most 1 month" } require(duration.inSeconds > 0) { "duration must be greater than 0 second" } return this.mute(duration.inSeconds.toInt()) -} \ No newline at end of file +} + +suspend inline fun Member.mute(durationSeconds: Long) = this.mute(durationSeconds.toInt()) \ No newline at end of file From 227a22d31118534b6e22fc965f0ef911c6ea04d2 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 13 Feb 2020 16:30:18 +0800 Subject: [PATCH 05/43] Ignore receipt events --- .../network/protocol/packet/chat/receive/OnlinePush.kt | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 91880a4d3..edacd2626 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -157,6 +157,8 @@ internal class OnlinePush { val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") reqPushMsg.vMsgInfos.forEach { msgInfo: MsgInfo -> msgInfo.vMsg!!.read { + + // TODO: 2020/2/13 可能会同时收到多个事件. 使用 map 而不要直接 return when { msgInfo.shMsgType.toInt() == 732 -> { val group = bot.getGroup(this.readUInt().toLong()) @@ -164,7 +166,11 @@ internal class OnlinePush { when (val internalType = this.readShort().toInt()) { 3073 -> { // mute - val operator = group[this.readUInt().toLong()] + val operatorUin = this.readUInt().toLong() + if (operatorUin == bot.uin) { + return NoPacket + } + val operator = group[operatorUin] this.readUInt().toLong() // time this.discardExact(2) val target = this.readUInt().toLong() From 1058377663324cba10299479746419337958e9df Mon Sep 17 00:00:00 2001 From: Him188 Date: Fri, 14 Feb 2020 10:21:33 +0800 Subject: [PATCH 06/43] Support AtAll in message.first() --- .../src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt | 2 +- .../kotlin/net.mamoe.mirai/message/data/MessageChain.kt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt index 00877d77b..69bb6c392 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/AtAll.kt @@ -14,7 +14,7 @@ package net.mamoe.mirai.message.data * * @see At at 单个群成员 */ -object AtAll : Message { +object AtAll : Message, Message.Key { override fun toString(): String = "@全体成员" // 自动为消息补充 " " diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt index 7da1c5d10..5e1ff2061 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageChain.kt @@ -155,6 +155,7 @@ inline fun MessageChain.any(): Boolean = this.any { it is @Suppress("UNCHECKED_CAST") fun MessageChain.firstOrNull(key: Message.Key): M? = when (key) { At -> first() + AtAll -> first() PlainText -> first() Image -> first<Image>() Face -> first<Face>() From 4218cdb7bbf288917dcb3a88306bf8e9076a4f71 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 13:40:11 +0800 Subject: [PATCH 07/43] Ignore redundant if --- .../network/protocol/packet/login/WtLogin.kt | 42 ++++++++++++------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt index 57145c8c0..3ad8f07ed 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt @@ -29,7 +29,7 @@ import net.mamoe.mirai.utils.io.* import net.mamoe.mirai.utils.io.discardExact import net.mamoe.mirai.utils.md5 -internal class WtLogin{ +internal class WtLogin { /** * OicqRequest */ @@ -359,28 +359,38 @@ internal class WtLogin{ @InternalAPI @UseExperimental(MiraiDebugAPI::class) private fun onSolveLoginCaptcha(tlvMap: TlvMap, bot: QQAndroidBot): LoginPacketResponse.Captcha { + /* + java.lang.IllegalStateException: UNKNOWN CAPTCHA QUESTION: + 00 00 00 01 0A 70 69 63 5F 72 65 61 73 6F 6E 00 00 00 7F 51 51 E5 AE 89 E5 85 A8 E4 B8 AD E5 BF 83 E6 B8 A9 E9 A6 A8 E6 8F 90 E7 A4 BA EF BC 9A E5 BD 93 E5 89 8D E7 BD 91 E7 BB 9C E7 8E AF E5 A2 83 E6 9C 89 E5 8D B1 E5 8F 8A 51 51 E5 AE 89 E5 85 A8 E7 9A 84 E8 A1 8C E4 B8 BA EF BC 8C E4 B8 BA E4 BA 86 E4 BD A0 E7 9A 84 E5 B8 90 E5 8F B7 E5 AE 89 E5 85 A8 EF BC 8C E8 AF B7 E4 BD A0 E5 A1 AB E5 86 99 E9 AA 8C E8 AF 81 E7 A0 81 E3 80 82, + tlvMap={ + 0x00000104(260)=41 74 78 43 52 56 6A 46 61 79 33 76 56 5A 66 56 47 50 4B 63 4F 59 54 6D 76 32 4A 67 35 35 76 6A 51 67 3D 3D, + 0x00000105(261)=00 04 41 7A 55 47 08 88 FF D8 FF E0 00 10 4A 46 49 46 00 01 01 00 00 01 00 01 00 00 FF FE 00 22 39 35 30 35 34 31 36 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 88 5C DF 07 FF 7F 00 00 FF DB 00 43 00 0A 07 07 08 07 06 0A 08 08 08 0B 0A 0A 0B 0E 18 10 0E 0D 0D 0E 1D 15 16 11 18 23 1F 25 24 22 1F 22 21 26 2B 37 2F 26 29 34 29 21 22 30 41 31 34 39 3B 3E 3E 3E 25 2E 44 49 43 3C 48 37 3D 3E 3B FF DB 00 43 01 0A 0B 0B 0E 0D 0E 1C 10 10 1C 3B 28 22 28 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B 3B FF C0 00 11 08 00 35 00 82 03 01 22 00 02 11 01 03 11 01 FF C4 00 1F 00 00 01 05 01 01 01 01 01 01 00 00 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B FF C4 00 B5 10 00 02 01 03 03 02 04 03 05 05 04 04 00 00 01 7D 01 02 03 00 04 11 05 12 21 31 41 06 13 51 61 07 22 71 14 32 81 91 A1 08 23 42 B1 C1 15 52 D1 F0 24 33 62 72 82 09 0A 16 17 18 19 1A 25 26 27 28 29 2A 34 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E1 E2 E3 E4 E5 E6 E7 E8 E9 EA F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FF C4 00 1F 01 00 03 01 01 01 01 01 01 01 01 01 00 00 00 00 00 00 01 02 03 04 05 06 07 08 09 0A 0B FF C4 00 B5 11 00 02 01 02 04 04 03 04 07 05 04 04 00 01 02 77 00 01 02 03 11 04 05 21 31 06 12 41 51 07 61 71 13 22 32 81 08 14 42 91 A1 B1 C1 09 23 33 52 F0 15 62 72 D1 0A 16 24 34 E1 25 F1 17 18 19 1A 26 27 28 29 2A 35 36 37 38 39 3A 43 44 45 46 47 48 49 4A 53 54 55 56 57 58 59 5A 63 64 65 66 67 68 69 6A 73 74 75 76 77 78 79 7A 82 83 84 85 86 87 88 89 8A 92 93 94 95 96 97 98 99 9A A2 A3 A4 A5 A6 A7 A8 A9 AA B2 B3 B4 B5 B6 B7 B8 B9 BA C2 C3 C4 C5 C6 C7 C8 C9 CA D2 D3 D4 D5 D6 D7 D8 D9 DA E2 E3 E4 E5 E6 E7 E8 E9 EA F2 F3 F4 F5 F6 F7 F8 F9 FA FF DA 00 0C 03 01 00 02 11 03 11 00 3F 00 F5 EA 42 40 EA 40 AC CF 10 E9 D7 BA A6 96 6D AC 6F 05 AC 85 C3 12 77 00 EA 3F 87 2A 41 19 E3 91 5C BE 9D A7 E8 D2 5C B6 99 AB E9 CF 6B AA 85 3B 16 7B A9 5E 29 FD D1 8B 72 3D BA D7 4D 2A 31 9C 1C 9B F9 25 7F 9E E8 CA 53 69 DA C7 72 F2 C7 1A EE 92 45 45 F5 66 00 54 0B A9 D8 3C CB 0A DF 5B 34 8C 70 A8 25 5D C7 F0 CD 72 36 3A 22 18 2D 3F B5 EC 64 B4 8B 4A DC B2 24 8C B3 41 3E EE EA 0E 4F 24 8F A7 4A DE B6 F0 FD 9B 5D 45 76 F6 16 D6 C2 16 DF 0C 11 42 80 A9 EC 58 81 C9 F6 1C 0F 7A 73 A3 4A 1B CA FF 00 D7 A8 94 A4 FA 0F 6D 7C 16 B9 36 FA 75 D5 CC 56 AE D1 CB 32 49 0A AA B2 FD E0 77 C8 A4 63 DC 0E 39 1C 10 6A 7B 9D 5E 3B 5D 32 1B E9 2D AE 07 9D B0 2C 25 42 B8 66 E8 AD B8 85 53 DB 92 06 78 EA 40 34 0D F5 AE 16 39 60 86 6B 7D 55 F3 70 F1 96 C0 49 41 48 49 04 74 65 40 87 91 83 8F 5A 9B 4F 7B B8 ED 9A C6 ED 66 91 AC 64 09 E7 1D DF E9 0A 30 63 3B 8E 32 C7 20 37 6C AB 67 82 28 74 E2 B5 E5 FE BF E1 FD 37 40 A4 FB 96 ED 35 19 6E 2E 8D BC BA 65 DD A1 D8 5F 74 CD 11 5E A0 63 E4 76 20 F3 DF D0 D3 2F 7C 41 A4 69 C4 AD D6 A1 02 3A F5 8C 36 E7 FF 00 BE 46 4F E9 58 D7 A8 FA D4 36 33 C5 21 B3 1A D5 98 86 42 06 FD AE BF BD 55 23 8E 02 F9 EA 7A 75 FA 54 96 96 EB 1F 85 2F E2 B4 B4 B7 86 F6 DC 4B 14 AB 6B 17 97 BD D7 38 C6 39 F9 97 07 FE 05 55 EC 61 A3 97 A5 97 DD 7B BB F5 0E 77 B2 34 35 8D 7A 0D 2F 4D 82 F5 7C B9 56 E5 D5 62 67 93 CB 8F 90 58 16 62 0E 06 07 A1 ED 55 2E 24 F1 16 EB 77 7B DB 0B 61 2C EA B1 C3 0C 46 52 E3 A9 05 D8 8F E1 0C 78 03 A5 3B FE 12 7D 1A EE D0 43 69 1C D7 EB 24 7B 7C 8B 7B 76 7F 94 8E 87 8C 0F C4 D1 73 6D 35 A7 83 E0 DE 18 CD A7 C5 14 D8 E0 B7 EE C8 62 BC 77 21 4A FE 34 E3 1E 4B 27 1B 36 FA FF 00 97 90 9B BE CC DF A2 A8 DF 6B 5A 76 98 B1 35 E5 D2 45 E7 0C C6 30 58 B8 F6 03 93 D4 55 55 F1 56 8E CB 21 FB 44 8A 23 88 CA 7C CB 79 13 2A 08 1C 6E 51 9E 58 0C 0F 51 5C CA 8D 49 2B A8 BF B8 D1 CA 2B 76 6C 51 58 47 C5 0A 0A 96 D1 75 65 8C BA AF 98 D6 E1 46 58 80 38 2D 9E A4 76 A8 A4 F1 45 CB FD AD EC 34 77 B9 82 D2 46 8E 49 9E E5 23 1B 97 A8 DB CB 7D 38 E7 8A A5 87 A8 FA 7E 28 5E D2 27 45 45 47 0B BC 90 46 F2 46 62 76 50 59 09 CE D3 8E 46 7D AA 4A C4 B0 A2 8A 29 01 15 C5 C4 36 90 34 F7 12 AC 51 20 CB 3B 9C 01 59 1A 91 B3 D4 AD 3E D9 7B 6D 8B 1B 43 E7 87 96 32 1D 8A F3 95 1D 40 FE 7F 4A D2 BF D3 AD 75 3B 71 6F 77 19 92 30 C1 C0 0E CB C8 E8 72 08 35 53 FE 11 8D 14 FD EB 14 93 FE BA 33 3F F3 35 D1 4A 54 E3 AB 6E FF 00 D7 99 12 52 7A 74 32 8D FF 00 F6 CD C1 B1 D4 52 C6 EB 49 BD 83 CE 8E 58 A4 2A 62 00 F0 1B 3D F3 D0 8C 74 3E 95 9D 71 AC DC 78 6A 17 B3 6D 45 75 3D 3D C1 54 9A 2B 84 FB 5D B8 3C 63 04 FC E7 D0 FF 00 FA AB AD 7D 13 4A 94 C6 64 D3 AD 5C C6 81 13 74 4A 76 A8 E8 07 1D 2A 58 B4 FB 18 08 30 D9 C1 1E 3F B9 12 8F E9 5B AC 45 25 A7 2D D7 6F D7 D4 87 09 3E BA 99 D6 B6 F3 EB 16 BA 94 3A 95 9C 90 59 DD 95 F2 12 57 53 22 A1 8D 41 E0 64 2E 18 12 39 CE 49 E0 63 9B 3A 58 BF 96 18 BF B4 E2 D9 35 B6 50 B6 50 89 98 71 E6 80 07 CA 08 E8 38 FB CC 08 E0 13 A3 45 72 CA AD D5 AD FD 6D F8 F5 34 51 B1 CB B4 7A 89 D2 3E CF 16 8D 7B 1D CA DD 35 DC 6E CD 03 2A 39 94 C9 B7 89 41 23 E6 2A 4F 19 04 FA E2 B4 2C 1A 58 35 B9 A3 9D 04 6F 7B 6D 1D C3 22 9D C0 48 BF 24 98 3D F8 F2 C5 6C 56 36 A5 71 24 3A E5 A3 26 9D 77 72 63 85 F6 B4 0A 30 4B 10 36 96 24 28 1F 2E 79 3E 95 B2 A8 EA 5E 36 5A DF FC FA BE E8 97 1E 5D 48 61 D3 20 D6 A6 BB 7B F9 EE 9F CA B8 78 8D A8 9D 92 34 00 E5 78 5C 67 2A 55 B9 CF 5A 97 4A B0 87 4D D4 6F B4 DB 78 F6 D9 B4 71 CC 91 F5 08 5B 72 B0 FA 1D 80 FE 26 A3 B3 D3 EF E5 D7 46 AA F1 36 9F 1C 8B 99 AD C5 CF 99 E7 1D BB 46 E5 03 68 20 63 90 C7 A0 15 6E 6D 0E 2B 8B D9 AE 24 BC BC 0B 36 37 43 1C C6 34 E0 01 D5 70 DD BA 67 1D 69 CE 69 5E 2E 5A 5B EE 7F 90 92 EB 63 9F 8E DA 57 41 69 6D 1D CD BE B7 A4 44 56 DE 46 C8 8E EA 14 6C 2A 93 9C 30 61 B7 39 E4 13 53 DD DF 0B A7 B5 D4 D2 DD 6E EC 35 5B 6F B2 98 64 5D DE 54 B9 25 41 F4 05 B2 AD E8 42 D7 43 65 A5 D8 69 BB BE C7 69 14 25 F1 BD 95 7E 67 C7 4C 9E A7 F1 AC C4 B7 D4 74 7D 4E EB EC 36 02 EE CA ED 84 C1 44 CA 9E 4C A7 87 EB D8 F0 78 EF 9A D1 56 8C DB B7 E3 A7 AF A6 BA AD 7B F7 27 91 A4 43 7A E2 6B 69 B4 8D 33 CC 5B DD 21 22 9A DC 13 81 36 D1 C2 8E 79 07 05 4F A1 35 7E C4 34 EF 1C AD 0B 42 F7 04 DD 4C 8D C1 1C 05 45 61 EB 80 3F 14 A8 6F 34 8B C5 6B 2B DB 03 08 BF B6 67 DE 25 76 58 E5 59 39 75 24 02 7E F6 08 E3 B5 68 D8 C5 72 A8 D2 DE F9 5F 68 93 1B 84 44 95 50 3A 00 48 04 F7 3C FA 9A CA 73 8F 27 BB FF 00 07 FE 1B A9 49 3B EA 5A A2 8A 2B 90 D4 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 28 A2 8A 00 FF D9, + 0x00000165(357)=00 00 00 01 0A 70 69 63 5F 72 65 61 73 6F 6E 00 00 00 7F 51 51 E5 AE 89 E5 85 A8 E4 B8 AD E5 BF 83 E6 B8 A9 E9 A6 A8 E6 8F 90 E7 A4 BA EF BC 9A E5 BD 93 E5 89 8D E7 BD 91 E7 BB 9C E7 8E AF E5 A2 83 E6 9C 89 E5 8D B1 E5 8F 8A 51 51 E5 AE 89 E5 85 A8 E7 9A 84 E8 A1 8C E4 B8 BA EF BC 8C E4 B8 BA E4 BA 86 E4 BD A0 E7 9A 84 E5 B8 90 E5 8F B7 E5 AE 89 E5 85 A8 EF BC 8C E8 AF B7 E4 BD A0 E5 A1 AB E5 86 99 E9 AA 8C E8 AF 81 E7 A0 81 E3 80 82 + } + + */ // val ret = tlvMap[0x104]?.let { println(it.toUHexString()) } bot.client.t104 = tlvMap.getOrFail(0x104) tlvMap[0x192]?.let { return LoginPacketResponse.Captcha.Slider(it.encodeToString()) } - tlvMap[0x165]?.let { question -> - if (question[18].toInt() == 0x36) { - //图片验证 - DebugLogger.debug("是一个图片验证码") - val imageData = tlvMap.getOrFail(0x105).toReadPacket() - val signInfoLength = imageData.readShort() - imageData.discardExact(2)//image Length - val sign = imageData.readBytes(signInfoLength.toInt()) + tlvMap[0x165]?.let { + // if (question[18].toInt() == 0x36) { + // 图片验证 + // DebugLogger.debug("是一个图片验证码") + val imageData = tlvMap.getOrFail(0x105).toReadPacket() + val signInfoLength = imageData.readShort() + imageData.discardExact(2)//image Length + val sign = imageData.readBytes(signInfoLength.toInt()) - val buffer = IoBuffer.Pool.borrow() - imageData.readFully(buffer) - return LoginPacketResponse.Captcha.Picture( - data = buffer, - sign = sign - ) - } else error("UNKNOWN CAPTCHA QUESTION: ${question.toUHexString()}, tlvMap=" + tlvMap.contentToString()) + val buffer = IoBuffer.Pool.borrow() + imageData.readFully(buffer) + return LoginPacketResponse.Captcha.Picture( + data = buffer, + sign = sign + ) + // } else error("UNKNOWN CAPTCHA QUESTION: ${question.toUHexString()}, tlvMap=" + tlvMap.contentToString()) } error("UNKNOWN CAPTCHA, tlvMap=" + tlvMap.contentToString()) From 8bf302d386ff7734c899f44e8eda9c90485974e9 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 13:45:46 +0800 Subject: [PATCH 08/43] Annotate readTlvMap with @MiraiInternalIp --- .../commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt index ee7ccc2d4..ea9f51f73 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt @@ -81,7 +81,7 @@ inline fun TlvMap.getOrFail(tag: Int, lazyMessage: (tag: Int) -> String): ByteAr return this[tag] ?: error(lazyMessage(tag)) } -@MiraiDebugAPI +@MiraiInternalAPI inline fun Input.readTLVMap(tagSize: Int = 2, suppressDuplication: Boolean = true): TlvMap = readTLVMap(true, tagSize, suppressDuplication) @MiraiDebugAPI From 6635ca78fd4ea82ce3d5f1277f4db37efb85f0b8 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 13:46:01 +0800 Subject: [PATCH 09/43] Use gradle 5.6.4 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 28f135b7f..d07e15f57 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Thu Feb 06 14:10:33 CST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From ed66d0bffdf6efd6187ddc662e06b2fedf81a0e3 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 16:55:44 +0800 Subject: [PATCH 10/43] 6.1.1 --- gradle/wrapper/gradle-wrapper.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index d07e15f57..3dbe6db2a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ #Thu Feb 06 14:10:33 CST 2020 -distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From 1f6d81314a94e9670ce6fdd6ed15a734dbf79d05 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:19:55 +0800 Subject: [PATCH 11/43] Fix captcha read --- .../mirai/qqandroid/network/protocol/packet/login/WtLogin.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt index 3ad8f07ed..6c7c5b26b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/login/WtLogin.kt @@ -385,7 +385,7 @@ internal class WtLogin { val buffer = IoBuffer.Pool.borrow() - imageData.readFully(buffer) + imageData.readAvailable(buffer) return LoginPacketResponse.Captcha.Picture( data = buffer, sign = sign From 98b0073f81b66f8361adb5416414a01adaf5818d Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:20:31 +0800 Subject: [PATCH 12/43] Add `BotOfflineEvent.Dropped` and `BotReloginEvent` --- .../net.mamoe.mirai/event/events/BotEvents.kt | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt index 75aee9c06..9047df8e0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/events/BotEvents.kt @@ -42,19 +42,32 @@ data class BotOnlineEvent(override val bot: Bot) : BotActiveEvent /** * [Bot] 离线. */ -sealed class BotOfflineEvent : BotActiveEvent { +sealed class BotOfflineEvent : BotEvent { /** * 主动离线 */ - data class Active(override val bot: Bot, val cause: Throwable?) : BotOfflineEvent() + data class Active(override val bot: Bot, val cause: Throwable?) : BotOfflineEvent(), BotActiveEvent /** * 被挤下线 */ - data class Force(override val bot: Bot, val title: String, val message: String) : BotOfflineEvent(), Packet + data class Force(override val bot: Bot, val title: String, val message: String) : BotOfflineEvent(), Packet, BotPassiveEvent + + /** + * 被服务器断开或因网络问题而掉线 + */ + data class Dropped(override val bot: Bot) : BotOfflineEvent(), Packet, BotPassiveEvent } +/** + * [Bot] 主动重新登录. + */ +data class BotReloginEvent( + override val bot: Bot, + val cause: Throwable? +) : BotEvent, BotActiveEvent + // endregion // region 消息 From 2bbc324245738699cb89be440384ba53bb1aeabc Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:33:35 +0800 Subject: [PATCH 13/43] Make `@MessageDsl` public --- .../kotlin/net.mamoe.mirai/event/MessageSubscribers.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt index ee8a75cfd..5fe31559e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/MessageSubscribers.kt @@ -631,4 +631,4 @@ class MessageSubscribersBuilder<T : MessagePacket<*, *>>( @Retention(AnnotationRetention.SOURCE) @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS, AnnotationTarget.TYPE) @DslMarker -internal annotation class MessageDsl \ No newline at end of file +annotation class MessageDsl \ No newline at end of file From ba946eb249fd167cea39f9d0c1d2bf63ab15ee8c Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:37:20 +0800 Subject: [PATCH 14/43] Add ForceOfflineException for clearer close reason --- .../kotlin/net.mamoe.mirai/network/ForceOfflineException.kt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt new file mode 100644 index 000000000..8bfcafb8c --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/ForceOfflineException.kt @@ -0,0 +1,3 @@ +package net.mamoe.mirai.network + +class ForceOfflineException(override val message: String?) : RuntimeException() \ No newline at end of file From c03fb41fd00484d459b9a606707ec5564ef6fb1a Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:40:04 +0800 Subject: [PATCH 15/43] Add LoginFailedException --- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 7 ++++-- .../network/LoginFailedException.kt | 22 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/LoginFailedException.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt index c8fac4b3f..759c5041c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -24,6 +24,7 @@ import net.mamoe.mirai.data.GroupInfo import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.network.BotNetworkHandler +import net.mamoe.mirai.network.LoginFailedException import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.io.transferTo @@ -175,9 +176,11 @@ abstract class Bot : CoroutineScope { /** * 登录, 或重新登录. - * 不建议调用这个函数. + * 重新登录时不会再次拉取联系人列表. * - * 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.login] + * 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.relogin] + * + * @throws LoginFailedException */ abstract suspend fun login() // endregion diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/LoginFailedException.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/LoginFailedException.kt new file mode 100644 index 000000000..74573fb1b --- /dev/null +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/LoginFailedException.kt @@ -0,0 +1,22 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.network + +/** + * 正常登录失败时抛出 + */ +sealed class LoginFailedException : RuntimeException { + constructor() : super() + constructor(message: String?) : super(message) + constructor(message: String?, cause: Throwable?) : super(message, cause) + constructor(cause: Throwable?) : super(cause) +} + +class WrongPasswordException(message: String?) : LoginFailedException(message) \ No newline at end of file From 19930472218459fbc7d8996c52a1b4a7976db0b7 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:41:24 +0800 Subject: [PATCH 16/43] Redesign reconnecting logic --- .../network/QQAndroidBotNetworkHandler.kt | 91 ++++++++------- .../kotlin/net.mamoe.mirai/BotImpl.kt | 107 +++++++++++------- .../network/BotNetworkHandler.kt | 14 ++- 3 files changed, 128 insertions(+), 84 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 9126bc908..46b499888 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -20,9 +20,13 @@ import kotlinx.io.core.buildPacket import kotlinx.io.core.use import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.* +import net.mamoe.mirai.event.BroadcastControllable +import net.mamoe.mirai.event.CancellableEvent +import net.mamoe.mirai.event.Event +import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.network.BotNetworkHandler +import net.mamoe.mirai.network.WrongPasswordException import net.mamoe.mirai.qqandroid.FriendInfoImpl import net.mamoe.mirai.qqandroid.GroupImpl import net.mamoe.mirai.qqandroid.QQAndroidBot @@ -37,7 +41,10 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.login.Heartbeat import net.mamoe.mirai.qqandroid.network.protocol.packet.login.StatSvc import net.mamoe.mirai.qqandroid.network.protocol.packet.login.WtLogin import net.mamoe.mirai.utils.* -import net.mamoe.mirai.utils.io.* +import net.mamoe.mirai.utils.io.ByteArrayPool +import net.mamoe.mirai.utils.io.PlatformSocket +import net.mamoe.mirai.utils.io.readPacket +import net.mamoe.mirai.utils.io.useBytes import kotlin.coroutines.CoroutineContext import kotlin.jvm.Volatile import kotlin.time.ExperimentalTime @@ -55,13 +62,42 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler private lateinit var channel: PlatformSocket - override suspend fun login() { + private var _packetReceiverJob: Job? = null + + private val packetReceiveLock: Mutex = Mutex() + + private fun startPacketReceiverJobOrGet(): Job { + val job = _packetReceiverJob + if (job != null && job.isActive && channel.isOpen) { + return job + } + + return this.launch(CoroutineName("Incoming Packet Receiver")) { + while (channel.isOpen) { + val rawInput = try { + channel.read() + } catch (e: CancellationException) { + return@launch + } catch (e: Throwable) { + BotOfflineEvent.Dropped(bot).broadcast() + return@launch + } + packetReceiveLock.withLock { + processPacket(rawInput) + } + } + }.also { _packetReceiverJob = it } + } + + + override suspend fun relogin() { if (::channel.isInitialized) { channel.close() } channel = PlatformSocket() + // TODO: 2020/2/14 连接多个服务器 channel.connect("113.96.13.208", 8080) - this.launch(CoroutineName("Incoming Packet Receiver")) { processReceive() } + startPacketReceiverJobOrGet() // logger.info("Trying login") var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect() @@ -94,7 +130,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } } - is WtLogin.Login.LoginPacketResponse.Error -> error(response.toString()) + is WtLogin.Login.LoginPacketResponse.Error -> + throw WrongPasswordException(response.toString()) is WtLogin.Login.LoginPacketResponse.DeviceLockLogin -> { response = WtLogin.Login.SubCommand20( @@ -112,18 +149,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") - StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow + + repeat(2) { + StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow + } } @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) override suspend fun init(): Unit = coroutineScope { - this@QQAndroidBotNetworkHandler.subscribeAlways<BotOfflineEvent> { - if (this@QQAndroidBotNetworkHandler.bot == this.bot) { - logger.error("被挤下线") - close() - } - } - MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() bot.qqs.delegate.clear() @@ -172,6 +205,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler launch { try { bot.groups.delegate.addLast( + @Suppress("DuplicatedCode") GroupImpl( bot = bot, coroutineContext = bot.coroutineContext, @@ -218,7 +252,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (failException != null) { delay(bot.configuration.firstReconnectDelayMillis) close() - bot.tryReinitializeNetworkHandler(failException) + BotOfflineEvent.Dropped(bot).broadcast() } } } @@ -408,33 +442,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } - @UseExperimental(ExperimentalCoroutinesApi::class) - private suspend fun processReceive() { - while (channel.isOpen) { - val rawInput = try { - channel.read() - } catch (e: ClosedChannelException) { - bot.tryReinitializeNetworkHandler(e) - return - } catch (e: ReadPacketInternalException) { - logger.error("Socket channel read failed: ${e.message}") - bot.tryReinitializeNetworkHandler(e) - return - } catch (e: CancellationException) { - return - } catch (e: Throwable) { - logger.error("Caught unexpected exceptions", e) - bot.tryReinitializeNetworkHandler(e) - return - } - packetReceiveLock.withLock { - processPacket(rawInput) - } - } - } - - private val packetReceiveLock: Mutex = Mutex() - /** * 发送一个包, 但不期待任何返回. */ @@ -517,5 +524,5 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler super.close(cause) } - override suspend fun awaitDisconnection() = supervisor.join() + override suspend fun awaitDisconnection() = _packetReceiverJob?.join() ?: Unit } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index 3793b2ceb..32a77cdd0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -12,10 +12,15 @@ package net.mamoe.mirai import kotlinx.coroutines.* +import net.mamoe.mirai.event.Listener import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.events.BotOfflineEvent +import net.mamoe.mirai.event.events.BotReloginEvent +import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.network.BotNetworkHandler +import net.mamoe.mirai.network.ForceOfflineException +import net.mamoe.mirai.network.LoginFailedException import net.mamoe.mirai.network.closeAndJoin import net.mamoe.mirai.utils.* import net.mamoe.mirai.utils.io.logStacktrace @@ -78,60 +83,70 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( @Suppress("PropertyName") internal lateinit var _network: N - final override suspend fun login() = reinitializeNetworkHandler(null) + @Suppress("unused") + private val offlineListener: Listener<BotOfflineEvent> = this.subscribeAlways { event -> + when (event) { + is BotOfflineEvent.Dropped -> { + bot.logger.info("Connection dropped or lost by server, retrying login") - // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close - fun tryReinitializeNetworkHandler( - cause: Throwable? - ): Job = launch { - var lastFailedException: Throwable? = null - repeat(configuration.reconnectionRetryTimes) { - try { - reinitializeNetworkHandler(cause) - logger.info("Reconnected successfully") - return@launch - } catch (e: Throwable) { - lastFailedException = e - delay(configuration.reconnectPeriodMillis) + var lastFailedException: Throwable? = null + repeat(configuration.reconnectionRetryTimes) { + try { + network.relogin() + logger.info("Reconnected successfully") + return@subscribeAlways + } catch (e: Throwable) { + lastFailedException = e + delay(configuration.reconnectPeriodMillis) + } + } + if (lastFailedException != null) { + throw lastFailedException!! + } + } + is BotOfflineEvent.Active -> { + val msg = if (event.cause == null) { + "" + } else { + " with exception: " + event.cause.message + } + bot.logger.info("Bot is closed manually$msg") + close(CancellationException(event.toString())) + } + is BotOfflineEvent.Force -> { + bot.logger.info("Connection occupied by another android device: ${event.message}") + close(ForceOfflineException(event.toString())) } } - if (lastFailedException != null) { - throw lastFailedException!! - } } + final override suspend fun login() = reinitializeNetworkHandler(null) + private suspend fun reinitializeNetworkHandler( cause: Throwable? ) { - logger.info("BotAccount: $uin") - logger.info("Initializing BotNetworkHandler") - try { - if (::_network.isInitialized) { - BotOfflineEvent.Active(this, cause).broadcast() - _network.closeAndJoin(cause) + suspend fun doRelogin() { + while (true) { + _network = createNetworkHandler(this.coroutineContext) + try { + _network.relogin() + return + } catch (e: LoginFailedException) { + throw e + } catch (e: Exception) { + network.logger.error(e) + _network.closeAndJoin(e) + } + logger.warning("Login failed. Retrying in 3s...") + delay(3000) } - } catch (e: Exception) { - logger.error("Cannot close network handler", e) } - loginLoop@ while (true) { - _network = createNetworkHandler(this.coroutineContext) - try { - _network.login() - break@loginLoop - } catch (e: Exception) { - e.logStacktrace() - _network.closeAndJoin(e) - } - logger.warning("Login failed. Retrying in 3s...") - delay(3000) - } - - repeat(1) block@{ + suspend fun doInit() { repeat(2) { try { _network.init() - return@block + return } catch (e: Exception) { e.logStacktrace() } @@ -141,6 +156,16 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( logger.error("cannot init. some features may be affected") } + logger.info("Initializing BotNetworkHandler") + + if (::_network.isInitialized) { + BotReloginEvent(this, cause).broadcast() + doRelogin() + return + } + + doRelogin() + doInit() } protected abstract fun createNetworkHandler(coroutineContext: CoroutineContext): N @@ -153,9 +178,11 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( if (cause == null) { network.close() this.botJob.complete() + offlineListener.complete() } else { network.close(cause) this.botJob.completeExceptionally(cause) + offlineListener.completeExceptionally(cause) } } groups.delegate.clear() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index c7d286b97..c281223bb 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt @@ -36,6 +36,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel * * [BotNetworkHandler.close] 时将会 [取消][Job.cancel] 所有此作用域下的协程 */ +@MiraiInternalAPI @Suppress("PropertyName") abstract class BotNetworkHandler : CoroutineScope { /** @@ -55,12 +56,20 @@ abstract class BotNetworkHandler : CoroutineScope { /** * 依次尝试登录到可用的服务器. 在任一服务器登录完成后返回. - * 本函数将挂起直到登录成功. + * + * - 会断开连接并重新登录. + * - 不会停止网络层的 [Job]. + * - 重新登录时不会再次拉取联系人列表. + * - 挂起直到登录成功. * * 不要使用这个 API. 请使用 [Bot.login] + * + * @throws LoginFailedException 登录失败时 + * @throws WrongPasswordException 密码错误时 */ + @Suppress("SpellCheckingInspection") @MiraiInternalAPI - abstract suspend fun login() + abstract suspend fun relogin() /** * 初始化获取好友列表等值. @@ -92,6 +101,7 @@ abstract class BotNetworkHandler : CoroutineScope { } } +@UseExperimental(MiraiInternalAPI::class) suspend fun BotNetworkHandler.closeAndJoin(cause: Throwable? = null) { this.close(cause) this.supervisor.join() From a7055ed92d2f2ae9d9d9a13f2de8657c531b26a3 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 18:46:34 +0800 Subject: [PATCH 17/43] Try register only if possible. Close #47 --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 46b499888..af4c665df 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -89,9 +89,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler }.also { _packetReceiverJob = it } } - override suspend fun relogin() { if (::channel.isInitialized) { + if (channel.isOpen) { + kotlin.runCatching { + registerClientOnline() + }.exceptionOrNull() ?: return + } channel.close() } channel = PlatformSocket() @@ -149,10 +153,11 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") + registerClientOnline() + } - repeat(2) { - StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow - } + private suspend fun registerClientOnline() { + StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow } @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) From f37434c663238d1bb9bb5c67243c65097ff7dcfb Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 19:12:50 +0800 Subject: [PATCH 18/43] Remove `@MiraiInternalAPI` from NetworkHandler --- .../kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index c281223bb..76ffb50d1 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt @@ -36,7 +36,6 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel * * [BotNetworkHandler.close] 时将会 [取消][Job.cancel] 所有此作用域下的协程 */ -@MiraiInternalAPI @Suppress("PropertyName") abstract class BotNetworkHandler : CoroutineScope { /** From afb74ec652aad3277e2f02fde0410973822e2ea5 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 19:21:43 +0800 Subject: [PATCH 19/43] Annotate `subscribeInternal` with `@MiraiInternalAPI` --- .../net.mamoe.mirai/event/internal/InternalEventListeners.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt index 2a9f8f3b7..14e69a1e5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/internal/InternalEventListeners.kt @@ -23,8 +23,8 @@ import kotlin.reflect.KClass val EventLogger: MiraiLoggerWithSwitch = DefaultLogger("Event").withSwitch(false) -@PublishedApi -internal fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L { +@MiraiInternalAPI +fun <L : Listener<E>, E : Event> KClass<out E>.subscribeInternal(listener: L): L { this.listeners().addLast(listener) return listener } From 5b4e99c52df42813a1de6feca755830c5cc3ce96 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:13:40 +0800 Subject: [PATCH 20/43] Override close explicitly --- .../kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt | 2 +- .../kotlin/net.mamoe.mirai/utils/io/PlatformSocket.kt | 3 ++- .../jvmMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt index 1401f70fb..f20543980 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt @@ -32,7 +32,7 @@ actual class PlatformSocket : Closeable { actual val isOpen: Boolean get() = socket.isConnected - override fun close() = socket.close() + actual override fun close() = socket.close() @PublishedApi internal lateinit var writeChannel: BufferedOutputStream diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/PlatformSocket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/PlatformSocket.kt index 6b71d2885..70b411fae 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/PlatformSocket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/PlatformSocket.kt @@ -11,7 +11,6 @@ package net.mamoe.mirai.utils.io import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.Closeable -import kotlinx.io.errors.IOException import net.mamoe.mirai.utils.MiraiInternalAPI /** @@ -37,4 +36,6 @@ expect class PlatformSocket() : Closeable { suspend fun read(): ByteReadPacket val isOpen: Boolean + + override fun close() } \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt index 33aa5c19e..07f22e1e3 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt @@ -32,7 +32,7 @@ actual class PlatformSocket : Closeable { actual val isOpen: Boolean get() = socket.isConnected - override fun close() { + actual override fun close() { if (::socket.isInitialized) { socket.close() } From 74519919730b86e94e2abaf9b250fc07faa7f6e9 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:19:38 +0800 Subject: [PATCH 21/43] Catch missing exceptions thrown under Bot CoroutineScope --- mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt index 32a77cdd0..23a913e50 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -38,7 +38,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( private val botJob = SupervisorJob(configuration.parentCoroutineContext[Job]) override val coroutineContext: CoroutineContext = configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler] - ?: CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }) + ?: CoroutineExceptionHandler { _, e -> logger.error("An exception was thrown under a coroutine of Bot", e) }) @Suppress("CanBePrimaryConstructorProperty") // for logger final override val account: BotAccount = account From 843643a78d92db8ecb40f9d529dafb68a396f1e5 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:20:28 +0800 Subject: [PATCH 22/43] Add internal functions for japt --- .../net.mamoe.mirai/event/Subscribers.kt | 6 ++++ .../mirai/event/internal/EventInternalJvm.kt | 30 +++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt index 234ed239e..fd6887e85 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt @@ -16,6 +16,7 @@ import kotlinx.coroutines.GlobalScope import net.mamoe.mirai.Bot import net.mamoe.mirai.event.internal.Handler import net.mamoe.mirai.event.internal.subscribeInternal +import net.mamoe.mirai.utils.MiraiInternalAPI import kotlin.coroutines.CoroutineContext /* @@ -96,6 +97,7 @@ interface Listener<in E : Event> : CompletableJob { * @see subscribeGroupMessages 监听群消息 DSL * @see subscribeFriendMessages 监听好友消息 DSL */ +@UseExperimental(MiraiInternalAPI::class) inline fun <reified E : Event> CoroutineScope.subscribe(crossinline handler: suspend E.(E) -> ListeningStatus): Listener<E> = E::class.subscribeInternal(Handler { it.handler(it); }) @@ -107,6 +109,7 @@ inline fun <reified E : Event> CoroutineScope.subscribe(crossinline handler: sus * * @see subscribe 获取更多说明 */ +@UseExperimental(MiraiInternalAPI::class) inline fun <reified E : Event> CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener<E> = E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.LISTENING }) @@ -118,6 +121,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeAlways(crossinline listen * * @see subscribe 获取更多说明 */ +@UseExperimental(MiraiInternalAPI::class) inline fun <reified E : Event> CoroutineScope.subscribeOnce(crossinline listener: suspend E.(E) -> Unit): Listener<E> = E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.STOPPED }) @@ -129,6 +133,7 @@ inline fun <reified E : Event> CoroutineScope.subscribeOnce(crossinline listener * * @see subscribe 获取更多说明 */ +@UseExperimental(MiraiInternalAPI::class) inline fun <reified E : Event, T> CoroutineScope.subscribeUntil(valueIfStop: T, crossinline listener: suspend E.(E) -> T): Listener<E> = E::class.subscribeInternal(Handler { if (it.listener(it) == valueIfStop) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) @@ -141,6 +146,7 @@ inline fun <reified E : Event, T> CoroutineScope.subscribeUntil(valueIfStop: T, * * @see subscribe 获取更多说明 */ +@UseExperimental(MiraiInternalAPI::class) inline fun <reified E : Event, T> CoroutineScope.subscribeWhile(valueIfContinue: T, crossinline listener: suspend E.(E) -> T): Listener<E> = E::class.subscribeInternal(Handler { if (it.listener(it) != valueIfContinue) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt new file mode 100644 index 000000000..ccc2a718f --- /dev/null +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/EventInternalJvm.kt @@ -0,0 +1,30 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.event.internal + +import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.event.Event +import net.mamoe.mirai.event.Listener +import net.mamoe.mirai.event.ListeningStatus +import net.mamoe.mirai.utils.MiraiInternalAPI +import java.util.function.Consumer +import java.util.function.Function + +@MiraiInternalAPI +@Suppress("FunctionName") +fun <E : Event> Class<E>._subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Function<E, ListeningStatus>): Listener<E> { + return this.kotlin.subscribeInternal(scope.Handler { onEvent.apply(it) }) +} + +@MiraiInternalAPI +@Suppress("FunctionName") +fun <E : Event> Class<E>._subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Consumer<E>): Listener<E> { + return this.kotlin.subscribeInternal(scope.Handler { onEvent.accept(it); ListeningStatus.LISTENING; }) +} \ No newline at end of file From 61973170f92d5c91591b80284fcf39fa1814c4c8 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:20:51 +0800 Subject: [PATCH 23/43] Cancel heartbeat job if network is dead --- .../mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index af4c665df..b050db9a4 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -63,6 +63,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler private lateinit var channel: PlatformSocket private var _packetReceiverJob: Job? = null + private var heartbeatJob: Job? = null private val packetReceiveLock: Mutex = Mutex() @@ -90,11 +91,13 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } override suspend fun relogin() { + heartbeatJob?.cancel() if (::channel.isInitialized) { if (channel.isOpen) { kotlin.runCatching { registerClientOnline() }.exceptionOrNull() ?: return + logger.info("Cannot do fast relogin. Trying slow relogin") } channel.close() } @@ -157,7 +160,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } private suspend fun registerClientOnline() { - StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>(6000) // it's slow + StatSvc.Register(bot.client).sendAndExpect<StatSvc.Register.Response>() } @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) @@ -250,7 +253,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler joinAll(friendListJob, groupJob) - this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { + heartbeatJob = this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { while (this.isActive) { delay(bot.configuration.heartbeatPeriodMillis) val failException = doHeartBeat() From 617b231865da835f3cb615658fb49e30a1f1beb1 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:21:05 +0800 Subject: [PATCH 24/43] japt Events --- .../java/net/mamoe/mirai/japt/Events.java | 39 +++++++++++++++++++ .../mamoe/mirai/japt/internal/EventsImpl.kt | 16 +++----- 2 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 mirai-japt/src/main/java/net/mamoe/mirai/japt/Events.java rename mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt => mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/EventsImpl.kt (57%) diff --git a/mirai-japt/src/main/java/net/mamoe/mirai/japt/Events.java b/mirai-japt/src/main/java/net/mamoe/mirai/japt/Events.java new file mode 100644 index 000000000..76d7af4e7 --- /dev/null +++ b/mirai-japt/src/main/java/net/mamoe/mirai/japt/Events.java @@ -0,0 +1,39 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.japt; + +import kotlinx.coroutines.GlobalScope; +import net.mamoe.mirai.event.Event; +import net.mamoe.mirai.event.Listener; +import net.mamoe.mirai.event.ListeningStatus; +import net.mamoe.mirai.event.internal.EventInternalJvmKt; +import net.mamoe.mirai.japt.internal.EventsImplKt; +import org.jetbrains.annotations.NotNull; + +import java.util.function.Consumer; +import java.util.function.Function; + +public final class Events { + + @NotNull + public static <E extends Event> Listener<E> subscribe(@NotNull Class<E> eventClass, @NotNull Function<E, ListeningStatus> onEvent) { + return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); + } + + @NotNull + public static <E extends Event> Listener<E> subscribeAlways(@NotNull Class<E> eventClass, @NotNull Consumer<E> onEvent) { + return EventInternalJvmKt._subscribeEventForJaptOnly(eventClass, GlobalScope.INSTANCE, onEvent); + } + + @NotNull + public static <E extends Event> E broadcast(@NotNull E event) { + return EventsImplKt.broadcast(event); + } +} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/EventsImpl.kt similarity index 57% rename from mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt rename to mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/EventsImpl.kt index 9282eec6b..d2029bb2b 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/SubscribersJvm.kt +++ b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/EventsImpl.kt @@ -7,16 +7,10 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -package net.mamoe.mirai.event +package net.mamoe.mirai.japt.internal +import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.event.Event +import net.mamoe.mirai.event.broadcast -// TODO 添加更多 -/** - * Jvm 调用实现(阻塞) - */ -object Events { - /* - @JvmStatic - fun <E : Event> subscribe(type: Class<E>, handler: suspend (E) -> ListeningStatus) = - runBlocking { type.kotlin.subscribe(handler) }*/ -} +internal fun <E : Event> broadcast(e: E): E = runBlocking { e.broadcast() } \ No newline at end of file From bf7189fdd543dc53695d9c58538ae40837bb8b8c Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 20:31:22 +0800 Subject: [PATCH 25/43] Slow down heartbeat --- .../commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt index 46dd763e9..899f3d177 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt @@ -57,7 +57,7 @@ class BotConfiguration { /** * 心跳周期. 过长会导致被服务器断开连接. */ - var heartbeatPeriodMillis: Long = 30.secondsToMillis + var heartbeatPeriodMillis: Long = 60.secondsToMillis /** * 每次心跳时等待结果的时间. * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 5s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响. From 32e854db299f32895e22e47d03c9dad158a89e15 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 21:09:36 +0800 Subject: [PATCH 26/43] Improve DeviceInfo --- .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 13 ++- .../net.mamoe.mirai/utils/BotConfiguration.kt | 2 +- .../net.mamoe.mirai/utils/DeviceInfo.kt | 9 +- .../net.mamoe.mirai/utils/SystemDeviceInfo.kt | 8 +- .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 105 ++++++++++++++---- 5 files changed, 103 insertions(+), 34 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index b20ffbca2..30e01dc1b 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -14,13 +14,23 @@ import android.net.wifi.WifiManager import android.os.Build import android.telephony.TelephonyManager import kotlinx.io.core.toByteArray +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import java.io.File /** * 部分引用指向 [Build]. * 部分需要权限, 若无权限则会使用默认值. */ -actual open class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(context) { +@Serializable +actual open class SystemDeviceInfo actual constructor() : DeviceInfo() { + actual constructor(context: Context) : this() { + this.context = context + } + + @Transient + final override lateinit var context: Context + override val display: ByteArray get() = Build.DISPLAY.toByteArray() override val product: ByteArray get() = Build.PRODUCT.toByteArray() override val device: ByteArray get() = Build.DEVICE.toByteArray() @@ -88,6 +98,7 @@ actual open class SystemDeviceInfo actual constructor(context: Context) : Device override val androidId: ByteArray get() = Build.ID.toByteArray() override val apn: ByteArray get() = "wifi".toByteArray() + @Serializable object Version : DeviceInfo.Version { override val incremental: ByteArray get() = Build.VERSION.INCREMENTAL.toByteArray() override val release: ByteArray get() = Build.VERSION.RELEASE.toByteArray() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt index 899f3d177..b23e274d6 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt @@ -45,7 +45,7 @@ class BotConfiguration { */ var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") } /** - * 设备信息覆盖 + * 设备信息覆盖. 默认使用随机的设备信息. */ var deviceInfo: ((Context) -> DeviceInfo)? = null diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt index 89e76eabe..491b952fe 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt @@ -11,16 +11,15 @@ package net.mamoe.mirai.utils import kotlinx.serialization.SerialId import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import kotlinx.serialization.protobuf.ProtoBuf -import net.mamoe.mirai.utils.cryptor.contentToString /** * 设备信息. 可通过继承 [SystemDeviceInfo] 来在默认的基础上修改 */ -abstract class DeviceInfo internal constructor( - context: Context -) { - val context: Context by context.unsafeWeakRef() +abstract class DeviceInfo { + @Transient + abstract val context: Context abstract val display: ByteArray abstract val product: ByteArray diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt index ef4780220..bd4f0b259 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt @@ -9,13 +9,13 @@ package net.mamoe.mirai.utils -import net.mamoe.mirai.utils.Context -import net.mamoe.mirai.utils.DeviceInfo - /** * 通过本机信息来获取设备信息. * * Android: 获取手机信息, 与 QQ 官方相同. * JVM: 部分为常量, 部分为随机 */ -open expect class SystemDeviceInfo(context: Context) : DeviceInfo \ No newline at end of file +expect open class SystemDeviceInfo : DeviceInfo { + constructor() + constructor(context: Context) +} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index 217b202ce..b1274bdaf 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -10,38 +10,97 @@ package net.mamoe.mirai.utils import kotlinx.io.core.toByteArray +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.UnstableDefault +import kotlinx.serialization.json.Json import net.mamoe.mirai.utils.io.getRandomByteArray import net.mamoe.mirai.utils.io.getRandomString +import java.io.File +/** + * 加载或创建一个设备信息. + */ +@UseExperimental(UnstableDefault::class) +fun File.loadAsDeviceInfo(context: Context = ContextImpl()): DeviceInfo { + if (!this.exists() || this.length() == 0L) { + return SystemDeviceInfo(context).also { + this.writeText(Json.plain.stringify(SystemDeviceInfo.serializer(), it)) + } + } + return Json.nonstrict.parse(DeviceInfoData.serializer(), this.readText()).also { + it.context = context + } +} + + +@Serializable @UseExperimental(ExperimentalUnsignedTypes::class) -actual open class SystemDeviceInfo actual constructor(context: Context) : DeviceInfo(context) { - override val display: ByteArray get() = "MIRAI.200122.001".toByteArray() - override val product: ByteArray get() = "mirai".toByteArray() - override val device: ByteArray get() = "mirai".toByteArray() - override val board: ByteArray get() = "mirai".toByteArray() - override val brand: ByteArray get() = "mamoe".toByteArray() - override val model: ByteArray get() = "mirai".toByteArray() - override val bootloader: ByteArray get() = "unknown".toByteArray() - override val fingerprint: ByteArray get() = "mamoe/mirai/mirai:10/MIRAI.200122.001/5891938:user/release-keys".toByteArray() +actual open class SystemDeviceInfo actual constructor() : DeviceInfo() { + actual constructor(context: Context) : this() { + this.context = context + } + + @Transient + final override lateinit var context: Context + + override val display: ByteArray = "MIRAI.200122.001".toByteArray() + override val product: ByteArray = "mirai".toByteArray() + override val device: ByteArray = "mirai".toByteArray() + override val board: ByteArray = "mirai".toByteArray() + override val brand: ByteArray = "mamoe".toByteArray() + override val model: ByteArray = "mirai".toByteArray() + override val bootloader: ByteArray = "unknown".toByteArray() + override val fingerprint: ByteArray = "mamoe/mirai/mirai:10/MIRAI.200122.001/${getRandomString(7, '0'..'9')}:user/release-keys".toByteArray() override val bootId: ByteArray = ExternalImage.generateUUID(md5(getRandomByteArray(16))).toByteArray() - override val procVersion: ByteArray get() = "Linux version 3.0.31-g6fb96c9 (android-build@xxx.xxx.xxx.xxx.com)".toByteArray() - override val baseBand: ByteArray get() = byteArrayOf() + override val procVersion: ByteArray = "Linux version 3.0.31-${getRandomString(8)} (android-build@xxx.xxx.xxx.xxx.com)".toByteArray() + override val baseBand: ByteArray = byteArrayOf() override val version: DeviceInfo.Version get() = Version - override val simInfo: ByteArray get() = "T-Mobile".toByteArray() - override val osType: ByteArray get() = "android".toByteArray() - override val macAddress: ByteArray get() = "02:00:00:00:00:00".toByteArray() - override val wifiBSSID: ByteArray? get() = "02:00:00:00:00:00".toByteArray() - override val wifiSSID: ByteArray? get() = "<unknown ssid>".toByteArray() - override val imsiMd5: ByteArray get() = md5(getRandomByteArray(16)) - override val imei: String get() = getRandomString(15, '0'..'9') + override val simInfo: ByteArray = "T-Mobile".toByteArray() + override val osType: ByteArray = "android".toByteArray() + override val macAddress: ByteArray = "02:00:00:00:00:00".toByteArray() + override val wifiBSSID: ByteArray? = "02:00:00:00:00:00".toByteArray() + override val wifiSSID: ByteArray? = "<unknown ssid>".toByteArray() + override val imsiMd5: ByteArray = md5(getRandomByteArray(16)) + override val imei: String = getRandomString(15, '0'..'9') override val ipAddress: ByteArray get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf() override val androidId: ByteArray get() = display - override val apn: ByteArray get() = "wifi".toByteArray() + override val apn: ByteArray = "wifi".toByteArray() + @Serializable object Version : DeviceInfo.Version { - override val incremental: ByteArray get() = "5891938".toByteArray() - override val release: ByteArray get() = "10".toByteArray() - override val codename: ByteArray get() = "REL".toByteArray() - override val sdk: Int get() = 29 + override val incremental: ByteArray = "5891938".toByteArray() + override val release: ByteArray = "10".toByteArray() + override val codename: ByteArray = "REL".toByteArray() + override val sdk: Int = 29 } +} + +@Serializable +class DeviceInfoData( + override val display: ByteArray, + override val product: ByteArray, + override val device: ByteArray, + override val board: ByteArray, + override val brand: ByteArray, + override val model: ByteArray, + override val bootloader: ByteArray, + override val fingerprint: ByteArray, + override val bootId: ByteArray, + override val procVersion: ByteArray, + override val baseBand: ByteArray, + override val version: Version, + override val simInfo: ByteArray, + override val osType: ByteArray, + override val macAddress: ByteArray, + override val wifiBSSID: ByteArray?, + override val wifiSSID: ByteArray?, + override val imsiMd5: ByteArray, + override val imei: String, + override val ipAddress: ByteArray, + override val androidId: ByteArray, + override val apn: ByteArray +) : DeviceInfo() { + @Transient + override lateinit var context: Context } \ No newline at end of file From c6a2229fc2656f593dfb84ba267d709c9a8640c1 Mon Sep 17 00:00:00 2001 From: ryoii <ryoii@foxmail.com> Date: Fri, 14 Feb 2020 21:25:34 +0800 Subject: [PATCH 27/43] http-api support AtAll --- mirai-api-http/README_CH.md | 15 ++++++++++++++- .../mirai/api/http/data/common/MessageDTO.kt | 5 +++++ .../kotlin/net/mamoe/mirai/api/http/util/Json.kt | 1 + 3 files changed, 20 insertions(+), 1 deletion(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 550b63e75..0216f73f6 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -343,9 +343,10 @@ Content-Type:multipart/form-data #### 消息是构成消息链的基本对象,目前支持的消息类型有 + [x] At,@消息 ++ [x] AtAll,@全体成员 + [x] Face,表情消息 + [x] Plain,文字消息 -+ [ ] Image,图片消息 ++ [x] Image,图片消息 + [ ] Xml,Xml卡片消息 + [ ] 敬请期待 @@ -364,6 +365,18 @@ Content-Type:multipart/form-data | target | Long | 群员QQ号 | | display | String | @时显示的文本如:"@Mirai" | +#### AtAll + +```json5 +{ + "type": "AtAll" +} +``` + +| 名字 | 类型 | 说明 | +| ------- | ------ | ------------------------- | +| - | - | - | + #### Face ```json5 diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt index b928c9696..ccd6d2440 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt @@ -39,6 +39,9 @@ data class UnKnownMessagePacketDTO(val msg: String) : MessagePacketDTO() @SerialName("At") data class AtDTO(val target: Long, val display: String) : MessageDTO() @Serializable +@SerialName("AtAll") +data class AtAllDTO(val target: Long = 0) : MessageDTO() // target为保留字段 +@Serializable @SerialName("Face") data class FaceDTO(val faceId: Int) : MessageDTO() @Serializable @@ -83,6 +86,7 @@ fun MessageChainDTO.toMessageChain() = @UseExperimental(ExperimentalUnsignedTypes::class) fun Message.toDTO() = when (this) { is At -> AtDTO(target, display) + is AtAll -> AtAllDTO(0L) is Face -> FaceDTO(id.value.toInt()) is PlainText -> PlainDTO(stringValue) is Image -> ImageDTO(imageId) @@ -93,6 +97,7 @@ fun Message.toDTO() = when (this) { @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) fun MessageDTO.toMessage() = when (this) { is AtDTO -> At(target, display) + is AtAllDTO -> AtAll is FaceDTO -> Face(FaceId(faceId.toUByte())) is PlainDTO -> PlainText(text) is ImageDTO -> Image(imageId) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt index b12c2ce6a..8b37ebd80 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt @@ -51,6 +51,7 @@ object MiraiJson { } polymorphic(MessageDTO.serializer()) { AtDTO::class with AtDTO.serializer() + AtAllDTO::class with AtAllDTO.serializer() FaceDTO::class with FaceDTO.serializer() PlainDTO::class with PlainDTO.serializer() ImageDTO::class with ImageDTO.serializer() From ace117467837c4a995c3ec50e869d6aac4e3745b Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 21:54:03 +0800 Subject: [PATCH 28/43] Fix configuration --- .../mirai/utils/BotConfigurationAndroid.kt | 131 ++++++++++++++++++ .../mamoe/mirai/utils/defaultLoginSolver.kt | 30 ---- .../net.mamoe.mirai/utils/BotConfiguration.kt | 45 ++++-- ...chaSolverJvm.kt => BotConfigurationJvm.kt} | 97 +++++++++++++ .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 21 ++- 5 files changed, 274 insertions(+), 50 deletions(-) create mode 100644 mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt delete mode 100644 mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/defaultLoginSolver.kt rename mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/{DefaultCaptchaSolverJvm.kt => BotConfigurationJvm.kt} (67%) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt new file mode 100644 index 000000000..611b8927d --- /dev/null +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2020 Mamoe Technologies and contributors. + * + * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. + * + * https://github.com/mamoe/mirai/blob/master/LICENSE + */ + +package net.mamoe.mirai.utils + +import kotlinx.io.core.IoBuffer +import net.mamoe.mirai.Bot +import net.mamoe.mirai.network.BotNetworkHandler +import java.io.File +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext + +/** + * 在各平台实现的默认的验证码处理器. + */ +actual var defaultLoginSolver: LoginSolver = object : LoginSolver() { + override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? { + error("should be implemented manually by you") + } + + override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { + error("should be implemented manually by you") + } + + override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { + error("should be implemented manually by you") + } +} + +@Suppress("ClassName", "PropertyName") +actual open class BotConfiguration actual constructor() { + /** + * 日志记录器 + */ + actual var botLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Bot(${it.uin})") } + /** + * 网络层日志构造器 + */ + actual var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") } + /** + * 设备信息覆盖. 默认使用随机的设备信息. + */ + actual var deviceInfo: ((Context) -> DeviceInfo)? = null + + /** + * 父 [CoroutineContext] + */ + actual var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + + /** + * 心跳周期. 过长会导致被服务器断开连接. + */ + actual var heartbeatPeriodMillis: Long = 60.secondsToMillis + /** + * 每次心跳时等待结果的时间. + * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 5s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响. + */ + actual var heartbeatTimeoutMillis: Long = 2.secondsToMillis + /** + * 心跳失败后的第一次重连前的等待时间. + */ + actual var firstReconnectDelayMillis: Long = 5.secondsToMillis + /** + * 重连失败后, 继续尝试的每次等待时间 + */ + actual var reconnectPeriodMillis: Long = 60.secondsToMillis + /** + * 最多尝试多少次重连 + */ + actual var reconnectionRetryTimes: Int = 3 + /** + * 验证码处理器 + */ + actual var loginSolver: LoginSolver = defaultLoginSolver + + actual companion object { + /** + * 默认的配置实例 + */ + @JvmStatic + actual val Default = BotConfiguration() + } + + @Suppress("NOTHING_TO_INLINE") + @BotConfigurationDsl + inline operator fun FileBasedDeviceInfo.unaryPlus() { + deviceInfo = { File(filepath).loadAsDeviceInfo() } + } + + @Suppress("NOTHING_TO_INLINE") + @BotConfigurationDsl + inline operator fun FileBasedDeviceInfo.ByDeviceDotJson.unaryPlus() { + deviceInfo = { File("device.json").loadAsDeviceInfo() } + } + + actual operator fun _NoNetworkLog.unaryPlus() { + networkLoggerSupplier = supplier + } + + /** + * 不记录网络层的 log. + * 网络层 log 包含包接收, 包发送, 和一些调试用的记录. + */ + @BotConfigurationDsl + actual val NoNetworkLog: _NoNetworkLog + get() = _NoNetworkLog + + + @BotConfigurationDsl + actual object _NoNetworkLog { + internal val supplier = { _: BotNetworkHandler -> SilentLogger } + } +} + +/** + * 使用文件系统存储设备信息. + */ +@BotConfigurationDsl +inline class FileBasedDeviceInfo @BotConfigurationDsl constructor(val filepath: String) { + /** + * 使用 "device.json" 存储设备信息 + */ + @BotConfigurationDsl + companion object ByDeviceDotJson +} \ No newline at end of file diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/defaultLoginSolver.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/defaultLoginSolver.kt deleted file mode 100644 index ccd94b74c..000000000 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/defaultLoginSolver.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 Mamoe Technologies and contributors. - * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. - * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link. - * - * https://github.com/mamoe/mirai/blob/master/LICENSE - */ - -package net.mamoe.mirai.utils - -import kotlinx.io.core.IoBuffer -import net.mamoe.mirai.Bot - -/** - * 在各平台实现的默认的验证码处理器. - */ -actual var defaultLoginSolver: LoginSolver = object : LoginSolver() { - override suspend fun onSolvePicCaptcha(bot: Bot, data: IoBuffer): String? { - error("should be implemented manually by you") - } - - override suspend fun onSolveSliderCaptcha(bot: Bot, url: String): String? { - error("should be implemented manually by you") - } - - override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { - error("should be implemented manually by you") - } -} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt index b23e274d6..3ebb748ec 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt @@ -13,7 +13,6 @@ import kotlinx.io.core.IoBuffer import net.mamoe.mirai.Bot import net.mamoe.mirai.network.BotNetworkHandler import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.EmptyCoroutineContext import kotlin.jvm.JvmStatic /** @@ -33,58 +32,74 @@ abstract class LoginSolver { expect var defaultLoginSolver: LoginSolver /** - * 网络和连接配置 + * [Bot] 配置 */ -class BotConfiguration { +@Suppress("PropertyName") +expect open class BotConfiguration() { /** * 日志记录器 */ - var botLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Bot(${it.uin})") } + var botLoggerSupplier: ((Bot) -> MiraiLogger) /** * 网络层日志构造器 */ - var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") } + var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) /** * 设备信息覆盖. 默认使用随机的设备信息. */ - var deviceInfo: ((Context) -> DeviceInfo)? = null + var deviceInfo: ((Context) -> DeviceInfo)? /** * 父 [CoroutineContext] */ - var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + var parentCoroutineContext: CoroutineContext /** * 心跳周期. 过长会导致被服务器断开连接. */ - var heartbeatPeriodMillis: Long = 60.secondsToMillis + var heartbeatPeriodMillis: Long /** * 每次心跳时等待结果的时间. * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 5s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响. */ - var heartbeatTimeoutMillis: Long = 2.secondsToMillis + var heartbeatTimeoutMillis: Long /** * 心跳失败后的第一次重连前的等待时间. */ - var firstReconnectDelayMillis: Long = 5.secondsToMillis + var firstReconnectDelayMillis: Long /** * 重连失败后, 继续尝试的每次等待时间 */ - var reconnectPeriodMillis: Long = 60.secondsToMillis + var reconnectPeriodMillis: Long /** * 最多尝试多少次重连 */ - var reconnectionRetryTimes: Int = 3 + var reconnectionRetryTimes: Int /** * 验证码处理器 */ - var loginSolver: LoginSolver = defaultLoginSolver + var loginSolver: LoginSolver companion object { /** * 默认的配置实例 */ @JvmStatic - val Default = BotConfiguration() + val Default: BotConfiguration } -} \ No newline at end of file + + operator fun _NoNetworkLog.unaryPlus() + + /** + * 不记录网络层的 log. + * 网络层 log 包含包接收, 包发送, 和一些调试用的记录. + */ + @BotConfigurationDsl + val NoNetworkLog: _NoNetworkLog + + @Suppress("ClassName") + object _NoNetworkLog +} + +@DslMarker +annotation class BotConfigurationDsl \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt similarity index 67% rename from mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt rename to mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt index ec265bd0e..a136328e3 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/DefaultCaptchaSolverJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt @@ -22,12 +22,14 @@ import kotlinx.coroutines.withContext import kotlinx.io.core.IoBuffer import kotlinx.io.core.use import net.mamoe.mirai.Bot +import net.mamoe.mirai.network.BotNetworkHandler import java.awt.Image import java.awt.image.BufferedImage import java.io.File import java.io.RandomAccessFile import javax.imageio.ImageIO import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * 平台默认的验证码识别器. @@ -157,3 +159,98 @@ private fun BufferedImage.createCharImg(outputWidth: Int = 100, ignoreRate: Doub } } +@Suppress("ClassName", "PropertyName") +actual open class BotConfiguration actual constructor() { + /** + * 日志记录器 + */ + actual var botLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Bot(${it.uin})") } + /** + * 网络层日志构造器 + */ + actual var networkLoggerSupplier: ((BotNetworkHandler) -> MiraiLogger) = { DefaultLogger("Network(${it.bot.uin})") } + /** + * 设备信息覆盖. 默认使用随机的设备信息. + */ + actual var deviceInfo: ((Context) -> DeviceInfo)? = null + + /** + * 父 [CoroutineContext] + */ + actual var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + + /** + * 心跳周期. 过长会导致被服务器断开连接. + */ + actual var heartbeatPeriodMillis: Long = 60.secondsToMillis + /** + * 每次心跳时等待结果的时间. + * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 5s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响. + */ + actual var heartbeatTimeoutMillis: Long = 2.secondsToMillis + /** + * 心跳失败后的第一次重连前的等待时间. + */ + actual var firstReconnectDelayMillis: Long = 5.secondsToMillis + /** + * 重连失败后, 继续尝试的每次等待时间 + */ + actual var reconnectPeriodMillis: Long = 60.secondsToMillis + /** + * 最多尝试多少次重连 + */ + actual var reconnectionRetryTimes: Int = 3 + /** + * 验证码处理器 + */ + actual var loginSolver: LoginSolver = defaultLoginSolver + + actual companion object { + /** + * 默认的配置实例 + */ + @JvmStatic + actual val Default = BotConfiguration() + } + + @Suppress("NOTHING_TO_INLINE") + @BotConfigurationDsl + inline operator fun FileBasedDeviceInfo.unaryPlus() { + deviceInfo = { File(filepath).loadAsDeviceInfo() } + } + + @Suppress("NOTHING_TO_INLINE") + @BotConfigurationDsl + inline operator fun FileBasedDeviceInfo.ByDeviceDotJson.unaryPlus() { + deviceInfo = { File("device.json").loadAsDeviceInfo() } + } + + actual operator fun _NoNetworkLog.unaryPlus() { + networkLoggerSupplier = supplier + } + + /** + * 不记录网络层的 log. + * 网络层 log 包含包接收, 包发送, 和一些调试用的记录. + */ + @BotConfigurationDsl + actual val NoNetworkLog: _NoNetworkLog + get() = _NoNetworkLog + + @BotConfigurationDsl + actual object _NoNetworkLog { + internal val supplier = { _: BotNetworkHandler -> SilentLogger } + } +} + +/** + * 使用文件系统存储设备信息. + */ +@BotConfigurationDsl +inline class FileBasedDeviceInfo @BotConfigurationDsl constructor(val filepath: String) { + /** + * 使用 "device.json" 存储设备信息 + */ + @BotConfigurationDsl + companion object ByDeviceDotJson +} \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index b1274bdaf..c1176eabf 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -19,7 +19,7 @@ import net.mamoe.mirai.utils.io.getRandomString import java.io.File /** - * 加载或创建一个设备信息. + * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存. */ @UseExperimental(UnstableDefault::class) fun File.loadAsDeviceInfo(context: Context = ContextImpl()): DeviceInfo { @@ -55,7 +55,7 @@ actual open class SystemDeviceInfo actual constructor() : DeviceInfo() { override val bootId: ByteArray = ExternalImage.generateUUID(md5(getRandomByteArray(16))).toByteArray() override val procVersion: ByteArray = "Linux version 3.0.31-${getRandomString(8)} (android-build@xxx.xxx.xxx.xxx.com)".toByteArray() override val baseBand: ByteArray = byteArrayOf() - override val version: DeviceInfo.Version get() = Version + override val version: Version = Version override val simInfo: ByteArray = "T-Mobile".toByteArray() override val osType: ByteArray = "android".toByteArray() override val macAddress: ByteArray = "02:00:00:00:00:00".toByteArray() @@ -89,7 +89,7 @@ class DeviceInfoData( override val bootId: ByteArray, override val procVersion: ByteArray, override val baseBand: ByteArray, - override val version: Version, + override val version: VersionData, override val simInfo: ByteArray, override val osType: ByteArray, override val macAddress: ByteArray, @@ -97,10 +97,21 @@ class DeviceInfoData( override val wifiSSID: ByteArray?, override val imsiMd5: ByteArray, override val imei: String, - override val ipAddress: ByteArray, - override val androidId: ByteArray, override val apn: ByteArray ) : DeviceInfo() { @Transient override lateinit var context: Context + + @UseExperimental(ExperimentalUnsignedTypes::class) + override val ipAddress: ByteArray + get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf() + override val androidId: ByteArray get() = display + + @Serializable + class VersionData( + override val incremental: ByteArray, + override val release: ByteArray, + override val codename: ByteArray, + override val sdk: Int + ) : Version } \ No newline at end of file From 2ae7c75a16218ad8a2a022d1c61257592c360a3e Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 21:55:28 +0800 Subject: [PATCH 29/43] Add default values --- .../kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index c1176eabf..a8e18f3a4 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -109,9 +109,9 @@ class DeviceInfoData( @Serializable class VersionData( - override val incremental: ByteArray, - override val release: ByteArray, - override val codename: ByteArray, - override val sdk: Int + override val incremental: ByteArray = SystemDeviceInfo.Version.incremental, + override val release: ByteArray = SystemDeviceInfo.Version.release, + override val codename: ByteArray = SystemDeviceInfo.Version.codename, + override val sdk: Int = SystemDeviceInfo.Version.sdk ) : Version } \ No newline at end of file From 67bf197148fd78147b113749c929db419936d0c3 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 21:56:04 +0800 Subject: [PATCH 30/43] Cancel packet receiver job before reconnecting --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index b050db9a4..5d49e7451 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -67,11 +67,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler private val packetReceiveLock: Mutex = Mutex() - private fun startPacketReceiverJobOrGet(): Job { - val job = _packetReceiverJob - if (job != null && job.isActive && channel.isOpen) { - return job - } + private fun startPacketReceiverJobOrKill(cancelCause: CancellationException? = null): Job { + _packetReceiverJob?.cancel(cancelCause) return this.launch(CoroutineName("Incoming Packet Receiver")) { while (channel.isOpen) { @@ -103,8 +100,10 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } channel = PlatformSocket() // TODO: 2020/2/14 连接多个服务器 - channel.connect("113.96.13.208", 8080) - startPacketReceiverJobOrGet() + withTimeout(3000) { + channel.connect("113.96.13.208", 8080) + } + startPacketReceiverJobOrKill(CancellationException("reconnect")) // logger.info("Trying login") var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect() From 4738de337513a5c96b8980b36dccc1aa93d197fb Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 21:58:42 +0800 Subject: [PATCH 31/43] Add timeout message --- .../mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 5d49e7451..965eea377 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -100,9 +100,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } channel = PlatformSocket() // TODO: 2020/2/14 连接多个服务器 - withTimeout(3000) { + withTimeoutOrNull(3000) { channel.connect("113.96.13.208", 8080) - } + } ?: error("timeout connecting server") startPacketReceiverJobOrKill(CancellationException("reconnect")) // logger.info("Trying login") From 797cef15e247c693641cce4ae9c96589ca8a7f8e Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:04:32 +0800 Subject: [PATCH 32/43] Logger: Accept String over Any; Introduce common optional log functions --- .../net.mamoe.mirai/utils/MiraiLogger.kt | 161 +++++++++--------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt index cb01c8a83..267cc897b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/MiraiLogger.kt @@ -86,7 +86,7 @@ interface MiraiLogger { * 记录一个 `verbose` 级别的日志. * 无关紧要的, 经常大量输出的日志应使用它. */ - fun verbose(any: Any?) + fun verbose(message: String?) fun verbose(e: Throwable?) = verbose(null, e) fun verbose(message: String?, e: Throwable?) @@ -94,7 +94,7 @@ interface MiraiLogger { /** * 记录一个 _调试_ 级别的日志. */ - fun debug(any: Any?) + fun debug(message: String?) fun debug(e: Throwable?) = debug(null, e) fun debug(message: String?, e: Throwable?) @@ -103,7 +103,7 @@ interface MiraiLogger { /** * 记录一个 _信息_ 级别的日志. */ - fun info(any: Any?) + fun info(message: String?) fun info(e: Throwable?) = info(null, e) fun info(message: String?, e: Throwable?) @@ -112,7 +112,7 @@ interface MiraiLogger { /** * 记录一个 _警告_ 级别的日志. */ - fun warning(any: Any?) + fun warning(message: String?) fun warning(e: Throwable?) = warning(null, e) fun warning(message: String?, e: Throwable?) @@ -121,7 +121,7 @@ interface MiraiLogger { /** * 记录一个 _错误_ 级别的日志. */ - fun error(e: Any?) + fun error(message: String?) fun error(e: Throwable?) = error(null, e) fun error(message: String?, e: Throwable?) @@ -149,6 +149,47 @@ interface MiraiLogger { operator fun plusAssign(follower: MiraiLogger) } + +inline fun MiraiLogger.verbose(lazyMessage: () -> String) { + if (this is MiraiLoggerWithSwitch && switch) verbose(lazyMessage()) +} + +inline fun MiraiLogger.verbose(lazyMessage: () -> String, e: Throwable?) { + if (this is MiraiLoggerWithSwitch && switch) verbose(lazyMessage(), e) +} + +inline fun MiraiLogger.debug(lazyMessage: () -> String?) { + if (this is MiraiLoggerWithSwitch && switch) debug(lazyMessage()) +} + +inline fun MiraiLogger.debug(lazyMessage: () -> String?, e: Throwable?) { + if (this is MiraiLoggerWithSwitch && switch) debug(lazyMessage(), e) +} + +inline fun MiraiLogger.info(lazyMessage: () -> String?) { + if (this is MiraiLoggerWithSwitch && switch) info(lazyMessage()) +} + +inline fun MiraiLogger.info(lazyMessage: () -> String?, e: Throwable?) { + if (this is MiraiLoggerWithSwitch && switch) info(lazyMessage(), e) +} + +inline fun MiraiLogger.warning(lazyMessage: () -> String?) { + if (this is MiraiLoggerWithSwitch && switch) warning(lazyMessage()) +} + +inline fun MiraiLogger.warning(lazyMessage: () -> String?, e: Throwable?) { + if (this is MiraiLoggerWithSwitch && switch) warning(lazyMessage(), e) +} + +inline fun MiraiLogger.error(lazyMessage: () -> String?) { + if (this is MiraiLoggerWithSwitch && switch) error(lazyMessage()) +} + +inline fun MiraiLogger.error(lazyMessage: () -> String?, e: Throwable?) { + if (this is MiraiLoggerWithSwitch && switch) error(lazyMessage(), e) +} + /** * 当前平台的默认的日志记录器. * 在 _JVM 控制台_ 端的实现为 [println] @@ -165,11 +206,11 @@ expect open class PlatformLogger @JvmOverloads internal constructor(identity: St object SilentLogger : PlatformLogger() { override val identity: String? = null - override fun error0(any: Any?) = Unit - override fun debug0(any: Any?) = Unit - override fun warning0(any: Any?) = Unit - override fun verbose0(any: Any?) = Unit - override fun info0(any: Any?) = Unit + override fun error0(message: String?) = Unit + override fun debug0(message: String?) = Unit + override fun warning0(message: String?) = Unit + override fun verbose0(message: String?) = Unit + override fun info0(message: String?) = Unit } /** @@ -180,15 +221,15 @@ class SimpleLogger(override val identity: String?, private val logger: (String?, operator fun invoke(logger: (String?, Throwable?) -> Unit): SimpleLogger = SimpleLogger(null, logger) } - override fun verbose0(any: Any?) = logger(any?.toString(), null) + override fun verbose0(message: String?) = logger(message, null) override fun verbose0(message: String?, e: Throwable?) = logger(message, e) - override fun debug0(any: Any?) = logger(any?.toString(), null) + override fun debug0(message: String?) = logger(message, null) override fun debug0(message: String?, e: Throwable?) = logger(message, e) - override fun info0(any: Any?) = logger(any?.toString(), null) + override fun info0(message: String?) = logger(message, null) override fun info0(message: String?, e: Throwable?) = logger(message, e) - override fun warning0(any: Any?) = logger(any?.toString(), null) + override fun warning0(message: String?) = logger(message, null) override fun warning0(message: String?, e: Throwable?) = logger(message, e) - override fun error0(any: Any?) = logger(any?.toString(), null) + override fun error0(message: String?) = logger(message, null) override fun error0(message: String?, e: Throwable?) = logger(message, e) } @@ -218,56 +259,16 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg switch = false } - override fun verbose0(any: Any?) = if (switch) delegate.verbose(any) else Unit + override fun verbose0(message: String?) = if (switch) delegate.verbose(message) else Unit override fun verbose0(message: String?, e: Throwable?) = if (switch) delegate.verbose(message, e) else Unit - override fun debug0(any: Any?) = if (switch) delegate.debug(any) else Unit + override fun debug0(message: String?) = if (switch) delegate.debug(message) else Unit override fun debug0(message: String?, e: Throwable?) = if (switch) delegate.debug(message, e) else Unit - override fun info0(any: Any?) = if (switch) delegate.info(any) else Unit + override fun info0(message: String?) = if (switch) delegate.info(message) else Unit override fun info0(message: String?, e: Throwable?) = if (switch) delegate.info(message, e) else Unit - override fun warning0(any: Any?) = if (switch) delegate.warning(any) else Unit + override fun warning0(message: String?) = if (switch) delegate.warning(message) else Unit override fun warning0(message: String?, e: Throwable?) = if (switch) delegate.warning(message, e) else Unit - override fun error0(any: Any?) = if (switch) delegate.error(any) else Unit + override fun error0(message: String?) = if (switch) delegate.error(message) 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) - } } /** @@ -280,9 +281,9 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg abstract class MiraiLoggerPlatformBase : MiraiLogger { final override var follower: MiraiLogger? = null - final override fun verbose(any: Any?) { - follower?.verbose(any) - verbose0(any) + final override fun verbose(message: String?) { + follower?.verbose(message) + verbose0(message) } final override fun verbose(message: String?, e: Throwable?) { @@ -290,9 +291,9 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { verbose0(message, e) } - final override fun debug(any: Any?) { - follower?.debug(any) - debug0(any) + final override fun debug(message: String?) { + follower?.debug(message) + debug0(message) } final override fun debug(message: String?, e: Throwable?) { @@ -300,9 +301,9 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { debug0(message, e) } - final override fun info(any: Any?) { - follower?.info(any) - info0(any) + final override fun info(message: String?) { + follower?.info(message) + info0(message) } final override fun info(message: String?, e: Throwable?) { @@ -310,9 +311,9 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { info0(message, e) } - final override fun warning(any: Any?) { - follower?.warning(any) - warning0(any) + final override fun warning(message: String?) { + follower?.warning(message) + warning0(message) } final override fun warning(message: String?, e: Throwable?) { @@ -320,9 +321,9 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { warning0(message, e) } - final override fun error(e: Any?) { - follower?.error(e) - error0(e) + final override fun error(message: String?) { + follower?.error(message) + error0(message) } final override fun error(message: String?, e: Throwable?) { @@ -330,15 +331,15 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { error0(message, e) } - protected abstract fun verbose0(any: Any?) + protected abstract fun verbose0(message: String?) protected abstract fun verbose0(message: String?, e: Throwable?) - protected abstract fun debug0(any: Any?) + protected abstract fun debug0(message: String?) protected abstract fun debug0(message: String?, e: Throwable?) - protected abstract fun info0(any: Any?) + protected abstract fun info0(message: String?) protected abstract fun info0(message: String?, e: Throwable?) - protected abstract fun warning0(any: Any?) + protected abstract fun warning0(message: String?) protected abstract fun warning0(message: String?, e: Throwable?) - protected abstract fun error0(any: Any?) + protected abstract fun error0(message: String?) protected abstract fun error0(message: String?, e: Throwable?) override operator fun <T : MiraiLogger> plus(follower: T): T { From 8a4750badb69045c617763f0ac07aa8addaf064a Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:05:59 +0800 Subject: [PATCH 33/43] Fix platform implementations --- .../mirai/utils/PlatformLoggerAndroid.kt | 20 +++++++++---------- .../net/mamoe/mirai/utils/MiraiLoggerJvm.kt | 13 ++++++------ 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLoggerAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLoggerAndroid.kt index f513231f6..6370f53c5 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLoggerAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformLoggerAndroid.kt @@ -16,40 +16,40 @@ import android.util.Log * 不应该直接构造这个类的实例. 需使用 [DefaultLogger] */ actual open class PlatformLogger actual constructor(override val identity: String?) : MiraiLoggerPlatformBase() { - override fun verbose0(any: Any?) { - Log.v(identity, any?.toString() ?: "") + override fun verbose0(message: String?) { + Log.v(identity, message ?: "") } override fun verbose0(message: String?, e: Throwable?) { Log.v(identity, message ?: "", e) } - override fun debug0(any: Any?) { - Log.d(identity, any?.toString() ?: "") + override fun debug0(message: String?) { + Log.d(identity, message ?: "") } override fun debug0(message: String?, e: Throwable?) { Log.d(identity, message ?: "", e) } - override fun info0(any: Any?) { - Log.i(identity, any?.toString() ?: "") + override fun info0(message: String?) { + Log.i(identity, message ?: "") } override fun info0(message: String?, e: Throwable?) { Log.i(identity, message ?: "", e) } - override fun warning0(any: Any?) { - Log.w(identity, any?.toString() ?: "") + override fun warning0(message: String?) { + Log.w(identity, message ?: "") } override fun warning0(message: String?, e: Throwable?) { Log.w(identity, message ?: "", e) } - override fun error0(any: Any?) { - Log.e(identity, any?.toString() ?: "") + override fun error0(message: String?) { + Log.e(identity, message ?: "") } override fun error0(message: String?, e: Throwable?) { diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/MiraiLoggerJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/MiraiLoggerJvm.kt index b6e704964..0f8bf91c6 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/MiraiLoggerJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/MiraiLoggerJvm.kt @@ -18,37 +18,37 @@ import java.util.* actual open class PlatformLogger @JvmOverloads internal actual constructor( override val identity: String? ) : MiraiLoggerPlatformBase() { - override fun verbose0(any: Any?) = println(any, LoggerTextFormat.RESET) + override fun verbose0(message: String?) = println(message, LoggerTextFormat.RESET) override fun verbose0(message: String?, e: Throwable?) { if (message != null) verbose(message.toString()) e?.printStackTrace() } - override fun info0(any: Any?) = println(any, LoggerTextFormat.LIGHT_GREEN) + override fun info0(message: String?) = println(message, LoggerTextFormat.LIGHT_GREEN) override fun info0(message: String?, e: Throwable?) { if (message != null) info(message.toString()) e?.printStackTrace() } - override fun warning0(any: Any?) = println(any, LoggerTextFormat.LIGHT_RED) + override fun warning0(message: String?) = println(message, LoggerTextFormat.LIGHT_RED) override fun warning0(message: String?, e: Throwable?) { if (message != null) warning(message.toString()) e?.printStackTrace() } - override fun error0(any: Any?) = println(any, LoggerTextFormat.RED) + override fun error0(message: String?) = println(message, LoggerTextFormat.RED) override fun error0(message: String?, e: Throwable?) { if (message != null) error(message.toString()) e?.printStackTrace() } - override fun debug0(any: Any?) = println(any, LoggerTextFormat.LIGHT_CYAN) + override fun debug0(message: String?) = println(message, LoggerTextFormat.LIGHT_CYAN) override fun debug0(message: String?, e: Throwable?) { if (message != null) debug(message.toString()) e?.printStackTrace() } - private fun println(value: Any?, color: LoggerTextFormat) { + private fun println(value: String?, color: LoggerTextFormat) { val time = SimpleDateFormat("HH:mm:ss", Locale.SIMPLIFIED_CHINESE).format(Date()) if (identity == null) { @@ -62,6 +62,7 @@ actual open class PlatformLogger @JvmOverloads internal actual constructor( /** * @author NaturalHG */ +@Suppress("unused") internal enum class LoggerTextFormat(private val format: String) { RESET("\u001b[0m"), From 32c15a47de6c23f2ac9202779204c05eb21a1cb6 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:06:52 +0800 Subject: [PATCH 34/43] Remove debugPrintln --- .../jvmTest/kotlin/androidPacketTests/clientToServer.kt | 2 +- .../kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt index 2233b8534..01eae0859 100644 --- a/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt +++ b/mirai-core-qqandroid/src/jvmTest/kotlin/androidPacketTests/clientToServer.kt @@ -124,7 +124,7 @@ fun ByteReadPacket.decodeMultiClientToServerPackets() { } fun Map<Int, ByteArray>.printTLVMap(name: String = "", keyLength: Int = 2) = - debugPrintln("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() }.mapKeys { + DebugLogger.debug("TLVMap $name= " + this.mapValues { (_, value) -> value.toUHexString() }.mapKeys { when (keyLength) { 1 -> it.key.toUByte().contentToString() 2 -> it.key.toUShort().contentToString() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt index ce1d87248..ed1abaa03 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt @@ -15,11 +15,13 @@ package net.mamoe.mirai.utils.io import kotlinx.io.core.* import kotlinx.io.pool.useInstance -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.DefaultLogger +import net.mamoe.mirai.utils.MiraiDebugAPI +import net.mamoe.mirai.utils.MiraiLoggerWithSwitch +import net.mamoe.mirai.utils.withSwitch import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract -import kotlin.js.JsName import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -30,9 +32,6 @@ val DebugLogger : MiraiLoggerWithSwitch = DefaultLogger("Packet Debug").withSwit @MiraiDebugAPI("Unstable") inline fun Throwable.logStacktrace(message: String? = null) = DebugLogger.error(message, this) -@MiraiDebugAPI("Low efficiency.") -inline fun debugPrintln(any: Any?) = DebugLogger.debug(any) - @MiraiDebugAPI("Low efficiency.") inline fun String.debugPrintThis(name: String): String { DebugLogger.debug("$name=$this") From f8cbdf1c9b21835c0327d86dffef7aac3d1a0ee0 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:15:05 +0800 Subject: [PATCH 35/43] Fix log reference --- .../qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index edacd2626..3e4db515b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -35,6 +35,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.packet.IncomingPacketFactory import net.mamoe.mirai.qqandroid.network.protocol.packet.OutgoingPacket import net.mamoe.mirai.qqandroid.network.protocol.packet.buildResponseUniPacket import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.debug import net.mamoe.mirai.utils.io.discardExact import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.readString From 8eda95659c9d3b31664a22a2386d529f75e11b19 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:15:29 +0800 Subject: [PATCH 36/43] Fix multiplatform BotConfiguration --- .../mirai/utils/BotConfigurationAndroid.kt | 4 +- .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 19 ++++++++- .../net.mamoe.mirai/utils/DeviceInfo.kt | 39 +++++++++++++++++ .../net.mamoe.mirai/utils/SystemDeviceInfo.kt | 2 + .../mamoe/mirai/utils/BotConfigurationJvm.kt | 4 +- .../net/mamoe/mirai/utils/SystemDeviceInfo.kt | 42 +------------------ 6 files changed, 64 insertions(+), 46 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt index 611b8927d..a0849fcdc 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt @@ -90,13 +90,13 @@ actual open class BotConfiguration actual constructor() { @Suppress("NOTHING_TO_INLINE") @BotConfigurationDsl inline operator fun FileBasedDeviceInfo.unaryPlus() { - deviceInfo = { File(filepath).loadAsDeviceInfo() } + deviceInfo = { File(filepath).loadAsDeviceInfo(it) } } @Suppress("NOTHING_TO_INLINE") @BotConfigurationDsl inline operator fun FileBasedDeviceInfo.ByDeviceDotJson.unaryPlus() { - deviceInfo = { File("device.json").loadAsDeviceInfo() } + deviceInfo = { File("device.json").loadAsDeviceInfo(it) } } actual operator fun _NoNetworkLog.unaryPlus() { diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index 30e01dc1b..11990fa36 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -16,8 +16,25 @@ import android.telephony.TelephonyManager import kotlinx.io.core.toByteArray import kotlinx.serialization.Serializable import kotlinx.serialization.Transient +import kotlinx.serialization.UnstableDefault +import kotlinx.serialization.json.Json import java.io.File +/** + * 加载一个设备信息. 若文件不存在或为空则随机并创建一个设备信息保存. + */ +@UseExperimental(UnstableDefault::class) +fun File.loadAsDeviceInfo(context: Context): DeviceInfo { + if (!this.exists() || this.length() == 0L) { + return SystemDeviceInfo(context).also { + this.writeText(Json.plain.stringify(SystemDeviceInfo.serializer(), it)) + } + } + return Json.nonstrict.parse(DeviceInfoData.serializer(), this.readText()).also { + it.context = context + } +} + /** * 部分引用指向 [Build]. * 部分需要权限, 若无权限则会使用默认值. @@ -99,7 +116,7 @@ actual open class SystemDeviceInfo actual constructor() : DeviceInfo() { override val apn: ByteArray get() = "wifi".toByteArray() @Serializable - object Version : DeviceInfo.Version { + actual object Version : DeviceInfo.Version { override val incremental: ByteArray get() = Build.VERSION.INCREMENTAL.toByteArray() override val release: ByteArray get() = Build.VERSION.RELEASE.toByteArray() override val codename: ByteArray get() = Build.VERSION.CODENAME.toByteArray() diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt index 491b952fe..cf911eff2 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/DeviceInfo.kt @@ -94,6 +94,45 @@ abstract class DeviceInfo { } } +@Serializable +class DeviceInfoData( + override val display: ByteArray, + override val product: ByteArray, + override val device: ByteArray, + override val board: ByteArray, + override val brand: ByteArray, + override val model: ByteArray, + override val bootloader: ByteArray, + override val fingerprint: ByteArray, + override val bootId: ByteArray, + override val procVersion: ByteArray, + override val baseBand: ByteArray, + override val version: VersionData, + override val simInfo: ByteArray, + override val osType: ByteArray, + override val macAddress: ByteArray, + override val wifiBSSID: ByteArray?, + override val wifiSSID: ByteArray?, + override val imsiMd5: ByteArray, + override val imei: String, + override val apn: ByteArray +) : DeviceInfo() { + @Transient + override lateinit var context: Context + + @UseExperimental(ExperimentalUnsignedTypes::class) + override val ipAddress: ByteArray + get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf() + override val androidId: ByteArray get() = display + + @Serializable + class VersionData( + override val incremental: ByteArray = SystemDeviceInfo.Version.incremental, + override val release: ByteArray = SystemDeviceInfo.Version.release, + override val codename: ByteArray = SystemDeviceInfo.Version.codename, + override val sdk: Int = SystemDeviceInfo.Version.sdk + ) : Version +} /** * Defaults "%4;7t>;28<fc.5*6".toByteArray() */ diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt index bd4f0b259..761114287 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/SystemDeviceInfo.kt @@ -18,4 +18,6 @@ package net.mamoe.mirai.utils expect open class SystemDeviceInfo : DeviceInfo { constructor() constructor(context: Context) + + object Version : DeviceInfo.Version } \ No newline at end of file diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt index a136328e3..7ca0f9173 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt @@ -216,13 +216,13 @@ actual open class BotConfiguration actual constructor() { @Suppress("NOTHING_TO_INLINE") @BotConfigurationDsl inline operator fun FileBasedDeviceInfo.unaryPlus() { - deviceInfo = { File(filepath).loadAsDeviceInfo() } + deviceInfo = { File(filepath).loadAsDeviceInfo(it) } } @Suppress("NOTHING_TO_INLINE") @BotConfigurationDsl inline operator fun FileBasedDeviceInfo.ByDeviceDotJson.unaryPlus() { - deviceInfo = { File("device.json").loadAsDeviceInfo() } + deviceInfo = { File("device.json").loadAsDeviceInfo(it) } } actual operator fun _NoNetworkLog.unaryPlus() { diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt index a8e18f3a4..8bcbf6f42 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/SystemDeviceInfo.kt @@ -68,50 +68,10 @@ actual open class SystemDeviceInfo actual constructor() : DeviceInfo() { override val apn: ByteArray = "wifi".toByteArray() @Serializable - object Version : DeviceInfo.Version { + actual object Version : DeviceInfo.Version { override val incremental: ByteArray = "5891938".toByteArray() override val release: ByteArray = "10".toByteArray() override val codename: ByteArray = "REL".toByteArray() override val sdk: Int = 29 } -} - -@Serializable -class DeviceInfoData( - override val display: ByteArray, - override val product: ByteArray, - override val device: ByteArray, - override val board: ByteArray, - override val brand: ByteArray, - override val model: ByteArray, - override val bootloader: ByteArray, - override val fingerprint: ByteArray, - override val bootId: ByteArray, - override val procVersion: ByteArray, - override val baseBand: ByteArray, - override val version: VersionData, - override val simInfo: ByteArray, - override val osType: ByteArray, - override val macAddress: ByteArray, - override val wifiBSSID: ByteArray?, - override val wifiSSID: ByteArray?, - override val imsiMd5: ByteArray, - override val imei: String, - override val apn: ByteArray -) : DeviceInfo() { - @Transient - override lateinit var context: Context - - @UseExperimental(ExperimentalUnsignedTypes::class) - override val ipAddress: ByteArray - get() = localIpAddress().split(".").map { it.toUByte().toByte() }.takeIf { it.size == 4 }?.toByteArray() ?: byteArrayOf() - override val androidId: ByteArray get() = display - - @Serializable - class VersionData( - override val incremental: ByteArray = SystemDeviceInfo.Version.incremental, - override val release: ByteArray = SystemDeviceInfo.Version.release, - override val codename: ByteArray = SystemDeviceInfo.Version.codename, - override val sdk: Int = SystemDeviceInfo.Version.sdk - ) : Version } \ No newline at end of file From 066ad395612d9b8cefa214c0dd9ced84e80e5c4b Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:16:01 +0800 Subject: [PATCH 37/43] Remove ambiguous functions on Android --- .../mamoe/mirai/utils/BotConfigurationAndroid.kt | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt index a0849fcdc..e781c9697 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt @@ -12,7 +12,6 @@ package net.mamoe.mirai.utils import kotlinx.io.core.IoBuffer import net.mamoe.mirai.Bot import net.mamoe.mirai.network.BotNetworkHandler -import java.io.File import kotlin.coroutines.CoroutineContext import kotlin.coroutines.EmptyCoroutineContext @@ -87,18 +86,6 @@ actual open class BotConfiguration actual constructor() { actual val Default = BotConfiguration() } - @Suppress("NOTHING_TO_INLINE") - @BotConfigurationDsl - inline operator fun FileBasedDeviceInfo.unaryPlus() { - deviceInfo = { File(filepath).loadAsDeviceInfo(it) } - } - - @Suppress("NOTHING_TO_INLINE") - @BotConfigurationDsl - inline operator fun FileBasedDeviceInfo.ByDeviceDotJson.unaryPlus() { - deviceInfo = { File("device.json").loadAsDeviceInfo(it) } - } - actual operator fun _NoNetworkLog.unaryPlus() { networkLoggerSupplier = supplier } From 3f356af62017a204c48adaf481d71854ae0c8598 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:17:35 +0800 Subject: [PATCH 38/43] Demo: add DSL sample --- .../src/main/java/demo/subscribe/SubscribeSamples.kt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt index 0ffe941b8..79c921519 100644 --- a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt +++ b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt @@ -27,6 +27,7 @@ import net.mamoe.mirai.message.data.firstOrNull import net.mamoe.mirai.message.sendAsImageTo import net.mamoe.mirai.qqandroid.Bot import net.mamoe.mirai.qqandroid.QQAndroid +import net.mamoe.mirai.utils.FileBasedDeviceInfo import java.io.File private fun readTestAccount(): BotAccount? { @@ -51,7 +52,7 @@ suspend fun main() { "123456" ) { // 覆盖默认的配置 - + +FileBasedDeviceInfo // 使用 "device.json" 保存设备信息 // networkLoggerSupplier = { SilentLogger } // 禁用网络层输出 }.alsoLogin() From 2b464a287e704df1c326b30e4636465587dcc5e9 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:26:40 +0800 Subject: [PATCH 39/43] Add `MessageSource.quote` --- .../kotlin/net.mamoe.mirai/message/data/MessageSource.kt | 2 ++ .../kotlin/net.mamoe.mirai/message/data/QuoteReply.kt | 9 +++++++++ 2 files changed, 11 insertions(+) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt index c133938a8..3d1246dd5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/MessageSource.kt @@ -14,6 +14,8 @@ package net.mamoe.mirai.message.data * 消息源只用于 [QuoteReply] * * `mirai-core-qqandroid`: `net.mamoe.mirai.qqandroid.message.MessageSourceFromMsg` + * + * @see MessageSource.quote 引用这条消息, 创建 [MessageChain] */ interface MessageSource : Message { companion object : Message.Key<MessageSource> diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt index 428958a7c..8921b1eca 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/QuoteReply.kt @@ -33,4 +33,13 @@ fun MessageChain.quote(sender: Member): MessageChain { return QuoteReply(it) + sender.at() + " " // required } error("cannot find MessageSource") +} + +/** + * 引用这条消息. + * 返回 `[QuoteReply] + [At] + [PlainText]`(必要的结构) + */ +fun MessageSource.quote(sender: Member): MessageChain { + @UseExperimental(MiraiInternalAPI::class) + return QuoteReply(this) + sender.at() + " " // required } \ No newline at end of file From 04bed22ea25212eb107d468a8fe8a1f63a7278f8 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:27:45 +0800 Subject: [PATCH 40/43] Fix `awaitDisconnection()` --- .../mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt index 965eea377..d9b83e5c5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt @@ -531,5 +531,5 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler super.close(cause) } - override suspend fun awaitDisconnection() = _packetReceiverJob?.join() ?: Unit + override suspend fun awaitDisconnection() = supervisor.join() } \ No newline at end of file From 698c8b1c76efae170a3f5d789037c005840b94ae Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:34:04 +0800 Subject: [PATCH 41/43] Format --- .../network/protocol/packet/chat/receive/OnlinePush.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt index 3e4db515b..5b2bd3fe2 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/OnlinePush.kt @@ -251,7 +251,7 @@ internal class OnlinePush { ) } else -> { - bot.network.logger.debug{"Unknown server messages $message"} + bot.network.logger.debug { "Unknown server messages $message" } return NoPacket } } From 8ea7027fc9d5df4037c0e1455881b09b64464955 Mon Sep 17 00:00:00 2001 From: Him188 <Him188@mamoe.net> Date: Fri, 14 Feb 2020 22:34:25 +0800 Subject: [PATCH 42/43] 0.15.0 released --- CHANGELOG.md | 25 ++++++++++++++++++++++++- gradle.properties | 2 +- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index acba4cca6..738c3690e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,11 +2,34 @@ 开发版本. 频繁更新, 不保证高稳定性 -## `0.14.0` 2020/2/13 +## `0.15.0` 2020/2/14 + ### mirai-core + +- 新增事件: `BotReloginEvent` 和 `BotOfflineEvent.Dropped` +- `AtAll` 现在实现 `Message.Key` +- 新增 `BotConfiguration` DSL, 支持自动将设备信息存储在文件系统等 +- 新增 `MessageSource.quote(Member)` + +- 更好的网络层连接逻辑 +- 密码错误后不再重试登录 +- 掉线后尝试快速重连, 失败则普通重连 (#47) +- 有原因的登录失败时将抛出特定异常: `LoginFailedException` +- 默认心跳时间调整为 60s + +### mirai-core-qqandroid + +- 解决一些验证码无法识别的问题 +- 忽略一些不需要处理的事件(机器人主动操作触发的事件) + +## `0.14.0` 2020/2/13 + +### mirai-core + - **支持 at 全体成员: `AtAll`** ### mirai-core-qqandroid + - **支持 `AtAll` 的发送和解析** - **修复某些情况下禁言处理异常** diff --git a/gradle.properties b/gradle.properties index 5d173aa3c..98a69c925 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.14.0 +mirai_version=0.15.0 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true # kotlin From 2b60130bb4b2ab7188c7918f77d6f3398e808876 Mon Sep 17 00:00:00 2001 From: ryoii <ryoii@foxmail.com> Date: Fri, 14 Feb 2020 23:35:58 +0800 Subject: [PATCH 43/43] http-api support quoteReply --- mirai-api-http/README_CH.md | 54 +++++++++++++++++++ .../mirai/api/http/data/common/MessageDTO.kt | 6 ++- .../mirai/api/http/queue/MessageQueue.kt | 17 +++++- .../api/http/route/SendMessageRouteModule.kt | 12 ++++- .../net/mamoe/mirai/api/http/util/Json.kt | 2 + 5 files changed, 87 insertions(+), 4 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 0216f73f6..8fd0da5f1 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -220,6 +220,44 @@ fun main() { +### 发送引用回复消息(仅支持群消息) + +``` +[POST] /sendQuoteMessage +``` + +使用此方法向指定的消息进行引用回复 + +#### 请求 + +```json5 +{ + "sessionKey": "YourSession", + "target": 987654321, + "messageChain": [ + { "type": "Plain", "text":"hello\n" }, + { "type": "Plain", "text":"world" } + ] +} +``` + +| 名字 | 类型 | 可选 | 举例 | 说明 | +| ------------ | ------ | ----- | ----------- | -------------------------------- | +| sessionKey | String | false | YourSession | 已经激活的Session | +| target | Long | false | 987654321 | 引用消息的Message Source的Uid | +| messageChain | Array | false | [] | 消息链,是一个消息对象构成的数组 | + +#### 响应: 返回统一状态码 + +```json5 +{ + "code": 0, + "msg": "success" +} +``` + + + ### 发送图片消息(通过URL) ``` @@ -308,6 +346,9 @@ Content-Type:multipart/form-data [{ "type": "GroupMessage", // 消息类型:GroupMessage或FriendMessage "messageChain": [{ // 消息链,是一个消息对象构成的数组 + "type": "Source", + "uid": 123456 + },{ "type": "Plain", "text": "Miral牛逼" }], @@ -350,6 +391,19 @@ Content-Type:multipart/form-data + [ ] Xml,Xml卡片消息 + [ ] 敬请期待 +#### Source + +```json5 +{ + "type": "Source", + "uid": 123456 +} +``` + +| 名字 | 类型 | 说明 | +| ---- | ---- | ------------------------------------------------------------ | +| uid | Long | 消息的识别号,用于引用回复(Source类型只在群消息中返回,且永远为chain的第一个元素) | + #### At ```json5 diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt index ccd6d2440..f50f00e11 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt @@ -36,6 +36,9 @@ data class UnKnownMessagePacketDTO(val msg: String) : MessagePacketDTO() // Message @Serializable +@SerialName("Source") +data class MessageSourceDTO(val uid: Long) : MessageDTO() +@Serializable @SerialName("At") data class AtDTO(val target: Long, val display: String) : MessageDTO() @Serializable @@ -85,6 +88,7 @@ fun MessageChainDTO.toMessageChain() = @UseExperimental(ExperimentalUnsignedTypes::class) fun Message.toDTO() = when (this) { + is MessageSource -> MessageSourceDTO(messageUid) is At -> AtDTO(target, display) is AtAll -> AtAllDTO(0L) is Face -> FaceDTO(id.value.toInt()) @@ -102,7 +106,7 @@ fun MessageDTO.toMessage() = when (this) { is PlainDTO -> PlainText(text) is ImageDTO -> Image(imageId) is XmlDTO -> XMLMessage(xml) - is UnknownMessageDTO -> PlainText("assert cannot reach") + is MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach") } diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt index 28a79f184..e3a1637ef 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/queue/MessageQueue.kt @@ -9,17 +9,32 @@ package net.mamoe.mirai.api.http.queue +import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket +import net.mamoe.mirai.message.data.MessageSource +import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentLinkedDeque class MessageQueue : ConcurrentLinkedDeque<MessagePacket<*, *>>() { + val quoteCache = ConcurrentHashMap<Long, GroupMessage>() + fun fetch(size: Int): List<MessagePacket<*, *>> { var count = size + quoteCache.clear() val ret = ArrayList<MessagePacket<*, *>>(count) while (!this.isEmpty() && count-- > 0) { - ret.add(this.pop()) + val packet = pop() + ret.add(packet) + + if (packet is GroupMessage) { + addCache(packet) + } } return ret } + + private fun addCache(msg: GroupMessage) { + quoteCache[msg.message[MessageSource].messageUid] = msg + } } \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt index 6a41fe76c..aa2beb5b8 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/SendMessageRouteModule.kt @@ -52,6 +52,12 @@ fun Application.messageModule() { call.respondStateCode(StateCode.Success) } + miraiVerify<SendDTO>("/quoteMessage") { + it.session.messageQueue.quoteCache[it.target]?.quoteReply(it.messageChain.toMessageChain()) + ?: throw NoSuchElementException() + call.respondStateCode(StateCode.Success) + } + miraiVerify<SendImageDTO>("sendImageMessage") { val bot = it.session.bot val contact = when { @@ -72,12 +78,14 @@ fun Application.messageModule() { if (!SessionManager.containSession(sessionKey)) throw IllegalSessionException val session = try { SessionManager[sessionKey] as AuthedSession - } catch (e: TypeCastException) { throw NotVerifiedSessionException } + } catch (e: TypeCastException) { + throw NotVerifiedSessionException + } val type = parts.value("type") parts.file("img")?.apply { val image = streamProvider().use { - when(type) { + when (type) { "group" -> session.bot.groups.toList().random().uploadImage(it) "friend" -> session.bot.qqs.toList().random().uploadImage(it) else -> null diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt index 8b37ebd80..e46fbb1f5 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/util/Json.kt @@ -13,6 +13,7 @@ import kotlinx.serialization.* import kotlinx.serialization.json.Json import kotlinx.serialization.modules.SerializersModule import net.mamoe.mirai.api.http.data.common.* +import net.mamoe.mirai.message.data.MessageSource // 解析失败时直接返回null,由路由判断响应400状态 @UseExperimental(ImplicitReflectionSerializer::class) @@ -50,6 +51,7 @@ object MiraiJson { UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer() } polymorphic(MessageDTO.serializer()) { + MessageSourceDTO::class with MessageSourceDTO.serializer() AtDTO::class with AtDTO.serializer() AtAllDTO::class with AtAllDTO.serializer() FaceDTO::class with FaceDTO.serializer()