Commit 7bb482de authored by jiahua.liu's avatar jiahua.liu

Merge remote-tracking branch 'origin/master'

parents 3eeb640f 75ad1e17
...@@ -9,9 +9,15 @@ jobs: ...@@ -9,9 +9,15 @@ jobs:
steps: steps:
- uses: actions/checkout@v1 - uses: actions/checkout@v1
- name: setup-android - name: Setup Java JDK
uses: msfjarvis/setup-android@0.2 uses: actions/setup-java@v1.3.0
with: with:
# Gradle tasks to run - If you want to run ./gradlew assemble, specify assemble here. # 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)
gradleTasks: build -x mirai-core:jvmTest java-version: 11
# The package type (jre, jdk, jdk+fx)
java-package: jdk+fx
- name: Gradle Command
uses: eskatos/gradle-command-action@v1
with:
# Gradle command line arguments, see gradle --help
arguments: build -x mirai-core:jvmTest
...@@ -43,7 +43,7 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -43,7 +43,7 @@ internal abstract class QQAndroidBotBase constructor(
context: Context, context: Context,
account: BotAccount, account: BotAccount,
configuration: BotConfiguration configuration: BotConfiguration
) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) { ) : BotImpl<QQAndroidBotNetworkHandler>(context, account, configuration) {
val client: QQAndroidClient = val client: QQAndroidClient =
QQAndroidClient( QQAndroidClient(
context, context,
...@@ -88,10 +88,10 @@ internal abstract class QQAndroidBotBase constructor( ...@@ -88,10 +88,10 @@ internal abstract class QQAndroidBotBase constructor(
}.groups.asSequence().map { it.groupUin.shl(32) and it.groupCode } }.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( TroopManagement.GetGroupInfo(
client = bot.client, client = bot.client,
groupCode = id groupCode = groupCode
).sendAndExpect<GroupInfoImpl>(retry = 2) ).sendAndExpect<GroupInfoImpl>(retry = 2)
} }
......
...@@ -547,5 +547,5 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler ...@@ -547,5 +547,5 @@ internal class QQAndroidBotNetworkHandler(bot: QQAndroidBot) : BotNetworkHandler
super.close(cause) super.close(cause)
} }
override suspend fun awaitDisconnection() = supervisor.join() override suspend fun join() = supervisor.join()
} }
\ No newline at end of file
...@@ -33,7 +33,7 @@ import kotlin.jvm.JvmStatic ...@@ -33,7 +33,7 @@ import kotlin.jvm.JvmStatic
* 机器人对象. 一个机器人实例登录一个 QQ 账号. * 机器人对象. 一个机器人实例登录一个 QQ 账号.
* Mirai 为多账号设计, 可同时维护多个机器人. * Mirai 为多账号设计, 可同时维护多个机器人.
* *
* 注: Bot 为全协程实现, 没有其他任务时若不使用 [awaitDisconnection], 主线程将会退出. * 注: Bot 为全协程实现, 没有其他任务时若不使用 [join], 主线程将会退出.
* *
* @see Contact * @see Contact
*/ */
...@@ -44,7 +44,8 @@ abstract class Bot : CoroutineScope { ...@@ -44,7 +44,8 @@ abstract class Bot : CoroutineScope {
* 复制一份此时的 [Bot] 实例列表. * 复制一份此时的 [Bot] 实例列表.
*/ */
@JvmStatic @JvmStatic
val instances: List<WeakRef<Bot>> get() = BotImpl.instances.toList() val instances: List<WeakRef<Bot>>
get() = BotImpl.instances.toList()
/** /**
* 遍历每一个 [Bot] 实例 * 遍历每一个 [Bot] 实例
...@@ -58,6 +59,14 @@ abstract class Bot : CoroutineScope { ...@@ -58,6 +59,14 @@ abstract class Bot : CoroutineScope {
fun instanceWhose(qq: Long): Bot = BotImpl.instanceWhose(qq = qq) fun instanceWhose(qq: Long): Bot = BotImpl.instanceWhose(qq = qq)
} }
/**
* [Bot] 运行的 [Context].
*
* 在 JVM 的默认实现为 `class ContextImpl : Context`
* 在 Android 实现为 `android.content.Context`
*/
abstract val context: Context
/** /**
* 账号信息 * 账号信息
*/ */
...@@ -135,7 +144,9 @@ abstract class Bot : CoroutineScope { ...@@ -135,7 +144,9 @@ abstract class Bot : CoroutineScope {
abstract val groups: ContactList<Group> abstract val groups: ContactList<Group>
/** /**
* 获取一个机器人加入的群. 若没有这个群, 则会抛出异常 [NoSuchElementException] * 获取一个机器人加入的群.
*
* @throws NoSuchElementException 当不存在这个群时
*/ */
fun getGroup(id: Long): Group { fun getGroup(id: Long): Group {
return groups.delegate.getOrNull(id) return groups.delegate.getOrNull(id)
...@@ -143,21 +154,23 @@ abstract class Bot : CoroutineScope { ...@@ -143,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> abstract suspend fun queryGroupList(): Sequence<Long>
/** /**
* 查询群资料. 获得的仅为当前时刻的资料. * 向服务器查询群资料. 获得的仅为当前时刻的资料.
* 请优先使用 [getGroup] 然后查看群资料. * 请优先使用 [getGroup] 然后查看群资料.
*/ */
abstract suspend fun queryGroupInfo(id: Long): GroupInfo abstract suspend fun queryGroupInfo(groupCode: Long): GroupInfo
/** /**
* 查询群成员列表. * 向服务器查询群成员列表.
* 请优先使用 [getGroup], [Group.members] 查看群成员. * 请优先使用 [getGroup], [Group.members] 查看群成员.
* *
* 这个函数很慢. 请不要频繁使用. * 这个函数很慢. 请不要频繁使用.
*
* @see Group.calculateGroupUinByGroupCode 使用 groupCode 计算 groupUin
*/ */
abstract suspend fun queryGroupMemberList(groupUin: Long, groupCode: Long, ownerId: Long): Sequence<MemberInfo> abstract suspend fun queryGroupMemberList(groupUin: Long, groupCode: Long, ownerId: Long): Sequence<MemberInfo>
...@@ -175,7 +188,10 @@ abstract class Bot : CoroutineScope { ...@@ -175,7 +188,10 @@ abstract class Bot : CoroutineScope {
/** /**
* 挂起直到 [Bot] 下线. * 挂起直到 [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()
/** /**
* 登录, 或重新登录. * 登录, 或重新登录.
...@@ -220,6 +236,8 @@ abstract class Bot : CoroutineScope { ...@@ -220,6 +236,8 @@ abstract class Bot : CoroutineScope {
* 注: 不可重新登录. 必须重新实例化一个 [Bot]. * 注: 不可重新登录. 必须重新实例化一个 [Bot].
* *
* @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭 * @param cause 原因. 为 null 时视为正常关闭, 非 null 时视为异常关闭
*
* @see closeAndJoin
*/ */
abstract fun close(cause: Throwable? = null) abstract fun close(cause: Throwable? = null)
...@@ -244,6 +262,18 @@ abstract class Bot : CoroutineScope { ...@@ -244,6 +262,18 @@ abstract class Bot : CoroutineScope {
// endregion // 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.containsFriend(id: Long): Boolean = this.qqs.contains(id)
inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id) inline fun Bot.containsGroup(id: Long): Boolean = this.groups.contains(id)
......
...@@ -32,6 +32,7 @@ import kotlin.coroutines.CoroutineContext ...@@ -32,6 +32,7 @@ import kotlin.coroutines.CoroutineContext
@UseExperimental(MiraiExperimentalAPI::class) @UseExperimental(MiraiExperimentalAPI::class)
@MiraiInternalAPI @MiraiInternalAPI
abstract class BotImpl<N : BotNetworkHandler> constructor( abstract class BotImpl<N : BotNetworkHandler> constructor(
context: Context,
account: BotAccount, account: BotAccount,
val configuration: BotConfiguration val configuration: BotConfiguration
) : Bot(), CoroutineScope { ) : Bot(), CoroutineScope {
...@@ -39,6 +40,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -39,6 +40,7 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
override val coroutineContext: CoroutineContext = override val coroutineContext: CoroutineContext =
configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler] configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler]
?: CoroutineExceptionHandler { _, e -> logger.error("An exception was thrown under a coroutine of Bot", e) }) ?: 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 @Suppress("CanBePrimaryConstructorProperty") // for logger
final override val account: BotAccount = account final override val account: BotAccount = account
......
...@@ -80,9 +80,10 @@ abstract class BotNetworkHandler : CoroutineScope { ...@@ -80,9 +80,10 @@ abstract class BotNetworkHandler : CoroutineScope {
} }
/** /**
* 等待直到与服务器断开连接. 若未连接则立即返回 * 当 [Bot] 正常运作时, 这个函数将一直挂起协程到 [Bot] 被 [Bot.close]
* 当 [Bot] 离线时, 这个函数立即返回.
*/ */
abstract suspend fun awaitDisconnection() abstract suspend fun join()
/** /**
* 关闭网络接口, 停止所有有关协程和任务 * 关闭网络接口, 停止所有有关协程和任务
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment