From b59ae076ec9a4580a6789a33e5e2dd5c4ee441e9 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 00:16:50 +0800
Subject: [PATCH 1/6] Add context getter

---
 .../kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt  |  2 +-
 .../src/commonMain/kotlin/net.mamoe.mirai/Bot.kt      | 11 ++++++++++-
 .../src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt  |  2 ++
 3 files changed, 13 insertions(+), 2 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 5671f2088..093f7f9c8 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
@@ -43,7 +43,7 @@ internal abstract class QQAndroidBotBase constructor(
     context: Context,
     account: BotAccount,
     configuration: BotConfiguration
-) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) {
+) : BotImpl<QQAndroidBotNetworkHandler>(context, account, configuration) {
     val client: QQAndroidClient =
         QQAndroidClient(
             context,
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 4430c4514..aea4f1683 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
@@ -44,7 +44,8 @@ abstract class Bot : CoroutineScope {
          * 复制一份此时的 [Bot] 实例列表.
          */
         @JvmStatic
-        val instances: List<WeakRef<Bot>> get() = BotImpl.instances.toList()
+        val instances: List<WeakRef<Bot>>
+            get() = BotImpl.instances.toList()
 
         /**
          * 遍历每一个 [Bot] 实例
@@ -58,6 +59,14 @@ abstract class Bot : CoroutineScope {
         fun instanceWhose(qq: Long): Bot = BotImpl.instanceWhose(qq = qq)
     }
 
+    /**
+     * [Bot] 运行的 [Context].
+     *
+     * 在 JVM 的默认实现为 `class ContextImpl : Context`
+     * 在 Android 实现为 `android.content.Context`
+     */
+    abstract val context: Context
+
     /**
      * 账号信息
      */
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 23a913e50..a8686f90f 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt
@@ -32,6 +32,7 @@ import kotlin.coroutines.CoroutineContext
 @UseExperimental(MiraiExperimentalAPI::class)
 @MiraiInternalAPI
 abstract class BotImpl<N : BotNetworkHandler> constructor(
+    context: Context,
     account: BotAccount,
     val configuration: BotConfiguration
 ) : Bot(), CoroutineScope {
@@ -39,6 +40,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
     override val coroutineContext: CoroutineContext =
         configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler]
             ?: CoroutineExceptionHandler { _, e -> logger.error("An exception was thrown under a coroutine of Bot", e) })
+    override val context: Context by context.unsafeWeakRef()
 
     @Suppress("CanBePrimaryConstructorProperty") // for logger
     final override val account: BotAccount = account

From 7d283808f7876197e114401852a289050466fabd Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 09:26:32 +0800
Subject: [PATCH 2/6] Rename `awaitDisconnection` to `join`

---
 .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt |  4 ++--
 .../network/QQAndroidBotNetworkHandler.kt     |  2 +-
 .../commonMain/kotlin/net.mamoe.mirai/Bot.kt  | 21 ++++++++++++-------
 .../network/BotNetworkHandler.kt              |  5 +++--
 4 files changed, 20 insertions(+), 12 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 093f7f9c8..6670eed35 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
@@ -88,10 +88,10 @@ internal abstract class QQAndroidBotBase constructor(
         }.groups.asSequence().map { it.groupUin.shl(32) and it.groupCode }
     }
 
-    override suspend fun queryGroupInfo(id: Long): GroupInfo = network.run {
+    override suspend fun queryGroupInfo(groupCode: Long): GroupInfo = network.run {
         TroopManagement.GetGroupInfo(
             client = bot.client,
-            groupCode = id
+            groupCode = groupCode
         ).sendAndExpect<GroupInfoImpl>(retry = 2)
     }
 
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 3cd073c91..9ac70b87e 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
@@ -547,5 +547,5 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
         super.close(cause)
     }
 
-    override suspend fun awaitDisconnection() = supervisor.join()
+    override suspend fun join() = supervisor.join()
 }
\ No newline at end of file
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 aea4f1683..542dffc49 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
@@ -33,7 +33,7 @@ import kotlin.jvm.JvmStatic
  * 机器人对象. 一个机器人实例登录一个 QQ 账号.
  * Mirai 为多账号设计, 可同时维护多个机器人.
  *
- * 注: Bot 为全协程实现, 没有其他任务时若不使用 [awaitDisconnection], 主线程将会退出.
+ * 注: Bot 为全协程实现, 没有其他任务时若不使用 [join], 主线程将会退出.
  *
  * @see Contact
  */
@@ -144,7 +144,9 @@ abstract class Bot : CoroutineScope {
     abstract val groups: ContactList<Group>
 
     /**
-     * 获取一个机器人加入的群. 若没有这个群, 则会抛出异常 [NoSuchElementException]
+     * 获取一个机器人加入的群.
+     *
+     * @throws NoSuchElementException 当不存在这个群时
      */
     fun getGroup(id: Long): Group {
         return groups.delegate.getOrNull(id)
@@ -152,21 +154,23 @@ abstract class Bot : CoroutineScope {
     }
 
     /**
-     * 获取群列表. 返回值前 32 bits 为 uin, 后 32 bits 为 groupCode
+     * 向服务器查询群列表. 返回值前 32 bits 为 uin, 后 32 bits 为 groupCode
      */
     abstract suspend fun queryGroupList(): Sequence<Long>
 
     /**
-     * 查询群资料. 获得的仅为当前时刻的资料.
+     * 向服务器查询群资料. 获得的仅为当前时刻的资料.
      * 请优先使用 [getGroup] 然后查看群资料.
      */
-    abstract suspend fun queryGroupInfo(id: Long): GroupInfo
+    abstract suspend fun queryGroupInfo(groupCode: Long): GroupInfo
 
     /**
-     * 查询群成员列表.
+     * 向服务器查询群成员列表.
      * 请优先使用 [getGroup], [Group.members] 查看群成员.
      *
      * 这个函数很慢. 请不要频繁使用.
+     *
+     * @see Group.calculateGroupUinByGroupCode 使用 groupCode 计算 groupUin
      */
     abstract suspend fun queryGroupMemberList(groupUin: Long, groupCode: Long, ownerId: Long): Sequence<MemberInfo>
 
@@ -184,7 +188,10 @@ abstract class Bot : CoroutineScope {
     /**
      * 挂起直到 [Bot] 下线.
      */
-    suspend inline fun awaitDisconnection() = network.awaitDisconnection()
+    suspend inline fun join() = network.join()
+
+    @Deprecated("使用 join()", ReplaceWith("this.join()"), level = DeprecationLevel.HIDDEN)
+    suspend inline fun awaitDisconnection() = join()
 
     /**
      * 登录, 或重新登录.
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 76ffb50d1..66e4a544e 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
@@ -80,9 +80,10 @@ abstract class BotNetworkHandler : CoroutineScope {
     }
 
     /**
-     * 等待直到与服务器断开连接. 若未连接则立即返回
+     * 当 [Bot] 正常运作时, 这个函数将一直挂起协程到 [Bot] 被 [Bot.close]
+     * 当 [Bot] 离线时, 这个函数立即返回.
      */
-    abstract suspend fun awaitDisconnection()
+    abstract suspend fun join()
 
     /**
      * 关闭网络接口, 停止所有有关协程和任务

From 9b3bc88b3da8cce4821d6a6040a0d7f8c0a7dd43 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 09:39:02 +0800
Subject: [PATCH 3/6] Add Bot.closeAndJoin

---
 .../src/commonMain/kotlin/net.mamoe.mirai/Bot.kt   | 14 ++++++++++++++
 1 file changed, 14 insertions(+)

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 542dffc49..a8dea8551 100644
--- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
+++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt
@@ -236,6 +236,8 @@ abstract class Bot : CoroutineScope {
      * 注: 不可重新登录. 必须重新实例化一个 [Bot].
      *
      * @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭
+     *
+     * @see closeAndJoin
      */
     abstract fun close(cause: Throwable? = null)
 
@@ -260,6 +262,18 @@ abstract class Bot : CoroutineScope {
     // endregion
 }
 
+/**
+ * 关闭这个 [Bot], 停止一切相关活动. 所有引用都会被释放.
+ *
+ * 注: 不可重新登录. 必须重新实例化一个 [Bot].
+ *
+ * @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭
+ */
+suspend inline fun Bot.closeAndJoin(cause: Throwable? = null) {
+    close(cause)
+    coroutineContext[Job]?.join()
+}
+
 inline fun Bot.containsFriend(id: Long): Boolean = this.qqs.contains(id)
 
 inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id)

From feb641057d0ccbb048f4ff6b80acb20cf4f20847 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 16:23:02 +0800
Subject: [PATCH 4/6] Update main.yml

---
 .github/workflows/main.yml | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index e365cd46c..cad8de6b2 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -9,9 +9,15 @@ jobs:
 
     steps:
     - uses: actions/checkout@v1
+    - name: Setup Java JDK
+      uses: actions/setup-java@v1.3.0
+      with:
+        # The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)
+        java-version: 1.8
+        # The package type (jre, jdk, jdk+fx)
+        java-package: jdk+fx
     - name: setup-android
       uses: msfjarvis/setup-android@0.2
       with:
         # Gradle tasks to run - If you want to run ./gradlew assemble, specify assemble here. 
         gradleTasks: build -x mirai-core:jvmTest
-    

From 649d8f6ac29a37512574476045a3b9223e31f677 Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 16:28:10 +0800
Subject: [PATCH 5/6] Update main.yml

---
 .github/workflows/main.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index cad8de6b2..40d86aa04 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -13,7 +13,7 @@ jobs:
       uses: actions/setup-java@v1.3.0
       with:
         # The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x)
-        java-version: 1.8
+        java-version: 11
         # The package type (jre, jdk, jdk+fx)
         java-package: jdk+fx
     - name: setup-android

From 75ad1e17e511705518ec46a4fde3902b80e340fa Mon Sep 17 00:00:00 2001
From: Him188 <Him188@mamoe.net>
Date: Mon, 17 Feb 2020 16:31:00 +0800
Subject: [PATCH 6/6] Update main.yml

---
 .github/workflows/main.yml | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 40d86aa04..70e881e1f 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -16,8 +16,8 @@ jobs:
         java-version: 11
         # The package type (jre, jdk, jdk+fx)
         java-package: jdk+fx
-    - name: setup-android
-      uses: msfjarvis/setup-android@0.2
+    - name: Gradle Command
+      uses: eskatos/gradle-command-action@v1
       with:
-        # Gradle tasks to run - If you want to run ./gradlew assemble, specify assemble here. 
-        gradleTasks: build -x mirai-core:jvmTest
+        # Gradle command line arguments, see gradle --help
+        arguments: build -x mirai-core:jvmTest