From 29a5ab53a964e5073a091814b69747428dcbd0d9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 20:02:13 +0800 Subject: [PATCH 001/111] Use default shareKey if ECDH is not available --- .../src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt index 0d6e93829..f24f61c72 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt @@ -77,6 +77,7 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { } actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray { + if (!isECDHAvailable) return keyPair.initialShareKey return calculateShareKey(keyPair.privateKey, peerPublicKey) } From 714137f662ef7d517ba2c9334a9adaafa04e79ee Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 20:02:21 +0800 Subject: [PATCH 002/111] 0.15.3 --- CHANGELOG.md | 4 ++++ gradle.properties | 2 +- gradle/publish.gradle | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8679417be..6c914a6bd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ 开发版本. 频繁更新, 不保证高稳定性 +## `0.15.3` 2020/2/18 + +修复无法引入依赖的问题. + ## `0.15.2` 2020/2/18 ### mirai-core diff --git a/gradle.properties b/gradle.properties index 525f0504f..3ffff5320 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.15.2 +mirai_version=0.15.3 mirai_japt_version=1.0.1 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true diff --git a/gradle/publish.gradle b/gradle/publish.gradle index 6d58f8d23..842ca6910 100644 --- a/gradle/publish.gradle +++ b/gradle/publish.gradle @@ -94,7 +94,7 @@ publishing { it.artifactId = "$project.name-common" break case 'jvm': - it.artifactId = "${project.name.replace("-jvm", "")}" + it.artifactId = "$project.name-jvm" break case 'js': case 'native': From bbd2f2696ebd28f9f4f55d1fc6687b0d59374afb Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 20:27:05 +0800 Subject: [PATCH 003/111] Update README --- README.md | 6 +++--- mirai-japt/README.md | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e8ed69843..f9151ddc1 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,7 @@ Mirai既可以作为你项目中的QQ协议支持Lib, 也可以作为单独的Ap - 已支持大部分使用场景, 详情请在[Project](https://github.com/mamoe/mirai/projects/3)查看 ### mirai-core-timpc -TIM PC (2.3.2 版本,2019 年 8 月)协议的实现,相较于 core,仅新增少量 API. 详见 [README.md](mirai-core-timpc/) +TIM PC (2.3.2 版本,2019 年 8 月)协议的实现 支持的功能: - 消息收发:图片文字复合消息,图片消息 - 群管功能:群员列表,禁言 @@ -75,7 +75,7 @@ Kotlin 在 Maven 上只支持 JVM 平台. net.mamoe - mirai-core-qqandroid + mirai-core-qqandroid-jvm 0.15.1 @@ -98,7 +98,7 @@ Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。 **jvm** (JVM 平台) ```kotlin -implementation("net.mamoe:mirai-core-qqandroid:VERSION") +implementation("net.mamoe:mirai-core-qqandroid-jvm:VERSION") ``` **common** (通用平台) ```kotlin diff --git a/mirai-japt/README.md b/mirai-japt/README.md index 234ef52b6..73586ab92 100644 --- a/mirai-japt/README.md +++ b/mirai-japt/README.md @@ -32,7 +32,7 @@ Mirai Java Apt net.mamoe - mirai-core-qqandroid + mirai-core-qqandroid-jvm CORE_VERSION @@ -51,7 +51,7 @@ repositories { } dependencies { - implementation("net.mamoe:mirai-core-qqandroid:CORE_VERSION") + implementation("net.mamoe:mirai-core-qqandroid-jvm:CORE_VERSION") implementation("net.mamoe:mirai-japt:JAPT_VERSION") } ``` From eafa943e5f85afbd9d05aaf7d8374a3215533e18 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 20:35:44 +0800 Subject: [PATCH 004/111] Remove redundant `apply` --- mirai-core/build.gradle.kts | 2 -- 1 file changed, 2 deletions(-) diff --git a/mirai-core/build.gradle.kts b/mirai-core/build.gradle.kts index ebecaf2f9..c543159c5 100644 --- a/mirai-core/build.gradle.kts +++ b/mirai-core/build.gradle.kts @@ -8,8 +8,6 @@ plugins { id("com.jfrog.bintray") version "1.8.4-jetbrains-3" } -apply(from = rootProject.file("gradle/publish.gradle")) - val kotlinVersion: String by rootProject.ext val atomicFuVersion: String by rootProject.ext val coroutinesVersion: String by rootProject.ext From 7ad3bfbf8fad427bca4c16cc6b655e443a5903ff Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:05:51 +0800 Subject: [PATCH 005/111] Add MiraiAtomicBoolean, fuck atomicfu --- .../event/internal/MiraiAtomicBoolean.kt | 17 +++++++++++++ .../event/internal/InternalEventListeners.kt | 24 +++++++++---------- .../event/internal/MiraiAtomicBoolean.kt | 18 ++++++++++++++ 3 files changed, 46 insertions(+), 13 deletions(-) create mode 100644 mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt create mode 100644 mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt new file mode 100644 index 000000000..1b3fb785f --- /dev/null +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt @@ -0,0 +1,17 @@ +package net.mamoe.mirai.event.internal + +import java.util.concurrent.atomic.AtomicBoolean + +internal actual class MiraiAtomicBoolean actual constructor(initial: Boolean) { + private val delegate: AtomicBoolean = AtomicBoolean(initial) + + actual fun compareAndSet(expect: Boolean, update: Boolean): Boolean { + return delegate.compareAndSet(expect, update) + } + + actual var value: Boolean + get() = delegate.get() + set(value) { + delegate.set(value) + } +} \ No newline at end of file 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 e439a0974..fe2ff0f8c 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 @@ -9,7 +9,6 @@ package net.mamoe.mirai.event.internal -import kotlinx.atomicfu.atomic import kotlinx.coroutines.* import net.mamoe.mirai.event.Event import net.mamoe.mirai.event.EventDisabled @@ -79,6 +78,13 @@ internal fun KClass.listeners(): EventListeners = EventLis internal class EventListeners : LockFreeLinkedList>() +internal expect class MiraiAtomicBoolean(initial: Boolean) { + + fun compareAndSet(expect: Boolean, update: Boolean): Boolean + + var value: Boolean +} + /** * 管理每个事件 class 的 [EventListeners]. * [EventListeners] 是 lazy 的: 它们只会在被需要的时候才创建和存储. @@ -88,16 +94,8 @@ internal object EventListenerManager { private val registries = LockFreeLinkedList>() - private val lock = atomic(false) - - private fun setLockValue(value: Boolean) { - lock.value = value - } - - @Suppress("BooleanLiteralArgument") - private fun trySetLockTrue(): Boolean { - return lock.compareAndSet(false, true) - } + // 不要用 atomicfu. 在 publish 后会出现 VerifyError + private val lock: MiraiAtomicBoolean = MiraiAtomicBoolean(false) @Suppress("UNCHECKED_CAST", "BooleanLiteralArgument") internal tailrec fun get(clazz: KClass): EventListeners { @@ -106,10 +104,10 @@ internal object EventListenerManager { return it.listeners as EventListeners } } - if (trySetLockTrue()) { + if (lock.compareAndSet(false, true)) { val registry = Registry(clazz, EventListeners()) registries.addLast(registry) - setLockValue(false) + lock.value = false return registry.listeners as EventListeners } return get(clazz) diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt new file mode 100644 index 000000000..0b468cf04 --- /dev/null +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/event/internal/MiraiAtomicBoolean.kt @@ -0,0 +1,18 @@ +package net.mamoe.mirai.event.internal + +import java.util.concurrent.atomic.AtomicBoolean + + +internal actual class MiraiAtomicBoolean actual constructor(initial: Boolean) { + private val delegate: AtomicBoolean = AtomicBoolean(initial) + + actual fun compareAndSet(expect: Boolean, update: Boolean): Boolean { + return delegate.compareAndSet(expect, update) + } + + actual var value: Boolean + get() = delegate.get() + set(value) { + delegate.set(value) + } +} \ No newline at end of file From d4fdeee58cf0b0221a361fd6668ab47b2424d76f Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:08:40 +0800 Subject: [PATCH 006/111] 0.15.4, close #60 --- CHANGELOG.md | 6 +++++- gradle.properties | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c914a6bd..4c40d0ae9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,13 @@ 开发版本. 频繁更新, 不保证高稳定性 +## `0.15.4` 2020/2/18 + +- 放弃使用 `atomicfu` 以解决其编译错误的问题. (#60) + ## `0.15.3` 2020/2/18 -修复无法引入依赖的问题. +- 修复无法引入依赖的问题. ## `0.15.2` 2020/2/18 diff --git a/gradle.properties b/gradle.properties index 3ffff5320..5ededee39 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.15.3 +mirai_version=0.15.4 mirai_japt_version=1.0.1 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true From 35b8cfeb2a6aa40a82ad88e666b7622b28ead6d9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:09:45 +0800 Subject: [PATCH 007/111] Fix test --- .../kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt index 413a510ce..fd32c5933 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt @@ -64,7 +64,7 @@ internal class LockFreeLinkedListTest { //delay(1) // let addJob fly if (addJob.isCompleted) { - println("Number of elements are not enough") + return } val foreachJob = async { list.concurrentDo(1, 10000) { From 998989480257d386d69b43a41dcf21ff8d08ad2f Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:10:18 +0800 Subject: [PATCH 008/111] Fix test --- .../kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt | 3 --- 1 file changed, 3 deletions(-) diff --git a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt index fd32c5933..1ffc86c6a 100644 --- a/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt +++ b/mirai-core/src/jvmTest/kotlin/net/mamoe/mirai/utils/LockFreeLinkedListTest.kt @@ -63,9 +63,6 @@ internal class LockFreeLinkedListTest { val addJob = async { list.concurrentDo(2, 30000) { addLast(1) } } //delay(1) // let addJob fly - if (addJob.isCompleted) { - return - } val foreachJob = async { list.concurrentDo(1, 10000) { forEach { it + it } From 9b586063668c259cca945f8159a95ef7e92e0ed7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:46:09 +0800 Subject: [PATCH 009/111] Fix initialization error --- .../commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt index 36ac8186e..2e93e0385 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt @@ -66,8 +66,8 @@ expect class ECDH(keyPair: ECDHKeyPair) { @Suppress("FunctionName") expect fun ECDH(): ECDH -val initialPublicKey = - ECDH.constructPublicKey("3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8".chunkedHexToBytes()) +val initialPublicKey + get() = ECDH.constructPublicKey("3046301006072A8648CE3D020106052B8104001F03320004928D8850673088B343264E0C6BACB8496D697799F37211DEB25BB73906CB089FEA9639B4E0260498B51A992D50813DA8".chunkedHexToBytes()) private val commonHeadFor02 = "302E301006072A8648CE3D020106052B8104001F031A00".chunkedHexToBytes() private val commonHeadForNot02 = "3046301006072A8648CE3D020106052B8104001F033200".chunkedHexToBytes() private const val constantHead = "3046301006072A8648CE3D020106052B8104001F03320004" From 3ce17cf9e13277504a54f0a616a0c4e14713c0c9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 18 Feb 2020 21:46:18 +0800 Subject: [PATCH 010/111] Use implementation --- mirai-japt/build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-japt/build.gradle.kts b/mirai-japt/build.gradle.kts index 3bd7d20a5..423789c2e 100644 --- a/mirai-japt/build.gradle.kts +++ b/mirai-japt/build.gradle.kts @@ -59,7 +59,7 @@ fun kotlinx(id: String, version: String) = "org.jetbrains.kotlinx:kotlinx-$id:$v fun ktor(id: String, version: String) = "io.ktor:ktor-$id:$version" dependencies { - api(project(":mirai-core")) + implementation(project(":mirai-core")) runtimeOnly(files("../mirai-core/build/classes/kotlin/jvm/main")) // classpath is not added correctly by IDE api(group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-javafx", version = "1.3.2") From 78ebe4c7cd8c3a75253081033bd26934722fcfd3 Mon Sep 17 00:00:00 2001 From: ryoii Date: Tue, 18 Feb 2020 22:47:48 +0800 Subject: [PATCH 011/111] logo --- .../src/main/resources/logo.png | Bin 3974 -> 4752 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mirai-console-graphical/src/main/resources/logo.png b/mirai-console-graphical/src/main/resources/logo.png index 7be6c687173594899ce8f3ef3a8ea47d763168b1..bded5f13787965fb184119546f61ba11c0a5f317 100644 GIT binary patch literal 4752 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 e;r|QY5hTy*X-9PTK0dzDB)$5-@qW=ezF(R1& literal 3974 zcmV;14|(v3P)004R>004l5008;`004mK004C`008P>0026e000+ooVrmw000jW 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 From f68df356659382370a7f6c2f8922aeb682d66e1c Mon Sep 17 00:00:00 2001 From: ryoii Date: Tue, 18 Feb 2020 22:58:15 +0800 Subject: [PATCH 012/111] update md --- mirai-api-http/README_CH.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index d056170e4..895d1b2e3 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -12,7 +12,7 @@ fun main() { MiraiHttpAPIServer.start() - bot.network.awaitDisconnection() + bot.join() } ``` @@ -463,7 +463,7 @@ Content-Type:multipart/form-data { "type": "Image", "imageId": "{01E9451B-70ED-EAE3-B37C-101F1EEBF5B5}.png" //群图片格式 - "imageId": "/f8f1ab55-bf8e-4236-b55e-955848d7069f" //好友图片格式 + //"imageId": "/f8f1ab55-bf8e-4236-b55e-955848d7069f" //好友图片格式 } ``` From 83611ac09f001de829620b764d170aa9b7168856 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 02:07:18 +0800 Subject: [PATCH 013/111] f**k javafx --- .../mirai/console/graphical/MiraiGraphical.kt | 8 +- .../mirai/console/graphical/model/BotModel.kt | 6 ++ .../mirai/console/graphical/view/Decorator.kt | 9 ++ .../console/graphical/view/LoginFragment.kt | 38 +++++---- .../console/graphical/view/PrimaryView.kt | 84 +++++++------------ 5 files changed, 77 insertions(+), 68 deletions(-) create mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/Decorator.kt diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt index 7e5633dee..b543a06ee 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt @@ -1,9 +1,15 @@ package net.mamoe.mirai.console.graphical +import com.jfoenix.controls.JFXDecorator +import javafx.scene.control.Button +import javafx.stage.Stage import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController +import net.mamoe.mirai.console.graphical.view.Decorator import net.mamoe.mirai.console.graphical.view.PrimaryView import tornadofx.App +import tornadofx.FX.Companion.primaryStage +import tornadofx.UIComponent import tornadofx.find import tornadofx.launch @@ -11,7 +17,7 @@ fun main(args: Array) { launch(args) } -class MiraiGraphicalUI: App(PrimaryView::class) { +class MiraiGraphicalUI: App(Decorator::class) { override fun init() { super.init() diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt index 8d15d6998..542f8b146 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/model/BotModel.kt @@ -11,3 +11,9 @@ class BotModel(val uin: Long) { val logHistory = observableListOf() val admins = observableListOf() } + +class BotViewModel(botModel: BotModel? = null) : ItemViewModel(botModel) { + val bot = bind(BotModel::botProperty) + val logHistory = bind(BotModel::logHistory) + val admins = bind(BotModel::admins) +} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/Decorator.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/Decorator.kt new file mode 100644 index 000000000..9ecff5fda --- /dev/null +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/Decorator.kt @@ -0,0 +1,9 @@ +package net.mamoe.mirai.console.graphical.view + +import com.jfoenix.controls.JFXDecorator +import tornadofx.View + +class Decorator: View() { + + override val root = JFXDecorator(primaryStage, find().root) +} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt index 437031ca4..387fcc7da 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt @@ -1,6 +1,9 @@ package net.mamoe.mirai.console.graphical.view +import com.jfoenix.controls.JFXAlert +import com.jfoenix.controls.JFXPopup import javafx.beans.property.SimpleStringProperty +import javafx.scene.control.Label import kotlinx.coroutines.runBlocking import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController import net.mamoe.mirai.console.graphical.util.jfxButton @@ -8,26 +11,31 @@ import net.mamoe.mirai.console.graphical.util.jfxPasswordfield import net.mamoe.mirai.console.graphical.util.jfxTextfield import tornadofx.* -class LoginFragment : Fragment() { +class LoginView : View() { - private val controller = find(FX.defaultScope) - private val qq = SimpleStringProperty("0") + private val controller = find() + private val qq = SimpleStringProperty("") private val psd = SimpleStringProperty("") - override val root = form { - fieldset("登录") { - field("QQ") { - jfxTextfield(qq) + override val root = pane { + form { + fieldset("登录") { + field("QQ") { + jfxTextfield(qq) + } + field("密码") { + jfxPasswordfield(psd) + } } - field("密码") { - jfxPasswordfield(psd) + jfxButton("登录").action { + runAsync { + runBlocking { + controller.login(qq.value, psd.value) + } + }.ui { + // show dialog + } } } - jfxButton("登录").action { - runBlocking { - controller.login(qq.value, psd.value) - } - close() - } } } \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt index 58036ac6e..1a81c3721 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/PrimaryView.kt @@ -1,20 +1,15 @@ package net.mamoe.mirai.console.graphical.view -import com.jfoenix.controls.JFXListCell -import javafx.geometry.Insets -import javafx.geometry.Pos +import com.jfoenix.controls.* +import javafx.collections.ObservableList import javafx.scene.control.Tab import javafx.scene.control.TabPane import javafx.scene.image.Image -import javafx.scene.paint.Color -import javafx.scene.text.FontWeight import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController import net.mamoe.mirai.console.graphical.model.BotModel -import net.mamoe.mirai.console.graphical.util.jfxButton import net.mamoe.mirai.console.graphical.util.jfxListView import net.mamoe.mirai.console.graphical.util.jfxTabPane import tornadofx.* -import java.io.FileInputStream class PrimaryView : View() { @@ -35,20 +30,12 @@ class PrimaryView : View() { setCellFactory { object : JFXListCell() { - var tab: Tab? = null - init { onDoubleClick { - if (tab == null) { - (center as TabPane).tab(item.uin.toString()) { - listview(item.logHistory) - onDoubleClick { close() } - tab = this - } - } else { - (center as TabPane).tabs.add(tab) - } - tab?.select() + (center as TabPane).logTab( + text = item.uin.toString(), + logs = item.logHistory + ).select() } } @@ -65,44 +52,37 @@ class PrimaryView : View() { } } } - - hbox { - padding = Insets(10.0) - spacing = 10.0 - alignment = Pos.CENTER - - jfxButton("L").action { - find().openModal() - } - jfxButton("P") - jfxButton("S") - - - style { backgroundColor += c("00BCD4") } - children.style(true) { - backgroundColor += c("00BCD4") - fontSize = 15.px - fontWeight = FontWeight.BOLD - textFill = Color.WHITE - borderRadius += box(25.px) - backgroundRadius += box(25.px) - } - } } center = jfxTabPane { - tab("Main") { - listview(controller.mainLog) { - fitToParentSize() - cellFormat { - graphic = label(it) { - maxWidthProperty().bind(this@listview.widthProperty()) - isWrapText = true - } - } - } + tab("Login") { + this += find().root } + + tab("Plugin") + + tab("Settings") + + logTab("Main", controller.mainLog) } } } + +private fun TabPane.logTab( + text: String? = null, + logs: ObservableList, + op: Tab.() -> Unit = {} +)= tab(text) { + listview(logs) { + + fitToParentSize() + cellFormat { + graphic = label(it) { + maxWidthProperty().bind(this@listview.widthProperty()) + isWrapText = true + } + } + } + also(op) +} \ No newline at end of file From ef679aba6391791bfb1ae365a6fed4ee7fec1be4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 09:08:33 +0800 Subject: [PATCH 014/111] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f9151ddc1..4e77e9bca 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ JVM 上启动需 80M 内存, 每多一个机器人实例需要 30M 内存. 您的 star 是对我们最大的鼓励(点击项目右上角) ## Wiki -在 [Wiki](https://github.com/mamoe/mirai/wiki/Home) 中查看各类帮助,**如 API 示例**(可能过时,待 QQ Android 协议完成后会重写)。 +在 [Wiki](https://github.com/mamoe/mirai/wiki/Home) 中查看各类帮助,**如 API 示例**。 ## Try @@ -187,4 +187,4 @@ bot.subscribeAlways { ## Acknowledgement 特别感谢 [JetBrains](https://www.jetbrains.com/?from=mirai) 为开源项目提供免费的 [IntelliJ IDEA](https://www.jetbrains.com/idea/?from=mirai) 等 IDE 的授权 [](https://www.jetbrains.com/?from=mirai) - \ No newline at end of file + From 12e62c8aeeb9e839f336b8234867bf28db2547f7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 10:28:10 +0800 Subject: [PATCH 015/111] Deprecate BlockingBot.dispose --- .../main/java/net/mamoe/mirai/japt/BlockingBot.java | 10 +++++++++- .../net/mamoe/mirai/japt/internal/BlockingBotImpl.kt | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingBot.java b/mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingBot.java index fb55493a6..6b2e17197 100644 --- a/mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingBot.java +++ b/mirai-japt/src/main/java/net/mamoe/mirai/japt/BlockingBot.java @@ -184,5 +184,13 @@ public interface BlockingBot { /** * 关闭这个 [Bot], 停止一切相关活动. 不可重新登录. */ - void dispose(@Nullable Throwable throwable); + void close(@Nullable Throwable throwable); + + /** + * @deprecated 使用 {@link #close(Throwable)} + */ + @Deprecated + default void dispose(@Nullable Throwable throwable) { + close(throwable); + } } diff --git a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt index 0fbc212b4..d589fed7c 100644 --- a/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt +++ b/mirai-japt/src/main/kotlin/net/mamoe/mirai/japt/internal/BlockingBotImpl.kt @@ -65,5 +65,5 @@ internal class BlockingBotImpl(private val bot: Bot) : BlockingBot { override fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult = runBlocking { bot.addFriend(id, message, remark) } override fun approveFriendAddRequest(id: Long, remark: String?) = runBlocking { bot.approveFriendAddRequest(id, remark) } - override fun dispose(throwable: Throwable?) = bot.close(throwable) + override fun close(throwable: Throwable?) = bot.close(throwable) } \ No newline at end of file From 0ce0b336a184222bb5e1c3011290e584b587a2b3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 10:59:29 +0800 Subject: [PATCH 016/111] Fix #62 --- .../network/QQAndroidBotNetworkHandler.kt | 86 +++++++++++-------- 1 file changed, 50 insertions(+), 36 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 232e06e7a..4fea899ae 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 @@ -88,8 +88,24 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler }.also { _packetReceiverJob = it } } + private fun startHeartbeatJobOrKill(cancelCause: CancellationException? = null): Job { + heartbeatJob?.cancel(cancelCause) + + return this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { + while (this.isActive) { + delay(bot.configuration.heartbeatPeriodMillis) + val failException = doHeartBeat() + if (failException != null) { + delay(bot.configuration.firstReconnectDelayMillis) + close() + BotOfflineEvent.Dropped(bot).broadcast() + } + } + } + } + override suspend fun relogin() { - heartbeatJob?.cancel() + heartbeatJob?.cancel(CancellationException("relogin")) if (::channel.isInitialized) { if (channel.isOpen) { kotlin.runCatching { @@ -100,13 +116,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler channel.close() } channel = PlatformSocket() - // TODO: 2020/2/14 连接多个服务器 + // TODO: 2020/2/14 连接多个服务器, #52 withTimeoutOrNull(3000) { channel.connect("113.96.13.208", 8080) } ?: error("timeout connecting server") startPacketReceiverJobOrKill(CancellationException("reconnect")) - // logger.info("Trying login") var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect() mainloop@ while (true) { when (response) { @@ -159,8 +174,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler registerClientOnline() } - private suspend fun registerClientOnline() { - StatSvc.Register(bot.client).sendAndExpect() + private suspend fun registerClientOnline(timeoutMillis: Long = 3000) { + StatSvc.Register(bot.client).sendAndExpect(timeoutMillis) } // caches @@ -176,19 +191,27 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler bot.groups.delegate.clear() val friendListJob = launch { - try { + lateinit var loadFriends: suspend () -> Unit + // 不要用 fun, 不要 join declaration, 不要用 val, 编译失败警告 + loadFriends = suspend loadFriends@{ logger.info("开始加载好友信息") var currentFriendCount = 0 var totalFriendCount: Short while (true) { - val data = FriendList.GetFriendGroupList( - bot.client, - currentFriendCount, - 150, - 0, - 0 - ).sendAndExpect(timeoutMillis = 5000, retry = 2) - + val data = runCatching { + FriendList.GetFriendGroupList( + bot.client, + currentFriendCount, + 150, + 0, + 0 + ).sendAndExpect(timeoutMillis = 5000, retry = 2) + }.getOrElse { + logger.error("无法加载好友列表", it) + this@QQAndroidBotNetworkHandler.launch { delay(10.secondsToMillis); loadFriends() } + logger.error("稍后重试加载好友列表") + return@loadFriends + } totalFriendCount = data.totalFriendCount data.friendList.forEach { // atomic add @@ -196,16 +219,16 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler currentFriendCount++ } } - logger.verbose("正在加载好友列表 ${currentFriendCount}/${totalFriendCount}") + logger.verbose { "正在加载好友列表 ${currentFriendCount}/${totalFriendCount}" } if (currentFriendCount >= totalFriendCount) { break } // delay(200) } - logger.info("好友列表加载完成, 共 ${currentFriendCount}个") - } catch (e: Exception) { - logger.error("加载好友列表失败|一般这是由于加载过于频繁导致/将以热加载方式加载好友列表") + logger.info { "好友列表加载完成, 共 ${currentFriendCount}个" } } + + loadFriends() } val groupJob = launch { @@ -247,7 +270,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler )) ) }?.let { - logger.error("群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试") + logger.error { "群${troopNum.groupCode}的列表拉取失败, 一段时间后将会重试" } logger.error(it) this@QQAndroidBotNetworkHandler.launch { delay(10_000) @@ -260,27 +283,16 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler loadGroup() } } - logger.info("群组列表与群成员加载完成, 共 ${troopListData.groups.size}个") + logger.info { "群组列表与群成员加载完成, 共 ${troopListData.groups.size}个" } } catch (e: Exception) { - logger.error("加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表") + logger.error { "加载组信息失败|一般这是由于加载过于频繁导致/将以热加载方式加载群列表" } logger.error(e) } } + heartbeatJob = startHeartbeatJobOrKill() + joinAll(friendListJob, groupJob) - - heartbeatJob = this@QQAndroidBotNetworkHandler.launch(CoroutineName("Heartbeat")) { - while (this.isActive) { - delay(bot.configuration.heartbeatPeriodMillis) - val failException = doHeartBeat() - if (failException != null) { - delay(bot.configuration.firstReconnectDelayMillis) - close() - BotOfflineEvent.Dropped(bot).broadcast() - } - } - } - bot.firstLoginSucceed = true _pendingEnabled.value = false @@ -288,10 +300,12 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler @Suppress("UNCHECKED_CAST") KnownPacketFactories.handleIncomingPacket(it as KnownPacketFactories.IncomingPacket, bot, it.flag2, it.consumer) } - pendingIncomingPackets = null // release + val list = pendingIncomingPackets + pendingIncomingPackets = null // release, help gc + list?.clear() // help gc BotOnlineEvent(bot).broadcast() - Unit + Unit // dont remove. can help type inference } suspend fun doHeartBeat(): Exception? { From b2e0114e4f4a8fe1ab8bb0fb74610fe43c7233b0 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 11:28:23 +0800 Subject: [PATCH 017/111] Adjust job cancelling hence fix #65 --- .../network/QQAndroidBotNetworkHandler.kt | 11 ++++- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 22 +++++----- .../kotlin/net.mamoe.mirai/BotImpl.kt | 43 +++++++++---------- 3 files changed, 41 insertions(+), 35 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 4fea899ae..a8715c781 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 @@ -78,7 +78,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } catch (e: CancellationException) { return@launch } catch (e: Throwable) { - BotOfflineEvent.Dropped(bot).broadcast() + if (this@QQAndroidBotNetworkHandler.isActive) { + BotOfflineEvent.Dropped(bot).broadcast() + } return@launch } packetReceiveLock.withLock { @@ -185,6 +187,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler @UseExperimental(MiraiExperimentalAPI::class, ExperimentalTime::class) override suspend fun init(): Unit = coroutineScope { + check(bot.isActive) { "bot is dead therefore network can't init" } + check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" } MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() bot.qqs.delegate.clear() @@ -494,6 +498,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler * 发送一个包, 但不期待任何返回. */ suspend fun OutgoingPacket.sendWithoutExpect() { + check(bot.isActive) { "bot is dead therefore can't send any packet" } + check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" } logger.info("Send: ${this.commandName}") withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) { channel.send(delegate) @@ -509,6 +515,9 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler require(timeoutMillis > 0) { "timeoutMillis must > 0" } require(retry >= 0) { "retry must >= 0" } + check(bot.isActive) { "bot is dead therefore can't send any packet" } + check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" } + var lastException: Exception? = null if (retry == 0) { val handler = PacketListener(commandName = commandName, sequenceId = sequenceId) 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 a8dea8551..96fd0db38 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -7,7 +7,7 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ -@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE") +@file:Suppress("EXPERIMENTAL_API_USAGE", "unused", "FunctionName", "NOTHING_TO_INLINE", "UnusedImport") package net.mamoe.mirai @@ -35,7 +35,8 @@ import kotlin.jvm.JvmStatic * * 注: Bot 为全协程实现, 没有其他任务时若不使用 [join], 主线程将会退出. * - * @see Contact + * @see Contact 联系人 + * @see kotlinx.coroutines.isActive 判断 [Bot] 是否正常运行中. (在线, 且没有被 [close]) */ @UseExperimental(MiraiInternalAPI::class) abstract class Bot : CoroutineScope { @@ -195,7 +196,9 @@ abstract class Bot : CoroutineScope { /** * 登录, 或重新登录. - * 重新登录时不会再次拉取联系人列表. + * 这个函数总是关闭一切现有网路任务, 然后重新登录并重新缓存好友列表和群列表. + * + * 一般情况下不需要重新登录. Mirai 能够自动处理掉线情况. * * 最终调用 [net.mamoe.mirai.network.BotNetworkHandler.relogin] * @@ -231,24 +234,19 @@ abstract class Bot : CoroutineScope { // endregion /** - * 关闭这个 [Bot], 停止一切相关活动. 所有引用都会被释放. + * 关闭这个 [Bot], 立即取消 [Bot] 的 [kotlinx.coroutines.SupervisorJob]. + * 之后 [kotlinx.coroutines.isActive] 将会返回 `false`. * - * 注: 不可重新登录. 必须重新实例化一个 [Bot]. + * **注意:** 不可重新登录. 必须重新实例化一个 [Bot]. * * @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭 * - * @see closeAndJoin + * @see closeAndJoin 取消并 [Bot.join], 以确保 [Bot] 相关的活动被完全关闭 */ abstract fun close(cause: Throwable? = null) // region extensions - @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this.toLong())")) - fun Int.qq(): QQ = getFriend(this.toLong()) - - @Deprecated(message = "这个函数有歧义, 将在不久后删除", replaceWith = ReplaceWith("getFriend(this)")) - fun Long.qq(): QQ = getFriend(this) - final override fun toString(): String { return "Bot(${uin})" } 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 a8686f90f..b574d7419 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -89,22 +89,17 @@ abstract class BotImpl constructor( private val offlineListener: Listener = this.subscribeAlways { event -> when (event) { is BotOfflineEvent.Dropped -> { + if (!_network.isActive) { + return@subscribeAlways + } bot.logger.info("Connection dropped or lost by server, retrying login") - 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!! - } + tryNTimesOrException(configuration.reconnectionRetryTimes) { + delay(configuration.reconnectPeriodMillis) + network.relogin() + logger.info("Reconnected successfully") + return@subscribeAlways + }?.let { throw it } } is BotOfflineEvent.Active -> { val msg = if (event.cause == null) { @@ -112,12 +107,12 @@ abstract class BotImpl constructor( } else { " with exception: " + event.cause.message } - bot.logger.info("Bot is closed manually$msg") - close(CancellationException(event.toString())) + bot.logger.info { "Bot is closed manually$msg" } + closeAndJoin(CancellationException(event.toString())) } is BotOfflineEvent.Force -> { - bot.logger.info("Connection occupied by another android device: ${event.message}") - close(ForceOfflineException(event.toString())) + bot.logger.info { "Connection occupied by another android device: ${event.message}" } + closeAndJoin(ForceOfflineException(event.toString())) } } } @@ -176,15 +171,19 @@ abstract class BotImpl constructor( @UseExperimental(MiraiInternalAPI::class) override fun close(cause: Throwable?) { + if (!this.botJob.isActive) { + // already cancelled + return + } kotlin.runCatching { if (cause == null) { + this.botJob.cancel() network.close() - this.botJob.complete() - offlineListener.complete() + offlineListener.cancel() } else { + this.botJob.cancel(CancellationException("bot cancelled", cause)) network.close(cause) - this.botJob.completeExceptionally(cause) - offlineListener.completeExceptionally(cause) + offlineListener.cancel(CancellationException("bot cancelled", cause)) } } groups.delegate.clear() From 016be17049e15a7d88ed934e00ffe1130565e46e Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 11:36:24 +0800 Subject: [PATCH 018/111] Fix #70 --- .../mamoe/mirai/utils/cryptor/ECDHAndroid.kt | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt index 98db0234f..93d59f082 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.utils.cryptor +import android.annotation.SuppressLint import net.mamoe.mirai.utils.md5 import java.security.* import java.security.spec.X509EncodedKeySpec @@ -32,6 +33,26 @@ actual fun ECDH() = ECDH(ECDH.generateKeyPair()) actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { actual companion object { + init { + kotlin.runCatching { + @SuppressLint("PrivateApi") + val clazz = Class.forName( + "com.android.org.bouncycastle.jce.provider.BouncyCastleProvider", + true, + ClassLoader.getSystemClassLoader() + ) + + val providerName = clazz.getDeclaredField("PROVIDER_NAME").get(null) as String + + if (Security.getProvider(providerName) != null) { + Security.removeProvider(providerName) + } + Security.addProvider(clazz.newInstance() as Provider) + }.exceptionOrNull()?.let { + throw IllegalStateException("cannot init BouncyCastle", it) + } + } + actual fun generateKeyPair(): ECDHKeyPair { return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair()) } From 67c31ed0cb27b9b659f6bb45fb552f3f4d080ed9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 11:41:14 +0800 Subject: [PATCH 019/111] Add logs before and after logging in --- mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 6 +++++- 1 file changed, 5 insertions(+), 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 b574d7419..c988b0a79 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -117,7 +117,11 @@ abstract class BotImpl constructor( } } - final override suspend fun login() = reinitializeNetworkHandler(null) + final override suspend fun login() { + logger.info("Logging in...") + reinitializeNetworkHandler(null) + logger.info("Login successful") + } private suspend fun reinitializeNetworkHandler( cause: Throwable? From 3b7a9b6d42af572efd2e3323ccba2cf8381e890b Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 12:16:05 +0800 Subject: [PATCH 020/111] Fix logger --- .../net.mamoe.mirai/utils/MiraiLogger.kt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 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 068e67d4a..69eb7d299 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 @@ -151,43 +151,43 @@ interface MiraiLogger { inline fun MiraiLogger.verbose(lazyMessage: () -> String) { - if (this is MiraiLoggerWithSwitch && switch) verbose(lazyMessage()) + if (this !is MiraiLoggerWithSwitch || switch) verbose(lazyMessage()) } inline fun MiraiLogger.verbose(lazyMessage: () -> String, e: Throwable?) { - if (this is MiraiLoggerWithSwitch && switch) verbose(lazyMessage(), e) + if (this !is MiraiLoggerWithSwitch || switch) verbose(lazyMessage(), e) } inline fun MiraiLogger.debug(lazyMessage: () -> String?) { - if (this is MiraiLoggerWithSwitch && switch) debug(lazyMessage()) + if (this !is MiraiLoggerWithSwitch || switch) debug(lazyMessage()) } inline fun MiraiLogger.debug(lazyMessage: () -> String?, e: Throwable?) { - if (this is MiraiLoggerWithSwitch && switch) debug(lazyMessage(), e) + if (this !is MiraiLoggerWithSwitch || switch) debug(lazyMessage(), e) } inline fun MiraiLogger.info(lazyMessage: () -> String?) { - if (this is MiraiLoggerWithSwitch && switch) info(lazyMessage()) + if (this !is MiraiLoggerWithSwitch || switch) info(lazyMessage()) } inline fun MiraiLogger.info(lazyMessage: () -> String?, e: Throwable?) { - if (this is MiraiLoggerWithSwitch && switch) info(lazyMessage(), e) + if (this !is MiraiLoggerWithSwitch || switch) info(lazyMessage(), e) } inline fun MiraiLogger.warning(lazyMessage: () -> String?) { - if (this is MiraiLoggerWithSwitch && switch) warning(lazyMessage()) + if (this !is MiraiLoggerWithSwitch || switch) warning(lazyMessage()) } inline fun MiraiLogger.warning(lazyMessage: () -> String?, e: Throwable?) { - if (this is MiraiLoggerWithSwitch && switch) warning(lazyMessage(), e) + if (this !is MiraiLoggerWithSwitch || switch) warning(lazyMessage(), e) } inline fun MiraiLogger.error(lazyMessage: () -> String?) { - if (this is MiraiLoggerWithSwitch && switch) error(lazyMessage()) + if (this !is MiraiLoggerWithSwitch || switch) error(lazyMessage()) } inline fun MiraiLogger.error(lazyMessage: () -> String?, e: Throwable?) { - if (this is MiraiLoggerWithSwitch && switch) error(lazyMessage(), e) + if (this !is MiraiLoggerWithSwitch || switch) error(lazyMessage(), e) } /** From 4f7b266e03d6cc0dba15011310fd6ee8c2574e4b Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 12:16:17 +0800 Subject: [PATCH 021/111] Add tryCount param to lambda --- .../kotlin/net.mamoe.mirai/utils/tryNTimes.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt index 417d8536a..57f418797 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt @@ -15,12 +15,12 @@ expect fun Throwable.addSuppressed(e: Throwable) @MiraiInternalAPI @Suppress("DuplicatedCode") -inline fun tryNTimes(repeat: Int, block: () -> R): R { +inline fun tryNTimes(repeat: Int, block: (Int) -> R): R { var lastException: Throwable? = null repeat(repeat) { try { - return block() + return block(it) } catch (e: Throwable) { if (lastException == null) { lastException = e @@ -34,12 +34,12 @@ inline fun tryNTimes(repeat: Int, block: () -> R): R { @MiraiInternalAPI @Suppress("DuplicatedCode") -inline fun tryNTimesOrNull(repeat: Int, block: () -> R): R? { +inline fun tryNTimesOrNull(repeat: Int, block: (Int) -> R): R? { var lastException: Throwable? = null repeat(repeat) { try { - return block() + return block(it) } catch (e: Throwable) { if (lastException == null) { lastException = e @@ -53,12 +53,12 @@ inline fun tryNTimesOrNull(repeat: Int, block: () -> R): R? { @MiraiInternalAPI @Suppress("DuplicatedCode") -inline fun tryNTimesOrException(repeat: Int, block: () -> R): Throwable? { +inline fun tryNTimesOrException(repeat: Int, block: (Int) -> R): Throwable? { var lastException: Throwable? = null repeat(repeat) { try { - block() + block(it) return null } catch (e: Throwable) { if (lastException == null) { From c9375114124b339e8072cec1a083f990300d6697 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 12:16:28 +0800 Subject: [PATCH 022/111] Fix login retry --- mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) 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 c988b0a79..e1d603d87 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -94,8 +94,10 @@ abstract class BotImpl constructor( } bot.logger.info("Connection dropped or lost by server, retrying login") - tryNTimesOrException(configuration.reconnectionRetryTimes) { - delay(configuration.reconnectPeriodMillis) + tryNTimesOrException(configuration.reconnectionRetryTimes) { tryCount -> + if (tryCount != 0) { + delay(configuration.reconnectPeriodMillis) + } network.relogin() logger.info("Reconnected successfully") return@subscribeAlways From c20040f1ac71108724d3654026ce63c1e21bd85e Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 12:20:21 +0800 Subject: [PATCH 023/111] Add common property `isEnabled` to all loggers --- .../net.mamoe.mirai/utils/MiraiLogger.kt | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 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 69eb7d299..c44a0d558 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 @@ -70,6 +70,13 @@ interface MiraiLogger { */ val identity: String? + /** + * 获取 [MiraiLogger] 是否已开启 + * + * 除 [MiraiLoggerWithSwitch] 可控制开关外, 其他的所有 [MiraiLogger] 均一直开启. + */ + val isEnabled: Boolean + /** * 随从. 在 this 中调用所有方法后都应继续往 [follower] 传递调用. * [follower] 的存在可以让一次日志被多个日志记录器记录. @@ -151,43 +158,43 @@ interface MiraiLogger { inline fun MiraiLogger.verbose(lazyMessage: () -> String) { - if (this !is MiraiLoggerWithSwitch || switch) verbose(lazyMessage()) + if (isEnabled) verbose(lazyMessage()) } inline fun MiraiLogger.verbose(lazyMessage: () -> String, e: Throwable?) { - if (this !is MiraiLoggerWithSwitch || switch) verbose(lazyMessage(), e) + if (isEnabled) verbose(lazyMessage(), e) } inline fun MiraiLogger.debug(lazyMessage: () -> String?) { - if (this !is MiraiLoggerWithSwitch || switch) debug(lazyMessage()) + if (isEnabled) debug(lazyMessage()) } inline fun MiraiLogger.debug(lazyMessage: () -> String?, e: Throwable?) { - if (this !is MiraiLoggerWithSwitch || switch) debug(lazyMessage(), e) + if (isEnabled) debug(lazyMessage(), e) } inline fun MiraiLogger.info(lazyMessage: () -> String?) { - if (this !is MiraiLoggerWithSwitch || switch) info(lazyMessage()) + if (isEnabled) info(lazyMessage()) } inline fun MiraiLogger.info(lazyMessage: () -> String?, e: Throwable?) { - if (this !is MiraiLoggerWithSwitch || switch) info(lazyMessage(), e) + if (isEnabled) info(lazyMessage(), e) } inline fun MiraiLogger.warning(lazyMessage: () -> String?) { - if (this !is MiraiLoggerWithSwitch || switch) warning(lazyMessage()) + if (isEnabled) warning(lazyMessage()) } inline fun MiraiLogger.warning(lazyMessage: () -> String?, e: Throwable?) { - if (this !is MiraiLoggerWithSwitch || switch) warning(lazyMessage(), e) + if (isEnabled) warning(lazyMessage(), e) } inline fun MiraiLogger.error(lazyMessage: () -> String?) { - if (this !is MiraiLoggerWithSwitch || switch) error(lazyMessage()) + if (isEnabled) error(lazyMessage()) } inline fun MiraiLogger.error(lazyMessage: () -> String?, e: Throwable?) { - if (this !is MiraiLoggerWithSwitch || switch) error(lazyMessage(), e) + if (isEnabled) error(lazyMessage(), e) } /** @@ -268,7 +275,7 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg @PublishedApi internal var switch: Boolean = default - val isEnabled: Boolean get() = switch + override val isEnabled: Boolean get() = switch fun enable() { switch = true @@ -298,6 +305,7 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg * 在定义 logger 变量时, 请一直使用 [MiraiLogger] 或者 [MiraiLoggerWithSwitch]. */ abstract class MiraiLoggerPlatformBase : MiraiLogger { + override val isEnabled: Boolean get() = true final override var follower: MiraiLogger? = null final override fun verbose(message: String?) { From f6ab87f1ef44386ebc643f532b549b1162ecd795 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 12:23:09 +0800 Subject: [PATCH 024/111] Unified `bot.logger` and `network.logger` --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 9 ++++++++- 1 file changed, 8 insertions(+), 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 a8715c781..94bc47a07 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 @@ -404,7 +404,14 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (packet is CancellableEvent && packet.isCancelled) return } - logger.info("Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}") + if (bot.logger.isEnabled || logger.isEnabled) { + val logMessage = "Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}" + + if (packet is Event) { + bot.logger.verbose(logMessage) + } + logger.verbose(logMessage) + } packetFactory?.run { when (this) { From 9488ea26341ce87507eb0ae0d85d7458e60dd68a Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:07:11 +0800 Subject: [PATCH 025/111] Make generic type TPacket nullable --- .../qqandroid/network/protocol/packet/PacketFactory.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index e3978b082..b0da3edd0 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -33,7 +33,7 @@ import kotlin.contracts.contract import kotlin.jvm.JvmName -internal sealed class PacketFactory { +internal sealed class PacketFactory { /** * 筛选从服务器接收到的包时的 commandName */ @@ -49,7 +49,7 @@ internal sealed class PacketFactory { * @param TPacket 服务器回复包解析结果 */ @UseExperimental(ExperimentalUnsignedTypes::class) -internal abstract class OutgoingPacketFactory( +internal abstract class OutgoingPacketFactory( /** * 命令名. 如 `wtlogin.login`, `ConfigPushSvc.PushDomain` */ @@ -73,7 +73,7 @@ internal abstract class OutgoingPacketFactory( * 这个工厂可以在 [handle] 时回复一个 commandId 为 [responseCommandName] 的包, 也可以不回复. * 必须先到 [KnownPacketFactories] 中注册工厂, 否则不能处理. */ -internal abstract class IncomingPacketFactory( +internal abstract class IncomingPacketFactory( /** * 接收自服务器的包的 commandName */ @@ -263,7 +263,7 @@ internal object KnownPacketFactories { private inline fun inline(block: () -> R): R = block() - class IncomingPacket( + class IncomingPacket( val packetFactory: PacketFactory?, val sequenceId: Int, val data: ByteReadPacket, From 64a02f1ea6a17917fbe657db942bc909f24c7fe7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:08:10 +0800 Subject: [PATCH 026/111] Unwrap inline class --- .../packet/chat/receive/OnlinePush.kt | 51 +++++++------------ 1 file changed, 18 insertions(+), 33 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 24710fb7c..50e91ef90 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 @@ -17,7 +17,6 @@ import kotlinx.io.core.readUInt import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.NoPacket import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.broadcast import net.mamoe.mirai.event.events.* import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.qqandroid.GroupImpl @@ -41,58 +40,44 @@ import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.readString import net.mamoe.mirai.utils.io.toUHexString -internal inline class GroupMessageOrNull(val delegate: GroupMessage?) : Packet { - override fun toString(): String { - return delegate?.toString() ?: "" - } -} - internal class OnlinePush { /** * 接受群消息 */ - internal object PbPushGroupMsg : IncomingPacketFactory("OnlinePush.PbPushGroupMsg") { + internal object PbPushGroupMsg : IncomingPacketFactory("OnlinePush.PbPushGroupMsg") { @UseExperimental(ExperimentalStdlibApi::class) - override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): GroupMessageOrNull { + override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): GroupMessage? { // 00 00 02 E4 0A D5 05 0A 4F 08 A2 FF 8C F0 03 10 DD F1 92 B7 07 18 52 20 00 28 BC 3D 30 8C 82 AB F1 05 38 D2 80 E0 8C 80 80 80 80 02 4A 21 08 E7 C1 AD B8 02 10 01 18 BA 05 22 09 48 69 6D 31 38 38 6D 6F 65 30 06 38 02 42 05 4D 69 72 61 69 50 01 58 01 60 00 88 01 08 12 06 08 01 10 00 18 00 1A F9 04 0A F6 04 0A 26 08 00 10 87 82 AB F1 05 18 B7 B4 BF 30 20 00 28 0C 30 00 38 86 01 40 22 4A 0C E5 BE AE E8 BD AF E9 9B 85 E9 BB 91 12 E6 03 42 E3 03 12 2A 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 22 00 2A 04 03 00 00 00 32 60 15 36 20 39 36 6B 45 31 41 38 35 32 32 39 64 63 36 39 38 34 37 39 37 37 62 20 20 20 20 20 20 35 30 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 7B 34 45 31 38 35 38 32 32 2D 30 45 37 42 2D 46 38 30 46 2D 43 35 42 31 2D 33 34 34 38 38 33 37 34 44 33 39 43 7D 2E 6A 70 67 31 32 31 32 41 38 C6 BB 8A A9 08 40 FB AE 9E C2 09 48 50 50 41 5A 00 60 01 6A 10 4E 18 58 22 0E 7B F8 0F C5 B1 34 48 83 74 D3 9C 72 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 31 39 38 3F 74 65 72 6D 3D 32 82 01 57 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 30 3F 74 65 72 6D 3D 32 B0 01 4D B8 01 2E C8 01 FF 05 D8 01 4D E0 01 2E FA 01 59 2F 67 63 68 61 74 70 69 63 5F 6E 65 77 2F 31 30 34 30 34 30 30 32 39 30 2F 36 35 35 30 35 37 31 32 37 2D 32 32 33 33 36 33 38 33 34 32 2D 34 45 31 38 35 38 32 32 30 45 37 42 46 38 30 46 43 35 42 31 33 34 34 38 38 33 37 34 44 33 39 43 2F 34 30 30 3F 74 65 72 6D 3D 32 80 02 4D 88 02 2E 12 45 AA 02 42 50 03 60 00 68 00 9A 01 39 08 09 20 BF 50 80 01 01 C8 01 00 F0 01 00 F8 01 00 90 02 00 98 03 00 A0 03 20 B0 03 00 C0 03 00 D0 03 00 E8 03 00 8A 04 04 08 02 08 01 90 04 80 80 80 10 B8 04 00 C0 04 00 12 06 4A 04 08 00 40 01 12 14 82 01 11 0A 09 48 69 6D 31 38 38 6D 6F 65 18 06 20 08 28 03 10 8A CA 9D A1 07 1A 00 - if (!bot.firstLoginSucceed) return GroupMessageOrNull(null) + if (!bot.firstLoginSucceed) return null val pbPushMsg = readProtoBuf(MsgOnlinePush.PbPushMsg.serializer()) val extraInfo: ImMsgBody.ExtraInfo? = pbPushMsg.msg.msgBody.richText.elems.firstOrNull { it.extraInfo != null }?.extraInfo if (pbPushMsg.msg.msgHead.fromUin == bot.uin) { - return GroupMessageOrNull(null) + return null } val group = bot.getGroup(pbPushMsg.msg.msgHead.groupInfo!!.groupCode) // println(pbPushMsg.msg.msgBody.richText.contentToString()) val flags = extraInfo?.flags ?: 0 - return GroupMessageOrNull( - GroupMessage( - bot = bot, - group = group, - senderName = pbPushMsg.msg.msgHead.groupInfo.groupCard, - sender = group[pbPushMsg.msg.msgHead.fromUin], - message = pbPushMsg.msg.toMessageChain(), - permission = when { - flags and 16 != 0 -> MemberPermission.ADMINISTRATOR - flags and 8 != 0 -> MemberPermission.OWNER - flags == 0 -> MemberPermission.MEMBER - else -> { - bot.logger.warning("判断群员权限失败") - MemberPermission.MEMBER - } + return GroupMessage( + bot = bot, + group = group, + senderName = pbPushMsg.msg.msgHead.groupInfo.groupCard, + sender = group[pbPushMsg.msg.msgHead.fromUin], + message = pbPushMsg.msg.toMessageChain(), + permission = when { + flags and 16 != 0 -> MemberPermission.ADMINISTRATOR + flags and 8 != 0 -> MemberPermission.OWNER + flags == 0 -> MemberPermission.MEMBER + else -> { + bot.logger.warning("判断群员权限失败") + MemberPermission.MEMBER } - ) + } ) } - - override suspend fun QQAndroidBot.handle(packet: GroupMessageOrNull, sequenceId: Int): OutgoingPacket? { - packet.delegate?.broadcast() - return null - } - } internal object PbPushTransMsg : IncomingPacketFactory("OnlinePush.PbPushTransMsg", "OnlinePush.RespPush") { From 41a12089e3e25c08e4a92b08c35348726a9d298b Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:08:44 +0800 Subject: [PATCH 027/111] Improve performance: use object --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 7aad3fefa..83b5f69f0 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -103,7 +103,7 @@ internal class MessageSvc { } @UseExperimental(MiraiInternalAPI::class) - internal class GetMsgSuccess(delegate: List) : Response(MsgSvc.SyncFlag.STOP, delegate) + open class GetMsgSuccess(delegate: List) : Response(MsgSvc.SyncFlag.STOP, delegate) /** * 不要直接 expect 这个 class. 它可能 @@ -119,7 +119,7 @@ internal class MessageSvc { } } - object EmptyResponse : Response(MsgSvc.SyncFlag.STOP, emptyList()) + object EmptyResponse : GetMsgSuccess(emptyList()) @UseExperimental(MiraiInternalAPI::class, MiraiExperimentalAPI::class) override suspend fun ByteReadPacket.decode(bot: QQAndroidBot): Response { @@ -127,8 +127,8 @@ internal class MessageSvc { val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer()) if (resp.result != 0) { - // println("!!! Result=${resp.result} !!!: " + resp.contentToString()) - return GetMsgSuccess(mutableListOf()) + // println("!!! Result=${resp.result} !!!: " + resp.contentToString()) + return EmptyResponse } bot.client.c2cMessageSync.syncCookie = resp.syncCookie From 985f368f7d3e7d007d58bbe198395c5c854c95cc Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:09:05 +0800 Subject: [PATCH 028/111] Fix friend message syncing --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 9 +++++---- 1 file changed, 5 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 94bc47a07..23d4d8983 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 @@ -189,7 +189,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler override suspend fun init(): Unit = coroutineScope { check(bot.isActive) { "bot is dead therefore network can't init" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't init" } - MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() bot.qqs.delegate.clear() bot.groups.delegate.clear() @@ -297,6 +296,8 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler heartbeatJob = startHeartbeatJobOrKill() joinAll(friendListJob, groupJob) + MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect() + bot.firstLoginSucceed = true _pendingEnabled.value = false @@ -507,7 +508,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler suspend fun OutgoingPacket.sendWithoutExpect() { check(bot.isActive) { "bot is dead therefore can't send any packet" } check(this@QQAndroidBotNetworkHandler.isActive) { "network is dead therefore can't send any packet" } - logger.info("Send: ${this.commandName}") + logger.verbose("Send: ${this.commandName}") withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) { channel.send(delegate) } @@ -533,7 +534,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) { channel.send(delegate) } - logger.info("Send: ${this.commandName}") + logger.verbose("Send: ${this.commandName}") return withTimeoutOrNull(timeoutMillis) { @Suppress("UNCHECKED_CAST") handler.await() as E @@ -552,7 +553,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler withContext(this@QQAndroidBotNetworkHandler.coroutineContext + CoroutineName("Packet sender")) { channel.send(data, 0, length) } - logger.info("Send: ${this.commandName}") + logger.verbose("Send: ${this.commandName}") return withTimeoutOrNull(timeoutMillis) { @Suppress("UNCHECKED_CAST") handler.await() as E From 57479e0db6830bbeb24d090d863179220614f2ea Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:25:41 +0800 Subject: [PATCH 029/111] =?UTF-8?q?Replace=20all=20=E7=99=BB=E9=99=86s=20w?= =?UTF-8?q?ith=20=E7=99=BB=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt | 4 ++-- .../src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt | 4 ++-- .../kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt index 0195627cd..70cf38f3b 100644 --- a/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt +++ b/mirai-console-terminal/src/main/kotlin/net/mamoe/mirai/console/MiraiConsoleTerminalUI.kt @@ -187,8 +187,8 @@ object MiraiConsoleTerminalUI : MiraiConsoleUI { override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? { pushLog(0, "[Login Solver]需要进行账户安全认证") - pushLog(0, "[Login Solver]该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题") - pushLog(0, "[Login Solver]完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次") + pushLog(0, "[Login Solver]该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题") + pushLog(0, "[Login Solver]完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次") pushLog(0, "[Login Solver]请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符") pushLog(0, "[Login Solver]这步操作将在后续的版本中优化") pushLog(0, url) diff --git a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt index 66aa8a304..6a5e16ad3 100644 --- a/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt +++ b/mirai-console/src/main/kotlin/net/mamoe/mirai/console/MiraiConsole.kt @@ -77,7 +77,7 @@ object MiraiConsole { logger("Mirai-console 启动完成") logger("\"/login qqnumber qqpassword \" to login a bot") - logger("\"/login qq号 qq密码 \" 来登陆一个BOT") + logger("\"/login qq号 qq密码 \" 来登录一个BOT") } fun stop() { @@ -208,7 +208,7 @@ object MiraiConsole { } val bot: Bot? = if (it.size == 2) { if (bots.size == 0) { - logger("还没有BOT登陆") + logger("还没有BOT登录") return@onCommand false } bots[0].get() 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 fe4402025..241034f30 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 @@ -105,8 +105,8 @@ class DefaultLoginSolver( override suspend fun onSolveUnsafeDeviceLoginVerify(bot: Bot, url: String): String? = loginSolverLock.withLock { val logger = getLogger(bot) logger.info("需要进行账户安全认证") - logger.info("该账户有[设备锁]/[不常用登陆地点]/[不常用设备登陆]的问题") - logger.info("完成以下账号认证即可成功登陆|理论本认证在mirai每个账户中最多出现1次") + logger.info("该账户有[设备锁]/[不常用登录地点]/[不常用设备登录]的问题") + logger.info("完成以下账号认证即可成功登录|理论本认证在mirai每个账户中最多出现1次") logger.info("请将该链接在QQ浏览器中打开并完成认证, 成功后输入任意字符") logger.info("这步操作将在后续的版本中优化") logger.info(url) From 4798b8c1ec2b3367da948186ce769011e8e5bf58 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:26:17 +0800 Subject: [PATCH 030/111] Remove unnecessary `if` --- .../net.mamoe.mirai/utils/MiraiLogger.kt | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 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 c44a0d558..f912a8e0f 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 @@ -285,16 +285,16 @@ class MiraiLoggerWithSwitch internal constructor(private val delegate: MiraiLogg switch = false } - 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(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(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(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(message: String?) = if (switch) delegate.error(message) else Unit - override fun error0(message: String?, e: Throwable?) = if (switch) delegate.error(message, e) else Unit + override fun verbose0(message: String?) = delegate.verbose(message) + override fun verbose0(message: String?, e: Throwable?) = delegate.verbose(message, e) + override fun debug0(message: String?) = delegate.debug(message) + override fun debug0(message: String?, e: Throwable?) = delegate.debug(message, e) + override fun info0(message: String?) = delegate.info(message) + override fun info0(message: String?, e: Throwable?) = delegate.info(message, e) + override fun warning0(message: String?) = delegate.warning(message) + override fun warning0(message: String?, e: Throwable?) = delegate.warning(message, e) + override fun error0(message: String?) = delegate.error(message) + override fun error0(message: String?, e: Throwable?) = delegate.error(message, e) } /** @@ -309,51 +309,61 @@ abstract class MiraiLoggerPlatformBase : MiraiLogger { final override var follower: MiraiLogger? = null final override fun verbose(message: String?) { + if (!isEnabled) return follower?.verbose(message) verbose0(message) } final override fun verbose(message: String?, e: Throwable?) { + if (!isEnabled) return follower?.verbose(message, e) verbose0(message, e) } final override fun debug(message: String?) { + if (!isEnabled) return follower?.debug(message) debug0(message) } final override fun debug(message: String?, e: Throwable?) { + if (!isEnabled) return follower?.debug(message, e) debug0(message, e) } final override fun info(message: String?) { + if (!isEnabled) return follower?.info(message) info0(message) } final override fun info(message: String?, e: Throwable?) { + if (!isEnabled) return follower?.info(message, e) info0(message, e) } final override fun warning(message: String?) { + if (!isEnabled) return follower?.warning(message) warning0(message) } final override fun warning(message: String?, e: Throwable?) { + if (!isEnabled) return follower?.warning(message, e) warning0(message, e) } final override fun error(message: String?) { + if (!isEnabled) return follower?.error(message) error0(message) } final override fun error(message: String?, e: Throwable?) { + if (!isEnabled) return follower?.error(message, e) error0(message, e) } From d9a8719e211ded2a0f47f1032ba5857d31735840 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:28:48 +0800 Subject: [PATCH 031/111] 0.15.5 --- CHANGELOG.md | 16 ++++++++++++++++ gradle.properties | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4c40d0ae9..3de31fee8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,22 @@ 开发版本. 频繁更新, 不保证高稳定性 +## `0.15.5` 2020/2/19 + +### mirai-core +- 为 `MiraiLogger` 添加 common property `val isEnabled: Boolean` +- 修复 #62: 掉线重连后无 heartbeat +- 修复 #65: `Bot` close 后仍会重连 +- 修复 #70: ECDH is not available on Android platform + +### mirai-core-qqandroid +- 从服务器收到的事件将会额外使用 `bot.logger` 记录 (verbose). +- 降低包记录的等级: `info` -> `verbose` +- 改善 `Bot` 的 log 记录 +- 加载好友列表失败时会重试 +- 改善 `Bot` 或 `NetworkHandler` 关闭时取消 job 的逻辑 +- 修复初始化(init)时同步历史好友消息时出错的问题 + ## `0.15.4` 2020/2/18 - 放弃使用 `atomicfu` 以解决其编译错误的问题. (#60) diff --git a/gradle.properties b/gradle.properties index 5ededee39..81732c549 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.15.4 +mirai_version=0.15.5 mirai_japt_version=1.0.1 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true From 0508e8d894fe146b0cb1ca102207ad94c894e713 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 13:32:43 +0800 Subject: [PATCH 032/111] Add details in exception --- .../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 6c7c5b26b..6bca8ade1 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 @@ -325,7 +325,7 @@ internal class WtLogin { 2 -> onSolveLoginCaptcha(tlvMap, bot) 160 /*-96*/ -> onUnsafeDeviceLogin(tlvMap) 204 /*-52*/ -> onSMSVerifyNeeded(tlvMap, bot) - else -> tlvMap[0x149]?.let { analysisTlv149(it) } ?: error("unknown login result type: $type") + else -> tlvMap[0x149]?.let { analysisTlv149(it) } ?: error("unknown login result type: $type, TLVMap = ${tlvMap.contentToString()}") } } From 9de13ca6fd58eeed14cc63d84ccc9e08c10580f9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:15:38 +0800 Subject: [PATCH 033/111] Fix ECDH --- .../network/protocol/packet/EncryptMethod.kt | 34 +++++++++---- .../network/protocol/packet/login/WtLogin.kt | 10 ++-- .../mamoe/mirai/utils/cryptor/ECDHAndroid.kt | 22 +++++--- .../net.mamoe.mirai/utils/cryptor/ECDH.kt | 18 +++++-- .../net/mamoe/mirai/utils/cryptor/ECDHJvm.kt | 50 ++++++++----------- 5 files changed, 81 insertions(+), 53 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt index 344c9dba2..fe32747ff 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt @@ -14,7 +14,9 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.qqandroid.network.QQAndroidClient +import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.cryptor.ECDH +import net.mamoe.mirai.utils.cryptor.ECDHKeyPair import net.mamoe.mirai.utils.io.encryptAndWrite import net.mamoe.mirai.utils.io.writeShortLVByteArray @@ -65,17 +67,25 @@ inline class EncryptMethodSessionKeyLoginState3(override val sessionKey: ByteArr override val currentLoginState: Int get() = 3 } -inline class EncryptMethodECDH135(override val ecdh: ECDH) : +internal inline class EncryptMethodECDH135(override val ecdh: ECDH) : EncryptMethodECDH { override val id: Int get() = 135 } -inline class EncryptMethodECDH7(override val ecdh: ECDH) : +internal inline class EncryptMethodECDH7(override val ecdh: ECDH) : EncryptMethodECDH { override val id: Int get() = 7 } internal interface EncryptMethodECDH : EncryptMethod { + companion object { + operator fun invoke(ecdh: ECDH): EncryptMethodECDH { + return if (ecdh.keyPair === ECDHKeyPair.DefaultStub) { + EncryptMethodECDH135(ecdh) + } else EncryptMethodECDH7(ecdh) + } + } + val ecdh: ECDH /** @@ -97,13 +107,19 @@ internal interface EncryptMethodECDH : EncryptMethod { // writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) - writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { - // it.toUHexString().debugPrint("PUBLIC KEY") - check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } - //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } - }) + if (ecdh.keyPair === ECDHKeyPair.DefaultStub) { + writeShortLVByteArray(ECDHKeyPair.DefaultStub.defaultPublicKey) + encryptAndWrite(ECDHKeyPair.DefaultStub.defaultShareKey, body) + } else { + MiraiLogger.info("Using custom") + writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { + // it.toUHexString().debugPrint("PUBLIC KEY") + check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } + //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } + }) - // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) - encryptAndWrite(ecdh.keyPair.initialShareKey, body) + // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) + encryptAndWrite(ecdh.keyPair.initialShareKey, body) + } } } \ No newline at end of file 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 6bca8ade1..29ea3b873 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 @@ -47,7 +47,7 @@ internal class WtLogin { ticket: String ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) { - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) { + writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) { writeShort(2) // subCommand writeShort(4) // count of TLVs t193(ticket) @@ -64,7 +64,7 @@ internal class WtLogin { captchaAnswer: String ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) { - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) { + writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) { writeShort(2) // subCommand writeShort(4) // count of TLVs t2(captchaAnswer, captchaSign, 0) @@ -83,7 +83,7 @@ internal class WtLogin { t402: ByteArray ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) { - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) { + writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) { writeShort(20) // subCommand writeShort(4) // count of TLVs, probably ignored by server? t8(2052) @@ -103,7 +103,7 @@ internal class WtLogin { client: QQAndroidClient ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId, unknownHex = "01 00 00 00 00 00 00 00 00 00 01 00") { - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) { + writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) { writeShort(8) // subCommand writeShort(6) // count of TLVs, probably ignored by server?TODO t8(2052) @@ -131,7 +131,7 @@ internal class WtLogin { client: QQAndroidClient ): OutgoingPacket = buildLoginOutgoingPacket(client, bodyType = 2) { sequenceId -> writeSsoPacket(client, subAppId, commandName, sequenceId = sequenceId) { - writeOicqRequestPacket(client, EncryptMethodECDH7(client.ecdh), 0x0810) { + writeOicqRequestPacket(client, EncryptMethodECDH(client.ecdh), 0x0810) { writeShort(9) // subCommand writeShort(17) // count of TLVs, probably ignored by server? //writeShort(LoginType.PASSWORD.value.toShort()) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt index 93d59f082..89f582f46 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt @@ -19,13 +19,13 @@ import javax.crypto.KeyAgreement actual typealias ECDHPrivateKey = PrivateKey actual typealias ECDHPublicKey = PublicKey -actual class ECDHKeyPair( +internal actual class ECDHKeyPairImpl( private val delegate: KeyPair -) { - actual val privateKey: ECDHPrivateKey get() = delegate.private - actual val publicKey: ECDHPublicKey get() = delegate.public +) : ECDHKeyPair { + override val privateKey: ECDHPrivateKey get() = delegate.private + override val publicKey: ECDHPublicKey get() = delegate.public - actual val initialShareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey) + override val initialShareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey) } @Suppress("FunctionName") @@ -33,6 +33,10 @@ actual fun ECDH() = ECDH(ECDH.generateKeyPair()) actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { actual companion object { + @Suppress("ObjectPropertyName") + private var _isECDHAvailable: Boolean = false // because `runCatching` has no contract. + actual val isECDHAvailable: Boolean get() = _isECDHAvailable + init { kotlin.runCatching { @SuppressLint("PrivateApi") @@ -48,13 +52,19 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { Security.removeProvider(providerName) } Security.addProvider(clazz.newInstance() as Provider) + generateKeyPair() + _isECDHAvailable = true }.exceptionOrNull()?.let { throw IllegalStateException("cannot init BouncyCastle", it) } + _isECDHAvailable = false } actual fun generateKeyPair(): ECDHKeyPair { - return ECDHKeyPair(KeyPairGenerator.getInstance("ECDH").genKeyPair()) + if (!isECDHAvailable) { + return ECDHKeyPair.DefaultStub + } + return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH").genKeyPair()) } actual fun calculateShareKey( diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt index 2e93e0385..0b93f83b5 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/ECDH.kt @@ -19,7 +19,9 @@ expect interface ECDHPublicKey { fun getEncoded(): ByteArray } -expect class ECDHKeyPair { +internal expect class ECDHKeyPairImpl : ECDHKeyPair + +interface ECDHKeyPair { val privateKey: ECDHPrivateKey val publicKey: ECDHPublicKey @@ -27,6 +29,15 @@ expect class ECDHKeyPair { * 私匙和固定公匙([initialPublicKey]) 计算得到的 shareKey */ val initialShareKey: ByteArray + + object DefaultStub : ECDHKeyPair { + val defaultPublicKey = "020b03cf3d99541f29ffec281bebbd4ea211292ac1f53d7128".chunkedHexToBytes() + val defaultShareKey = "4da0f614fc9f29c2054c77048a6566d7".chunkedHexToBytes() + + override val privateKey: Nothing get() = error("stub!") + override val publicKey: Nothing get() = error("stub!") + override val initialShareKey: ByteArray get() = defaultShareKey + } } /** @@ -41,6 +52,8 @@ expect class ECDH(keyPair: ECDHKeyPair) { fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray companion object { + val isECDHAvailable: Boolean + /** * 由完整的 publicKey ByteArray 得到 [ECDHPublicKey] */ @@ -60,9 +73,6 @@ expect class ECDH(keyPair: ECDHKeyPair) { override fun toString(): String } -/** - * - */ @Suppress("FunctionName") expect fun ECDH(): ECDH diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt index f24f61c72..c261cb80e 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt @@ -9,11 +9,9 @@ package net.mamoe.mirai.utils.cryptor -import net.mamoe.mirai.utils.io.chunkedHexToBytes import net.mamoe.mirai.utils.md5 import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.* -import java.security.spec.ECGenParameterSpec import java.security.spec.X509EncodedKeySpec import javax.crypto.KeyAgreement @@ -21,20 +19,13 @@ import javax.crypto.KeyAgreement actual typealias ECDHPrivateKey = PrivateKey actual typealias ECDHPublicKey = PublicKey -actual class ECDHKeyPair( - private val delegate: KeyPair? -) { - actual val privateKey: ECDHPrivateKey get() = delegate?.private ?: error("ECDH is not available") - actual val publicKey: ECDHPublicKey get() = delegate?.public ?: defaultPublicKey +internal actual class ECDHKeyPairImpl( + private val delegate: KeyPair +) : ECDHKeyPair { + override val privateKey: ECDHPrivateKey get() = delegate.private + override val publicKey: ECDHPublicKey get() = delegate.public - actual val initialShareKey: ByteArray = if (delegate == null) { - defaultShareKey - } else ECDH.calculateShareKey(privateKey, initialPublicKey) - - companion object { - internal val defaultPublicKey = "020b03cf3d99541f29ffec281bebbd4ea211292ac1f53d7128".chunkedHexToBytes().adjustToPublicKey() - internal val defaultShareKey = "4da0f614fc9f29c2054c77048a6566d7".chunkedHexToBytes() - } + override val initialShareKey: ByteArray = ECDH.calculateShareKey(privateKey, initialPublicKey) } @Suppress("FunctionName") @@ -42,33 +33,35 @@ actual fun ECDH() = ECDH(ECDH.generateKeyPair()) actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { actual companion object { - private var isECDHAvailable = true + @Suppress("ObjectPropertyName") + private val _isECDHAvailable: Boolean + actual val isECDHAvailable: Boolean get() = _isECDHAvailable init { - isECDHAvailable = kotlin.runCatching { + _isECDHAvailable = kotlin.runCatching { + if (Security.getProvider("BouncyCastle") != null) { + Security.removeProvider("BouncyCastle") + } Security.addProvider(BouncyCastleProvider()) generateKeyPair() // try if it is working }.isSuccess } actual fun generateKeyPair(): ECDHKeyPair { - return if (!isECDHAvailable) { - ECDHKeyPair(null) - } else ECDHKeyPair(KeyPairGenerator.getInstance("EC", "BC").apply { initialize(ECGenParameterSpec("secp192k1")) }.genKeyPair()) + if (!isECDHAvailable) { + return ECDHKeyPair.DefaultStub + } + return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH").genKeyPair()) } actual fun calculateShareKey( privateKey: ECDHPrivateKey, publicKey: ECDHPublicKey ): ByteArray { - return if (!isECDHAvailable) { - ECDHKeyPair.defaultShareKey - } else { - val instance = KeyAgreement.getInstance("ECDH", "BC") - instance.init(privateKey) - instance.doPhase(publicKey, true) - md5(instance.generateSecret()) - } + val instance = KeyAgreement.getInstance("ECDH", "BC") + instance.init(privateKey) + instance.doPhase(publicKey, true) + return md5(instance.generateSecret()) } actual fun constructPublicKey(key: ByteArray): ECDHPublicKey { @@ -77,7 +70,6 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { } actual fun calculateShareKeyByPeerPublicKey(peerPublicKey: ECDHPublicKey): ByteArray { - if (!isECDHAvailable) return keyPair.initialShareKey return calculateShareKey(keyPair.privateKey, peerPublicKey) } From 8f94935e08a5d64c02ce83d6a6742956f24700be Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:16:22 +0800 Subject: [PATCH 034/111] Remove redundant log --- .../mirai/qqandroid/network/protocol/packet/EncryptMethod.kt | 2 -- 1 file changed, 2 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt index fe32747ff..7684a8a4c 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt @@ -14,7 +14,6 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.buildPacket import kotlinx.io.core.writeFully import net.mamoe.mirai.qqandroid.network.QQAndroidClient -import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.cryptor.ECDH import net.mamoe.mirai.utils.cryptor.ECDHKeyPair import net.mamoe.mirai.utils.io.encryptAndWrite @@ -111,7 +110,6 @@ internal interface EncryptMethodECDH : EncryptMethod { writeShortLVByteArray(ECDHKeyPair.DefaultStub.defaultPublicKey) encryptAndWrite(ECDHKeyPair.DefaultStub.defaultShareKey, body) } else { - MiraiLogger.info("Using custom") writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { // it.toUHexString().debugPrint("PUBLIC KEY") check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } From d1153e3c029306bb9216b063ada54fbc1b3d02da Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:16:51 +0800 Subject: [PATCH 035/111] Remove redundant log --- .../network/protocol/packet/EncryptMethod.kt | 28 ------------------- 1 file changed, 28 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt index 7684a8a4c..80d0d6141 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/EncryptMethod.kt @@ -19,9 +19,6 @@ import net.mamoe.mirai.utils.cryptor.ECDHKeyPair import net.mamoe.mirai.utils.io.encryptAndWrite import net.mamoe.mirai.utils.io.writeShortLVByteArray -/** - * Encryption method to be used for packet body. - */ @UseExperimental(ExperimentalUnsignedTypes::class) internal interface EncryptMethod { val id: Int @@ -34,16 +31,6 @@ internal interface EncryptMethodSessionKey : EncryptMethod { val currentLoginState: Int val sessionKey: ByteArray - /** - * buildPacket{ - * byte 1 - * byte if (currentLoginState == 2) 3 else 2 - * fully key - * short 258 - * short 0 - * fully encrypted - * } - */ override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = buildPacket { require(currentLoginState == 2 || currentLoginState == 3) { "currentLoginState must be either 2 or 3" } @@ -87,16 +74,6 @@ internal interface EncryptMethodECDH : EncryptMethod { val ecdh: ECDH - /** - * **Packet Structure** - * byte 1 - * byte 1 - * byte[] [ECDH.privateKey] - * short 258 - * short [ECDH.publicKey].size - * byte[] [ECDH.publicKey] - * byte[] encrypted `body()` by [ECDH.shareKey] - */ override fun makeBody(client: QQAndroidClient, body: BytePacketBuilder.() -> Unit): ByteReadPacket = buildPacket { writeByte(1) // const @@ -104,19 +81,14 @@ internal interface EncryptMethodECDH : EncryptMethod { writeFully(client.randomKey) writeShort(258) // const - // writeShortLVByteArray("04 CB 36 66 98 56 1E 93 6E 80 C1 57 E0 74 CA B1 3B 0B B6 8D DE B2 82 45 48 A1 B1 8D D4 FB 61 22 AF E1 2F E4 8C 52 66 D8 D7 26 9D 76 51 A8 EB 6F E7".hexToBytes()) - if (ecdh.keyPair === ECDHKeyPair.DefaultStub) { writeShortLVByteArray(ECDHKeyPair.DefaultStub.defaultPublicKey) encryptAndWrite(ECDHKeyPair.DefaultStub.defaultShareKey, body) } else { writeShortLVByteArray(ecdh.keyPair.publicKey.getEncoded().drop(23).take(49).toByteArray().also { - // it.toUHexString().debugPrint("PUBLIC KEY") check(it[0].toInt() == 0x04) { "Bad publicKey generated. Expected first element=0x04, got${it[0]}" } - //check(ecdh.calculateShareKeyByPeerPublicKey(it.adjustToPublicKey()).contentEquals(ecdh.keyPair.shareKey)) { "PublicKey Validation failed" } }) - // encryptAndWrite("26 33 BA EC 86 EB 79 E6 BC E0 20 06 5E A9 56 6C".hexToBytes(), body) encryptAndWrite(ecdh.keyPair.initialShareKey, body) } } From 171929d93816f5f5ba72868589f3427b4d3faa3f Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:21:30 +0800 Subject: [PATCH 036/111] Add warning log --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 83b5f69f0..358f88b30 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -127,7 +127,7 @@ internal class MessageSvc { val resp = readProtoBuf(MsgSvc.PbGetMsgResp.serializer()) if (resp.result != 0) { - // println("!!! Result=${resp.result} !!!: " + resp.contentToString()) + bot.network.logger.warning("MessageSvc.PushNotify: result != 0, result = ${resp.result}, errorMsg=${resp.errmsg}") return EmptyResponse } @@ -149,7 +149,7 @@ internal class MessageSvc { val group = bot.getGroupByUinOrNull(msg.msgHead.fromUin) if (msg.msgHead.authUin == bot.uin) { if (group != null) { - error("group is not null while bot is invited to the group") + return@mapNotNull null } // 新群 From 9aa79e69b001699704c4d75a1db7bc4535f014b0 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:22:55 +0800 Subject: [PATCH 037/111] Add doc --- .../network/protocol/packet/chat/receive/MessageSvc.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/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 358f88b30..f134451ab 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -106,7 +106,7 @@ internal class MessageSvc { open class GetMsgSuccess(delegate: List) : Response(MsgSvc.SyncFlag.STOP, delegate) /** - * 不要直接 expect 这个 class. 它可能 + * 不要直接 expect 这个 class. 它可能还没同步完成 */ @MiraiInternalAPI open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List) : MultiPacket(delegate), From 3e3a792c6c253bffb8e7aebda1e7a54e452a896f Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:24:23 +0800 Subject: [PATCH 038/111] Suppress warnings --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index f134451ab..b94dafdfd 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -159,6 +159,7 @@ internal class MessageSvc { }.groups.first { it.groupUin == msg.msgHead.fromUin } + @Suppress("DuplicatedCode") val newGroup = GroupImpl( bot = bot, coroutineContext = bot.coroutineContext, @@ -264,6 +265,7 @@ internal class MessageSvc { /** * 发送好友消息 */ + @Suppress("FunctionName") fun ToFriend( client: QQAndroidClient, toUin: Long, @@ -293,6 +295,7 @@ internal class MessageSvc { /** * 发送群消息 */ + @Suppress("FunctionName") fun ToGroup( client: QQAndroidClient, groupCode: Long, From e878307c132cb925544e3e3c6799386cb351e56e Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:43:31 +0800 Subject: [PATCH 039/111] Fix event broadcasting --- .../kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 5 ----- mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 6 ------ .../commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt | 5 ----- .../kotlin/net.mamoe.mirai/message/FriendMessage.kt | 1 - 4 files changed, 17 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index 6670eed35..5c6c89699 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -20,7 +20,6 @@ import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.data.FriendInfo import net.mamoe.mirai.data.GroupInfo import net.mamoe.mirai.data.MemberInfo -import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.qqandroid.network.QQAndroidClient @@ -116,10 +115,6 @@ internal abstract class QQAndroidBotBase constructor( return sequence } - override fun onEvent(event: BotEvent): Boolean { - return firstLoginSucceed - } - override suspend fun addFriend(id: Long, message: String?, remark: String?): AddFriendResult { TODO("not implemented") } 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 e1d603d87..edf384811 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -14,7 +14,6 @@ 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 @@ -73,11 +72,6 @@ abstract class BotImpl constructor( } } - /** - * 可阻止事件广播 - */ - abstract fun onEvent(event: BotEvent): Boolean - // region network final override val network: N get() = _network diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt index 3aff7e809..0a9d19223 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt @@ -11,8 +11,6 @@ package net.mamoe.mirai.event -import net.mamoe.mirai.BotImpl -import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.internal.broadcastInternal import net.mamoe.mirai.utils.MiraiInternalAPI @@ -73,9 +71,6 @@ suspend fun E.broadcast(): E = apply { if (this is BroadcastControllable && !this.shouldBroadcast) { return@apply } - if (this is BotEvent && !(this.bot as BotImpl<*>).onEvent(this)) { - return@apply - } this@broadcast.broadcastInternal() // inline, no extra cost } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt index 14c42998e..8ead2fe6a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/FriendMessage.kt @@ -13,7 +13,6 @@ import net.mamoe.mirai.Bot import net.mamoe.mirai.contact.QQ import net.mamoe.mirai.event.BroadcastControllable import net.mamoe.mirai.message.data.MessageChain -import net.mamoe.mirai.utils.MiraiInternalAPI class FriendMessage( bot: Bot, From 89c614d0a1030fdaed9801086bd20cfd619d5faf Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 14:44:03 +0800 Subject: [PATCH 040/111] Fix ECDH curve --- .../mamoe/mirai/utils/cryptor/ECDHAndroid.kt | 6 ++++- .../net/mamoe/mirai/utils/cryptor/ECDHJvm.kt | 24 +++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt index 89f582f46..5fe233778 100644 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt +++ b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHAndroid.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.utils.cryptor import android.annotation.SuppressLint import net.mamoe.mirai.utils.md5 import java.security.* +import java.security.spec.ECGenParameterSpec import java.security.spec.X509EncodedKeySpec import javax.crypto.KeyAgreement @@ -60,11 +61,14 @@ actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { _isECDHAvailable = false } + actual fun generateKeyPair(): ECDHKeyPair { if (!isECDHAvailable) { return ECDHKeyPair.DefaultStub } - return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH").genKeyPair()) + return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH") + .also { it.initialize(ECGenParameterSpec("secp192k1")) } + .genKeyPair()) } actual fun calculateShareKey( diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt index c261cb80e..a0e236b71 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/utils/cryptor/ECDHJvm.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.utils.cryptor import net.mamoe.mirai.utils.md5 import org.bouncycastle.jce.provider.BouncyCastleProvider import java.security.* +import java.security.spec.ECGenParameterSpec import java.security.spec.X509EncodedKeySpec import javax.crypto.KeyAgreement @@ -34,24 +35,23 @@ actual fun ECDH() = ECDH(ECDH.generateKeyPair()) actual class ECDH actual constructor(actual val keyPair: ECDHKeyPair) { actual companion object { @Suppress("ObjectPropertyName") - private val _isECDHAvailable: Boolean - actual val isECDHAvailable: Boolean get() = _isECDHAvailable + private val _isECDHAvailable: Boolean = kotlin.runCatching { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) != null) { + Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME) + } + Security.addProvider(BouncyCastleProvider()) + generateKeyPair() // try if it is working + }.isSuccess - init { - _isECDHAvailable = kotlin.runCatching { - if (Security.getProvider("BouncyCastle") != null) { - Security.removeProvider("BouncyCastle") - } - Security.addProvider(BouncyCastleProvider()) - generateKeyPair() // try if it is working - }.isSuccess - } + actual val isECDHAvailable: Boolean get() = _isECDHAvailable actual fun generateKeyPair(): ECDHKeyPair { if (!isECDHAvailable) { return ECDHKeyPair.DefaultStub } - return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH").genKeyPair()) + return ECDHKeyPairImpl(KeyPairGenerator.getInstance("ECDH") + .also { it.initialize(ECGenParameterSpec("secp192k1")) } + .genKeyPair()) } actual fun calculateShareKey( From 10e70ac3703e5eaa1d3a28448bbaf30e7c09fb18 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 15:42:46 +0800 Subject: [PATCH 041/111] correct http api readme.md --- mirai-api-http/README_CH.md | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 895d1b2e3..88c7fa665 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -16,6 +16,8 @@ fun main() { } ``` + + ## 认证相关 ### 开始会话-认证(Authorize) @@ -141,6 +143,8 @@ fun main() { > SessionKey与Bot 对应错误时将会返回状态码5:指定对象不存在 + + ## 消息相关 @@ -261,10 +265,10 @@ fun main() { ### 发送图片消息(通过URL) ``` -[POST] /sendGroupMessage +[POST] /sendImageMessage ``` -使用此方法向指定群发送消息 +使用此方法向指定对象(群或好友)发送图片消息 #### 请求 @@ -303,7 +307,7 @@ fun main() { ### 图片文件上传 ``` -[POST] /sendGroupMessage +[POST] /uploadImage ``` 使用此方法上传图片文件至服务器并返回ImageId @@ -385,7 +389,7 @@ Content-Type:multipart/form-data + [x] At,@消息 + [x] AtAll,@全体成员 -+ [x] Face,表情消息 ++ [ ] Face,表情消息 + [x] Plain,文字消息 + [x] Image,图片消息 + [ ] Xml,Xml卡片消息 @@ -409,15 +413,13 @@ Content-Type:multipart/form-data ```json5 { "type": "At", - "target": 123456, - "display": "@Mirai" + "target": 123456 } ``` -| 名字 | 类型 | 说明 | -| ------- | ------ | ------------------------- | -| target | Long | 群员QQ号 | -| display | String | @时显示的文本如:"@Mirai" | +| 名字 | 类型 | 说明 | +| ------ | ---- | -------- | +| target | Long | 群员QQ号 | #### AtAll @@ -517,6 +519,7 @@ Content-Type:multipart/form-data ``` + ### 获取群列表 使用此方法获取bot的群列表 @@ -786,6 +789,8 @@ Content-Type:multipart/form-data } ``` + + ### 获取群设置 使用此方法获取群设置 @@ -816,6 +821,7 @@ Content-Type:multipart/form-data ``` + ### 修改群员资料 使用此方法修改群员资料(需要有相关限权) @@ -856,6 +862,8 @@ Content-Type:multipart/form-data } ``` + + ### 获取群员资料 使用此方法获取群员资料 From 59c0af75f13553ffada86b7fd986037b491ab7d9 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 16:19:36 +0800 Subject: [PATCH 042/111] http api default at display --- mirai-api-http/README_CH.md | 10 ++++++---- .../mamoe/mirai/api/http/data/common/MessageDTO.kt | 13 ++++++++----- .../mirai/api/http/route/SendMessageRouteModule.kt | 13 +++++++++---- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index 88c7fa665..edd44d09e 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -413,13 +413,15 @@ Content-Type:multipart/form-data ```json5 { "type": "At", - "target": 123456 + "target": 123456, + "display": "@Mirai" } ``` -| 名字 | 类型 | 说明 | -| ------ | ---- | -------- | -| target | Long | 群员QQ号 | +| 名字 | 类型 | 说明 | +| ------- | ------ | ---------------------------------------------- | +| target | Long | 群员QQ号 | +| dispaly | String | At时显示的文字,发送消息时无效,自动使用群名片 | #### AtAll 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 f50f00e11..f46fc2567 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 @@ -11,6 +11,9 @@ package net.mamoe.mirai.api.http.data.common import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable +import net.mamoe.mirai.contact.Contact +import net.mamoe.mirai.contact.Group +import net.mamoe.mirai.contact.Member import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket @@ -40,7 +43,7 @@ data class UnKnownMessagePacketDTO(val msg: String) : MessagePacketDTO() data class MessageSourceDTO(val uid: Long) : MessageDTO() @Serializable @SerialName("At") -data class AtDTO(val target: Long, val display: String) : MessageDTO() +data class AtDTO(val target: Long, val display: String = "") : MessageDTO() @Serializable @SerialName("AtAll") data class AtAllDTO(val target: Long = 0) : MessageDTO() // target为保留字段 @@ -83,8 +86,8 @@ suspend fun MessagePacket<*, *>.toDTO(): MessagePacketDTO = when (this) { else -> UnKnownMessagePacketDTO("UnKnown Message Packet") }.apply { messageChain = Array(message.size){ message[it].toDTO() }} -fun MessageChainDTO.toMessageChain() = - MessageChain().apply { this@toMessageChain.forEach { add(it.toMessage()) } } +fun MessageChainDTO.toMessageChain(contact: Contact) = + MessageChain().apply { this@toMessageChain.forEach { add(it.toMessage(contact)) } } @UseExperimental(ExperimentalUnsignedTypes::class) fun Message.toDTO() = when (this) { @@ -99,8 +102,8 @@ fun Message.toDTO() = when (this) { } @UseExperimental(ExperimentalUnsignedTypes::class, MiraiInternalAPI::class) -fun MessageDTO.toMessage() = when (this) { - is AtDTO -> At(target, display) +fun MessageDTO.toMessage(contact: Contact) = when (this) { + is AtDTO -> At((contact as Group)[target]) is AtAllDTO -> AtAll is FaceDTO -> Face(FaceId(faceId.toUByte())) is PlainDTO -> PlainText(text) 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 aa2beb5b8..b6d34549e 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 @@ -43,18 +43,23 @@ fun Application.messageModule() { } miraiVerify("/sendFriendMessage") { - it.session.bot.getFriend(it.target).sendMessage(it.messageChain.toMessageChain()) + it.session.bot.getFriend(it.target).apply { + sendMessage(it.messageChain.toMessageChain(this)) // this aka QQ + } call.respondStateCode(StateCode.Success) } miraiVerify("/sendGroupMessage") { - it.session.bot.getGroup(it.target).sendMessage(it.messageChain.toMessageChain()) + it.session.bot.getGroup(it.target).apply { + sendMessage(it.messageChain.toMessageChain(this)) // this aka Group + } call.respondStateCode(StateCode.Success) } miraiVerify("/quoteMessage") { - it.session.messageQueue.quoteCache[it.target]?.quoteReply(it.messageChain.toMessageChain()) - ?: throw NoSuchElementException() + it.session.messageQueue.quoteCache[it.target]?.apply { + quoteReply(it.messageChain.toMessageChain(group)) + } ?: throw NoSuchElementException() call.respondStateCode(StateCode.Success) } From 9dc50ccfb8185b57e794c75b8423565191dd8814 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 17:54:53 +0800 Subject: [PATCH 043/111] graphical console decorator --- .../mirai/console/graphical/MiraiGraphical.kt | 11 +++------- .../graphical/styleSheet/PrimaryStyleSheet.kt | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/PrimaryStyleSheet.kt diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt index b543a06ee..1a45580fa 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/MiraiGraphical.kt @@ -1,15 +1,10 @@ package net.mamoe.mirai.console.graphical -import com.jfoenix.controls.JFXDecorator -import javafx.scene.control.Button -import javafx.stage.Stage import net.mamoe.mirai.console.MiraiConsole import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController +import net.mamoe.mirai.console.graphical.styleSheet.PrimaryStyleSheet import net.mamoe.mirai.console.graphical.view.Decorator -import net.mamoe.mirai.console.graphical.view.PrimaryView import tornadofx.App -import tornadofx.FX.Companion.primaryStage -import tornadofx.UIComponent import tornadofx.find import tornadofx.launch @@ -17,7 +12,7 @@ fun main(args: Array) { launch(args) } -class MiraiGraphicalUI: App(Decorator::class) { +class MiraiGraphicalUI : App(Decorator::class, PrimaryStyleSheet::class) { override fun init() { super.init() @@ -29,4 +24,4 @@ class MiraiGraphicalUI: App(Decorator::class) { super.stop() MiraiConsole.stop() } -} \ No newline at end of file +} diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/PrimaryStyleSheet.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/PrimaryStyleSheet.kt new file mode 100644 index 000000000..8f47b7a39 --- /dev/null +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/PrimaryStyleSheet.kt @@ -0,0 +1,21 @@ +package net.mamoe.mirai.console.graphical.styleSheet + +import tornadofx.* + +class PrimaryStyleSheet : Stylesheet() { + companion object { + val jfxTitle by cssclass("jfx-decorator-buttons-container") + val container by cssclass("jfx-decorator-content-container") + } + + init { + jfxTitle { + backgroundColor += c("00BCD4") + } + + container { + borderColor += box(c("00BCD4")) + borderWidth += box(0.px, 4.px, 4.px, 4.px) + } + } +} \ No newline at end of file From f96109c7c52c91b4496b07346f78fad0fb394fb8 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 18:02:13 +0800 Subject: [PATCH 044/111] Fix #71 --- .../net/mamoe/mirai/api/http/route/AuthRouteModule.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt index 40caf465d..45adcf2b3 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/route/AuthRouteModule.kt @@ -18,6 +18,7 @@ import net.mamoe.mirai.api.http.AuthedSession import net.mamoe.mirai.api.http.SessionManager import net.mamoe.mirai.api.http.data.NoSuchBotException import net.mamoe.mirai.api.http.data.StateCode +import net.mamoe.mirai.api.http.data.common.DTO import net.mamoe.mirai.api.http.data.common.VerifyDTO import kotlin.coroutines.EmptyCoroutineContext @@ -28,7 +29,7 @@ fun Application.authModule() { if (it.authKey != SessionManager.authKey) { call.respondStateCode(StateCode(1, "Auth Key错误")) } else { - call.respondStateCode(StateCode(0, SessionManager.createTempSession().key)) + call.respondDTO(AuthRetDTO(0, SessionManager.createTempSession().key)) } } @@ -55,6 +56,9 @@ fun Application.authModule() { } } +@Serializable +private data class AuthRetDTO(val code: Int, val session: String) : DTO + @Serializable private data class BindDTO(override val sessionKey: String, val qq: Long) : VerifyDTO() From bcaafbbe766218c2c9bb818f070d9f53697b331f Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:02:27 +0800 Subject: [PATCH 045/111] Fix inappropriate Event extend --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index b94dafdfd..6fdfa39a3 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -16,7 +16,6 @@ import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.Packet -import net.mamoe.mirai.event.BroadcastControllable import net.mamoe.mirai.event.events.BotJoinGroupEvent import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.MemberJoinEvent @@ -109,11 +108,7 @@ internal class MessageSvc { * 不要直接 expect 这个 class. 它可能还没同步完成 */ @MiraiInternalAPI - open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List) : MultiPacket(delegate), - BroadcastControllable { - override val shouldBroadcast: Boolean - get() = syncFlagFromServer == MsgSvc.SyncFlag.STOP - + open class Response(internal val syncFlagFromServer: MsgSvc.SyncFlag, delegate: List) : MultiPacket(delegate) { override fun toString(): String { return "MessageSvc.PbGetMsg.Response($syncFlagFromServer=$syncFlagFromServer, messages=List(size=${this.size}))" } From 32abb018618ef066aab6b9b9881f6d3cbc4a7d41 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:03:37 +0800 Subject: [PATCH 046/111] Fix tryNTimes --- .../commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt index 57f418797..c6b6884d0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/tryNTimes.kt @@ -24,8 +24,7 @@ inline fun tryNTimes(repeat: Int, block: (Int) -> R): R { } catch (e: Throwable) { if (lastException == null) { lastException = e - } - lastException!!.addSuppressed(e) + } else lastException!!.addSuppressed(e) } } @@ -43,8 +42,7 @@ inline fun tryNTimesOrNull(repeat: Int, block: (Int) -> R): R? { } catch (e: Throwable) { if (lastException == null) { lastException = e - } - lastException!!.addSuppressed(e) + } else lastException!!.addSuppressed(e) } } @@ -63,8 +61,7 @@ inline fun tryNTimesOrException(repeat: Int, block: (Int) -> R): Throwable? } catch (e: Throwable) { if (lastException == null) { lastException = e - } - lastException!!.addSuppressed(e) + } else lastException!!.addSuppressed(e) } } From 2deb1601a8c203885bef1666721ce9e8ad3bf7ca Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:28:58 +0800 Subject: [PATCH 047/111] No broadcast for events from friend message syncing --- .../network/QQAndroidBotNetworkHandler.kt | 17 ++++++++++++----- .../kotlin/net.mamoe.mirai/event/Subscribers.kt | 13 ++++++++++--- 2 files changed, 22 insertions(+), 8 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 23d4d8983..848622d27 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,10 +20,7 @@ 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.BroadcastControllable -import net.mamoe.mirai.event.CancellableEvent -import net.mamoe.mirai.event.Event -import net.mamoe.mirai.event.broadcast +import net.mamoe.mirai.event.* import net.mamoe.mirai.event.events.BotOfflineEvent import net.mamoe.mirai.event.events.BotOnlineEvent import net.mamoe.mirai.network.BotNetworkHandler @@ -296,7 +293,17 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler heartbeatJob = startHeartbeatJobOrKill() joinAll(friendListJob, groupJob) - MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendAndExpect() + + withTimeoutOrNull(5000) { + lateinit var listener: Listener + listener = this.subscribeAlways { + if (it.packet is MessageSvc.PbGetMsg.GetMsgSuccess) { + listener.complete() + } + } + + MessageSvc.PbGetMsg(bot.client, MsgSvc.SyncFlag.START, currentTimeSeconds).sendWithoutExpect() + } ?: error("timeout syncing friend message history") bot.firstLoginSucceed = true 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 fd6887e85..f3a2ae6a9 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 @@ -17,6 +17,9 @@ 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.contracts.ExperimentalContracts +import kotlin.contracts.InvocationKind +import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext /* @@ -109,9 +112,13 @@ inline fun CoroutineScope.subscribe(crossinline handler: sus * * @see subscribe 获取更多说明 */ -@UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener = - E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.LISTENING }) +@UseExperimental(MiraiInternalAPI::class, ExperimentalContracts::class) +inline fun CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener { + contract { + callsInPlace(listener, InvocationKind.UNKNOWN) + } + return E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.LISTENING }) +} /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. From f0fbebebc628d990a45fe7640f0337328a7ad275 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:29:14 +0800 Subject: [PATCH 048/111] Add `toString` --- .../network/protocol/packet/chat/receive/MessageSvc.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 6fdfa39a3..236581cc5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -102,7 +102,11 @@ internal class MessageSvc { } @UseExperimental(MiraiInternalAPI::class) - open class GetMsgSuccess(delegate: List) : Response(MsgSvc.SyncFlag.STOP, delegate) + open class GetMsgSuccess(delegate: List) : Response(MsgSvc.SyncFlag.STOP, delegate) { + override fun toString(): String { + return "MessageSvc.PbGetMsg.GetMsgSuccess(messages=List(size=${this.size}))" + } + } /** * 不要直接 expect 这个 class. 它可能还没同步完成 From 9a436271dbbb9a6257982c0568c3d00e0ac82632 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:33:11 +0800 Subject: [PATCH 049/111] Fix uninitialized vars --- .../kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt | 11 +++++++++-- .../kotlin/net/mamoe/mirai/utils/io/PlatformSocket.kt | 5 ++++- 2 files changed, 13 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 f20543980..f6c1d2513 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 @@ -30,9 +30,16 @@ actual class PlatformSocket : Closeable { private lateinit var socket: Socket actual val isOpen: Boolean - get() = socket.isConnected + get() = + if (::socket.isInitialized) + socket.isConnected + else false - actual override fun close() = socket.close() + actual override fun close() { + if (::socket.isInitialized) { + socket.close() + } + } @PublishedApi internal lateinit var writeChannel: BufferedOutputStream 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 07f22e1e3..f6c1d2513 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 @@ -30,7 +30,10 @@ actual class PlatformSocket : Closeable { private lateinit var socket: Socket actual val isOpen: Boolean - get() = socket.isConnected + get() = + if (::socket.isInitialized) + socket.isConnected + else false actual override fun close() { if (::socket.isInitialized) { From d8290600723c6322fa41f0094a35acb400f60596 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:33:20 +0800 Subject: [PATCH 050/111] Change default config values --- .../kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt | 4 ++-- .../kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt | 4 ++-- 2 files changed, 4 insertions(+), 4 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 e781c9697..061551147 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 @@ -68,11 +68,11 @@ actual open class BotConfiguration actual constructor() { /** * 重连失败后, 继续尝试的每次等待时间 */ - actual var reconnectPeriodMillis: Long = 60.secondsToMillis + actual var reconnectPeriodMillis: Long = 5.secondsToMillis /** * 最多尝试多少次重连 */ - actual var reconnectionRetryTimes: Int = 3 + actual var reconnectionRetryTimes: Int = 10 /** * 验证码处理器 */ 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 241034f30..280d27a99 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 @@ -221,11 +221,11 @@ actual open class BotConfiguration actual constructor() { /** * 重连失败后, 继续尝试的每次等待时间 */ - actual var reconnectPeriodMillis: Long = 60.secondsToMillis + actual var reconnectPeriodMillis: Long = 5.secondsToMillis /** * 最多尝试多少次重连 */ - actual var reconnectionRetryTimes: Int = 3 + actual var reconnectionRetryTimes: Int = 10 /** * 验证码处理器 */ From c3bd03fcae6194d167730c47d33bfb776b0a73b3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 18:36:04 +0800 Subject: [PATCH 051/111] Improve logs --- .../src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) 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 edf384811..66ffdd235 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -86,7 +86,7 @@ abstract class BotImpl constructor( if (!_network.isActive) { return@subscribeAlways } - bot.logger.info("Connection dropped or lost by server, retrying login") + bot.logger.info("Connection dropped by server or lost, retrying login") tryNTimesOrException(configuration.reconnectionRetryTimes) { tryCount -> if (tryCount != 0) { @@ -95,7 +95,10 @@ abstract class BotImpl constructor( network.relogin() logger.info("Reconnected successfully") return@subscribeAlways - }?.let { throw it } + }?.let { + logger.info("Cannot reconnect") + throw it + } } is BotOfflineEvent.Active -> { val msg = if (event.cause == null) { From 2322387f737307b28a1d19f6a23ae2adac18f49a Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 19:10:14 +0800 Subject: [PATCH 052/111] Add `bot.subscribe`, close #61 --- .../net.mamoe.mirai/event/Subscribable.kt | 2 +- .../net.mamoe.mirai/event/Subscribers.kt | 140 ++++++++---------- 2 files changed, 63 insertions(+), 79 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt index 0a9d19223..241656fdc 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/event/Subscribable.kt @@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.MiraiInternalAPI * 若监听这个类, 监听器将会接收所有事件的广播. * * @see subscribeAlways - * @see subscribeWhile + * @see subscribeOnce * * @see subscribeMessages * 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 f3a2ae6a9..a71882ab6 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 @@ -14,6 +14,7 @@ import kotlinx.coroutines.CoroutineExceptionHandler import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.GlobalScope import net.mamoe.mirai.Bot +import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.event.internal.Handler import net.mamoe.mirai.event.internal.subscribeInternal import net.mamoe.mirai.utils.MiraiInternalAPI @@ -21,6 +22,7 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext +import kotlin.jvm.JvmName /* * 该文件为所有的订阅事件的方法. @@ -71,15 +73,16 @@ interface Listener : CompletableJob { * `runBlocking` 不会结束, 也就是下一行 `foo()` 不会被执行. 直到监听时创建的 `Listener` 被停止. * * - * 要创建一个全局都存在的监听, 即守护协程, 请在 [GlobalScope] 下调用本函数: + * 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]). + * 这种方式创建的监听会自动筛选 [Bot]. * ```kotlin - * GlobalScope.subscribe { /* 一些处理 */ } + * bot1.subscribe { /* 只会处理来自 bot1 的事件 */ } * ``` * * - * 要创建一个仅在某个机器人在线时的监听, 请在 [Bot] 下调用本函数 (因为 [Bot] 也实现 [CoroutineScope]): + * 要创建一个全局都存在的监听, 即守护协程, 请在 [GlobalScope] 下调用本函数: * ```kotlin - * bot.subscribe { /* 一些处理 */ } + * GlobalScope.subscribe { /* 会收到来自全部 Bot 的事件和与 Bot 不相关的事件 */ } * ``` * * @@ -89,31 +92,34 @@ interface Listener : CompletableJob { * 若 [this] 没有 [CoroutineExceptionHandler], 则在事件广播方的 [CoroutineExceptionHandler] 处理 * 若均找不到, 则会触发 logger warning. * - 事件处理时抛出异常不会停止监听器. - * - 建议在事件处理中, 即 [handler] 里处理异常, 或在 [this] 指定 [CoroutineExceptionHandler]. + * - 建议在事件处理中 (即 [handler] 里) 处理异常, + * 或在 [this] 的 [CoroutineScope.coroutineContext] 中添加 [CoroutineExceptionHandler]. * * - * **注意:** 事件处理是 `suspend` 的, 请严格控制 JVM 阻塞方法的使用. 若致事件处理阻塞, 则会导致一些逻辑无法进行. + * **注意:** 事件处理是 `suspend` 的, 请规范处理 JVM 阻塞方法. * - * // TODO: 2020/2/13 在 bot 下监听时同时筛选对应 bot 实例 + * @see subscribeAlways 一直监听 + * @see subscribeOnce 只监听一次 * - * @see subscribeMessages 监听消息 DSL - * @see subscribeGroupMessages 监听群消息 DSL + * @see subscribeMessages 监听消息 DSL + * @see subscribeGroupMessages 监听群消息 DSL * @see subscribeFriendMessages 监听好友消息 DSL */ @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribe(crossinline handler: suspend E.(E) -> ListeningStatus): Listener = +inline fun CoroutineScope.subscribe(noinline handler: suspend E.(E) -> ListeningStatus): Listener = E::class.subscribeInternal(Handler { it.handler(it); }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行. * - * 仅当 [Listener.complete] 或 [Listener.cancel] 时结束. + * 可在任意时候通过 [Listener.complete] 来主动停止监听. + * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * * @see subscribe 获取更多说明 */ @UseExperimental(MiraiInternalAPI::class, ExperimentalContracts::class) -inline fun CoroutineScope.subscribeAlways(crossinline listener: suspend E.(E) -> Unit): Listener { +inline fun CoroutineScope.subscribeAlways(noinline listener: suspend E.(E) -> Unit): Listener { contract { callsInPlace(listener, InvocationKind.UNKNOWN) } @@ -124,91 +130,69 @@ inline fun CoroutineScope.subscribeAlways(crossinline listen * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. * 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行. * - * 在这之前, 可通过 [Listener.complete] 来停止监听. + * 可在任意时候通过 [Listener.complete] 来主动停止监听. + * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * * @see subscribe 获取更多说明 */ @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribeOnce(crossinline listener: suspend E.(E) -> Unit): Listener = +inline fun CoroutineScope.subscribeOnce(noinline listener: suspend E.(E) -> Unit): Listener = E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.STOPPED }) + +// +// 以下为带筛选 Bot 的监听 +// + + /** - * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行, 直到 [listener] 的返回值 [equals] 于 [valueIfStop] + * 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. + * 每当 [事件广播][Event.broadcast] 时, [handler] 都会被执行, + * 当 [handler] 返回 [ListeningStatus.STOPPED] 时停止监听 * - * 可在任意时刻通过 [Listener.complete] 来停止监听. + * 可在任意时候通过 [Listener.complete] 来主动停止监听. + * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * * @see subscribe 获取更多说明 */ +@JvmName("subscribeAlwaysForBot") @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribeUntil(valueIfStop: T, crossinline listener: suspend E.(E) -> T): Listener = - E::class.subscribeInternal(Handler { if (it.listener(it) == valueIfStop) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) +inline fun Bot.subscribe(noinline handler: suspend E.(E) -> ListeningStatus): Listener = + E::class.subscribeInternal(Handler { if (it.bot === this) it.handler(it) else ListeningStatus.LISTENING }) + /** - * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. - * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行, - * 如果 [listener] 的返回值 [equals] 于 [valueIfContinue], 则继续监听, 否则停止 + * 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. + * 每当 [事件广播][Event.broadcast] 时, [listener] 都会被执行. * - * 可在任意时刻通过 [Listener.complete] 来停止监听. + * 可在任意时候通过 [Listener.complete] 来主动停止监听. + * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * * @see subscribe 获取更多说明 */ +@JvmName("subscribeAlwaysForBot") @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribeWhile(valueIfContinue: T, crossinline listener: suspend E.(E) -> T): Listener = - E::class.subscribeInternal(Handler { if (it.listener(it) != valueIfContinue) ListeningStatus.STOPPED else ListeningStatus.LISTENING }) - -// endregion - -// region ListenerBuilder DSL - -/* -/** - * 监听构建器. 可同时进行多种方式的监听 - * - * ```kotlin - * FriendMessageEvent.subscribe { - * always{ - * it.reply("永远发生") - * } - * - * untilFalse { - * it.reply("你发送了 ${it.event}") - * it.event eq "停止" - * } - * } - * ``` - */ -@ListenersBuilderDsl -@Suppress("MemberVisibilityCanBePrivate", "unused") -inline class ListenerBuilder( - @PublishedApi internal inline val handlerConsumer: CoroutineCoroutineScope.(Listener) -> Unit -) { - fun CoroutineCoroutineScope.handler(listener: suspend E.(E) -> ListeningStatus) { - handlerConsumer(Handler { it.listener(it) }) - } - - fun CoroutineCoroutineScope.always(listener: suspend E.(E) -> Unit) = handler { listener(it); ListeningStatus.LISTENING } - - fun CoroutineCoroutineScope.until(until: T, listener: suspend E.(E) -> T) = - handler { if (listener(it) == until) ListeningStatus.STOPPED else ListeningStatus.LISTENING } - - fun CoroutineCoroutineScope.untilFalse(listener: suspend E.(E) -> Boolean) = until(false, listener) - fun CoroutineCoroutineScope.untilTrue(listener: suspend E.(E) -> Boolean) = until(true, listener) - fun CoroutineCoroutineScope.untilNull(listener: suspend E.(E) -> Any?) = until(null, listener) - - - fun CoroutineCoroutineScope.`while`(until: T, listener: suspend E.(E) -> T) = - handler { if (listener(it) !== until) ListeningStatus.STOPPED else ListeningStatus.LISTENING } - - fun CoroutineCoroutineScope.whileFalse(listener: suspend E.(E) -> Boolean) = `while`(false, listener) - fun CoroutineCoroutineScope.whileTrue(listener: suspend E.(E) -> Boolean) = `while`(true, listener) - fun CoroutineCoroutineScope.whileNull(listener: suspend E.(E) -> Any?) = `while`(null, listener) - - - fun CoroutineCoroutineScope.once(listener: suspend E.(E) -> Unit) = handler { listener(it); ListeningStatus.STOPPED } +inline fun Bot.subscribeAlways(noinline listener: suspend E.(E) -> Unit): Listener { + return E::class.subscribeInternal(Handler { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING }) } -@DslMarker -annotation class ListenersBuilderDsl -*/ +/** + * 在 [Bot] 的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. + * 仅在第一次 [事件广播][Event.broadcast] 时, [listener] 会被执行. + * + * 可在任意时候通过 [Listener.complete] 来主动停止监听. + * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. + * + * @see subscribe 获取更多说明 + */ +@JvmName("subscribeOnceForBot") +@UseExperimental(MiraiInternalAPI::class) +inline fun Bot.subscribeOnce(noinline listener: suspend E.(E) -> Unit): Listener = + E::class.subscribeInternal(Handler { + if (it.bot === this) { + it.listener(it) + ListeningStatus.STOPPED + } else ListeningStatus.LISTENING + }) + // endregion \ No newline at end of file From de153399297863e33efef5e4bdb90f9124bfd558 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 19:11:46 +0800 Subject: [PATCH 053/111] Fix platform declaration clash --- .../commonMain/kotlin/net.mamoe.mirai/event/Subscribers.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 a71882ab6..c42584f55 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 @@ -170,7 +170,7 @@ inline fun Bot.subscribe(noinline handler: suspend E.(E) * * @see subscribe 获取更多说明 */ -@JvmName("subscribeAlwaysForBot") +@JvmName("subscribeAlwaysForBot1") @UseExperimental(MiraiInternalAPI::class) inline fun Bot.subscribeAlways(noinline listener: suspend E.(E) -> Unit): Listener { return E::class.subscribeInternal(Handler { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING }) @@ -185,7 +185,7 @@ inline fun Bot.subscribeAlways(noinline listener: suspend * * @see subscribe 获取更多说明 */ -@JvmName("subscribeOnceForBot") +@JvmName("subscribeOnceForBot2") @UseExperimental(MiraiInternalAPI::class) inline fun Bot.subscribeOnce(noinline listener: suspend E.(E) -> Unit): Listener = E::class.subscribeInternal(Handler { From d108de672cd917696401c69687571982d101c301 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 19:19:48 +0800 Subject: [PATCH 054/111] 0.16.0 --- CHANGELOG.md | 11 +++++++++++ gradle.properties | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3de31fee8..dca1cb5f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,17 @@ 开发版本. 频繁更新, 不保证高稳定性 +## `0.16.0` 2020/2/19 + +### mirai-core +- 添加 `Bot.subscribe` 等筛选 Bot 实例的监听方法 +- 其他一些小问题修复 + +### mirai-core-qqandroid +- 优化重连处理逻辑 +- 确保好友消息和历史事件在初始化结束前同步完成 +- 同步好友消息记录时不广播 + ## `0.15.5` 2020/2/19 ### mirai-core diff --git a/gradle.properties b/gradle.properties index 81732c549..b80f2d1a0 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.15.5 +mirai_version=0.16.0 mirai_japt_version=1.0.1 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true From abe5db2023c0b3cb46f87972c37f32cdf4d0702a Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 19:56:00 +0800 Subject: [PATCH 055/111] Add `MessageChain.foreachContent(lambda)` and `Message.hasContent()` --- .../message/data/MessageChain.kt | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) 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 e9412ab1f..af0781be1 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 @@ -38,6 +38,7 @@ import kotlin.reflect.KProperty interface MessageChain : Message, MutableList { // region Message override override operator fun contains(sub: String): Boolean + override fun followedBy(tail: Message): MessageChain // endregion @@ -67,6 +68,36 @@ interface MessageChain : Message, MutableList { } } +/** + * 遍历每一个有内容的消息, 即 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage] + */ +inline fun MessageChain.foreachContent(block: (Message) -> Unit) { + this.forEachIndexed { index: Int, message: Message -> + if (message is At) { + if (index == 0 || this[index - 1] !is QuoteReply) { + block(message) + } + } else if (message.hasContent()) { + block(message) + } + } +} + +/** + * 判断这个 [Message] 是否含有内容, 即是否为 [At], [AtAll], [PlainText], [Image], [Face], [XMLMessage] + */ +fun Message.hasContent(): Boolean { + return when (this) { + is At, + is AtAll, + is PlainText, + is Image, + is Face, + is XMLMessage -> true + else -> false + } +} + /** * 提供一个类型的值. 若不存在则会抛出异常 [NoSuchElementException] */ From c32843fbf369cc805365ed5ee01d74123fa22fc2 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 20:13:57 +0800 Subject: [PATCH 056/111] Add Short.toByteArray() --- .../kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt index 75a93a88e..5e5f6973e 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt @@ -21,6 +21,16 @@ import kotlin.random.nextInt * 这些函数为内部函数, 可能会改变 */ +/** + * 255 -> 00 FF + */ +fun Short.toByteArray(): ByteArray = with(toInt()) { + byteArrayOf( + (shr(8) and 0xFF).toByte(), + (shr(0) and 0xFF).toByte() + ) +} + /** * 255 -> 00 00 00 FF */ From 7de048245e8769f50116a4183b6e751f0c355704 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 20:27:55 +0800 Subject: [PATCH 057/111] Fix null packet --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 10 +++++----- .../qqandroid/network/protocol/packet/PacketFactory.kt | 10 +++++----- 2 files changed, 10 insertions(+), 10 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 848622d27..365f7521d 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 @@ -373,7 +373,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // with generic type, less mistakes - private suspend inline fun

generifiedParsePacket(input: Input) { + private suspend fun

generifiedParsePacket(input: Input) { KnownPacketFactories.parseIncomingPacket(bot, input) { packetFactory: PacketFactory

, packet: P, commandName: String, sequenceId: Int -> handlePacket(packetFactory, packet, commandName, sequenceId) if (packet is MultiPacket<*>) { @@ -387,7 +387,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler /** * 处理解析完成的包. */ - suspend fun

handlePacket(packetFactory: PacketFactory

?, packet: P, commandName: String, sequenceId: Int) { + suspend fun

handlePacket(packetFactory: PacketFactory

?, packet: P, commandName: String, sequenceId: Int) { // highest priority: pass to listeners (attached by sendAndExpect). packetListeners.forEach { listener -> if (listener.filter(commandName, sequenceId) && packetListeners.remove(listener)) { @@ -396,7 +396,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } // check top-level cancelling - if (PacketReceivedEvent(packet).broadcast().isCancelled) { + if (packet != null && PacketReceivedEvent(packet).broadcast().isCancelled) { return } @@ -412,7 +412,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (packet is CancellableEvent && packet.isCancelled) return } - if (bot.logger.isEnabled || logger.isEnabled) { + if (packet != null && bot.logger.isEnabled || logger.isEnabled) { val logMessage = "Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}" if (packet is Event) { @@ -585,7 +585,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler internal inner class PacketListener( // callback val commandName: String, val sequenceId: Int - ) : CompletableDeferred by CompletableDeferred(supervisor) { + ) : CompletableDeferred by CompletableDeferred(supervisor) { fun filter(commandName: String, sequenceId: Int) = this.commandName == commandName && this.sequenceId == sequenceId } diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt index b0da3edd0..55b6dae7b 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/PacketFactory.kt @@ -97,10 +97,10 @@ internal abstract class IncomingPacketFactory( } @JvmName("decode0") -private suspend inline fun

OutgoingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot) +private suspend inline fun

OutgoingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket): P = packet.decode(bot) @JvmName("decode1") -private suspend inline fun

IncomingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket, sequenceId: Int): P = +private suspend inline fun

IncomingPacketFactory

.decode(bot: QQAndroidBot, packet: ByteReadPacket, sequenceId: Int): P = packet.decode(bot, sequenceId) internal val DECRYPTER_16_ZERO = ByteArray(16) @@ -169,7 +169,7 @@ internal object KnownPacketFactories { // do not inline. Exceptions thrown will not be reported correctly @UseExperimental(MiraiInternalAPI::class) @Suppress("UNCHECKED_CAST") - suspend fun parseIncomingPacket(bot: QQAndroidBot, rawInput: Input, consumer: PacketConsumer) = with(rawInput) { + suspend fun parseIncomingPacket(bot: QQAndroidBot, rawInput: Input, consumer: PacketConsumer) = with(rawInput) { // login val flag1 = readInt() @@ -229,7 +229,7 @@ internal object KnownPacketFactories { } @UseExperimental(MiraiInternalAPI::class) - internal suspend fun handleIncomingPacket(it: IncomingPacket, bot: QQAndroidBot, flag2: Int, consumer: PacketConsumer) { + internal suspend fun handleIncomingPacket(it: IncomingPacket, bot: QQAndroidBot, flag2: Int, consumer: PacketConsumer) { if (it.packetFactory == null) { bot.network.logger.debug("Received commandName: ${it.commandName}") PacketLogger.warning { "找不到 PacketFactory" } @@ -337,7 +337,7 @@ internal object KnownPacketFactories { return IncomingPacket(packetFactory, ssoSequenceId, packet, commandName) } - private suspend fun ByteReadPacket.parseOicqResponse( + private suspend fun ByteReadPacket.parseOicqResponse( bot: QQAndroidBot, packetFactory: OutgoingPacketFactory, ssoSequenceId: Int, From a81eea422b16bbb248ac0ebe90cd2629a1ee135a Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 20:28:10 +0800 Subject: [PATCH 058/111] Face decoding --- .../mirai/qqandroid/message/MessageQQA.kt | 14 +- .../net.mamoe.mirai/message/data/Face.kt | 446 ++++++------------ 2 files changed, 162 insertions(+), 298 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index ac3c7bade..133e37d13 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -86,6 +86,16 @@ _400Height=0x000000EB(235) pbReserve= } */ +val FACE_BUF = "00 01 00 04 52 CC F5 D0".hexToBytes() + +internal fun Face.toJceData(): ImMsgBody.Face { + return ImMsgBody.Face( + index = this.id, + old = (0x1445 - 4 + this.id).toShort().toByteArray(), + buf = FACE_BUF + ) +} + internal fun CustomFaceFromFile.toJceData(): ImMsgBody.CustomFace { return ImMsgBody.CustomFace( filePath = this.filepath, @@ -213,6 +223,7 @@ internal fun MessageChain.toRichTextElems(): MutableList { is NotOnlineImageFromServer -> elements.add(ImMsgBody.Elem(notOnlineImage = it.delegate)) is NotOnlineImageFromFile -> elements.add(ImMsgBody.Elem(notOnlineImage = it.toJceData())) is AtAll -> elements.add(atAllData) + is Face -> elements.add(ImMsgBody.Elem(face = it.toJceData())) is QuoteReply, is MessageSource -> { @@ -312,6 +323,7 @@ internal fun List.joinToMessageChain(message: MessageChain) { it.srcMsg != null -> message.add(QuoteReply(MessageSourceFromServer(it.srcMsg))) it.notOnlineImage != null -> message.add(NotOnlineImageFromServer(it.notOnlineImage)) it.customFace != null -> message.add(CustomFaceFromServer(it.customFace)) + it.face != null -> message.add(Face(it.face.index)) it.text != null -> { if (it.text.attr6Buf.isEmpty()) { message.add(it.text.str.toMessage()) @@ -323,7 +335,7 @@ internal fun List.joinToMessageChain(message: MessageChain) { discardExact(7) id = readUInt().toLong() } - if (id == 0L){ + if (id == 0L) { message.add(AtAll) } else { message.add(At(id, it.text.str)) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt index 53a35641e..69ab4596c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Face.kt @@ -14,309 +14,161 @@ package net.mamoe.mirai.message.data import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName -import kotlin.jvm.JvmStatic /** * QQ 自带表情 */ -inline class Face(val id: FaceId) : Message { - override fun toString(): String = "[face${id.value}]" +class Face(val id: Int) : Message { + override fun toString(): String = "[mirai:face$id]" - companion object Key : Message.Key + /** + * @author LamGC + */ + @Suppress("SpellCheckingInspection", "unused") + companion object IdList : Message.Key { + const val unknown: Int = 0xff + const val jingya: Int = 0 + const val piezui: Int = 1 + const val se: Int = 2 + const val fadai: Int = 3 + const val deyi: Int = 4 + const val liulei: Int = 5 + const val haixiu: Int = 6 + const val bizui: Int = 7 + const val shui: Int = 8 + const val daku: Int = 9 + const val ganga: Int = 10 + const val fanu: Int = 11 + const val tiaopi: Int = 12 + const val ciya: Int = 13 + const val weixiao: Int = 14 + const val nanguo: Int = 15 + const val ku: Int = 16 + const val zhuakuang: Int = 18 + const val tu: Int = 19 + const val touxiao: Int = 20 + const val keai: Int = 21 + const val baiyan: Int = 22 + const val aoman: Int = 23 + const val ji_e: Int = 24 + const val kun: Int = 25 + const val jingkong: Int = 26 + const val liuhan: Int = 27 + const val hanxiao: Int = 28 + const val dabing: Int = 29 + const val fendou: Int = 30 + const val zhouma: Int = 31 + const val yiwen: Int = 32 + const val yun: Int = 34 + const val zhemo: Int = 35 + const val shuai: Int = 36 + const val kulou: Int = 37 + const val qiaoda: Int = 38 + const val zaijian: Int = 39 + const val fadou: Int = 41 + const val aiqing: Int = 42 + const val tiaotiao: Int = 43 + const val zhutou: Int = 46 + const val yongbao: Int = 49 + const val dan_gao: Int = 53 + const val shandian: Int = 54 + const val zhadan: Int = 55 + const val dao: Int = 56 + const val zuqiu: Int = 57 + const val bianbian: Int = 59 + const val kafei: Int = 60 + const val fan: Int = 61 + const val meigui: Int = 63 + const val diaoxie: Int = 64 + const val aixin: Int = 66 + const val xinsui: Int = 67 + const val liwu: Int = 69 + const val taiyang: Int = 74 + const val yueliang: Int = 75 + const val qiang: Int = 76 + const val ruo: Int = 77 + const val woshou: Int = 78 + const val shengli: Int = 79 + const val feiwen: Int = 85 + const val naohuo: Int = 86 + const val xigua: Int = 89 + const val lenghan: Int = 96 + const val cahan: Int = 97 + const val koubi: Int = 98 + const val guzhang: Int = 99 + const val qiudale: Int = 100 + const val huaixiao: Int = 101 + const val zuohengheng: Int = 102 + const val youhengheng: Int = 103 + const val haqian: Int = 104 + const val bishi: Int = 105 + const val weiqu: Int = 106 + const val kuaikule: Int = 107 + const val yinxian: Int = 108 + const val qinqin: Int = 109 + const val xia: Int = 110 + const val kelian: Int = 111 + const val caidao: Int = 112 + const val pijiu: Int = 113 + const val lanqiu: Int = 114 + const val pingpang: Int = 115 + const val shiai: Int = 116 + const val piaochong: Int = 117 + const val baoquan: Int = 118 + const val gouyin: Int = 119 + const val quantou: Int = 120 + const val chajin: Int = 121 + const val aini: Int = 122 + const val bu: Int = 123 + const val hao: Int = 124 + const val zhuanquan: Int = 125 + const val ketou: Int = 126 + const val huitou: Int = 127 + const val tiaosheng: Int = 128 + const val huishou: Int = 129 + const val jidong: Int = 130 + const val jiewu: Int = 131 + const val xianwen: Int = 132 + const val zuotaiji: Int = 133 + const val youtaiji: Int = 134 + const val shuangxi: Int = 136 + const val bianpao: Int = 137 + const val denglong: Int = 138 + const val facai: Int = 139 + const val K_ge: Int = 140 + const val gouwu: Int = 141 + const val youjian: Int = 142 + const val shuai_qi: Int = 143 + const val hecai: Int = 144 + const val qidao: Int = 145 + const val baojin: Int = 146 + const val bangbangtang: Int = 147 + const val he_nai: Int = 148 + const val xiamian: Int = 149 + const val xiangjiao: Int = 150 + const val feiji: Int = 151 + const val kaiche: Int = 152 + const val gaotiezuochetou: Int = 153 + const val chexiang: Int = 154 + const val gaotieyouchetou: Int = 155 + const val duoyun: Int = 156 + const val xiayu: Int = 157 + const val chaopiao: Int = 158 + const val xiongmao: Int = 159 + const val dengpao: Int = 160 + const val fengche: Int = 161 + const val naozhong: Int = 162 + const val dasan: Int = 163 + const val caiqiu: Int = 164 + const val zuanjie: Int = 165 + const val shafa: Int = 166 + const val zhijin: Int = 167 + const val yao: Int = 168 + const val shouqiang: Int = 169 + const val qingwa: Int = 170 + } override fun eq(other: Message): Boolean { return other is Face && other.id == this.id } -} - -/** - * @author LamGC - */ -@Suppress("SpellCheckingInspection", "unused") -@UseExperimental(ExperimentalUnsignedTypes::class) -inline class FaceId constructor(inline val value: UByte) { - companion object { - @JvmStatic - val unknown: FaceId = FaceId(0xffu) - @JvmStatic - val jingya: FaceId = FaceId(0u) - @JvmStatic - val piezui: FaceId = FaceId(1u) - @JvmStatic - val se: FaceId = FaceId(2u) - @JvmStatic - val fadai: FaceId = FaceId(3u) - @JvmStatic - val deyi: FaceId = FaceId(4u) - @JvmStatic - val liulei: FaceId = FaceId(5u) - @JvmStatic - val haixiu: FaceId = FaceId(6u) - @JvmStatic - val bizui: FaceId = FaceId(7u) - @JvmStatic - val shui: FaceId = FaceId(8u) - @JvmStatic - val daku: FaceId = FaceId(9u) - @JvmStatic - val ganga: FaceId = FaceId(10u) - @JvmStatic - val fanu: FaceId = FaceId(11u) - @JvmStatic - val tiaopi: FaceId = FaceId(12u) - @JvmStatic - val ciya: FaceId = FaceId(13u) - @JvmStatic - val weixiao: FaceId = FaceId(14u) - @JvmStatic - val nanguo: FaceId = FaceId(15u) - @JvmStatic - val ku: FaceId = FaceId(16u) - @JvmStatic - val zhuakuang: FaceId = FaceId(18u) - @JvmStatic - val tu: FaceId = FaceId(19u) - @JvmStatic - val touxiao: FaceId = FaceId(20u) - @JvmStatic - val keai: FaceId = FaceId(21u) - @JvmStatic - val baiyan: FaceId = FaceId(22u) - @JvmStatic - val aoman: FaceId = FaceId(23u) - @JvmStatic - val ji_e: FaceId = FaceId(24u) - @JvmStatic - val kun: FaceId = FaceId(25u) - @JvmStatic - val jingkong: FaceId = FaceId(26u) - @JvmStatic - val liuhan: FaceId = FaceId(27u) - @JvmStatic - val hanxiao: FaceId = FaceId(28u) - @JvmStatic - val dabing: FaceId = FaceId(29u) - @JvmStatic - val fendou: FaceId = FaceId(30u) - @JvmStatic - val zhouma: FaceId = FaceId(31u) - @JvmStatic - val yiwen: FaceId = FaceId(32u) - @JvmStatic - val yun: FaceId = FaceId(34u) - @JvmStatic - val zhemo: FaceId = FaceId(35u) - @JvmStatic - val shuai: FaceId = FaceId(36u) - @JvmStatic - val kulou: FaceId = FaceId(37u) - @JvmStatic - val qiaoda: FaceId = FaceId(38u) - @JvmStatic - val zaijian: FaceId = FaceId(39u) - @JvmStatic - val fadou: FaceId = FaceId(41u) - @JvmStatic - val aiqing: FaceId = FaceId(42u) - @JvmStatic - val tiaotiao: FaceId = FaceId(43u) - @JvmStatic - val zhutou: FaceId = FaceId(46u) - @JvmStatic - val yongbao: FaceId = FaceId(49u) - @JvmStatic - val dan_gao: FaceId = FaceId(53u) - @JvmStatic - val shandian: FaceId = FaceId(54u) - @JvmStatic - val zhadan: FaceId = FaceId(55u) - @JvmStatic - val dao: FaceId = FaceId(56u) - @JvmStatic - val zuqiu: FaceId = FaceId(57u) - @JvmStatic - val bianbian: FaceId = FaceId(59u) - @JvmStatic - val kafei: FaceId = FaceId(60u) - @JvmStatic - val fan: FaceId = FaceId(61u) - @JvmStatic - val meigui: FaceId = FaceId(63u) - @JvmStatic - val diaoxie: FaceId = FaceId(64u) - @JvmStatic - val aixin: FaceId = FaceId(66u) - @JvmStatic - val xinsui: FaceId = FaceId(67u) - @JvmStatic - val liwu: FaceId = FaceId(69u) - @JvmStatic - val taiyang: FaceId = FaceId(74u) - @JvmStatic - val yueliang: FaceId = FaceId(75u) - @JvmStatic - val qiang: FaceId = FaceId(76u) - @JvmStatic - val ruo: FaceId = FaceId(77u) - @JvmStatic - val woshou: FaceId = FaceId(78u) - @JvmStatic - val shengli: FaceId = FaceId(79u) - @JvmStatic - val feiwen: FaceId = FaceId(85u) - @JvmStatic - val naohuo: FaceId = FaceId(86u) - @JvmStatic - val xigua: FaceId = FaceId(89u) - @JvmStatic - val lenghan: FaceId = FaceId(96u) - @JvmStatic - val cahan: FaceId = FaceId(97u) - @JvmStatic - val koubi: FaceId = FaceId(98u) - @JvmStatic - val guzhang: FaceId = FaceId(99u) - @JvmStatic - val qiudale: FaceId = FaceId(100u) - @JvmStatic - val huaixiao: FaceId = FaceId(101u) - @JvmStatic - val zuohengheng: FaceId = FaceId(102u) - @JvmStatic - val youhengheng: FaceId = FaceId(103u) - @JvmStatic - val haqian: FaceId = FaceId(104u) - @JvmStatic - val bishi: FaceId = FaceId(105u) - @JvmStatic - val weiqu: FaceId = FaceId(106u) - @JvmStatic - val kuaikule: FaceId = FaceId(107u) - @JvmStatic - val yinxian: FaceId = FaceId(108u) - @JvmStatic - val qinqin: FaceId = FaceId(109u) - @JvmStatic - val xia: FaceId = FaceId(110u) - @JvmStatic - val kelian: FaceId = FaceId(111u) - @JvmStatic - val caidao: FaceId = FaceId(112u) - @JvmStatic - val pijiu: FaceId = FaceId(113u) - @JvmStatic - val lanqiu: FaceId = FaceId(114u) - @JvmStatic - val pingpang: FaceId = FaceId(115u) - @JvmStatic - val shiai: FaceId = FaceId(116u) - @JvmStatic - val piaochong: FaceId = FaceId(117u) - @JvmStatic - val baoquan: FaceId = FaceId(118u) - @JvmStatic - val gouyin: FaceId = FaceId(119u) - @JvmStatic - val quantou: FaceId = FaceId(120u) - @JvmStatic - val chajin: FaceId = FaceId(121u) - @JvmStatic - val aini: FaceId = FaceId(122u) - @JvmStatic - val bu: FaceId = FaceId(123u) - @JvmStatic - val hao: FaceId = FaceId(124u) - @JvmStatic - val zhuanquan: FaceId = FaceId(125u) - @JvmStatic - val ketou: FaceId = FaceId(126u) - @JvmStatic - val huitou: FaceId = FaceId(127u) - @JvmStatic - val tiaosheng: FaceId = FaceId(128u) - @JvmStatic - val huishou: FaceId = FaceId(129u) - @JvmStatic - val jidong: FaceId = FaceId(130u) - @JvmStatic - val jiewu: FaceId = FaceId(131u) - @JvmStatic - val xianwen: FaceId = FaceId(132u) - @JvmStatic - val zuotaiji: FaceId = FaceId(133u) - @JvmStatic - val youtaiji: FaceId = FaceId(134u) - @JvmStatic - val shuangxi: FaceId = FaceId(136u) - @JvmStatic - val bianpao: FaceId = FaceId(137u) - @JvmStatic - val denglong: FaceId = FaceId(138u) - @JvmStatic - val facai: FaceId = FaceId(139u) - @JvmStatic - val K_ge: FaceId = FaceId(140u) - @JvmStatic - val gouwu: FaceId = FaceId(141u) - @JvmStatic - val youjian: FaceId = FaceId(142u) - @JvmStatic - val shuai_qi: FaceId = FaceId(143u) - @JvmStatic - val hecai: FaceId = FaceId(144u) - @JvmStatic - val qidao: FaceId = FaceId(145u) - @JvmStatic - val baojin: FaceId = FaceId(146u) - @JvmStatic - val bangbangtang: FaceId = FaceId(147u) - @JvmStatic - val he_nai: FaceId = FaceId(148u) - @JvmStatic - val xiamian: FaceId = FaceId(149u) - @JvmStatic - val xiangjiao: FaceId = FaceId(150u) - @JvmStatic - val feiji: FaceId = FaceId(151u) - @JvmStatic - val kaiche: FaceId = FaceId(152u) - @JvmStatic - val gaotiezuochetou: FaceId = FaceId(153u) - @JvmStatic - val chexiang: FaceId = FaceId(154u) - @JvmStatic - val gaotieyouchetou: FaceId = FaceId(155u) - @JvmStatic - val duoyun: FaceId = FaceId(156u) - @JvmStatic - val xiayu: FaceId = FaceId(157u) - @JvmStatic - val chaopiao: FaceId = FaceId(158u) - @JvmStatic - val xiongmao: FaceId = FaceId(159u) - @JvmStatic - val dengpao: FaceId = FaceId(160u) - @JvmStatic - val fengche: FaceId = FaceId(161u) - @JvmStatic - val naozhong: FaceId = FaceId(162u) - @JvmStatic - val dasan: FaceId = FaceId(163u) - @JvmStatic - val caiqiu: FaceId = FaceId(164u) - @JvmStatic - val zuanjie: FaceId = FaceId(165u) - @JvmStatic - val shafa: FaceId = FaceId(166u) - @JvmStatic - val zhijin: FaceId = FaceId(167u) - @JvmStatic - val yao: FaceId = FaceId(168u) - @JvmStatic - val shouqiang: FaceId = FaceId(169u) - @JvmStatic - val qingwa: FaceId = FaceId(170u) - } - - override fun toString(): String = "$FaceId($value)" -} +} \ No newline at end of file From e66cfc95a7482201c8f3d4de6336bd662b2d4095 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 20:28:29 +0800 Subject: [PATCH 059/111] Unified `toString`: "[mirai:$imageId]" --- .../src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt index 509dffe4a..f4e6dd98f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Image.kt @@ -47,7 +47,7 @@ sealed class Image : Message { abstract val imageId: String final override fun toString(): String { - return "[image::$imageId]" + return "[mirai:$imageId]" } final override fun eq(other: Message): Boolean { From 3c29474c0bb9a682405e28dd5b666b3107e972f3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 20:37:53 +0800 Subject: [PATCH 060/111] Correct `groupCardOrNick` to `nameCardOrNick` --- .../kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt | 2 +- .../src/commonMain/kotlin/net.mamoe.mirai/contact/Member.kt | 4 ++-- .../src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt index 3381390fb..8b538c35f 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/ContactDTO.kt @@ -37,7 +37,7 @@ data class MemberDTO( val group: GroupDTO ) : ContactDTO() { constructor(member: Member) : this( - member.id, member.groupCardOrNick, member.permission, + member.id, member.nameCardOrNick, member.permission, GroupDTO(member.group) ) } 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 66e8f2ca3..d21bf9b1d 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 @@ -37,7 +37,7 @@ interface Member : QQ, Contact { * * 在修改时将会异步上传至服务器. * - * @see [groupCardOrNick] 获取非空群名片或昵称 + * @see [nameCardOrNick] 获取非空群名片或昵称 * * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 * @throws PermissionDeniedException 无权限修改时 @@ -96,7 +96,7 @@ interface Member : QQ, Contact { * * 若 [群名片][Member.nameCard] 不为空则返回群名片, 为空则返回 [QQ.nick] */ -val Member.groupCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick +val Member.nameCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick @ExperimentalTime suspend inline fun Member.mute(duration: Duration) { diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt index a0e103fd0..949b7e6ae 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/At.kt @@ -15,7 +15,7 @@ package net.mamoe.mirai.message.data import net.mamoe.mirai.contact.Member -import net.mamoe.mirai.contact.groupCardOrNick +import net.mamoe.mirai.contact.nameCardOrNick import net.mamoe.mirai.utils.MiraiInternalAPI import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -28,7 +28,7 @@ import kotlin.jvm.JvmName */ class At @MiraiInternalAPI constructor(val target: Long, val display: String) : Message { @UseExperimental(MiraiInternalAPI::class) - constructor(member: Member) : this(member.id, "@${member.groupCardOrNick}") + constructor(member: Member) : this(member.id, "@${member.nameCardOrNick}") override fun toString(): String = display From 31adf3510ee23c5c44e7bd49b471081e7a6478e9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 21:00:46 +0800 Subject: [PATCH 061/111] Fix "Received: null" --- .../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 365f7521d..2188e349b 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 @@ -412,7 +412,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (packet is CancellableEvent && packet.isCancelled) return } - if (packet != null && bot.logger.isEnabled || logger.isEnabled) { + if (packet != null && (bot.logger.isEnabled || logger.isEnabled)) { val logMessage = "Received: ${packet.toString().replace("\n", """\n""").replace("\r", "")}" if (packet is Event) { From adb094f2f93a000f857bea4fd8c11e54b0013378 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 21:07:12 +0800 Subject: [PATCH 062/111] http api support Face --- mirai-api-http/README_CH.md | 2 +- .../net/mamoe/mirai/api/http/data/common/MessageDTO.kt | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/mirai-api-http/README_CH.md b/mirai-api-http/README_CH.md index edd44d09e..b5454b89e 100644 --- a/mirai-api-http/README_CH.md +++ b/mirai-api-http/README_CH.md @@ -389,7 +389,7 @@ Content-Type:multipart/form-data + [x] At,@消息 + [x] AtAll,@全体成员 -+ [ ] Face,表情消息 ++ [x] Face,表情消息 + [x] Plain,文字消息 + [x] Image,图片消息 + [ ] Xml,Xml卡片消息 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 f46fc2567..ccdaf2819 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 @@ -13,7 +13,6 @@ import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Group -import net.mamoe.mirai.contact.Member import net.mamoe.mirai.message.FriendMessage import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.MessagePacket @@ -80,7 +79,7 @@ sealed class MessageDTO : DTO /* Extend function */ -suspend fun MessagePacket<*, *>.toDTO(): MessagePacketDTO = when (this) { +fun MessagePacket<*, *>.toDTO(): MessagePacketDTO = when (this) { is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender)) is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender)) else -> UnKnownMessagePacketDTO("UnKnown Message Packet") @@ -94,7 +93,7 @@ fun Message.toDTO() = when (this) { is MessageSource -> MessageSourceDTO(messageUid) is At -> AtDTO(target, display) is AtAll -> AtAllDTO(0L) - is Face -> FaceDTO(id.value.toInt()) + is Face -> FaceDTO(id) is PlainText -> PlainDTO(stringValue) is Image -> ImageDTO(imageId) is XMLMessage -> XmlDTO(stringValue) @@ -105,7 +104,7 @@ fun Message.toDTO() = when (this) { fun MessageDTO.toMessage(contact: Contact) = when (this) { is AtDTO -> At((contact as Group)[target]) is AtAllDTO -> AtAll - is FaceDTO -> Face(FaceId(faceId.toUByte())) + is FaceDTO -> Face(faceId) is PlainDTO -> PlainText(text) is ImageDTO -> Image(imageId) is XmlDTO -> XMLMessage(xml) From 57dfd0f1eb9a1e19245b0190c75ddddec6a4c3a6 Mon Sep 17 00:00:00 2001 From: Him188 Date: Wed, 19 Feb 2020 21:20:28 +0800 Subject: [PATCH 063/111] Log only once --- .../mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 3 +-- 1 file changed, 1 insertion(+), 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 2188e349b..c714511c5 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 @@ -417,8 +417,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (packet is Event) { bot.logger.verbose(logMessage) - } - logger.verbose(logMessage) + } else logger.verbose(logMessage) } packetFactory?.run { From 524de469542fba80c23348eb4ff7cffe0474c492 Mon Sep 17 00:00:00 2001 From: ryoii Date: Wed, 19 Feb 2020 23:37:27 +0800 Subject: [PATCH 064/111] play with ui any way --- .../styleSheet/LoginViewStyleSheet.kt | 47 ++++++++++++++++ .../console/graphical/util/JFoenixAdaptor.kt | 8 +-- .../console/graphical/view/LoginFragment.kt | 41 -------------- .../mirai/console/graphical/view/LoginView.kt | 50 ++++++++++++++++++ .../src/main/resources/character.png | Bin 0 -> 30438 bytes 5 files changed, 101 insertions(+), 45 deletions(-) create mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/LoginViewStyleSheet.kt delete mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt create mode 100644 mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginView.kt create mode 100644 mirai-console-graphical/src/main/resources/character.png diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/LoginViewStyleSheet.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/LoginViewStyleSheet.kt new file mode 100644 index 000000000..6e0b1f69c --- /dev/null +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/styleSheet/LoginViewStyleSheet.kt @@ -0,0 +1,47 @@ +package net.mamoe.mirai.console.graphical.styleSheet + +import javafx.scene.Cursor +import javafx.scene.effect.BlurType +import javafx.scene.effect.DropShadow +import javafx.scene.paint.Color +import javafx.scene.text.FontWeight +import tornadofx.* + +class LoginViewStyleSheet : Stylesheet() { + + companion object { + val vBox by csselement("VBox") + } + + init { + + vBox { + maxWidth = 500.px + maxHeight = 500.px + + backgroundColor += c("39c5BB", 0.3) + backgroundRadius += box(15.px) + + padding = box(50.px, 100.px) + spacing = 25.px + + borderRadius += box(15.px) + effect = DropShadow(BlurType.THREE_PASS_BOX, Color.GRAY, 10.0, 0.0, 15.0, 15.0) + } + + textField { + prefHeight = 30.px + textFill = Color.BLACK + fontWeight = FontWeight.BOLD + } + + button { + backgroundColor += c("00BCD4", 0.8) + padding = box(10.px, 0.px) + prefWidth = 500.px + textFill = Color.WHITE + fontWeight = FontWeight.BOLD + cursor = Cursor.HAND + } + } +} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt index 94663e510..5590d9c44 100644 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/util/JFoenixAdaptor.kt @@ -17,20 +17,20 @@ internal fun EventTarget.jfxButton(text: String = "", graphic: Node? = null, op: if (graphic != null) it.graphic = graphic } -fun EventTarget.jfxTextfield(value: String? = null, op: TextField.() -> Unit = {}) = JFXTextField().attachTo(this, op) { +fun EventTarget.jfxTextfield(value: String? = null, op: JFXTextField.() -> Unit = {}) = JFXTextField().attachTo(this, op) { if (value != null) it.text = value } -fun EventTarget.jfxTextfield(property: ObservableValue, op: TextField.() -> Unit = {}) = jfxTextfield().apply { +fun EventTarget.jfxTextfield(property: ObservableValue, op: JFXTextField.() -> Unit = {}) = jfxTextfield().apply { bind(property) op(this) } -fun EventTarget.jfxPasswordfield(value: String? = null, op: TextField.() -> Unit = {}) = JFXPasswordField().attachTo(this, op) { +fun EventTarget.jfxPasswordfield(value: String? = null, op: JFXPasswordField.() -> Unit = {}) = JFXPasswordField().attachTo(this, op) { if (value != null) it.text = value } -fun EventTarget.jfxPasswordfield(property: ObservableValue, op: TextField.() -> Unit = {}) = jfxPasswordfield().apply { +fun EventTarget.jfxPasswordfield(property: ObservableValue, op: JFXPasswordField.() -> Unit = {}) = jfxPasswordfield().apply { bind(property) op(this) } diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt deleted file mode 100644 index 387fcc7da..000000000 --- a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginFragment.kt +++ /dev/null @@ -1,41 +0,0 @@ -package net.mamoe.mirai.console.graphical.view - -import com.jfoenix.controls.JFXAlert -import com.jfoenix.controls.JFXPopup -import javafx.beans.property.SimpleStringProperty -import javafx.scene.control.Label -import kotlinx.coroutines.runBlocking -import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController -import net.mamoe.mirai.console.graphical.util.jfxButton -import net.mamoe.mirai.console.graphical.util.jfxPasswordfield -import net.mamoe.mirai.console.graphical.util.jfxTextfield -import tornadofx.* - -class LoginView : View() { - - private val controller = find() - private val qq = SimpleStringProperty("") - private val psd = SimpleStringProperty("") - - override val root = pane { - form { - fieldset("登录") { - field("QQ") { - jfxTextfield(qq) - } - field("密码") { - jfxPasswordfield(psd) - } - } - jfxButton("登录").action { - runAsync { - runBlocking { - controller.login(qq.value, psd.value) - } - }.ui { - // show dialog - } - } - } - } -} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginView.kt b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginView.kt new file mode 100644 index 000000000..46b9d59dc --- /dev/null +++ b/mirai-console-graphical/src/main/kotlin/net/mamoe/mirai/console/graphical/view/LoginView.kt @@ -0,0 +1,50 @@ +package net.mamoe.mirai.console.graphical.view + +import javafx.beans.property.SimpleStringProperty +import javafx.geometry.Pos +import javafx.scene.image.Image +import kotlinx.coroutines.runBlocking +import net.mamoe.mirai.console.graphical.controller.MiraiGraphicalUIController +import net.mamoe.mirai.console.graphical.styleSheet.LoginViewStyleSheet +import net.mamoe.mirai.console.graphical.util.jfxButton +import net.mamoe.mirai.console.graphical.util.jfxPasswordfield +import net.mamoe.mirai.console.graphical.util.jfxTextfield +import tornadofx.* + +class LoginView : View("CNM") { + + private val controller = find() + private val qq = SimpleStringProperty("") + private val psd = SimpleStringProperty("") + + override val root = borderpane { + + addStylesheet(LoginViewStyleSheet::class) + + center = vbox { + + imageview(Image(LoginView::class.java.classLoader.getResourceAsStream("character.png"))) { + alignment = Pos.CENTER + } + + jfxTextfield(qq) { + promptText = "QQ" + isLabelFloat = true + } + + jfxPasswordfield(psd) { + promptText = "Password" + isLabelFloat = true + } + + jfxButton("Login").action { + runAsync { + runBlocking { controller.login(qq.value, psd.value) } + }.ui { + qq.value = "" + psd.value = "" + } + } + } + } +} \ No newline at end of file diff --git a/mirai-console-graphical/src/main/resources/character.png b/mirai-console-graphical/src/main/resources/character.png new file mode 100644 index 0000000000000000000000000000000000000000..b55153f1ec3c344df01a0cbde83fa12319d413a3 GIT binary patch literal 30438 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 Date: Thu, 20 Feb 2020 01:31:23 +0800 Subject: [PATCH 065/111] http api event dto model --- .../mamoe/mirai/api/http/data/common/DTO.kt | 10 +- .../mirai/api/http/data/common/EventDTO.kt | 118 ++++++++++++++++++ 2 files changed, 125 insertions(+), 3 deletions(-) create mode 100644 mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt index 157f739bc..7c1d62daf 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt @@ -1,8 +1,7 @@ package net.mamoe.mirai.api.http.data.common -import kotlinx.serialization.* -import kotlinx.serialization.json.Json -import kotlinx.serialization.modules.SerializersModule +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient import net.mamoe.mirai.api.http.AuthedSession interface DTO @@ -16,3 +15,8 @@ abstract class VerifyDTO : DTO { @Transient lateinit var session: AuthedSession // 反序列化验证成功后传入 } + +@Serializable +open class EventDTO : DTO + +object IgnoreEventDTO : EventDTO() \ No newline at end of file diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt new file mode 100644 index 000000000..8cf70edad --- /dev/null +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt @@ -0,0 +1,118 @@ +package net.mamoe.mirai.api.http.data.common + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.event.events.BotEvent +import net.mamoe.mirai.event.events.* +import net.mamoe.mirai.message.MessagePacket +import net.mamoe.mirai.utils.MiraiExperimentalAPI + +@Serializable +open class BotEventDTO : EventDTO() + +@UseExperimental(MiraiExperimentalAPI::class) +fun BotEvent.toDTO() = when(this) { + is MessagePacket<*, *> -> toDTO() + else -> when(this) { + is BotOnlineEvent -> BotOnlineEventDTO(bot.uin) + is BotOfflineEvent.Active -> BotOfflineEventActiveDTO(bot.uin) + is BotOfflineEvent.Force -> BotOfflineEventForceDTO(bot.uin, title, message) + is BotOfflineEvent.Dropped -> BotOfflineEventDroppedDTO(bot.uin) + is BotReloginEvent -> BotReloginEventDTO(bot.uin) +// is MessageSendEvent.GroupMessageSendEvent -> {} +// is MessageSendEvent.FriendMessageSendEvent -> {} +// is BeforeImageUploadEvent -> {} +// is ImageUploadEvent.Succeed -> {} + is BotGroupPermissionChangeEvent -> BotGroupPermissionChangeEventDTO(origin, new, GroupDTO(group)) + is BotMuteEvent -> BotMuteEventDTO(durationSeconds, MemberDTO(operator)) + is BotUnmuteEvent -> BotUnmuteEventDTO(MemberDTO(operator)) + is BotJoinGroupEvent -> BotJoinGroupEventDTO(GroupDTO(group)) +// is GroupSettingChangeEvent<*> -> {} // 不知道会改什么 + is GroupNameChangeEvent -> GroupNameChangeEventDTO(origin, new, GroupDTO(group), isByBot) + is GroupEntranceAnnouncementChangeEvent -> GroupEntranceAnnouncementChangeEventDTO(origin, new, GroupDTO(group), operator?.let(::MemberDTO)) + is GroupMuteAllEvent -> GroupMuteAllEventDTO(origin, new, GroupDTO(group), operator?.let(::MemberDTO)) + is GroupAllowAnonymousChatEvent -> GroupAllowAnonymousChatEventDTO(origin, new, GroupDTO(group), operator?.let(::MemberDTO)) + is GroupAllowConfessTalkEvent -> GroupAllowConfessTalkEventDTO(origin, new, GroupDTO(group), isByBot) + is GroupAllowMemberInviteEvent -> GroupAllowMemberInviteEventDTO(origin, new, GroupDTO(group), operator?.let(::MemberDTO)) + is MemberJoinEvent -> MemberJoinEventDTO(MemberDTO(member)) + is MemberLeaveEvent.Kick -> MemberLeaveEventKickDTO(MemberDTO(member), operator?.let(::MemberDTO)) + is MemberLeaveEvent.Quit -> MemberLeaveEventQuitDTO(MemberDTO(member)) + is MemberCardChangeEvent -> MemberCardChangeEventDTO(origin, new, GroupDTO(group), operator?.let(::MemberDTO)) + is MemberSpecialTitleChangeEvent -> MemberSpecialTitleChangeEventDTO(origin, new, MemberDTO(member)) + is MemberPermissionChangeEvent -> MemberPermissionChangeEventDTO(origin, new, MemberDTO(member)) + is MemberMuteEvent -> MemberMuteEventDTO(durationSeconds, MemberDTO(member), operator?.let(::MemberDTO)) + is MemberUnmuteEvent -> MemberUnmuteEventDTO(MemberDTO(member), operator?.let(::MemberDTO)) + else -> IgnoreEventDTO + } +} + +@Serializable +@SerialName("BotOnlineEvent") +data class BotOnlineEventDTO(val qq: Long) : BotEventDTO() +@Serializable +@SerialName("BotOfflineEventActive") +data class BotOfflineEventActiveDTO(val qq: Long) : BotEventDTO() +@Serializable +@SerialName("BotOfflineEventForce") +data class BotOfflineEventForceDTO(val qq: Long, val title: String, val message: String) : BotEventDTO() +@Serializable +@SerialName("BotOfflineEventDropped") +data class BotOfflineEventDroppedDTO(val qq: Long) : BotEventDTO() +@Serializable +@SerialName("BotReloginEvent") +data class BotReloginEventDTO(val qq: Long) : BotEventDTO() +@Serializable +@SerialName("BotGroupPermissionChangeEvent") +data class BotGroupPermissionChangeEventDTO(val origin: MemberPermission, val new: MemberPermission, val groupDTO: GroupDTO) : BotEventDTO() +@Serializable +@SerialName("BotMuteEvent") +data class BotMuteEventDTO(val durationSeconds: Int, val operator: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("BotUnmuteEvent") +data class BotUnmuteEventDTO(val operator: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("BotJoinGroupEvent") +data class BotJoinGroupEventDTO(val group: GroupDTO) : BotEventDTO() +@Serializable +@SerialName("GroupNameChangeEvent") +data class GroupNameChangeEventDTO(val origin: String, val new: String, val group: GroupDTO, val isByBot: Boolean) : BotEventDTO() +@Serializable +@SerialName("GroupEntranceAnnouncementChangeEvent") +data class GroupEntranceAnnouncementChangeEventDTO(val origin: String, val new: String, val group: GroupDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("GroupMuteAllEvent") +data class GroupMuteAllEventDTO(val origin: Boolean, val new: Boolean, val group: GroupDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("GroupAllowAnonymousChatEvent") +data class GroupAllowAnonymousChatEventDTO(val origin: Boolean, val new: Boolean, val group: GroupDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("GroupAllowConfessTalkEvent") +data class GroupAllowConfessTalkEventDTO(val origin: Boolean, val new: Boolean, val group: GroupDTO, val isByBot: Boolean) : BotEventDTO() +@Serializable +@SerialName("GroupAllowMemberInviteEvent") +data class GroupAllowMemberInviteEventDTO(val origin: Boolean, val new: Boolean, val group: GroupDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("MemberJoinEvent") +data class MemberJoinEventDTO(val member: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("MemberLeaveEventKick") +data class MemberLeaveEventKickDTO(val member: MemberDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("MemberLeaveEventQuit") +data class MemberLeaveEventQuitDTO(val member: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("MemberCardChangeEvent") +data class MemberCardChangeEventDTO(val origin: String, val new: String, val group: GroupDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("MemberSpecialTitleChangeEvent") +data class MemberSpecialTitleChangeEventDTO(val origin: String, val new: String, val member: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("MemberPermissionChangeEvent") +data class MemberPermissionChangeEventDTO(val origin: MemberPermission, val new: MemberPermission, val member: MemberDTO) : BotEventDTO() +@Serializable +@SerialName("MemberMuteEvent") +data class MemberMuteEventDTO(val durationSeconds: Int, val member: MemberDTO, val operator: MemberDTO?) : BotEventDTO() +@Serializable +@SerialName("MemberUnmuteEvent") +data class MemberUnmuteEventDTO(val member: MemberDTO, val operator: MemberDTO?) : BotEventDTO() From 7838ccf042d99bc7cf60a53aae7204bfee1b4d8b Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:23:37 +0800 Subject: [PATCH 066/111] Adjust file names --- .../{SerializationUtils.kt => utils.kt} | 6 ++++- .../mirai/qqandroid/message/MessageQQA.kt | 7 +++--- .../utils/{Guid.kt => GuidSource.kt} | 6 ++++- .../qqandroid/utils/{Flags.kt => flags.kt} | 6 +++++ .../net/mamoe/mirai/qqandroid/utils/inline.kt | 5 ++++ .../net/mamoe/mirai/qqandroid/utils/type.kt | 8 +++++- .../net/mamoe/mirai/MiraiEnvironment.kt | 14 ----------- ...formUtilsAndroid.kt => platformAndroid.kt} | 0 .../net.mamoe.mirai/MiraiEnvironment.kt | 25 ------------------- .../utils/{Annotations.kt => annotataions.kt} | 0 .../utils/cryptor/{Proto.kt => protoBuf.kt} | 1 - .../io/{ByteArrayUtil.kt => byteArrays.kt} | 0 .../io/{TypeConversion.kt => conversion.kt} | 0 .../utils/io/{DebugUtil.kt => debugging.kt} | 0 .../utils/io/{InputUtils.kt => input.kt} | 0 .../utils/io/{OutputUtils.kt => output.kt} | 0 .../net.mamoe.mirai/utils/{map.kt => maps.kt} | 0 .../utils/{NumberUtils.kt => numbers.kt} | 0 .../utils/{PlatformUtils.kt => platform.kt} | 0 .../utils/{Time.kt => time.kt} | 1 - .../kotlin/net/mamoe/mirai/BotFactoryJvm.kt | 4 +-- .../net/mamoe/mirai/MiraiEnvironmentJvm.kt | 18 ------------- 22 files changed, 34 insertions(+), 67 deletions(-) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/{SerializationUtils.kt => utils.kt} (97%) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/{Guid.kt => GuidSource.kt} (95%) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/{Flags.kt => flags.kt} (88%) delete mode 100644 mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt rename mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/{PlatformUtilsAndroid.kt => platformAndroid.kt} (100%) delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/MiraiEnvironment.kt rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/{Annotations.kt => annotataions.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/{Proto.kt => protoBuf.kt} (99%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/{ByteArrayUtil.kt => byteArrays.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/{TypeConversion.kt => conversion.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/{DebugUtil.kt => debugging.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/{InputUtils.kt => input.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/{OutputUtils.kt => output.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/{map.kt => maps.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/{NumberUtils.kt => numbers.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/{PlatformUtils.kt => platform.kt} (100%) rename mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/{Time.kt => time.kt} (98%) delete mode 100644 mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/utils.kt similarity index 97% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/utils.kt index 5e5e732d4..fe8e46dd8 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/SerializationUtils.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/io/serialization/utils.kt @@ -7,6 +7,9 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("SerializationUtils") +@file:JvmMultifileClass + package net.mamoe.mirai.qqandroid.io.serialization import kotlinx.io.core.* @@ -20,7 +23,8 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestDataVersion3 import net.mamoe.mirai.qqandroid.network.protocol.data.jce.RequestPacket import net.mamoe.mirai.utils.firstValue import net.mamoe.mirai.utils.io.read -import net.mamoe.mirai.utils.io.toUHexString +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName fun ByteArray.loadAs(deserializer: DeserializationStrategy, c: JceCharset = JceCharset.UTF8): T { diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index 133e37d13..ef297c3b4 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -20,7 +20,7 @@ import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.toByteArray -private val AT_BUF_1 = byteArrayOf(0x00, 0x01, 0x00, 0x00, 0x00, 0x0A, 0x00) +private val AT_BUF_1 = byteArrayOf(0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00) // groupCard = 0x07; nick = 0x0A private val AT_BUF_2 = ByteArray(2) internal fun At.toJceData(): ImMsgBody.Text { @@ -328,8 +328,9 @@ internal fun List.joinToMessageChain(message: MessageChain) { if (it.text.attr6Buf.isEmpty()) { message.add(it.text.str.toMessage()) } else { - //00 01 00 00 00 05 01 00 00 00 00 00 00 all - //00 01 00 00 00 0A 00 3E 03 3F A2 00 00 one + // 00 01 00 00 00 05 01 00 00 00 00 00 00 all + // 00 01 00 00 00 0A 00 3E 03 3F A2 00 00 one/nick + // 00 01 00 00 00 07 00 44 71 47 90 00 00 one/groupCard val id: Long it.text.attr6Buf.read { discardExact(7) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Guid.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/GuidSource.kt similarity index 95% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Guid.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/GuidSource.kt index ee2085cec..f2405cde6 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Guid.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/GuidSource.kt @@ -7,9 +7,13 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("Utils") +@file:JvmMultifileClass + package net.mamoe.mirai.qqandroid.utils -import net.mamoe.mirai.utils.md5 +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName import kotlin.jvm.JvmStatic /** diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Flags.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/flags.kt similarity index 88% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Flags.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/flags.kt index a79cba42a..141d44bea 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/Flags.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/flags.kt @@ -7,8 +7,14 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("Utils") +@file:JvmMultifileClass + package net.mamoe.mirai.qqandroid.utils +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName + inline class MacOrAndroidIdChangeFlag(val value: Long = 0) { fun macChanged(): MacOrAndroidIdChangeFlag = MacOrAndroidIdChangeFlag(this.value or 0x1) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/inline.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/inline.kt index 26d1d44a0..ba27ce7d5 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/inline.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/inline.kt @@ -7,11 +7,16 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("Utils") +@file:JvmMultifileClass + package net.mamoe.mirai.qqandroid.utils import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName /** * Inline the block diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/type.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/type.kt index b295ccfa7..08dfe3c07 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/type.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/utils/type.kt @@ -7,10 +7,16 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:JvmName("Utils") +@file:JvmMultifileClass + package net.mamoe.mirai.qqandroid.utils +import kotlin.jvm.JvmMultifileClass +import kotlin.jvm.JvmName -fun Int.toIpV4AddressString(): String { + +internal fun Int.toIpV4AddressString(): String { @Suppress("NAME_SHADOWING") var var0 = this.toLong() and 0xFFFFFFFF return buildString { diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt deleted file mode 100644 index d7fce339d..000000000 --- a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/MiraiEnvironment.kt +++ /dev/null @@ -1,14 +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 - -actual object MiraiEnvironment { - actual val platform: Platform get() = Platform.ANDROID -} \ No newline at end of file diff --git a/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt b/mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/platformAndroid.kt similarity index 100% rename from mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/PlatformUtilsAndroid.kt rename to mirai-core/src/androidMain/kotlin/net/mamoe/mirai/utils/platformAndroid.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/MiraiEnvironment.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/MiraiEnvironment.kt deleted file mode 100644 index ea33d13e1..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/MiraiEnvironment.kt +++ /dev/null @@ -1,25 +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 - -/** - * 平台相关环境属性 - */ -expect object MiraiEnvironment { - val platform: Platform -} - -/** - * 可用平台列表 - */ -enum class Platform { - ANDROID, - JVM -} \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/annotataions.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Annotations.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/annotataions.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/Proto.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/protoBuf.kt similarity index 99% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/Proto.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/protoBuf.kt index 1096a3d6d..61dc928be 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/Proto.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/cryptor/protoBuf.kt @@ -17,7 +17,6 @@ import kotlinx.io.core.readUInt import kotlinx.io.core.readULong import net.mamoe.mirai.utils.MiraiDebugAPI import net.mamoe.mirai.utils.MiraiExperimentalAPI -import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.io.* import kotlin.jvm.JvmStatic diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/byteArrays.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/ByteArrayUtil.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/byteArrays.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/conversion.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/TypeConversion.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/conversion.kt 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/debugging.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/DebugUtil.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/debugging.kt 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/input.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/InputUtils.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/input.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/OutputUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/output.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/OutputUtils.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/io/output.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/map.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/maps.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/map.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/maps.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/NumberUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/numbers.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/NumberUtils.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/numbers.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/platform.kt similarity index 100% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/PlatformUtils.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/platform.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Time.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/time.kt similarity index 98% rename from mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Time.kt rename to mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/time.kt index b8cfd9ff8..81eba7d3b 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/Time.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/time.kt @@ -14,7 +14,6 @@ package net.mamoe.mirai.utils import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName -import kotlin.time.seconds // 临时使用, 待 Kotlin Duration 稳定后使用 Duration. // 内联属性, 则将来删除这些 API 将不会导致二进制不兼容. diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt index e1fff684c..ea27fb1eb 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt @@ -29,13 +29,13 @@ internal val factory: BotFactory = run { """ No BotFactory found. Please ensure that you've added dependency of protocol modules. Available modules: - - net.mamoe:mirai-core-timpc + - net.mamoe:mirai-core-timpc (stays at 0.12.0) - net.mamoe:mirai-core-qqandroid (recommended) You should have at lease one protocol module installed. ------------------------------------------------------- 找不到 BotFactory. 请确保你依赖了至少一个协议模块. 可用的协议模块: - - net.mamoe:mirai-core-timpc + - net.mamoe:mirai-core-timpc (0.12.0 后停止更新) - net.mamoe:mirai-core-qqandroid (推荐) 请添加上述任一模块的依赖(与 mirai-core 版本相同) """.trimIndent() diff --git a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt deleted file mode 100644 index ceebf145b..000000000 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/MiraiEnvironmentJvm.kt +++ /dev/null @@ -1,18 +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 - */ - -@file:Suppress("MayBeConstant", "unused") - -package net.mamoe.mirai - -actual object MiraiEnvironment { - @JvmStatic - actual val platform: Platform - get() = Platform.JVM -} \ No newline at end of file From c04a00414e3b854a3225b126dca3d5a02f280116 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:26:51 +0800 Subject: [PATCH 067/111] Make fast relogin faster --- .../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 c714511c5..5e17a3b4f 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 @@ -108,7 +108,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler if (::channel.isInitialized) { if (channel.isOpen) { kotlin.runCatching { - registerClientOnline() + registerClientOnline(500) }.exceptionOrNull() ?: return logger.info("Cannot do fast relogin. Trying slow relogin") } From 797dd598b315e66257edf4fba1078e3dfa27850b Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:33:10 +0800 Subject: [PATCH 068/111] Fix heartbeat --- .../mirai/qqandroid/network/QQAndroidBotNetworkHandler.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 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 5e17a3b4f..af8165357 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,7 +100,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler BotOfflineEvent.Dropped(bot).broadcast() } } - } + }.also { heartbeatJob = it } } override suspend fun relogin() { @@ -171,6 +171,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler // println("d2key=${bot.client.wLoginSigInfo.d2Key.toUHexString()}") registerClientOnline() + startHeartbeatJobOrKill() } private suspend fun registerClientOnline(timeoutMillis: Long = 3000) { @@ -290,8 +291,6 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler } } - heartbeatJob = startHeartbeatJobOrKill() - joinAll(friendListJob, groupJob) withTimeoutOrNull(5000) { From 3e29fbf34baf18f6becd22633b74a061f8973273 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:35:04 +0800 Subject: [PATCH 069/111] Reconnect always --- .../kotlin/net/mamoe/mirai/utils/BotConfigurationAndroid.kt | 2 +- .../jvmMain/kotlin/net/mamoe/mirai/utils/BotConfigurationJvm.kt | 2 +- 2 files changed, 2 insertions(+), 2 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 061551147..c245d0cde 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 @@ -72,7 +72,7 @@ actual open class BotConfiguration actual constructor() { /** * 最多尝试多少次重连 */ - actual var reconnectionRetryTimes: Int = 10 + actual var reconnectionRetryTimes: Int = Int.MAX_VALUE /** * 验证码处理器 */ 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 280d27a99..5f9115b07 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 @@ -225,7 +225,7 @@ actual open class BotConfiguration actual constructor() { /** * 最多尝试多少次重连 */ - actual var reconnectionRetryTimes: Int = 10 + actual var reconnectionRetryTimes: Int = Int.MAX_VALUE /** * 验证码处理器 */ From 8258fada231fb7ba6c70fe072a9dbdd4246ee825 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:36:43 +0800 Subject: [PATCH 070/111] 0.17.0 --- CHANGELOG.md | 12 ++++++++++++ gradle.properties | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index dca1cb5f9..83ea0e429 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ 开发版本. 频繁更新, 不保证高稳定性 +## `0.17.0` 2020/2/20 + +### mirai-core +- 支持原生表情 `Face` +- 修正 `groupCardOrNick` 为 `nameCardOrNick` +- 增加 `MessageChain.foreachContent(lambda)` 和 `Message.hasContent(): Boolean` + +### mirai-core-qqandroid +- 提高重连速度 +- 修复重连后某些情况不会心跳 +- 修复收包时可能产生异常 + ## `0.16.0` 2020/2/19 ### mirai-core diff --git a/gradle.properties b/gradle.properties index b80f2d1a0..4a4049d31 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ # style guide kotlin.code.style=official # config -mirai_version=0.16.0 +mirai_version=0.17.0 mirai_japt_version=1.0.1 kotlin.incremental.multiplatform=true kotlin.parallel.tasks.in.project=true From 1bcac33151defa7024f4a2ca5e9ad396e1568933 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 11:52:26 +0800 Subject: [PATCH 071/111] Move `At.member` from `GroupMessage` to `MessagePacket` --- .../commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt | 2 -- .../commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt | 2 ++ 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt index 0232fcecf..efd272542 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/GroupMessage.kt @@ -14,7 +14,6 @@ import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.MemberPermission import net.mamoe.mirai.event.Event -import net.mamoe.mirai.message.data.At import net.mamoe.mirai.message.data.Message import net.mamoe.mirai.message.data.MessageChain import net.mamoe.mirai.utils.getValue @@ -38,7 +37,6 @@ class GroupMessage( override val subject: Group get() = group - inline fun At.member(): Member = group[this.target] inline fun Long.member(): Member = group[this] diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt index 4aeb9c04c..6e53d8032 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt @@ -115,6 +115,8 @@ abstract class MessagePacketBase(_bot: Bot) : */ inline fun QQ.at(): At = At(this as? Member ?: error("`QQ.at` can only be used in GroupMessage")) + inline fun At.member(): Member = (this@MessagePacketBase as? GroupMessage)?.group?.get(this.target) ?: error("`At.member` can only be used in GroupMessage") + // endregion // region 下载图片 From 37cea58a1929d620d3be622f88d3502a9a7d1ec9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 13:18:59 +0800 Subject: [PATCH 072/111] Fix ambiguous `eq` --- .../commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt index 4234275ce..7614f5d4c 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/data/Message.kt @@ -57,7 +57,7 @@ interface Message { */ interface Key - infix fun eq(other: Message): Boolean = this == other + infix fun eq(other: Message): Boolean = this.toString() == other.toString() /** * 将 [toString] 与 [other] 比较 From f5a6040668cc3892cdccc14cabfb1336e23582f8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 13:20:36 +0800 Subject: [PATCH 073/111] Add additional `coroutineScope` parameter --- .../net.mamoe.mirai/event/Subscribers.kt | 55 +++++++++++++++---- .../event/internal/InternalEventListeners.kt | 8 ++- .../mirai/event/internal/EventInternalJvm.kt | 5 +- 3 files changed, 52 insertions(+), 16 deletions(-) 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 c42584f55..eeca3a407 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 @@ -22,6 +22,7 @@ import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext import kotlin.jvm.JvmName /* @@ -98,6 +99,8 @@ interface Listener : CompletableJob { * * **注意:** 事件处理是 `suspend` 的, 请规范处理 JVM 阻塞方法. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribeAlways 一直监听 * @see subscribeOnce 只监听一次 * @@ -106,8 +109,11 @@ interface Listener : CompletableJob { * @see subscribeFriendMessages 监听好友消息 DSL */ @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribe(noinline handler: suspend E.(E) -> ListeningStatus): Listener = - E::class.subscribeInternal(Handler { it.handler(it); }) +inline fun CoroutineScope.subscribe( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline handler: suspend E.(E) -> ListeningStatus +): Listener = + E::class.subscribeInternal(Handler(coroutineContext) { it.handler(it); }) /** * 在指定的 [CoroutineScope] 下订阅所有 [E] 及其子类事件. @@ -116,14 +122,19 @@ inline fun CoroutineScope.subscribe(noinline handler: suspen * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribe 获取更多说明 */ @UseExperimental(MiraiInternalAPI::class, ExperimentalContracts::class) -inline fun CoroutineScope.subscribeAlways(noinline listener: suspend E.(E) -> Unit): Listener { +inline fun CoroutineScope.subscribeAlways( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline listener: suspend E.(E) -> Unit +): Listener { contract { callsInPlace(listener, InvocationKind.UNKNOWN) } - return E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.LISTENING }) + return E::class.subscribeInternal(Handler(coroutineContext) { it.listener(it); ListeningStatus.LISTENING }) } /** @@ -133,11 +144,16 @@ inline fun CoroutineScope.subscribeAlways(noinline listener: * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribe 获取更多说明 */ @UseExperimental(MiraiInternalAPI::class) -inline fun CoroutineScope.subscribeOnce(noinline listener: suspend E.(E) -> Unit): Listener = - E::class.subscribeInternal(Handler { it.listener(it); ListeningStatus.STOPPED }) +inline fun CoroutineScope.subscribeOnce( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline listener: suspend E.(E) -> Unit +): Listener = + E::class.subscribeInternal(Handler(coroutineContext) { it.listener(it); ListeningStatus.STOPPED }) // @@ -153,12 +169,17 @@ inline fun CoroutineScope.subscribeOnce(noinline listener: s * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribe 获取更多说明 */ @JvmName("subscribeAlwaysForBot") @UseExperimental(MiraiInternalAPI::class) -inline fun Bot.subscribe(noinline handler: suspend E.(E) -> ListeningStatus): Listener = - E::class.subscribeInternal(Handler { if (it.bot === this) it.handler(it) else ListeningStatus.LISTENING }) +inline fun Bot.subscribe( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline handler: suspend E.(E) -> ListeningStatus +): Listener = + E::class.subscribeInternal(Handler(coroutineContext) { if (it.bot === this) it.handler(it) else ListeningStatus.LISTENING }) /** @@ -168,12 +189,17 @@ inline fun Bot.subscribe(noinline handler: suspend E.(E) * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribe 获取更多说明 */ @JvmName("subscribeAlwaysForBot1") @UseExperimental(MiraiInternalAPI::class) -inline fun Bot.subscribeAlways(noinline listener: suspend E.(E) -> Unit): Listener { - return E::class.subscribeInternal(Handler { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING }) +inline fun Bot.subscribeAlways( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline listener: suspend E.(E) -> Unit +): Listener { + return E::class.subscribeInternal(Handler(coroutineContext) { if (it.bot === this) it.listener(it); ListeningStatus.LISTENING }) } /** @@ -183,12 +209,17 @@ inline fun Bot.subscribeAlways(noinline listener: suspend * 可在任意时候通过 [Listener.complete] 来主动停止监听. * [Bot] 被关闭后事件监听会被 [取消][Listener.cancel]. * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see subscribe 获取更多说明 */ @JvmName("subscribeOnceForBot2") @UseExperimental(MiraiInternalAPI::class) -inline fun Bot.subscribeOnce(noinline listener: suspend E.(E) -> Unit): Listener = - E::class.subscribeInternal(Handler { +inline fun Bot.subscribeOnce( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + noinline listener: suspend E.(E) -> Unit +): Listener = + E::class.subscribeInternal(Handler(coroutineContext) { if (it.bot === this) { it.listener(it) ListeningStatus.STOPPED 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 fe2ff0f8c..fb604edaa 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 @@ -31,8 +31,12 @@ fun , E : Event> KClass.subscribeInternal(listener: L): L @PublishedApi @Suppress("FunctionName") -internal fun CoroutineScope.Handler(handler: suspend (E) -> ListeningStatus): Handler { - return Handler(coroutineContext[Job], coroutineContext, handler) +internal fun CoroutineScope.Handler( + coroutineContext: CoroutineContext, + handler: suspend (E) -> ListeningStatus +): Handler { + val context = this.newCoroutineContext(coroutineContext) + return Handler(context[Job], context, handler) } private inline fun inline(block: () -> Unit) = block() 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 index ccc2a718f..ddae0cdd2 100644 --- 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 @@ -16,15 +16,16 @@ import net.mamoe.mirai.event.ListeningStatus import net.mamoe.mirai.utils.MiraiInternalAPI import java.util.function.Consumer import java.util.function.Function +import kotlin.coroutines.EmptyCoroutineContext @MiraiInternalAPI @Suppress("FunctionName") fun Class._subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Function): Listener { - return this.kotlin.subscribeInternal(scope.Handler { onEvent.apply(it) }) + return this.kotlin.subscribeInternal(scope.Handler(EmptyCoroutineContext) { onEvent.apply(it) }) } @MiraiInternalAPI @Suppress("FunctionName") fun Class._subscribeEventForJaptOnly(scope: CoroutineScope, onEvent: Consumer): Listener { - return this.kotlin.subscribeInternal(scope.Handler { onEvent.accept(it); ListeningStatus.LISTENING; }) + return this.kotlin.subscribeInternal(scope.Handler(EmptyCoroutineContext) { onEvent.accept(it); ListeningStatus.LISTENING; }) } \ No newline at end of file From 3d4ff807af89edb0fa9a9518600f02172d2027ba Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 13:24:27 +0800 Subject: [PATCH 074/111] Add `MessageSource.time` --- .../mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt | 2 ++ .../kotlin/net.mamoe.mirai/message/data/MessageSource.kt | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt index c8e77f7d3..fe4aab43f 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageSourceFromMsg.kt @@ -21,6 +21,7 @@ import net.mamoe.mirai.qqandroid.network.protocol.data.proto.SourceMsg internal inline class MessageSourceFromServer( val delegate: ImMsgBody.SourceMsg ) : MessageSource { + override val time: Long get() = delegate.time.toLong() and 0xFFFFFFFF override val messageUid: Long get() = delegate.pbReserve.loadAs(SourceMsg.ResvAttr.serializer()).origUids!! override val sourceMessage: MessageChain get() = delegate.toMessageChain() override val senderId: Long get() = delegate.senderUin @@ -32,6 +33,7 @@ internal inline class MessageSourceFromServer( internal inline class MessageSourceFromMsg( val delegate: MsgComm.Msg ) : MessageSource { + override val time: Long get() = delegate.msgHead.msgTime.toLong() and 0xFFFFFFFF override val messageUid: Long get() = delegate.msgBody.richText.attr!!.random.toLong() override val sourceMessage: MessageChain get() = delegate.toMessageChain() override val senderId: Long get() = delegate.msgHead.fromUin 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 3653cfabb..e5b831b17 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 @@ -31,6 +31,11 @@ interface MessageSource : Message { */ val messageUid: Long + /** + * 发送时间, 单位为秒 + */ + val time: Long + /** * 发送人号码 */ From 588bfef817f0a54de0a3b01eaac0c52c2820f6ee Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 13:28:44 +0800 Subject: [PATCH 075/111] Update guide --- docs/guide_getting_started.md | 113 ++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 docs/guide_getting_started.md diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md new file mode 100644 index 000000000..6a57c6486 --- /dev/null +++ b/docs/guide_getting_started.md @@ -0,0 +1,113 @@ +#Mirai Guide - Getting Started + +由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.16.0``` + +假如仅仅使用Mirai,不需要对整个项目进行Clone,只需在项目内添加Gradle Dependency或使用即可。 + +下面介绍详细的入门步骤。 + +## With console + +使用mirai-console,以插件形式对服务器功能进行管理,启动无需任何IDE。 + +**由于mirai-terminal还没有开发完成,暂时不提供入门** + +## With loader + +通过编写Kotlin程序启动mirai-core,并定义你的Mirai Bot行为。 + +假如已经对Gradle有一定了解,可跳过1,2 + +### 1 安装IDEA与JDK + +JDK要求8以上 + +### 2 新建Gradle项目 + +- 在```File->new project```中选择```Gradle``` +- 在面板中的```Additional Libraries and Frameworks```中勾选```Java```以及```Kotlin/JVM``` +- 点击```next```,填入```GroupId```与```ArtifactId```(对于测试项目来说,可随意填写) +- 点击```next```,点击```Use default gradle wrapper(recommended)``` +- 创建项目完成 + +### 3 添加依赖 + +- 打开项目的```Project```面板,点击编辑```build.gradle``` + +- 首先添加repositories + + ``` + //添加jcenter仓库 + /* + repositories { + mavenCentral() + } + 原文内容,更新为下文 + */ + + repositories { + mavenCentral() + jcenter() + } + ``` + +- 添加依赖,将dependencies部分覆盖为 + + ``` + dependencies { + implementation 'net.mamoe:mirai-core:0.16.0' + implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.16.0' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + testCompile group: 'junit', name: 'junit', version: '4.12' + } + ``` + +- 打开右侧Gradle面板,点击刷新按钮 +- 至此,依赖添加完成 + +### 4 Try Bot + +- 在src/main文件夹下新建文件夹,命名为```kotlin``` +- 在```kotlin```下新建包(在```kotlin```文件夹上右键-```New```-```Packages```) 包名为```net.mamoe.mirai.simpleloader``` + +- 在包下新建kotlin文件```MyLoader.kt``` + + ``` + package net.mamoe.mirai.simpleloader + + import kotlinx.coroutines.* + import net.mamoe.mirai.Bot + import net.mamoe.mirai.alsoLogin + import net.mamoe.mirai.event.subscribeMessages + + fun main(args: Array) { + runBlocking {//阻塞,直到Mirai退出 + coroutineScope() { + launch { + val qqId = 10000L//Bot的QQ号,需为Long类型,在结尾处添加大写L + val password = "your_password"//Bot的密码 + val miraiBot = Bot(qqId, password).alsoLogin()//新建Bot并登陆 + miraiBot.subscribeMessages { + "你好" reply "你好!" + "profile" reply { sender.queryProfile() } + case("at me") { + reply(sender.at() + " 给爷爬 ") + } + + (contains("舔") or contains("刘老板")) { + "刘老板太强了".reply() + } + } + miraiBot.join() + } + } + } + } + ``` + +- 单击编辑器内第8行(```fun main```)左侧的run按钮(绿色三角),等待,MiraiBot成功登录。 +- 本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了” + + + +至此,简单的入门已经结束,下面可根据不同的需求参阅文档进行功能的添加。 From 7580e0f414e6c40762eeb557fbfa3684f0755d6d Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 13:31:00 +0800 Subject: [PATCH 076/111] update guide --- docs/guide_getting_started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index 6a57c6486..0e5f30f8a 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -1,4 +1,4 @@ -#Mirai Guide - Getting Started +# Mirai Guide - Getting Started 由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.16.0``` From a0843c1da5c4653a3278c8d5830631edc90d9b61 Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 13:32:35 +0800 Subject: [PATCH 077/111] Fix name 'mirai-terminal' in docs --- docs/guide_getting_started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index 0e5f30f8a..e8bd38801 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -10,7 +10,7 @@ 使用mirai-console,以插件形式对服务器功能进行管理,启动无需任何IDE。 -**由于mirai-terminal还没有开发完成,暂时不提供入门** +**由于mirai-console还没有开发完成,暂时不提供入门** ## With loader From cdd3053e1645f7435f6e10e493ee81a47d69deab Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 16:40:40 +0800 Subject: [PATCH 078/111] Better --- docs/guide_getting_started.md | 61 ++++++++++++++++------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index e8bd38801..b6299742a 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -36,7 +36,7 @@ JDK要求8以上 - 首先添加repositories - ``` + ```groovy //添加jcenter仓库 /* repositories { @@ -53,7 +53,7 @@ JDK要求8以上 - 添加依赖,将dependencies部分覆盖为 - ``` + ```groovy dependencies { implementation 'net.mamoe:mirai-core:0.16.0' implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.16.0' @@ -72,38 +72,31 @@ JDK要求8以上 - 在包下新建kotlin文件```MyLoader.kt``` - ``` - package net.mamoe.mirai.simpleloader - - import kotlinx.coroutines.* - import net.mamoe.mirai.Bot - import net.mamoe.mirai.alsoLogin - import net.mamoe.mirai.event.subscribeMessages - - fun main(args: Array) { - runBlocking {//阻塞,直到Mirai退出 - coroutineScope() { - launch { - val qqId = 10000L//Bot的QQ号,需为Long类型,在结尾处添加大写L - val password = "your_password"//Bot的密码 - val miraiBot = Bot(qqId, password).alsoLogin()//新建Bot并登陆 - miraiBot.subscribeMessages { - "你好" reply "你好!" - "profile" reply { sender.queryProfile() } - case("at me") { - reply(sender.at() + " 给爷爬 ") - } - - (contains("舔") or contains("刘老板")) { - "刘老板太强了".reply() - } - } - miraiBot.join() - } - } - } - } - ``` +```kotlin +package net.mamoe.mirai.simpleloader + +import kotlinx.coroutines.* +import net.mamoe.mirai.Bot +import net.mamoe.mirai.alsoLogin +import net.mamoe.mirai.event.subscribeMessages + +suspend fun main() { + val qqId = 10000L//Bot的QQ号,需为Long类型,在结尾处添加大写L + val password = "your_password"//Bot的密码 + val miraiBot = Bot(qqId, password).alsoLogin()//新建Bot并登陆 + miraiBot.subscribeMessages { + "你好" reply "你好!" + case("at me") { + reply(sender.at() + " 给爷爬 ") + } + + (contains("舔") or contains("刘老板")) { + "刘老板太强了".reply() + } + } + miraiBot.join() +} +``` - 单击编辑器内第8行(```fun main```)左侧的run按钮(绿色三角),等待,MiraiBot成功登录。 - 本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了” From 70b0205f6981d9492d5d19debd07d2bba9a7c73a Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 16:41:17 +0800 Subject: [PATCH 079/111] Better --- docs/guide_getting_started.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index b6299742a..b41003cb0 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -98,7 +98,7 @@ suspend fun main() { } ``` -- 单击编辑器内第8行(```fun main```)左侧的run按钮(绿色三角),等待,MiraiBot成功登录。 +- 单击编辑器内第8行(```suspend fun main```)左侧的run按钮(绿色三角),等待,MiraiBot成功登录。 - 本例的功能中,在任意群内任意成员发送包含“舔”字或“刘老板”字样的消息,MiraiBot会回复“刘老板太强了” From 3be9968bf67586ba218f45abdfaac2425373e456 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 16:53:01 +0800 Subject: [PATCH 080/111] fix #79 --- .../kotlin/net/mamoe/mirai/api/http/data/common/MessageDTO.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 ccdaf2819..b1c9cba48 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 @@ -70,7 +70,7 @@ sealed class MessagePacketDTO : DTO { lateinit var messageChain : MessageChainDTO } -typealias MessageChainDTO = Array +typealias MessageChainDTO = List @Serializable sealed class MessageDTO : DTO @@ -83,7 +83,7 @@ fun MessagePacket<*, *>.toDTO(): MessagePacketDTO = when (this) { is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender)) is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender)) else -> UnKnownMessagePacketDTO("UnKnown Message Packet") -}.apply { messageChain = Array(message.size){ message[it].toDTO() }} +}.apply { messageChain = mutableListOf().also{ ls -> message.foreachContent { ls.add(it.toDTO()) }}} fun MessageChainDTO.toMessageChain(contact: Contact) = MessageChain().apply { this@toMessageChain.forEach { add(it.toMessage(contact)) } } From 2d2fab449ff38323f0d5b2e4ea28beb94f665d31 Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 17:03:52 +0800 Subject: [PATCH 081/111] Format title in docs --- docs/guide_getting_started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index b41003cb0..cafb3440a 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -6,13 +6,13 @@ 下面介绍详细的入门步骤。 -## With console +## With Console 使用mirai-console,以插件形式对服务器功能进行管理,启动无需任何IDE。 **由于mirai-console还没有开发完成,暂时不提供入门** -## With loader +## With Loader 通过编写Kotlin程序启动mirai-core,并定义你的Mirai Bot行为。 @@ -103,4 +103,4 @@ suspend fun main() { -至此,简单的入门已经结束,下面可根据不同的需求参阅文档进行功能的添加。 +至此,简单的入门已经结束,下面可根据不同的需求参阅wiki进行功能的添加。 From 7c3debc00c4e4adff388d1894b107f6c9120f68d Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 17:16:46 +0800 Subject: [PATCH 082/111] Fix GroupMessage subscribing --- .../net.mamoe.mirai/data/EventPacket.kt | 19 ------------------- .../net.mamoe.mirai/message/MessagePacket.kt | 4 ++-- 2 files changed, 2 insertions(+), 21 deletions(-) delete mode 100644 mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt deleted file mode 100644 index 630db03e1..000000000 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/EventPacket.kt +++ /dev/null @@ -1,19 +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.data - -import net.mamoe.mirai.event.Event - -/** - * 事件包. 可被监听. - * - * @see Event - */ -interface EventPacket : Event, Packet \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt index 6e53d8032..a42a778fc 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/message/MessagePacket.kt @@ -19,7 +19,7 @@ import net.mamoe.mirai.contact.Contact import net.mamoe.mirai.contact.Group import net.mamoe.mirai.contact.Member import net.mamoe.mirai.contact.QQ -import net.mamoe.mirai.data.EventPacket +import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.data.* import net.mamoe.mirai.utils.* @@ -37,7 +37,7 @@ expect abstract class MessagePacket(bot: Bot) */ // Tips: 在 IntelliJ 中 (左侧边栏) 打开 `Structure`, 可查看类结构 @Suppress("NOTHING_TO_INLINE") @MiraiInternalAPI -abstract class MessagePacketBase(_bot: Bot) : EventPacket, BotEvent { +abstract class MessagePacketBase(_bot: Bot) : Packet, BotEvent { /** * 接受到这条消息的 */ From 395f20c27376f55b1194b0c52da352418e72f4e4 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 17:32:41 +0800 Subject: [PATCH 083/111] Fix event and improve performance --- .../event/internal/InternalEventListeners.kt | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 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 fb604edaa..c09b5f303 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 @@ -80,7 +80,25 @@ internal class Handler */ internal fun KClass.listeners(): EventListeners = EventListenerManager.get(this) -internal class EventListeners : LockFreeLinkedList>() +internal class EventListeners(clazz: KClass) : LockFreeLinkedList>() { + @Suppress("UNCHECKED_CAST") + val supertypes: Set> by lazy { + val supertypes = mutableSetOf>() + + fun addSupertypes(clazz: KClass) { + clazz.supertypes.forEach { + val classifier = it.classifier as? KClass + if (classifier != null) { + supertypes.add(classifier) + addSupertypes(classifier) + } + } + } + addSupertypes(clazz) + + supertypes + } +} internal expect class MiraiAtomicBoolean(initial: Boolean) { @@ -109,10 +127,10 @@ internal object EventListenerManager { } } if (lock.compareAndSet(false, true)) { - val registry = Registry(clazz, EventListeners()) + val registry = Registry(clazz as KClass, EventListeners(clazz)) registries.addLast(registry) lock.value = false - return registry.listeners as EventListeners + return registry.listeners } return get(clazz) } @@ -125,19 +143,10 @@ internal suspend inline fun Event.broadcastInternal() { EventLogger.info { "Event broadcast: $this" } - callAndRemoveIfRequired(this::class.listeners()) - - var supertypes = this::class.supertypes - while (true) { - val superSubscribableType = supertypes.firstOrNull { - it.classifier as? KClass != null - } - - superSubscribableType?.let { - callAndRemoveIfRequired((it.classifier as KClass).listeners()) - } - - supertypes = (superSubscribableType?.classifier as? KClass<*>)?.supertypes ?: return + val listeners = this::class.listeners() + callAndRemoveIfRequired(listeners) + listeners.supertypes.forEach { + callAndRemoveIfRequired(it.listeners()) } } From 61838a0e14bd8ee187d2d4330a8fb346f5a2efa3 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 17:47:49 +0800 Subject: [PATCH 084/111] Add additional `coroutineContext` --- .../event/MessageSubscribers.kt | 53 ++++++++++++++----- 1 file changed, 39 insertions(+), 14 deletions(-) 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 5cb5489c0..8c19b90fc 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 @@ -25,6 +25,8 @@ import net.mamoe.mirai.message.data.Message import kotlin.contracts.ExperimentalContracts import kotlin.contracts.InvocationKind import kotlin.contracts.contract +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * 订阅来自所有 [Bot] 的所有联系人的消息事件. 联系人可以是任意群或任意好友或临时会话. @@ -33,7 +35,10 @@ import kotlin.contracts.contract */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSubscribersBuilder>.() -> R): R { +inline fun CoroutineScope.subscribeMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder>.() -> R +): R { // contract 可帮助 IDE 进行类型推断. 无实际代码作用. contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) @@ -42,7 +47,7 @@ inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSu return MessageSubscribersBuilder { messageListener: MessageListener> -> // subscribeAlways 即注册一个监听器. 这个监听器收到消息后就传递给 [listener] // listener 即为 DSL 里 `contains(...) { }`, `startsWith(...) { }` 的代码块. - subscribeAlways { + subscribeAlways(coroutineContext) { messageListener.invoke(this, this.message.toString()) // this.message.toString() 即为 messageListener 中 it 接收到的值 } @@ -56,12 +61,15 @@ inline fun CoroutineScope.subscribeMessages(crossinline listeners: MessageSu */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun CoroutineScope.subscribeGroupMessages(crossinline listeners: MessageSubscribersBuilder.() -> R): R { +inline fun CoroutineScope.subscribeGroupMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder.() -> R +): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } return MessageSubscribersBuilder { listener -> - subscribeAlways { + subscribeAlways(coroutineContext) { listener(this, this.message.toString()) } }.run(listeners) @@ -74,12 +82,15 @@ inline fun CoroutineScope.subscribeGroupMessages(crossinline listeners: Mess */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun CoroutineScope.subscribeFriendMessages(crossinline listeners: MessageSubscribersBuilder.() -> R): R { +inline fun CoroutineScope.subscribeFriendMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder.() -> R +): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } return MessageSubscribersBuilder { listener -> - subscribeAlways { + subscribeAlways(coroutineContext) { listener(this, this.message.toString()) } }.run(listeners) @@ -92,12 +103,15 @@ inline fun CoroutineScope.subscribeFriendMessages(crossinline listeners: Mes */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun Bot.subscribeMessages(crossinline listeners: MessageSubscribersBuilder>.() -> R): R { +inline fun Bot.subscribeMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder>.() -> R +): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } return MessageSubscribersBuilder> { listener -> - this.subscribeAlways { + this.subscribeAlways(coroutineContext) { listener(this, this.message.toString()) } }.run(listeners) @@ -106,16 +120,21 @@ inline fun Bot.subscribeMessages(crossinline listeners: MessageSubscribersBu /** * 订阅来自这个 [Bot] 的所有群消息事件 * + * @param coroutineContext 给事件监听协程的额外的 [CoroutineContext] + * * @see CoroutineScope.incoming */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun Bot.subscribeGroupMessages(crossinline listeners: MessageSubscribersBuilder.() -> R): R { +inline fun Bot.subscribeGroupMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder.() -> R +): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } return MessageSubscribersBuilder { listener -> - this.subscribeAlways { + this.subscribeAlways(coroutineContext) { listener(this, this.message.toString()) } }.run(listeners) @@ -128,12 +147,15 @@ inline fun Bot.subscribeGroupMessages(crossinline listeners: MessageSubscrib */ @UseExperimental(ExperimentalContracts::class) @MessageDsl -inline fun Bot.subscribeFriendMessages(crossinline listeners: MessageSubscribersBuilder.() -> R): R { +inline fun Bot.subscribeFriendMessages( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + crossinline listeners: MessageSubscribersBuilder.() -> R +): R { contract { callsInPlace(listeners, InvocationKind.EXACTLY_ONCE) } return MessageSubscribersBuilder { listener -> - this.subscribeAlways { + this.subscribeAlways(coroutineContext) { listener(this, this.message.toString()) } }.run(listeners) @@ -148,9 +170,12 @@ inline fun Bot.subscribeFriendMessages(crossinline listeners: MessageSubscri * @see subscribeMessages * @see subscribeGroupMessages */ -inline fun CoroutineScope.incoming(capacity: Int = Channel.RENDEZVOUS): ReceiveChannel { +inline fun CoroutineScope.incoming( + coroutineContext: CoroutineContext = EmptyCoroutineContext, + capacity: Int = Channel.RENDEZVOUS +): ReceiveChannel { return Channel(capacity).apply { - subscribeAlways { + subscribeAlways(coroutineContext) { send(this) } } From 3a45832270c61d8ba1ce5461739844c58c593293 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 18:16:00 +0800 Subject: [PATCH 085/111] http event with bug --- .../net/mamoe/mirai/api/http/Session.kt | 8 ++-- .../common/{EventDTO.kt => BotEventDTO.kt} | 0 .../mirai/api/http/data/common/MessageDTO.kt | 2 +- .../mirai/api/http/queue/MessageQueue.kt | 8 ++-- .../net/mamoe/mirai/api/http/util/Json.kt | 37 ++++++++++++++++++- 5 files changed, 45 insertions(+), 10 deletions(-) rename mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/{EventDTO.kt => BotEventDTO.kt} (100%) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt index fda1a0395..32f7aeeb4 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/Session.kt @@ -13,6 +13,8 @@ import kotlinx.coroutines.* import net.mamoe.mirai.Bot import net.mamoe.mirai.api.http.queue.MessageQueue import net.mamoe.mirai.event.Listener +import net.mamoe.mirai.event.events.BotEvent +import net.mamoe.mirai.event.subscribeAlways import net.mamoe.mirai.event.subscribeMessages import net.mamoe.mirai.message.MessagePacket import kotlin.coroutines.CoroutineContext @@ -102,12 +104,10 @@ class TempSession internal constructor(coroutineContext: CoroutineContext) : Ses class AuthedSession internal constructor(val bot: Bot, coroutineContext: CoroutineContext) : Session(coroutineContext) { val messageQueue = MessageQueue() - private val _listener: Listener> + private val _listener: Listener init { - bot.subscribeMessages { - _listener = always { this.run(messageQueue::add) } // this aka messagePacket - } + _listener = bot.subscribeAlways{ this.run(messageQueue::add) } } override fun close() { diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt similarity index 100% rename from mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/EventDTO.kt rename to mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt 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 b1c9cba48..beaa2a7d2 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 @@ -66,7 +66,7 @@ data class UnknownMessageDTO(val text: String) : MessageDTO() * Abstract Class * */ @Serializable -sealed class MessagePacketDTO : DTO { +sealed class MessagePacketDTO : EventDTO() { lateinit var messageChain : MessageChainDTO } 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 e3a1637ef..873498dba 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,20 +9,20 @@ package net.mamoe.mirai.api.http.queue +import net.mamoe.mirai.event.events.BotEvent 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>() { +class MessageQueue : ConcurrentLinkedDeque() { val quoteCache = ConcurrentHashMap() - fun fetch(size: Int): List> { + fun fetch(size: Int): List { var count = size quoteCache.clear() - val ret = ArrayList>(count) + val ret = ArrayList(count) while (!this.isEmpty() && count-- > 0) { val packet = pop() ret.add(packet) 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 e46fbb1f5..90cdce053 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,7 +13,6 @@ 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) @@ -45,11 +44,47 @@ else MiraiJson.json.stringify(serializer, this) */ object MiraiJson { val json = Json(context = SerializersModule { + + polymorphic(EventDTO.serializer()) { + BotEventDTO::class with BotEventDTO.serializer() + MessagePacketDTO::class with MessagePacketDTO.serializer() + } + + polymorphic(MessagePacketDTO.serializer()) { GroupMessagePacketDTO::class with GroupMessagePacketDTO.serializer() FriendMessagePacketDTO::class with FriendMessagePacketDTO.serializer() UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer() } + + // Bot Event Polymorphic + polymorphic(BotEventDTO.serializer()) { + BotOnlineEventDTO::class with BotOnlineEventDTO.serializer() + BotOfflineEventActiveDTO::class with BotOfflineEventActiveDTO.serializer() + BotOfflineEventForceDTO::class with BotOfflineEventForceDTO.serializer() + BotOfflineEventDroppedDTO::class with BotOfflineEventDroppedDTO.serializer() + BotReloginEventDTO::class with BotReloginEventDTO.serializer() + BotGroupPermissionChangeEventDTO::class with BotGroupPermissionChangeEventDTO.serializer() + BotMuteEventDTO::class with BotMuteEventDTO.serializer() + BotUnmuteEventDTO::class with BotUnmuteEventDTO.serializer() + BotJoinGroupEventDTO::class with BotJoinGroupEventDTO.serializer() + GroupNameChangeEventDTO::class with GroupNameChangeEventDTO.serializer() + GroupEntranceAnnouncementChangeEventDTO::class with GroupEntranceAnnouncementChangeEventDTO.serializer() + GroupMuteAllEventDTO::class with GroupMuteAllEventDTO.serializer() + GroupAllowAnonymousChatEventDTO::class with GroupAllowAnonymousChatEventDTO.serializer() + GroupAllowConfessTalkEventDTO::class with GroupAllowConfessTalkEventDTO.serializer() + GroupAllowMemberInviteEventDTO::class with GroupAllowMemberInviteEventDTO.serializer() + MemberJoinEventDTO::class with MemberJoinEventDTO.serializer() + MemberLeaveEventKickDTO::class with MemberLeaveEventKickDTO.serializer() + MemberLeaveEventQuitDTO::class with MemberLeaveEventQuitDTO.serializer() + MemberCardChangeEventDTO::class with MemberCardChangeEventDTO.serializer() + MemberSpecialTitleChangeEventDTO::class with MemberSpecialTitleChangeEventDTO.serializer() + MemberPermissionChangeEventDTO::class with MemberPermissionChangeEventDTO.serializer() + MemberMuteEventDTO::class with MemberMuteEventDTO.serializer() + MemberUnmuteEventDTO::class with MemberUnmuteEventDTO.serializer() + } + + // Message Polymorphic polymorphic(MessageDTO.serializer()) { MessageSourceDTO::class with MessageSourceDTO.serializer() AtDTO::class with AtDTO.serializer() From f7ab3b2608ed87bc081a131890c092bfa9a19116 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 19:01:32 +0800 Subject: [PATCH 086/111] http api fix Polymorphic --- .../mirai/api/http/data/common/BotEventDTO.kt | 2 +- .../mamoe/mirai/api/http/data/common/DTO.kt | 2 +- .../net/mamoe/mirai/api/http/util/Json.kt | 29 +++++++------------ 3 files changed, 12 insertions(+), 21 deletions(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt index 8cf70edad..675a510d7 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt @@ -9,7 +9,7 @@ import net.mamoe.mirai.message.MessagePacket import net.mamoe.mirai.utils.MiraiExperimentalAPI @Serializable -open class BotEventDTO : EventDTO() +sealed class BotEventDTO : EventDTO() @UseExperimental(MiraiExperimentalAPI::class) fun BotEvent.toDTO() = when(this) { diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt index 7c1d62daf..c6339a200 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/DTO.kt @@ -17,6 +17,6 @@ abstract class VerifyDTO : DTO { } @Serializable -open class EventDTO : DTO +abstract class EventDTO : DTO object IgnoreEventDTO : EventDTO() \ No newline at end of file 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 90cdce053..e6f50776d 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 @@ -46,19 +46,10 @@ object MiraiJson { val json = Json(context = SerializersModule { polymorphic(EventDTO.serializer()) { - BotEventDTO::class with BotEventDTO.serializer() - MessagePacketDTO::class with MessagePacketDTO.serializer() - } - - - polymorphic(MessagePacketDTO.serializer()) { GroupMessagePacketDTO::class with GroupMessagePacketDTO.serializer() FriendMessagePacketDTO::class with FriendMessagePacketDTO.serializer() UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer() - } - // Bot Event Polymorphic - polymorphic(BotEventDTO.serializer()) { BotOnlineEventDTO::class with BotOnlineEventDTO.serializer() BotOfflineEventActiveDTO::class with BotOfflineEventActiveDTO.serializer() BotOfflineEventForceDTO::class with BotOfflineEventForceDTO.serializer() @@ -85,15 +76,15 @@ object MiraiJson { } // Message Polymorphic - polymorphic(MessageDTO.serializer()) { - MessageSourceDTO::class with MessageSourceDTO.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() - XmlDTO::class with XmlDTO.serializer() - UnknownMessageDTO::class with UnknownMessageDTO.serializer() - } +// polymorphic(MessageDTO.serializer()) { +// MessageSourceDTO::class with MessageSourceDTO.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() +// XmlDTO::class with XmlDTO.serializer() +// UnknownMessageDTO::class with UnknownMessageDTO.serializer() +// } }) } \ No newline at end of file From 47601918e2b1e27f819ce5ceb23d99493e895434 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 19:17:29 +0800 Subject: [PATCH 087/111] Add IgnoreEventDTO remove UnknownMessagePacketDTO --- .../mirai/api/http/data/common/MessageDTO.kt | 24 ++++++++++++------- .../net/mamoe/mirai/api/http/util/Json.kt | 1 - 2 files changed, 15 insertions(+), 10 deletions(-) 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 beaa2a7d2..61ebc46f8 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 @@ -32,32 +32,36 @@ data class FriendMessagePacketDTO(val sender: QQDTO) : MessagePacketDTO() @SerialName("GroupMessage") data class GroupMessagePacketDTO(val sender: MemberDTO) : MessagePacketDTO() -@Serializable -@SerialName("UnKnownMessage") -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 @SerialName("AtAll") data class AtAllDTO(val target: Long = 0) : MessageDTO() // target为保留字段 + @Serializable @SerialName("Face") data class FaceDTO(val faceId: Int) : MessageDTO() + @Serializable @SerialName("Plain") data class PlainDTO(val text: String) : MessageDTO() + @Serializable @SerialName("Image") data class ImageDTO(val imageId: String) : MessageDTO() + @Serializable @SerialName("Xml") data class XmlDTO(val xml: String) : MessageDTO() + @Serializable @SerialName("Unknown") data class UnknownMessageDTO(val text: String) : MessageDTO() @@ -67,7 +71,7 @@ data class UnknownMessageDTO(val text: String) : MessageDTO() * */ @Serializable sealed class MessagePacketDTO : EventDTO() { - lateinit var messageChain : MessageChainDTO + lateinit var messageChain: MessageChainDTO } typealias MessageChainDTO = List @@ -79,11 +83,15 @@ sealed class MessageDTO : DTO /* Extend function */ -fun MessagePacket<*, *>.toDTO(): MessagePacketDTO = when (this) { +fun MessagePacket<*, *>.toDTO() = when (this) { is FriendMessage -> FriendMessagePacketDTO(QQDTO(sender)) is GroupMessage -> GroupMessagePacketDTO(MemberDTO(sender)) - else -> UnKnownMessagePacketDTO("UnKnown Message Packet") -}.apply { messageChain = mutableListOf().also{ ls -> message.foreachContent { ls.add(it.toDTO()) }}} + else -> IgnoreEventDTO +}.apply { + if (this is MessagePacketDTO) { + messageChain = mutableListOf().also { ls -> message.foreachContent { ls.add(it.toDTO()) } } + } +} fun MessageChainDTO.toMessageChain(contact: Contact) = MessageChain().apply { this@toMessageChain.forEach { add(it.toMessage(contact)) } } @@ -111,5 +119,3 @@ fun MessageDTO.toMessage(contact: Contact) = when (this) { is MessageSourceDTO, is UnknownMessageDTO -> PlainText("assert cannot reach") } - - 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 e6f50776d..7769a411e 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 @@ -48,7 +48,6 @@ object MiraiJson { polymorphic(EventDTO.serializer()) { GroupMessagePacketDTO::class with GroupMessagePacketDTO.serializer() FriendMessagePacketDTO::class with FriendMessagePacketDTO.serializer() - UnKnownMessagePacketDTO::class with UnKnownMessagePacketDTO.serializer() BotOnlineEventDTO::class with BotOnlineEventDTO.serializer() BotOfflineEventActiveDTO::class with BotOfflineEventActiveDTO.serializer() From d9692c3b0f87089daab9995b3bb78dfe7e5465b2 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 19:34:21 +0800 Subject: [PATCH 088/111] ignore IgnoreEventDTO from fetch list --- .../mirai/api/http/queue/MessageQueue.kt | 23 +++++++++++++------ .../api/http/route/SendMessageRouteModule.kt | 3 +-- 2 files changed, 17 insertions(+), 9 deletions(-) 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 873498dba..eee8f85de 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,6 +9,9 @@ package net.mamoe.mirai.api.http.queue +import net.mamoe.mirai.api.http.data.common.EventDTO +import net.mamoe.mirai.api.http.data.common.IgnoreEventDTO +import net.mamoe.mirai.api.http.data.common.toDTO import net.mamoe.mirai.event.events.BotEvent import net.mamoe.mirai.message.GroupMessage import net.mamoe.mirai.message.data.MessageSource @@ -19,16 +22,22 @@ class MessageQueue : ConcurrentLinkedDeque() { val quoteCache = ConcurrentHashMap() - fun fetch(size: Int): List { + fun fetch(size: Int): List { var count = size quoteCache.clear() - val ret = ArrayList(count) - while (!this.isEmpty() && count-- > 0) { - val packet = pop() - ret.add(packet) + val ret = ArrayList(count) + while (!this.isEmpty() && count > 0) { + val event = pop() - if (packet is GroupMessage) { - addCache(packet) + event.toDTO().also { + if (it != IgnoreEventDTO) { + ret.add(it) + count-- + } + } + + if (event is GroupMessage) { + addCache(event) } } return ret 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 b6d34549e..be9be7b03 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 @@ -37,9 +37,8 @@ fun Application.messageModule() { miraiGet("/fetchMessage") { val count: Int = paramOrNull("count") val fetch = it.messageQueue.fetch(count) - val ls = Array(fetch.size) { index -> fetch[index].toDTO() } - call.respondJson(ls.toList().toJson()) + call.respondJson(fetch.toJson()) } miraiVerify("/sendFriendMessage") { From 538980b6d7aa521155ca292208deca47b82f9a69 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 19:50:51 +0800 Subject: [PATCH 089/111] Add version --- docs/guide_getting_started.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index cafb3440a..3111dcd47 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -51,12 +51,12 @@ JDK要求8以上 } ``` -- 添加依赖,将dependencies部分覆盖为 +- 添加依赖,将dependencies部分覆盖为: + `mirai-core` 的最新版本为: [![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) ```groovy dependencies { - implementation 'net.mamoe:mirai-core:0.16.0' - implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.16.0' + implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.17.0' // 替换成最新版本号 implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testCompile group: 'junit', name: 'junit', version: '4.12' } From a2c352d11129813004cf5aa197f86e73038bfa9a Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 19:52:34 +0800 Subject: [PATCH 090/111] Gradle 6.2 --- 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 3dbe6db2a..6768581dc 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-6.1.1-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.2-all.zip distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStorePath=wrapper/dists From c09d0086ec4142733b6f477e02e7b23c27640342 Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 20:01:12 +0800 Subject: [PATCH 091/111] Update guide --- docs/guide_getting_started.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index cafb3440a..05d3b4cfa 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -1,18 +1,22 @@ # Mirai Guide - Getting Started -由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.16.0``` +由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.17.0``` 假如仅仅使用Mirai,不需要对整个项目进行Clone,只需在项目内添加Gradle Dependency或使用即可。 下面介绍详细的入门步骤。 -## With Console +本文章使用Kotlin作为开发语言。**若你希望使用 Java 开发**, 请查看: [mirai-japt](mirai-japt/README.md) + +## Use Console 使用mirai-console,以插件形式对服务器功能进行管理,启动无需任何IDE。 -**由于mirai-console还没有开发完成,暂时不提供入门** +**由于mirai-console还没有开发完成,暂时不提供入门。** -## With Loader +*假如需要体验mirai-console,请clone整个项目,自行进行编译与部署。 + +## Use Loader 通过编写Kotlin程序启动mirai-core,并定义你的Mirai Bot行为。 @@ -55,8 +59,8 @@ JDK要求8以上 ```groovy dependencies { - implementation 'net.mamoe:mirai-core:0.16.0' - implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.16.0' + implementation 'net.mamoe:mirai-core:0.17.0' + implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.17.0' implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testCompile group: 'junit', name: 'junit', version: '4.12' } @@ -68,7 +72,7 @@ JDK要求8以上 ### 4 Try Bot - 在src/main文件夹下新建文件夹,命名为```kotlin``` -- 在```kotlin```下新建包(在```kotlin```文件夹上右键-```New```-```Packages```) 包名为```net.mamoe.mirai.simpleloader``` +- 在```kotlin```下新建包(在```kotlin```文件夹上右键-```New```-```Package```) 包名为```net.mamoe.mirai.simpleloader``` - 在包下新建kotlin文件```MyLoader.kt``` From 954468de1a572686ec8501176074c08ecd635a44 Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 20:58:40 +0800 Subject: [PATCH 092/111] Update readme & guide --- README.md | 149 +++++++++++----------------------- docs/guide_getting_started.md | 36 ++++++-- docs/guide_quick_start.md | 114 ++++++++++++++++++++++++++ 3 files changed, 192 insertions(+), 107 deletions(-) create mode 100644 docs/guide_quick_start.md diff --git a/README.md b/README.md index 4e77e9bca..553371a4f 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,12 @@

## Mirai + **[English](README-eng.md)** 多平台 **QQ Android 和 TimPC** 协议支持库与高效率的机器人框架. @@ -27,94 +32,59 @@ Mirai既可以作为你项目中的QQ协议支持Lib, 也可以作为单独的Ap 加入 Gitter, 或加入 QQ 群: 655057127 + + +## 开始使用Mirai + +Mirai支持以多种方式进行部署,但是目前,我们在集中对mirai-core,mirai-japt以及mirai-api-http等核心模块进行特性的开发,对于非开发者的使用暂时不做过多支持,仅展示开发计划。 + +### 开发者 + +- 假如你熟悉Kotlin及包管理工具,请参阅[Mirai Guide - Quick Start](/docs/guide_quick_start.md) +- 假如你不熟悉Kotlin,希望一份较详细的起步教程,请参阅[Mitai Guide - Getting Started](/docs/guide_getting_started.md) +- 假如你使用Java作为开发语言,请参阅[mirai-japt](/mirai-japt/README.md) +- 假如你是其他平台开发者,可以通过了解 [mirai-api-http](https://github.com/mamoe/mirai/tree/master/mirai-api-http) 进行接入,欢迎开发不同平台的mirai-sdk +- 此外,你还可以在 [Wiki](https://github.com/mamoe/mirai/wiki/Home) 中查看各类帮助,**如 API 示例**。 + +### 使用者 + +- [mirai-console](https://github.com/mamoe/mirai/tree/master/mirai-console) 支持插件, 在终端中启动 Mirai 并获得机器人服务,**本模块还未完善**,请耐心等待开发完成。 +- Mirai-WebPenel 支持Web控制台,以网页形式管理机器人。本模块在计划中,在其他模块稳定后即将开启开发。 + + + ## CHANGELOG + 在 [Project](https://github.com/mamoe/mirai/projects/3) 查看已支持功能和计划 在 [CHANGELOG](https://github.com/mamoe/mirai/blob/master/CHANGELOG.md) 查看版本更新记录 (仅发布的版本) + + ## Modules + ### mirai-core + 通用 API 模块,一套 API 适配两套协议。 **请参考此模块的 API** - + ### mirai-core-qqandroid + QQ for Android (8.2.0 版本,2019 年 12 月)协议的实现,目前完成大部分。 + - 高兼容性:协议仅含极少部分为硬编码,其余全部随官方方式动态生成 - 高安全性:密匙随机,ECDH 动态计算 - 已支持大部分使用场景, 详情请在[Project](https://github.com/mamoe/mirai/projects/3)查看 ### mirai-core-timpc + TIM PC (2.3.2 版本,2019 年 8 月)协议的实现 支持的功能: + - 消息收发:图片文字复合消息,图片消息 - 群管功能:群员列表,禁言 -(目前不再更新此协议,请关注上文的安卓协议) + (目前不再更新此协议,请关注上文的安卓协议) -## Use directly -**直接使用 Mirai(终端环境/网页面板(将来)).** -[Mirai-Console](https://github.com/mamoe/mirai/tree/master/mirai-console) 插件支持, 在终端中启动 Mirai 并获得机器人服务 -本模块还未完善。 -## Use as a library -**mirai-core 为独立设计, 可以作为库内置于任意 Java(JVM)/Android 项目中使用.** - -请将 `VERSION` 替换为最新的版本(如 `0.15.0`): -[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) -**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.** - -### Maven -Kotlin 在 Maven 上只支持 JVM 平台. -```xml - - - jcenter - https://jcenter.bintray.com/ - - -``` -```xml - - - net.mamoe - mirai-core-qqandroid-jvm - 0.15.1 - - -``` - -### Gradle -Mirai 只发布在 `jcenter`, 因此请确保添加 `jcenter()` 仓库: -```kotlin -repositories{ - jcenter() -} -``` -若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关多平台库的依赖是类似的。 -**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖.** - -**注意:** -Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。 -只添加 API 模块将无法正常工作。 -现在只推荐使用 QQAndroid 协议,请参照下文选择对应目标平台的依赖添加。 - -**jvm** (JVM 平台) -```kotlin -implementation("net.mamoe:mirai-core-qqandroid-jvm:VERSION") -``` -**common** (通用平台) -```kotlin -implementation("net.mamoe:mirai-core-qqandroid-common:VERSION") -``` -**android** (Android 平台) -```kotlin -implementation("net.mamoe:mirai-core-qqandroid-android:VERSION") -``` - -## Java Compatibility -**若你希望使用 Java 开发**, 请查看: [mirai-japt](mirai-japt/README.md) - -### Performance -Android 上, Mirai 运行需使用 80M 内存. -JVM 上启动需 80M 内存, 每多一个机器人实例需要 30M 内存. ## Contribution @@ -125,41 +95,12 @@ JVM 上启动需 80M 内存, 每多一个机器人实例需要 30M 内存. 您的 star 是对我们最大的鼓励(点击项目右上角) -## Wiki -在 [Wiki](https://github.com/mamoe/mirai/wiki/Home) 中查看各类帮助,**如 API 示例**。 - -## Try - -### On JVM or Android -现在体验低付出高效率的 Mirai - -```kotlin -val bot = Bot(qqId, password).alsoLogin() -bot.subscribeMessages { - "你好" reply "你好!" - "profile" reply { sender.queryProfile() } - contains("图片"){ File(imagePath).send() } -} -bot.subscribeAlways { - if (it.kind == BECOME_OPERATOR) - reply("${it.member.id} 成为了管理员") -} -``` - -1. Clone -2. Import as Gradle project -3. 运行 Demo 程序: [mirai-demo](#mirai-demo) 示例和演示程序 -## Build Requirements +## Libraries used -- Kotlin 1.3.61 -- JDK 8 (required) -- JDK 11(for protocol tools, optional) -- Android SDK 29 (for Android target, optional) - -#### Libraries used 感谢: + - [kotlin-stdlib](https://github.com/JetBrains/kotlin) - [kotlinx-coroutines](https://github.com/Kotlin/kotlinx.coroutines) - [kotlinx-io](https://github.com/Kotlin/kotlinx-io) @@ -176,15 +117,21 @@ bot.subscribeAlways { - [toml4j](https://github.com/mwanji/toml4j) - [snakeyaml](https://mvnrepository.com/artifact/org.yaml/snakeyaml) + + ## License + 协议原版权归属腾讯科技股份有限公司所有,本项目其他代码遵守: **GNU AFFERO GENERAL PUBLIC LICENSE version 3** 其中部分要求: + - (见 LICENSE 第 13 节) 尽管本许可协议有其他规定,但如果您修改本程序,则修改后的版本必须显着地为所有通过计算机网络与它进行远程交互的用户(如果您的版本支持这种交互)提供从网络服务器通过一些标准或惯用的软件复制方法**免费**访问相应的**源代码**的机会 - (见 LICENSE 第 4 节) 您可以免费或收费地传递这个项目的源代码或目标代码(即编译结果), **但前提是提供明显的版权声明** (您需要标注本 `GitHub` 项目地址) + + ## Acknowledgement + 特别感谢 [JetBrains](https://www.jetbrains.com/?from=mirai) 为开源项目提供免费的 [IntelliJ IDEA](https://www.jetbrains.com/idea/?from=mirai) 等 IDE 的授权 -[](https://www.jetbrains.com/?from=mirai) - +[](https://www.jetbrains.com/?from=mirai) \ No newline at end of file diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index cafb3440a..9cfb25ffd 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -1,18 +1,20 @@ # Mirai Guide - Getting Started -由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.16.0``` +由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.17.0``` 假如仅仅使用Mirai,不需要对整个项目进行Clone,只需在项目内添加Gradle Dependency或使用即可。 下面介绍详细的入门步骤。 -## With Console +本页采用Kotlin作为开发语言,**若你希望使用 Java 开发**, 请参阅: [mirai-japt](mirai-japt/README.md) + +## Use Console 使用mirai-console,以插件形式对服务器功能进行管理,启动无需任何IDE。 **由于mirai-console还没有开发完成,暂时不提供入门** -## With Loader +## Use Loader 通过编写Kotlin程序启动mirai-core,并定义你的Mirai Bot行为。 @@ -51,12 +53,11 @@ JDK要求8以上 } ``` -- 添加依赖,将dependencies部分覆盖为 +- 添加依赖,将dependencies部分覆盖 `mirai-core` 的最新版本为: [![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) ```groovy dependencies { - implementation 'net.mamoe:mirai-core:0.16.0' - implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.16.0' + implementation 'net.mamoe:mirai-core-qqandroid-jvm:0.17.0'//此处版本应替换为当前最新 implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" testCompile group: 'junit', name: 'junit', version: '4.12' } @@ -104,3 +105,26 @@ suspend fun main() { 至此,简单的入门已经结束,下面可根据不同的需求参阅wiki进行功能的添加。 + + +### 此外,还可以使用Maven作为包管理工具 +本项目推荐使用gradle,因此不提供详细入门指导 + +Kotlin 在 Maven 上只支持 JVM 平台. +```xml + + + jcenter + https://jcenter.bintray.com/ + + +``` +```xml + + + net.mamoe + mirai-core-qqandroid-jvm + 0.17.0 + + +``` \ No newline at end of file diff --git a/docs/guide_quick_start.md b/docs/guide_quick_start.md new file mode 100644 index 000000000..edd3eeadb --- /dev/null +++ b/docs/guide_quick_start.md @@ -0,0 +1,114 @@ +# Mirai Guide - Quick Start + +由于Mirai项目在快速推进中,因此内容时有变动,本文档的最后更新日期为```2020-02-20```,对应版本```0.17.0``` + +本文适用于对kotlin较熟悉的开发者 + +**若你希望一份更为基础且详细的guide**, 请参阅: [mirai-guide-getting-started](guide_getting_started.md) + +**若你希望使用 Java 开发**, 请参阅: [mirai-japt](/mirai-japt/README.md) + +## Build Requirements + +- Kotlin 1.3.61 +- JDK 8 (required) +- JDK 11(for protocol tools, optional) +- Android SDK 29 (for Android target, optional) + +## Use directly + +**直接使用 Mirai(终端环境/网页面板(将来)).** +[Mirai-Console](https://github.com/mamoe/mirai/tree/master/mirai-console) 插件支持, 在终端中启动 Mirai 并获得机器人服务 +本模块还未完善。 + +## Use as a library + +**mirai-core 为独立设计, 可以作为库内置于任意 Java(JVM)/Android 项目中使用.** + +请将 `VERSION` 替换为最新的版本(如 `0.15.0`): +[![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) +**Mirai 目前还处于实验性阶段, 我们无法保证任何稳定性, API 也可能会随时修改.** + +### Maven + +Kotlin 在 Maven 上只支持 JVM 平台. + +```xml + + + jcenter + https://jcenter.bintray.com/ + + +``` + +```xml + + + net.mamoe + mirai-core-qqandroid-jvm + 0.15.1 + + +``` + +### Gradle + +Mirai 只发布在 `jcenter`, 因此请确保添加 `jcenter()` 仓库: + +```kotlin +repositories{ + jcenter() +} +``` + +若您需要使用在跨平台项目, 则要对各个目标平台添加不同的依赖,这与 kotlin 相关多平台库的依赖是类似的。 +**若您只需要使用在单一平台, 则只需要添加一项该平台的依赖.** + +**注意:** +Mirai 核心由 API 模块(`mirai-core`)和协议模块组成。 +只添加 API 模块将无法正常工作。 +现在只推荐使用 QQAndroid 协议,请参照下文选择对应目标平台的依赖添加。 + +**jvm** (JVM 平台) + +```kotlin +implementation("net.mamoe:mirai-core-qqandroid-jvm:VERSION") +``` + +**common** (通用平台) + +```kotlin +implementation("net.mamoe:mirai-core-qqandroid-common:VERSION") +``` + +**android** (Android 平台) + +```kotlin +implementation("net.mamoe:mirai-core-qqandroid-android:VERSION") +``` + +## Try + +### On JVM or Android + +现在体验低付出高效率的 Mirai + +```kotlin +val bot = Bot(qqId, password).alsoLogin() +bot.subscribeMessages { + "你好" reply "你好!" + "profile" reply { sender.queryProfile() } + contains("图片"){ File(imagePath).send() } +} +bot.subscribeAlways { + if (it.kind == BECOME_OPERATOR) + reply("${it.member.id} 成为了管理员") +} +``` + +### Performance + +Android 上, Mirai 运行需使用 80M 内存. +JVM 上启动需 80M 内存, 每多一个机器人实例需要 30M 内存. + From d6e94f9d3a1c2e1dfdd24d2701c6fecd5b32224f Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 21:00:45 +0800 Subject: [PATCH 093/111] Fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 553371a4f..d7159d9ba 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ Mirai支持以多种方式进行部署,但是目前,我们在集中对mirai- ### 开发者 - 假如你熟悉Kotlin及包管理工具,请参阅[Mirai Guide - Quick Start](/docs/guide_quick_start.md) -- 假如你不熟悉Kotlin,希望一份较详细的起步教程,请参阅[Mitai Guide - Getting Started](/docs/guide_getting_started.md) +- 假如你不熟悉Kotlin,希望一份较详细的起步教程,请参阅[Mirai Guide - Getting Started](/docs/guide_getting_started.md) - 假如你使用Java作为开发语言,请参阅[mirai-japt](/mirai-japt/README.md) - 假如你是其他平台开发者,可以通过了解 [mirai-api-http](https://github.com/mamoe/mirai/tree/master/mirai-api-http) 进行接入,欢迎开发不同平台的mirai-sdk - 此外,你还可以在 [Wiki](https://github.com/mamoe/mirai/wiki/Home) 中查看各类帮助,**如 API 示例**。 From 492215aa65c83d1295058af63db6ae9c6c285ae9 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:03:13 +0800 Subject: [PATCH 094/111] Update guide_quick_start.md --- docs/guide_quick_start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide_quick_start.md b/docs/guide_quick_start.md index edd3eeadb..4602ba6e3 100644 --- a/docs/guide_quick_start.md +++ b/docs/guide_quick_start.md @@ -11,7 +11,7 @@ ## Build Requirements - Kotlin 1.3.61 -- JDK 8 (required) +- JDK 6 (required) - JDK 11(for protocol tools, optional) - Android SDK 29 (for Android target, optional) From abc2c83d8059ad205771921408996cf75997d170 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:04:18 +0800 Subject: [PATCH 095/111] Update guide_getting_started.md --- docs/guide_getting_started.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index 9cfb25ffd..c529d76cb 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -22,7 +22,7 @@ ### 1 安装IDEA与JDK -JDK要求8以上 +JDK要求6以上 ### 2 新建Gradle项目 @@ -127,4 +127,4 @@ Kotlin 在 Maven 上只支持 JVM 平台. 0.17.0
-``` \ No newline at end of file +``` From 69bb4232d26e41e3277caa96c0343aa165f26f16 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:06:30 +0800 Subject: [PATCH 096/111] Update guide_getting_started.md --- docs/guide_getting_started.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/docs/guide_getting_started.md b/docs/guide_getting_started.md index c529d76cb..3cd88b1db 100644 --- a/docs/guide_getting_started.md +++ b/docs/guide_getting_started.md @@ -53,7 +53,7 @@ JDK要求6以上 } ``` -- 添加依赖,将dependencies部分覆盖 `mirai-core` 的最新版本为: [![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) +- 添加依赖,将dependencies部分覆盖。 `mirai-core` 的最新版本为: [![Download](https://api.bintray.com/packages/him188moe/mirai/mirai-core/images/download.svg)](https://bintray.com/him188moe/mirai/mirai-core/) ```groovy dependencies { @@ -84,7 +84,7 @@ import net.mamoe.mirai.event.subscribeMessages suspend fun main() { val qqId = 10000L//Bot的QQ号,需为Long类型,在结尾处添加大写L val password = "your_password"//Bot的密码 - val miraiBot = Bot(qqId, password).alsoLogin()//新建Bot并登陆 + val miraiBot = Bot(qqId, password).alsoLogin()//新建Bot并登录 miraiBot.subscribeMessages { "你好" reply "你好!" case("at me") { @@ -95,7 +95,7 @@ suspend fun main() { "刘老板太强了".reply() } } - miraiBot.join() + miraiBot.join() // 等待 Bot 离线, 避免主线程退出 } ``` @@ -110,7 +110,6 @@ suspend fun main() { ### 此外,还可以使用Maven作为包管理工具 本项目推荐使用gradle,因此不提供详细入门指导 -Kotlin 在 Maven 上只支持 JVM 平台. ```xml From d48c60df24f443fde7fc8e0fbce3095244ccb0f7 Mon Sep 17 00:00:00 2001 From: jasonczc Date: Thu, 20 Feb 2020 21:09:49 +0800 Subject: [PATCH 097/111] Fix readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7159d9ba..cbc1fe1a0 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,7 @@ Mirai支持以多种方式进行部署,但是目前,我们在集中对mirai- ### 使用者 - [mirai-console](https://github.com/mamoe/mirai/tree/master/mirai-console) 支持插件, 在终端中启动 Mirai 并获得机器人服务,**本模块还未完善**,请耐心等待开发完成。 -- Mirai-WebPenel 支持Web控制台,以网页形式管理机器人。本模块在计划中,在其他模块稳定后即将开启开发。 +- mirai-webpanel Mirai的Web控制台,支持在网页中管理机器人与插件。本模块目前在计划中。在其他模块稳定后,将开始进行开发。 From 45c6c4dbfae68d14742535957fb095fc5a4fb1e7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:19:59 +0800 Subject: [PATCH 098/111] Adapt for concurrent events --- .../packet/chat/receive/OnlinePush.kt | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 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 50e91ef90..88f8db929 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 @@ -15,6 +15,7 @@ import kotlinx.io.core.ByteReadPacket import kotlinx.io.core.readBytes import kotlinx.io.core.readUInt import net.mamoe.mirai.contact.MemberPermission +import net.mamoe.mirai.data.MultiPacket import net.mamoe.mirai.data.NoPacket import net.mamoe.mirai.data.Packet import net.mamoe.mirai.event.events.* @@ -141,10 +142,9 @@ internal class OnlinePush { @UseExperimental(ExperimentalStdlibApi::class) override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet { val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") - reqPushMsg.vMsgInfos.forEach { msgInfo: MsgInfo -> + val packets = reqPushMsg.vMsgInfos.mapNotNull { msgInfo: MsgInfo -> msgInfo.vMsg!!.read { - // TODO: 2020/2/13 可能会同时收到多个事件. 使用 map 而不要直接 return when { msgInfo.shMsgType.toInt() == 732 -> { val group = bot.getGroup(this.readUInt().toLong()) @@ -154,7 +154,7 @@ internal class OnlinePush { 3073 -> { // mute val operatorUin = this.readUInt().toLong() if (operatorUin == bot.uin) { - return NoPacket + return@mapNotNull null } val operator = group[operatorUin] this.readUInt().toLong() // time @@ -162,7 +162,7 @@ internal class OnlinePush { val target = this.readUInt().toLong() val time = this.readInt() - return if (target == 0L) { + return@mapNotNull if (target == 0L) { if (time == 0) { GroupMuteAllEvent( origin = group.isMuteAll.also { group._muteAll = false }, @@ -179,14 +179,16 @@ internal class OnlinePush { ) } } else { - return if (target == bot.uin) { - if (time == 0) { + if (target == bot.uin) { + @Suppress("IMPLICIT_CAST_TO_ANY") // false positive + return@mapNotNull if (time == 0) { BotUnmuteEvent(operator) } else BotMuteEvent(durationSeconds = time, operator = operator) } else { val member = group[target] - if (time == 0) { + @Suppress("IMPLICIT_CAST_TO_ANY") // false positive + return@mapNotNull if (time == 0) { MemberUnmuteEvent(operator = operator, member = member) } else { MemberMuteEvent(operator = operator, member = member, durationSeconds = time) @@ -197,7 +199,7 @@ internal class OnlinePush { 3585 -> { // 匿名 val operator = group[this.readUInt().toLong()] val switch = this.readInt() == 0 - return GroupAllowAnonymousChatEvent( + return@mapNotNull GroupAllowAnonymousChatEvent( origin = group.isAnonymousChatEnabled.also { group._anonymousChat = switch }, new = switch, operator = operator, @@ -210,7 +212,7 @@ internal class OnlinePush { // println(dataBytes.toUHexString()) if (dataBytes[0].toInt() != 59) { - return GroupNameChangeEvent( + return@mapNotNull GroupNameChangeEvent( origin = group.name.also { group._name = message }, new = message, group = group, @@ -220,7 +222,7 @@ internal class OnlinePush { //println(message + ":" + dataBytes.toUHexString()) when (message) { "管理员已关闭群聊坦白说" -> { - return GroupAllowConfessTalkEvent( + return@mapNotNull GroupAllowConfessTalkEvent( origin = group.isConfessTalkEnabled.also { group._confessTalk = false }, new = false, group = group, @@ -228,7 +230,7 @@ internal class OnlinePush { ) } "管理员已开启群聊坦白说" -> { - return GroupAllowConfessTalkEvent( + return@mapNotNull GroupAllowConfessTalkEvent( origin = group.isConfessTalkEnabled.also { group._confessTalk = true }, new = true, group = group, @@ -237,7 +239,7 @@ internal class OnlinePush { } else -> { bot.network.logger.debug { "Unknown server messages $message" } - return NoPacket + return@mapNotNull NoPacket } } } @@ -261,9 +263,10 @@ internal class OnlinePush { } } } + return@mapNotNull null } - return NoPacket + return MultiPacket(packets) } From 828332b7d9ad4ebfb0855cd40caf139b23d9b0e7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:31:09 +0800 Subject: [PATCH 099/111] Fix `At`, close #73 --- .../mamoe/mirai/qqandroid/message/MessageQQA.kt | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt index ef297c3b4..5d0068691 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt @@ -9,6 +9,8 @@ package net.mamoe.mirai.qqandroid.message +import kotlinx.io.core.buildPacket +import kotlinx.io.core.readBytes import kotlinx.io.core.readUInt import net.mamoe.mirai.message.data.* import net.mamoe.mirai.qqandroid.network.protocol.data.proto.ImMsgBody @@ -20,13 +22,18 @@ import net.mamoe.mirai.utils.io.hexToBytes import net.mamoe.mirai.utils.io.read import net.mamoe.mirai.utils.io.toByteArray -private val AT_BUF_1 = byteArrayOf(0x00, 0x01, 0x00, 0x00, 0x00, 0x07, 0x00) // groupCard = 0x07; nick = 0x0A -private val AT_BUF_2 = ByteArray(2) - internal fun At.toJceData(): ImMsgBody.Text { + val text = this.toString() return ImMsgBody.Text( - str = this.toString(), - attr6Buf = AT_BUF_1 + this.target.toInt().toByteArray() + AT_BUF_2 + str = text, + attr6Buf = buildPacket { + writeShort(1) + writeShort(0) + writeShort(text.length.toShort()) + writeByte(1) + writeInt(target.toInt()) + writeShort(0) + }.readBytes() ) } From 48682f3090f714c2c4fc9a2cd1c197ae831192a6 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:33:52 +0800 Subject: [PATCH 100/111] correct filename --- .../mamoe/mirai/qqandroid/message/{MessageQQA.kt => messages.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/{MessageQQA.kt => messages.kt} (100%) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt similarity index 100% rename from mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/MessageQQA.kt rename to mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/message/messages.kt From 9437d1528d8681f980613527e15bbfadc8607fe2 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:42:20 +0800 Subject: [PATCH 101/111] Unified relogin cause --- .../qqandroid/network/QQAndroidBotNetworkHandler.kt | 12 ++++++------ .../src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 2 +- .../kotlin/net.mamoe.mirai/event/events/BotEvents.kt | 2 +- .../net.mamoe.mirai/network/BotNetworkHandler.kt | 2 +- 4 files changed, 9 insertions(+), 9 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 af8165357..4746a5fff 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 @@ -76,7 +76,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler return@launch } catch (e: Throwable) { if (this@QQAndroidBotNetworkHandler.isActive) { - BotOfflineEvent.Dropped(bot).broadcast() + BotOfflineEvent.Dropped(bot, e).broadcast() } return@launch } @@ -96,15 +96,15 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler val failException = doHeartBeat() if (failException != null) { delay(bot.configuration.firstReconnectDelayMillis) - close() - BotOfflineEvent.Dropped(bot).broadcast() + close(failException) + BotOfflineEvent.Dropped(bot, failException).broadcast() } } }.also { heartbeatJob = it } } - override suspend fun relogin() { - heartbeatJob?.cancel(CancellationException("relogin")) + override suspend fun relogin(cause: Throwable?) { + heartbeatJob?.cancel(CancellationException("relogin", cause)) if (::channel.isInitialized) { if (channel.isOpen) { kotlin.runCatching { @@ -119,7 +119,7 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler withTimeoutOrNull(3000) { channel.connect("113.96.13.208", 8080) } ?: error("timeout connecting server") - startPacketReceiverJobOrKill(CancellationException("reconnect")) + startPacketReceiverJobOrKill(CancellationException("relogin", cause)) var response: WtLogin.Login.LoginPacketResponse = WtLogin.Login.SubCommand9(bot.client).sendAndExpect() mainloop@ while (true) { 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 66ffdd235..4f6fc0f8a 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -92,7 +92,7 @@ abstract class BotImpl constructor( if (tryCount != 0) { delay(configuration.reconnectPeriodMillis) } - network.relogin() + network.relogin(event.cause) logger.info("Reconnected successfully") return@subscribeAlways }?.let { 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 a855e40b2..0deab64d0 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 @@ -57,7 +57,7 @@ sealed class BotOfflineEvent : BotEvent { /** * 被服务器断开或因网络问题而掉线 */ - data class Dropped(override val bot: Bot) : BotOfflineEvent(), Packet, BotPassiveEvent + data class Dropped(override val bot: Bot, val cause: Throwable?) : BotOfflineEvent(), Packet, BotPassiveEvent } /** 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 66e4a544e..b2f36d33b 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 @@ -68,7 +68,7 @@ abstract class BotNetworkHandler : CoroutineScope { */ @Suppress("SpellCheckingInspection") @MiraiInternalAPI - abstract suspend fun relogin() + abstract suspend fun relogin(cause: Throwable? = null) /** * 初始化获取好友列表等值. From 9660b44142fe2428df9a22260664c9199c2d535e Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 21:42:48 +0800 Subject: [PATCH 102/111] Broadcast BotReloginEvent, close #78 --- mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt | 1 + 1 file changed, 1 insertion(+) 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 4f6fc0f8a..7ee7f84b3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -94,6 +94,7 @@ abstract class BotImpl constructor( } network.relogin(event.cause) logger.info("Reconnected successfully") + BotReloginEvent(bot, event.cause).broadcast() return@subscribeAlways }?.let { logger.info("Cannot reconnect") From bebc806527d3d746563fd2926157efbd9ac1dcd1 Mon Sep 17 00:00:00 2001 From: ryoii Date: Thu, 20 Feb 2020 21:52:56 +0800 Subject: [PATCH 103/111] http api fix name --- .../kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt index 675a510d7..ded3ea9a4 100644 --- a/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt +++ b/mirai-api-http/src/main/kotlin/net/mamoe/mirai/api/http/data/common/BotEventDTO.kt @@ -64,7 +64,7 @@ data class BotOfflineEventDroppedDTO(val qq: Long) : BotEventDTO() data class BotReloginEventDTO(val qq: Long) : BotEventDTO() @Serializable @SerialName("BotGroupPermissionChangeEvent") -data class BotGroupPermissionChangeEventDTO(val origin: MemberPermission, val new: MemberPermission, val groupDTO: GroupDTO) : BotEventDTO() +data class BotGroupPermissionChangeEventDTO(val origin: MemberPermission, val new: MemberPermission, val group: GroupDTO) : BotEventDTO() @Serializable @SerialName("BotMuteEvent") data class BotMuteEventDTO(val durationSeconds: Int, val operator: MemberDTO) : BotEventDTO() From cb06520b8e4c046810703f20f2451226c37bc384 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:01:34 +0800 Subject: [PATCH 104/111] Explicitly override `hashCode` and `toString` in `interface Contact`, close #80 --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 23 +++++-------------- .../kotlin/net.mamoe.mirai/contact/Contact.kt | 10 ++++++++ .../kotlin/net.mamoe.mirai/contact/Group.kt | 5 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 5cad965a2..af1977697 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -162,16 +162,11 @@ internal class QQImpl( TODO("not implemented") } - override fun equals(other: Any?): Boolean { - if (this === other) return true - return other is QQ && other.id == this.id - } - - override fun hashCode(): Int = super.hashCode() + override fun toString(): String = "QQ($id)" } -@Suppress("MemberVisibilityCanBePrivate") +@Suppress("MemberVisibilityCanBePrivate", "DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE") internal class MemberImpl( qq: QQImpl, group: GroupImpl, @@ -279,12 +274,9 @@ internal class MemberImpl( } } - override fun equals(other: Any?): Boolean { - if (this === other) return true - return other is Member && other.id == this.id + override fun toString(): String { + return "Member($id)" } - - override fun hashCode(): Int = super.hashCode() } internal class MemberInfoImpl( @@ -600,10 +592,7 @@ internal class GroupImpl( image.input.close() } - override fun equals(other: Any?): Boolean { - if (this === other) return true - return other is Group && other.id == this.id + override fun toString(): String { + return "Group($id)" } - - override fun hashCode(): Int = super.hashCode() } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt index 80c2900bc..dcb80fe9f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Contact.kt @@ -74,6 +74,16 @@ interface Contact : CoroutineScope { * 而 [QQ] 含义为一个独立的人, 可以是好友, 也可以是陌生人. */ override fun equals(other: Any?): Boolean + + /** + * @return `bot.hashCode() * 31 + id.hashCode()` + */ + override fun hashCode(): Int + + /** + * @return "QQ($id)" or "Group($id)" or "Member($id)" + */ + override fun toString(): String } suspend inline fun Contact.sendMessage(message: Message) = sendMessage(message.toChain()) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index a3c2a8ff2..7d1fcdc98 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -97,11 +97,11 @@ interface Group : Contact, CoroutineScope { /** * 机器人在这个群里的权限 * - * **MiraiExperimentalAPI**: 在未来可能会被修改 + * @see Group.checkBotPermission + * @see Group.checkBotPermissionOperator * * @see BotGroupPermissionChangeEvent */ - @MiraiExperimentalAPI val botPermission: MemberPermission @@ -129,6 +129,7 @@ interface Group : Contact, CoroutineScope { /** * 让机器人退出这个群. 机器人必须为非群主才能退出. 否则将会失败 */ + @MiraiExperimentalAPI("还未支持") suspend fun quit(): Boolean /** From f8e31b6920c35000f7d15163fb7f60eb5ab2b5b7 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:19:41 +0800 Subject: [PATCH 105/111] Add docs --- .../kotlin/net.mamoe.mirai/contact/Group.kt | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt index 7d1fcdc98..3d618c9aa 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Group.kt @@ -12,6 +12,7 @@ package net.mamoe.mirai.contact import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.Bot import net.mamoe.mirai.data.MemberInfo import net.mamoe.mirai.event.events.* import net.mamoe.mirai.utils.MiraiExperimentalAPI @@ -89,18 +90,18 @@ interface Group : Contact, CoroutineScope { /** * 机器人被禁言还剩余多少秒 * - * @see BotMuteEvent - * @see isBotMuted + * @see BotMuteEvent 机器人被禁言事件 + * @see isBotMuted 判断机器人是否正在被禁言 */ val botMuteRemaining: Int /** * 机器人在这个群里的权限 * - * @see Group.checkBotPermission - * @see Group.checkBotPermissionOperator + * @see Group.checkBotPermission 检查 [Bot] 在这个群里的权限 + * @see Group.checkBotPermissionOperator 要求 [Bot] 在这个群里的权限为 [管理员或群主][MemberPermission.isOperator] * - * @see BotGroupPermissionChangeEvent + * @see BotGroupPermissionChangeEvent 机器人群员修改 */ val botPermission: MemberPermission From 97615e5d7ef0f7cc27820c0d03b235f91fd2b766 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:19:54 +0800 Subject: [PATCH 106/111] Add docs --- .../kotlin/net.mamoe.mirai/contact/Permission.kt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Permission.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Permission.kt index ac1137744..baeb5951f 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Permission.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/contact/Permission.kt @@ -9,6 +9,7 @@ package net.mamoe.mirai.contact +import net.mamoe.mirai.Bot import net.mamoe.mirai.utils.MiraiExperimentalAPI @@ -68,7 +69,6 @@ inline fun Member.isAdministrator(): Boolean = this.permission.isAdministrator() inline fun Member.isOperator(): Boolean = this.permission.isOperator() - /** * 权限不足 */ @@ -77,6 +77,11 @@ expect class PermissionDeniedException : IllegalStateException { constructor(message: String?) } +/** + * 要求 [Bot] 在这个群里的权限为 [required], 否则抛出异常 [PermissionDeniedException] + * + * @throws PermissionDeniedException + */ @UseExperimental(MiraiExperimentalAPI::class) inline fun Group.checkBotPermission( required: MemberPermission, @@ -89,6 +94,11 @@ inline fun Group.checkBotPermission( } } +/** + * 要求 [Bot] 在这个群里的权限为 [管理员或群主][MemberPermission.isOperator], 否则抛出异常 [PermissionDeniedException] + * + * @throws PermissionDeniedException + */ @UseExperimental(MiraiExperimentalAPI::class) inline fun Group.checkBotPermissionOperator( lazyMessage: () -> String = { From 68140a14ff44483df3a6747a4ee20f35bea90680 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:20:16 +0800 Subject: [PATCH 107/111] Fix botMuteTimeRemaining updating --- .../packet/chat/receive/OnlinePush.kt | 48 +++++++++++-------- 1 file changed, 29 insertions(+), 19 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 88f8db929..4aa8a4439 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 @@ -142,9 +142,10 @@ internal class OnlinePush { @UseExperimental(ExperimentalStdlibApi::class) override suspend fun ByteReadPacket.decode(bot: QQAndroidBot, sequenceId: Int): Packet { val reqPushMsg = decodeUniPacket(OnlinePushPack.SvcReqPushMsg.serializer(), "req") - val packets = reqPushMsg.vMsgInfos.mapNotNull { msgInfo: MsgInfo -> - msgInfo.vMsg!!.read { + @Suppress("USELESS_CAST") // 不要信任 kotlin 类型推断 + val packets: List = reqPushMsg.vMsgInfos.mapNotNull { msgInfo: MsgInfo -> + msgInfo.vMsg!!.read { when { msgInfo.shMsgType.toInt() == 732 -> { val group = bot.getGroup(this.readUInt().toLong()) @@ -162,41 +163,48 @@ internal class OnlinePush { val target = this.readUInt().toLong() val time = this.readInt() - return@mapNotNull if (target == 0L) { + if (target == 0L) { if (time == 0) { - GroupMuteAllEvent( + return@mapNotNull GroupMuteAllEvent( origin = group.isMuteAll.also { group._muteAll = false }, new = false, operator = operator, group = group - ) + ) as Packet } else { - GroupMuteAllEvent( + return@mapNotNull GroupMuteAllEvent( origin = group.isMuteAll.also { group._muteAll = true }, new = true, operator = operator, group = group - ) + ) as Packet } } else { if (target == bot.uin) { - @Suppress("IMPLICIT_CAST_TO_ANY") // false positive - return@mapNotNull if (time == 0) { - BotUnmuteEvent(operator) - } else - BotMuteEvent(durationSeconds = time, operator = operator) + if (group._botMuteRemaining != time) { + if (time == 0) { + group._botMuteRemaining = 0 + return@mapNotNull BotUnmuteEvent(operator) as Packet + } else { + group._botMuteRemaining = time + return@mapNotNull BotMuteEvent(durationSeconds = time, operator = operator) as Packet + } + } else { + return@mapNotNull null + } } else { val member = group[target] - @Suppress("IMPLICIT_CAST_TO_ANY") // false positive + // TODO: 2020/2/20 检查是否重复 return@mapNotNull if (time == 0) { MemberUnmuteEvent(operator = operator, member = member) } else { - MemberMuteEvent(operator = operator, member = member, durationSeconds = time) + MemberMuteEvent(operator = operator, member = member, durationSeconds = time) as Packet } } } } - 3585 -> { // 匿名 + 3585 -> { + // 匿名 val operator = group[this.readUInt().toLong()] val switch = this.readInt() == 0 return@mapNotNull GroupAllowAnonymousChatEvent( @@ -239,7 +247,7 @@ internal class OnlinePush { } else -> { bot.network.logger.debug { "Unknown server messages $message" } - return@mapNotNull NoPacket + return@mapNotNull null } } } @@ -250,26 +258,28 @@ internal class OnlinePush { // } else -> { bot.network.logger.debug { "unknown group internal type $internalType , data: " + this.readBytes().toUHexString() + " " } + return@mapNotNull null } } + return@mapNotNull null } msgInfo.shMsgType.toInt() == 528 -> { bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } // val content = msgInfo.vMsg.loadAs(OnlinePushPack.MsgType0x210.serializer()) // println(content.contentToString()) + return@mapNotNull null } else -> { bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } + return@mapNotNull null } } + return@mapNotNull null } - return@mapNotNull null } - return MultiPacket(packets) } - override suspend fun QQAndroidBot.handle(packet: Packet, sequenceId: Int): OutgoingPacket? { return buildResponseUniPacket(client, sequenceId = sequenceId) { From 086f04e1f508b5364f44d39f76bf9b729924e73f Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:36:19 +0800 Subject: [PATCH 108/111] Add member.muteTimeRemaining --- .../net/mamoe/mirai/qqandroid/ContactImpl.kt | 18 +++++++-- .../packet/chat/receive/OnlinePush.kt | 22 +++++----- .../kotlin/net.mamoe.mirai/contact/Member.kt | 40 ++++++++++++++++--- .../kotlin/net.mamoe.mirai/data/MemberInfo.kt | 2 + .../net.mamoe.mirai/event/events/BotEvents.kt | 9 ++++- 5 files changed, 71 insertions(+), 20 deletions(-) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index af1977697..708a07064 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -180,6 +180,15 @@ internal class MemberImpl( internal var _nameCard: String = memberInfo.nameCard internal var _specialTitle: String = memberInfo.specialTitle + var _muteTimestamp: Int = memberInfo.muteTimestamp + + override val muteTimeRemaining: Int = + if (_muteTimestamp == 0 || _muteTimestamp == 0xFFFFFFFF.toInt()) { + 0 + } else { + _muteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() + } + override var nameCard: String get() = _nameCard set(newValue) { @@ -215,7 +224,7 @@ internal class MemberImpl( newValue ).sendWithoutExpect() } - MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl).broadcast() + MemberSpecialTitleChangeEvent(oldValue, newValue, this@MemberImpl, null).broadcast() } } } @@ -293,6 +302,7 @@ internal class MemberInfoImpl( else -> MemberPermission.MEMBER } override val specialTitle: String get() = jceInfo.sSpecialTitle ?: "" + override val muteTimestamp: Int get() = jceInfo.dwShutupTimestap?.toInt() ?: 0 } /** @@ -315,13 +325,13 @@ internal class GroupImpl( @UseExperimental(MiraiExperimentalAPI::class) override lateinit var botPermission: MemberPermission - var _botMuteRemaining: Int = groupInfo.botMuteRemaining + var _botMuteTimestamp: Int = groupInfo.botMuteRemaining override val botMuteRemaining: Int = - if (_botMuteRemaining == 0 || _botMuteRemaining == 0xFFFFFFFF.toInt()) { + if (_botMuteTimestamp == 0 || _botMuteTimestamp == 0xFFFFFFFF.toInt()) { 0 } else { - _botMuteRemaining - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() + _botMuteTimestamp - currentTimeSeconds.toInt() - bot.client.timeDifference.toInt() } override val members: ContactList = ContactList(members.mapNotNull { 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 4aa8a4439..117b1601e 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 @@ -181,12 +181,12 @@ internal class OnlinePush { } } else { if (target == bot.uin) { - if (group._botMuteRemaining != time) { + if (group._botMuteTimestamp != time) { if (time == 0) { - group._botMuteRemaining = 0 + group._botMuteTimestamp = 0 return@mapNotNull BotUnmuteEvent(operator) as Packet } else { - group._botMuteRemaining = time + group._botMuteTimestamp = time return@mapNotNull BotMuteEvent(durationSeconds = time, operator = operator) as Packet } } else { @@ -194,11 +194,17 @@ internal class OnlinePush { } } else { val member = group[target] - // TODO: 2020/2/20 检查是否重复 - return@mapNotNull if (time == 0) { - MemberUnmuteEvent(operator = operator, member = member) + member as MemberImpl + if (member._muteTimestamp != time) { + if (time == 0) { + member._muteTimestamp = 0 + return@mapNotNull MemberUnmuteEvent(member, operator) as Packet + } else { + member._muteTimestamp = time + return@mapNotNull MemberMuteEvent(member, time, operator) as Packet + } } else { - MemberMuteEvent(operator = operator, member = member, durationSeconds = time) as Packet + return@mapNotNull null } } } @@ -261,7 +267,6 @@ internal class OnlinePush { return@mapNotNull null } } - return@mapNotNull null } msgInfo.shMsgType.toInt() == 528 -> { bot.network.logger.debug { "unknown shtype ${msgInfo.shMsgType.toInt()}" } @@ -274,7 +279,6 @@ internal class OnlinePush { return@mapNotNull null } } - return@mapNotNull null } } return MultiPacket(packets) 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 d21bf9b1d..74f0a1431 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 @@ -1,7 +1,7 @@ /* * Copyright 2020 Mamoe Technologies and contributors. * - * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证. + * 此源代码的使用受 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 @@ -29,33 +29,50 @@ interface Member : QQ, Contact { /** * 成员的权限, 动态更新. + * + * @see MemberPermissionChangeEvent 权限变更事件. 由群主或机器人的操作触发. */ val permission: MemberPermission /** - * 群名片. 可能为空. 修改时将会触发事件 + * 群名片. 可能为空. + * + * 管理员和群主都可修改任何人(包括群主)的群名片. * * 在修改时将会异步上传至服务器. * * @see [nameCardOrNick] 获取非空群名片或昵称 * - * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 + * @see MemberCardChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. * @throws PermissionDeniedException 无权限修改时 */ var nameCard: String /** - * 群头衔 + * 群头衔. + * + * 仅群主可以修改群头衔. * * 在修改时将会异步上传至服务器. * - * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件 + * @see MemberSpecialTitleChangeEvent 群名片被管理员, 自己或 [Bot] 改动事件. 修改时也会触发此事件. * @throws PermissionDeniedException 无权限修改时 */ var specialTitle: String /** - * 禁言 + * 被禁言剩余时长. 单位为秒. + * + * @see isMuted 判断改成员是否处于禁言状态 + * @see mute 设置禁言 + * @see unmute 取消禁言 + */ + val muteTimeRemaining: Int + + /** + * 禁言. + * + * 管理员可禁言成员, 群主可禁言管理员和群员. * * @param durationSeconds 持续时间. 精确到秒. 范围区间表示为 `(0s, 30days]`. 超过范围则会抛出异常. * @return 机器人无权限时返回 `false` @@ -72,6 +89,8 @@ interface Member : QQ, Contact { /** * 解除禁言. * + * 管理员可解除成员的禁言, 群主可解除管理员和群员的禁言. + * * @see MemberUnmuteEvent 成员被取消禁言事件. * @throws PermissionDeniedException 无权限修改时 */ @@ -80,6 +99,8 @@ interface Member : QQ, Contact { /** * 踢出该成员. * + * 管理员可踢出成员, 群主可踢出管理员和群员. + * * @see MemberLeaveEvent.Kick 成员被踢出事件. * @throws PermissionDeniedException 无权限修改时 */ @@ -98,6 +119,13 @@ interface Member : QQ, Contact { */ val Member.nameCardOrNick: String get() = this.nameCard.takeIf { it.isNotEmpty() } ?: this.nick +/** + * 判断改成员是否处于禁言状态. + */ +fun Member.isMuted(): Boolean { + return muteTimeRemaining != 0 && muteTimeRemaining != 0xFFFFFFFF.toInt() +} + @ExperimentalTime suspend inline fun Member.mute(duration: Duration) { require(duration.inDays <= 30) { "duration must be at most 1 month" } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt index 3ed39ef10..37e6ba4b0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/data/MemberInfo.kt @@ -17,4 +17,6 @@ interface MemberInfo : FriendInfo { val permission: MemberPermission val specialTitle: String + + val muteTimestamp: Int } \ No newline at end of file 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 0deab64d0..c9ad80052 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 @@ -333,7 +333,14 @@ data class MemberSpecialTitleChangeEvent( */ val new: String, - override val member: Member + override val member: Member, + + /** + * 操作人. + * 不为 null 时一定为群主. 可能与 [member] 引用相同, 此时为群员自己修改. + * 为 null 时则是机器人操作. + */ + val operator: Member? ) : GroupMemberEvent // endregion From 629c354e38353f2b8d224c3fbbdfd67db13f4e45 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:46:04 +0800 Subject: [PATCH 109/111] Fix build. close #82 --- .../qqandroid/network/protocol/packet/chat/receive/MessageSvc.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/MessageSvc.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt index 236581cc5..76d8e6e33 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/network/protocol/packet/chat/receive/MessageSvc.kt @@ -194,6 +194,7 @@ internal class MessageSvc { override val nameCard: String get() = "" override val permission: MemberPermission get() = MemberPermission.MEMBER override val specialTitle: String get() = "" + override val muteTimestamp: Int get() = 0 override val uin: Long get() = msg.msgHead.authUin override val nick: String get() = msg.msgHead.authNick.takeIf { it.isNotEmpty() } ?: msg.msgHead.fromNick }).also { group.members.delegate.addLast(it) }) From 247ad692d8223d2a0125845cd87254b8e5cdbd95 Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:55:19 +0800 Subject: [PATCH 110/111] Add extensions --- .../net.mamoe.mirai/event/events/BotEvents.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) 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 c9ad80052..749697d01 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 @@ -7,6 +7,8 @@ * https://github.com/mamoe/mirai/blob/master/LICENSE */ +@file:Suppress("unused") + package net.mamoe.mirai.event.events import net.mamoe.mirai.Bot @@ -194,7 +196,7 @@ data class GroupNameChangeEvent( override val origin: String, override val new: String, override val group: Group, - val isByBot: Boolean + val isByBot: Boolean // 无法获取 operator ) : GroupSettingChangeEvent, Packet /** @@ -210,6 +212,8 @@ data class GroupEntranceAnnouncementChangeEvent( val operator: Member? ) : GroupSettingChangeEvent, Packet +val GroupEntranceAnnouncementChangeEvent.isByBot: Boolean get() = operator != null + /** * 群 "全员禁言" 功能状态改变. 此事件广播前修改就已经完成. @@ -224,6 +228,8 @@ data class GroupMuteAllEvent( val operator: Member? ) : GroupSettingChangeEvent, Packet +val GroupMuteAllEvent.isByBot: Boolean get() = operator != null + /** * 群 "匿名聊天" 功能状态改变. 此事件广播前修改就已经完成. */ @@ -237,6 +243,8 @@ data class GroupAllowAnonymousChatEvent( val operator: Member? ) : GroupSettingChangeEvent, Packet +val GroupAllowAnonymousChatEvent.isByBot: Boolean get() = operator != null + /** * 群 "坦白说" 功能状态改变. 此事件广播前修改就已经完成. */ @@ -260,6 +268,8 @@ data class GroupAllowMemberInviteEvent( val operator: Member? ) : GroupSettingChangeEvent, Packet +val GroupAllowMemberInviteEvent.isByBot: Boolean get() = operator != null + // endregion @@ -293,6 +303,8 @@ sealed class MemberLeaveEvent : GroupMemberEvent { data class Quit(override val member: Member) : MemberLeaveEvent() } +val MemberLeaveEvent.Kick.isByBot: Boolean get() = operator != null + // endregion // region 名片和头衔 @@ -319,6 +331,8 @@ data class MemberCardChangeEvent( val operator: Member? ) : GroupMemberEvent +val MemberCardChangeEvent.isByBot: Boolean get() = operator != null + /** * 群头衔改动. 一定为群主操作 */ @@ -343,6 +357,8 @@ data class MemberSpecialTitleChangeEvent( val operator: Member? ) : GroupMemberEvent +val MemberSpecialTitleChangeEvent.isByBot: Boolean get() = operator != null + // endregion @@ -374,6 +390,8 @@ data class MemberMuteEvent( val operator: Member? ) : GroupMemberEvent, Packet +val MemberMuteEvent.isByBot: Boolean get() = operator != null + /** * 群成员被取消禁言事件. 被禁言的成员都不可能是机器人本人 */ @@ -385,6 +403,8 @@ data class MemberUnmuteEvent( val operator: Member? ) : GroupMemberEvent, Packet +val MemberUnmuteEvent.isByBot: Boolean get() = operator != null + // endregion // endregion From 1f4a41239e7d1fe12e882e4755f1b2a035a3e35b Mon Sep 17 00:00:00 2001 From: Him188 Date: Thu, 20 Feb 2020 22:55:29 +0800 Subject: [PATCH 111/111] Suppress warnings --- .../commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt | 3 +++ 1 file changed, 3 insertions(+) diff --git a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt index 708a07064..29a17b2c9 100644 --- a/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt +++ b/mirai-core-qqandroid/src/commonMain/kotlin/net/mamoe/mirai/qqandroid/ContactImpl.kt @@ -177,9 +177,12 @@ internal class MemberImpl( val qq: QQImpl by qq.unsafeWeakRef() override var permission: MemberPermission = memberInfo.permission + @Suppress("PropertyName") internal var _nameCard: String = memberInfo.nameCard + @Suppress("PropertyName") internal var _specialTitle: String = memberInfo.specialTitle + @Suppress("PropertyName") var _muteTimestamp: Int = memberInfo.muteTimestamp override val muteTimeRemaining: Int =