From a47ea07feb52d6d019a75cf6e84c9d91d05eb5c8 Mon Sep 17 00:00:00 2001 From: Him188 Date: Tue, 24 Dec 2019 14:48:07 +0800 Subject: [PATCH] Use BotConfiguration --- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 10 +-- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 9 +-- .../net/mamoe/mirai/qqandroid/QQAndroidBot.kt | 11 ++- .../kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt | 8 +-- .../kotlin/net.mamoe.mirai.timpc/TIMPC.kt | 64 ++--------------- .../kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt | 8 +-- .../network/TIMPCBotNetworkHandler.kt | 23 +++--- .../kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt | 8 +-- .../commonMain/kotlin/net.mamoe.mirai/Bot.kt | 23 ++---- .../kotlin/net.mamoe.mirai/BotFactory.kt | 59 +++------------ .../kotlin/net.mamoe.mirai/BotHelper.kt | 23 +----- .../kotlin/net.mamoe.mirai/BotImpl.kt | 31 ++++---- .../network/BotNetworkHandler.kt | 4 +- .../net.mamoe.mirai/utils/BotConfiguration.kt | 21 ++++-- .../kotlin/net/mamoe/mirai/BotFactoryJvm.kt | 71 ++----------------- .../java/demo/subscribe/SubscribeSamples.kt | 4 +- .../src/main/kotlin/demo/gentleman/Main.kt | 18 +++-- 17 files changed, 101 insertions(+), 294 deletions(-) diff --git a/mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index 4bf840092..def004a30 100644 --- a/mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/androidMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -1,13 +1,9 @@ package net.mamoe.mirai.qqandroid import net.mamoe.mirai.BotAccount -import net.mamoe.mirai.utils.MiraiLogger -import kotlin.coroutines.CoroutineContext +import net.mamoe.mirai.utils.BotConfiguration internal actual class QQAndroidBot actual constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : QQAndroidBotBase(account, logger, context) { - -} \ No newline at end of file + configuration: BotConfiguration +) : QQAndroidBotBase(account, configuration) \ No newline at end of file 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 105eeb56b..4d22b3c3e 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 @@ -9,21 +9,18 @@ import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.MiraiInternalAPI -import net.mamoe.mirai.utils.MiraiLogger import kotlin.coroutines.CoroutineContext internal expect class QQAndroidBot( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext + configuration: BotConfiguration ) : QQAndroidBotBase @UseExperimental(MiraiInternalAPI::class) internal abstract class QQAndroidBotBase constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : BotImpl(account, logger, context) { + configuration: BotConfiguration +) : BotImpl(account, configuration) { override val qqs: ContactList get() = TODO("not implemented") diff --git a/mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt b/mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt index 08d031a45..03b0702e3 100644 --- a/mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt +++ b/mirai-core-qqandroid/src/jvmMain/kotlin/net/mamoe/mirai/qqandroid/QQAndroidBot.kt @@ -1,18 +1,15 @@ package net.mamoe.mirai.qqandroid -import kotlinx.coroutines.GlobalScope import net.mamoe.mirai.BotAccount import net.mamoe.mirai.alsoLogin -import net.mamoe.mirai.utils.MiraiLogger -import kotlin.coroutines.CoroutineContext +import net.mamoe.mirai.utils.BotConfiguration internal actual class QQAndroidBot actual constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : QQAndroidBotBase(account, logger, context) + configuration: BotConfiguration +) : QQAndroidBotBase(account, configuration) suspend fun main() { - val bot = QQAndroidBot(BotAccount(1, ""), null, GlobalScope.coroutineContext).alsoLogin() + val bot = QQAndroidBot(BotAccount(1, ""), BotConfiguration()).alsoLogin() bot.network.awaitDisconnection() } \ No newline at end of file diff --git a/mirai-core-timpc/src/androidMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt b/mirai-core-timpc/src/androidMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt index 756b7ba83..a855b8db1 100644 --- a/mirai-core-timpc/src/androidMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt +++ b/mirai-core-timpc/src/androidMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt @@ -6,13 +6,11 @@ import kotlinx.io.InputStream import kotlinx.io.streams.inputStream import net.mamoe.mirai.BotAccount import net.mamoe.mirai.message.data.Image -import net.mamoe.mirai.utils.MiraiLogger -import kotlin.coroutines.CoroutineContext +import net.mamoe.mirai.utils.BotConfiguration internal actual class TIMPCBot actual constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : TIMPCBotBase(account, logger, context) { + configuration: BotConfiguration +) : TIMPCBotBase(account, configuration) { suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() } \ No newline at end of file diff --git a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPC.kt b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPC.kt index c508fd0a0..1ca3b6e2d 100644 --- a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPC.kt +++ b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPC.kt @@ -2,75 +2,19 @@ package net.mamoe.mirai.timpc -import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.Bot import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotFactory import net.mamoe.mirai.timpc.TIMPC.Bot -import net.mamoe.mirai.utils.MiraiLogger -import kotlin.coroutines.coroutineContext +import net.mamoe.mirai.utils.BotConfiguration /** * TIM PC 协议的 [Bot] 构造器. */ object TIMPC : BotFactory { /** - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` + * 使用指定的 [配置][configuration] 构造 [Bot] 实例 */ - override suspend fun Bot(account: BotAccount, logger: MiraiLogger?): Bot = - TIMPCBot(account, logger, coroutineContext) - - /** - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` - */ - override suspend fun Bot(qq: Long, password: String, logger: MiraiLogger?): Bot = - TIMPCBot(BotAccount(qq, password), logger, coroutineContext) - - /** - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ - override fun CoroutineScope.Bot(qq: Long, password: String, logger: MiraiLogger?): Bot = - TIMPCBot(BotAccount(qq, password), logger, coroutineContext) - - /** - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ - override fun CoroutineScope.Bot(account: BotAccount, logger: MiraiLogger?): Bot = - TIMPCBot(account, logger, coroutineContext) + override fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)?): Bot = + TIMPCBot(account, if (configuration == null) BotConfiguration.Default else BotConfiguration().apply(configuration)) } \ No newline at end of file diff --git a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt index 4128a110e..11b2a4140 100644 --- a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt +++ b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/TIMPCBot.kt @@ -37,16 +37,14 @@ import kotlin.jvm.JvmSynthetic internal expect class TIMPCBot constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext + configuration: BotConfiguration ) : TIMPCBotBase @UseExperimental(MiraiInternalAPI::class) internal abstract class TIMPCBotBase constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : BotImpl(account, logger ?: DefaultLogger("Bot(" + account.id + ")"), context) { + configuration: BotConfiguration +) : BotImpl(account, configuration) { @UseExperimental(ExperimentalUnsignedTypes::class) companion object { diff --git a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMPCBotNetworkHandler.kt b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMPCBotNetworkHandler.kt index ccd019d0e..b1f3e6443 100644 --- a/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMPCBotNetworkHandler.kt +++ b/mirai-core-timpc/src/commonMain/kotlin/net.mamoe.mirai.timpc/network/TIMPCBotNetworkHandler.kt @@ -20,8 +20,11 @@ import net.mamoe.mirai.timpc.TIMPCBot import net.mamoe.mirai.timpc.network.handler.DataPacketSocketAdapter import net.mamoe.mirai.timpc.network.handler.TemporaryPacketHandler import net.mamoe.mirai.timpc.network.packet.login.* -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.LockFreeLinkedList +import net.mamoe.mirai.utils.LoginFailedException +import net.mamoe.mirai.utils.OnlineStatus import net.mamoe.mirai.utils.io.* +import net.mamoe.mirai.utils.unsafeWeakRef import kotlin.coroutines.CoroutineContext import kotlin.random.Random @@ -90,8 +93,8 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor heartbeatJob?.join() } - override fun close(cause: Throwable?) { - super.close(cause) + override fun dispose(cause: Throwable?) { + super.dispose(cause) this.heartbeatJob?.cancel(CancellationException("handler closed")) this.heartbeatJob = null @@ -186,7 +189,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor try { launch { processReceive() } launch { - if (withTimeoutOrNull(currentBotConfiguration().touchTimeoutMillis) { expectingTouchResponse!!.join() } == null) { + if (withTimeoutOrNull(bot.configuration.touchTimeoutMillis) { expectingTouchResponse!!.join() } == null) { loginResult.complete(LoginResult.TIMEOUT) } } @@ -252,7 +255,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor if (e.cause !is CancellationException) { bot.logger.error("Caught SendPacketInternalException: ${e.cause?.message}") } - val configuration = currentBotConfiguration() + val configuration = bot.configuration delay(configuration.firstReconnectDelayMillis) bot.tryReinitializeNetworkHandler(configuration, e) return@withContext @@ -340,7 +343,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor privateKey = privateKey, token0825 = token0825, token00BA = null, - randomDeviceName = currentBotConfiguration().randomDeviceName + randomDeviceName = bot.configuration.randomDeviceName ) ) } @@ -370,7 +373,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor privateKey = privateKey, token0825 = token0825, token00BA = packet.token00BA, - randomDeviceName = currentBotConfiguration().randomDeviceName + randomDeviceName = bot.configuration.randomDeviceName ) ) } @@ -395,7 +398,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor this.captchaCache!!.writeFully(packet.captchaSectionN) this.token00BA = packet.token00BA - val configuration = currentBotConfiguration() + val configuration = bot.configuration if (packet.transmissionCompleted) { if (configuration.failOnCaptcha) { loginResult.complete(LoginResult.CAPTCHA) @@ -435,7 +438,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor privateKey = privateKey, token0825 = token0825, token00BA = packet.tokenUnknown ?: token00BA, - randomDeviceName = currentBotConfiguration().randomDeviceName, + randomDeviceName = bot.configuration.randomDeviceName, tlv0006 = packet.tlv0006 ) ) @@ -451,7 +454,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> { BotLoginSucceedEvent(bot).broadcast() - val configuration = currentBotConfiguration() + val configuration = bot.configuration heartbeatJob = this@TIMPCBotNetworkHandler.launch { while (socket.isOpen) { delay(configuration.heartbeatPeriodMillis) diff --git a/mirai-core-timpc/src/jvmMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt b/mirai-core-timpc/src/jvmMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt index 81f64456b..616a3984a 100644 --- a/mirai-core-timpc/src/jvmMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt +++ b/mirai-core-timpc/src/jvmMain/kotlin/net/mamoe/mirai/timpc/TIMPCBot.kt @@ -9,19 +9,17 @@ import kotlinx.io.core.use import kotlinx.io.streams.inputStream import net.mamoe.mirai.BotAccount import net.mamoe.mirai.message.data.Image +import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.ExternalImage -import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.toExternalImage import java.awt.image.BufferedImage import java.io.File import javax.imageio.ImageIO -import kotlin.coroutines.CoroutineContext internal actual class TIMPCBot actual constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext -) : TIMPCBotBase(account, logger, context) { + configuration: BotConfiguration +) : TIMPCBotBase(account, configuration) { suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } } suspend inline fun Image.downloadAsExternalImage(): ExternalImage = download().use { it.toExternalImage() } 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 5e8393f88..7efdf7392 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/Bot.kt @@ -12,9 +12,11 @@ import net.mamoe.mirai.data.AddFriendResult import net.mamoe.mirai.data.ImageLink import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.network.BotNetworkHandler -import net.mamoe.mirai.utils.* +import net.mamoe.mirai.utils.GroupNotFoundException +import net.mamoe.mirai.utils.LoginFailedException +import net.mamoe.mirai.utils.MiraiInternalAPI +import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.io.transferTo -import kotlin.coroutines.CoroutineContext /** * Mirai 的机器人. 一个机器人实例登录一个 QQ 账号. @@ -40,8 +42,6 @@ abstract class Bot : CoroutineScope { */ abstract val logger: MiraiLogger - abstract override val coroutineContext: CoroutineContext - // region contacts /** @@ -87,20 +87,11 @@ abstract class Bot : CoroutineScope { abstract val network: BotNetworkHandler /** - * 使用在默认配置基础上修改的配置进行登录 + * 登录 * * @throws LoginFailedException */ - suspend inline fun login(configuration: BotConfiguration.() -> Unit) { - return this.login(BotConfiguration().apply(configuration)) - } - - /** - * 使用特定配置进行登录 - * - * @throws LoginFailedException - */ - abstract suspend fun login(configuration: BotConfiguration = BotConfiguration.Default) + abstract suspend fun login() // endregion @@ -127,7 +118,7 @@ abstract class Bot : CoroutineScope { // endregion - abstract fun close(throwable: Throwable?) + abstract fun dispose(throwable: Throwable?) // region extensions diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotFactory.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotFactory.kt index 067608893..8e200c5fe 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotFactory.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotFactory.kt @@ -3,7 +3,11 @@ package net.mamoe.mirai import kotlinx.coroutines.CoroutineScope +import net.mamoe.mirai.network.packet.NullPacketId.factory +import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.MiraiLogger +import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext /** * 构造 [Bot] 的工厂. @@ -14,58 +18,13 @@ import net.mamoe.mirai.utils.MiraiLogger */ interface BotFactory { /** - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` + * 使用指定的 [配置][configuration] 构造 [Bot] 实例 */ - suspend fun Bot(account: BotAccount, logger: MiraiLogger? = null): Bot + fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)? = null) : Bot /** - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` + * 使用指定的 [配置][configuration] 构造 [Bot] 实例 */ - suspend fun Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot - - /** - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ - fun CoroutineScope.Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot - - /** - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ - fun CoroutineScope.Bot(account: BotAccount, logger: MiraiLogger? = null): Bot + fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)? = null): Bot = + this.Bot(BotAccount(qq, password), configuration) } \ No newline at end of file diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt index a06a5aac0..a537c21c3 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotHelper.kt @@ -4,11 +4,7 @@ package net.mamoe.mirai -import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.LoginFailedException -import kotlin.contracts.ExperimentalContracts -import kotlin.contracts.InvocationKind -import kotlin.contracts.contract import kotlin.jvm.JvmMultifileClass import kotlin.jvm.JvmName @@ -18,26 +14,11 @@ import kotlin.jvm.JvmName //Contacts /** - * 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回 [this] + * 登录, 返回 [this] * * @throws LoginFailedException */ -suspend inline fun Bot.alsoLogin(configuration: BotConfiguration = BotConfiguration.Default): Bot = - apply { login(configuration) } - -/** - * 使用在默认配置基础上修改的配置进行登录, 返回 [this] - * - * @throws LoginFailedException - */ -@UseExperimental(ExperimentalContracts::class) -suspend inline fun Bot.alsoLogin(configuration: BotConfiguration.() -> Unit): Bot { - contract { - callsInPlace(configuration, InvocationKind.EXACTLY_ONCE) - } - this.login(configuration) - return this -} +suspend inline fun Bot.alsoLogin(): Bot = also { login() } /** * 取得机器人的 QQ 号 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 06abb60a9..8f589465d 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/BotImpl.kt @@ -14,16 +14,16 @@ import kotlin.coroutines.CoroutineContext @MiraiInternalAPI abstract class BotImpl constructor( account: BotAccount, - logger: MiraiLogger?, - context: CoroutineContext + val configuration: BotConfiguration ) : Bot(), CoroutineScope { - private val supervisorJob = SupervisorJob(context[Job]) + private val botJob = SupervisorJob(configuration.parentCoroutineContext[Job]) override val coroutineContext: CoroutineContext = - context + supervisorJob + CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") } + configuration.parentCoroutineContext + botJob + (configuration.parentCoroutineContext[CoroutineExceptionHandler] + ?: CoroutineExceptionHandler { _, e -> e.logStacktrace("An exception was thrown under a coroutine of Bot") }) @Suppress("CanBePrimaryConstructorProperty") // for logger override val account: BotAccount = account - override val logger: MiraiLogger = logger ?: DefaultLogger("Bot(" + account.id + ")") + override val logger: MiraiLogger = configuration.logger ?: DefaultLogger("Bot(" + account.id + ")") init { @Suppress("LeakingThis") @@ -54,17 +54,15 @@ abstract class BotImpl constructor( private lateinit var _network: N - override suspend fun login(configuration: BotConfiguration) = - reinitializeNetworkHandler(configuration, null) + override suspend fun login() = reinitializeNetworkHandler(null) // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close fun tryReinitializeNetworkHandler( - configuration: BotConfiguration, cause: Throwable? ): Job = launch { repeat(configuration.reconnectionRetryTimes) { try { - reinitializeNetworkHandler(configuration, cause) + reinitializeNetworkHandler(cause) logger.info("Reconnected successfully") return@launch } catch (e: LoginFailedException) { @@ -74,19 +72,18 @@ abstract class BotImpl constructor( } private suspend fun reinitializeNetworkHandler( - configuration: BotConfiguration, cause: Throwable? ) { logger.info("BotAccount: $qqAccount") logger.info("Initializing BotNetworkHandler") try { if (::_network.isInitialized) { - _network.close(cause) + _network.dispose(cause) } } catch (e: Exception) { logger.error("Cannot close network handler", e) } - _network = createNetworkHandler(this.coroutineContext + configuration) + _network = createNetworkHandler(this.coroutineContext) _network.login() } @@ -96,15 +93,15 @@ abstract class BotImpl constructor( // endregion @UseExperimental(MiraiInternalAPI::class) - override fun close(throwable: Throwable?) { + override fun dispose(throwable: Throwable?) { if (throwable == null) { - network.close() - this.supervisorJob.complete() + network.dispose() + this.botJob.complete() groups.delegate.clear() qqs.delegate.clear() } else { - network.close(throwable) - this.supervisorJob.completeExceptionally(throwable) + network.dispose(throwable) + this.botJob.completeExceptionally(throwable) groups.delegate.clear() qqs.delegate.clear() } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/network/BotNetworkHandler.kt index 0eece10df..5708ecceb 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 @@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel * - SKey 刷新 [RequestSKeyPacket] * - 所有数据包处理和发送 * - * [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程 + * [BotNetworkHandler.dispose] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程 * * A BotNetworkHandler is used to connect with Tencent servers. */ @@ -46,7 +46,7 @@ abstract class BotNetworkHandler : CoroutineScope { /** * 关闭网络接口, 停止所有有关协程和任务 */ - open fun close(cause: Throwable? = null) { + open fun dispose(cause: Throwable? = null) { supervisor.cancel(CancellationException("handler closed", cause)) } diff --git a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt index 7fa19b109..3bc7d89b0 100644 --- a/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt +++ b/mirai-core/src/commonMain/kotlin/net.mamoe.mirai/utils/BotConfiguration.kt @@ -3,6 +3,7 @@ package net.mamoe.mirai.utils import kotlinx.io.core.IoBuffer import net.mamoe.mirai.Bot import kotlin.coroutines.CoroutineContext +import kotlin.coroutines.EmptyCoroutineContext import kotlin.coroutines.coroutineContext import kotlin.jvm.JvmStatic @@ -21,7 +22,17 @@ expect var DefaultCaptchaSolver: CaptchaSolver /** * 网络和连接配置 */ -class BotConfiguration : CoroutineContext.Element { +class BotConfiguration { + /** + * 日志记录器 + */ + var logger: PlatformLogger? = null + + /** + * 父 [CoroutineContext] + */ + var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + /** * 连接每个服务器的时间 */ @@ -68,15 +79,11 @@ class BotConfiguration : CoroutineContext.Element { */ var logPreviousMessages: Boolean = false - companion object Key : CoroutineContext.Key { + companion object { /** * 默认的配置实例 */ @JvmStatic val Default = BotConfiguration() } - - override val key: CoroutineContext.Key<*> get() = Key -} - -suspend inline fun currentBotConfiguration(): BotConfiguration = coroutineContext[BotConfiguration] ?: error("No BotConfiguration found") \ No newline at end of file +} \ No newline at end of file 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 e68d89139..85726ea76 100644 --- a/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt +++ b/mirai-core/src/jvmMain/kotlin/net/mamoe/mirai/BotFactoryJvm.kt @@ -2,8 +2,7 @@ package net.mamoe.mirai -import kotlinx.coroutines.CoroutineScope -import net.mamoe.mirai.utils.MiraiLogger +import net.mamoe.mirai.utils.BotConfiguration // Do not use ServiceLoader. Probably not working on MPP private val factory = run { @@ -22,69 +21,13 @@ private val factory = run { ) /** - * 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] - * - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` + * 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 */ -suspend fun Bot(account: BotAccount, logger: MiraiLogger? = null): Bot = - factory.Bot(account, logger) +fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)? = null): Bot = + factory.Bot(account, configuration) /** - * 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] - * - * 在当前 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * suspend fun myProcess(){ - * TIMPC.Bot(account, logger) - * } - * ``` + * 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例 */ -suspend fun Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot = - factory.Bot(qq, password, logger) - -/** - * 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] - * - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ -fun CoroutineScope.Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot = - factory.run { this@Bot.Bot(qq, password, logger) } - -/** - * 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] - * - * 在特定的 CoroutineScope 下构造 Bot 实例 - * 该 Bot 实例的生命周期将会跟随这个 CoroutineScope. - * 这个 CoroutineScope 也会等待 Bot 的结束才会结束. - * - * ```kotlin - * fun myProcess(){ - * TIMPC.run { - * GlobalScope.Bot(account, logger) - * } - * } - * ``` - */ -fun CoroutineScope.Bot(account: BotAccount, logger: MiraiLogger? = null): Bot = - factory.run { this@Bot.Bot(account, logger) } \ No newline at end of file +fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)? = null): Bot = + factory.Bot(qq, password, configuration) \ No newline at end of file diff --git a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt index 449daa1da..8465d568e 100644 --- a/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt +++ b/mirai-demos/mirai-demo-1/src/main/java/demo/subscribe/SubscribeSamples.kt @@ -43,10 +43,10 @@ suspend fun main() { id = 1994701121, password = "123456" ) - ).alsoLogin { + ) { // 覆盖默认的配置 randomDeviceName = false - } + }.alsoLogin() bot.messageDSL() directlySubscribe(bot) diff --git a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt index aa4c94160..986313e98 100644 --- a/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt +++ b/mirai-demos/mirai-demo-gentleman/src/main/kotlin/demo/gentleman/Main.kt @@ -49,29 +49,26 @@ suspend fun main() { id = 913366033, password = "a18260132383" ) - ).alsoLogin() + ) { + // override config here. + }.alsoLogin() - /** - * 监听所有事件 - */ + // 任何可以监听的对象都继承 Subscribable, 因此这个订阅会订阅全部的事件. GlobalScope.subscribeAlways { //bot.logger.verbose("收到了一个事件: $this") } + // 全局范围订阅事件, 不受 bot 实例影响 GlobalScope.subscribeAlways { it.approve() } - GlobalScope.subscribeGroupMessages { + // 订阅来自这个 bot 的群消息事件 + bot.subscribeGroupMessages { "群资料" reply { group.updateGroupInfo().toString().reply() } - startsWith("mt2months") { - val at: At by message - at.member().mute(1) - } - startsWith("mute") { val at: At by message at.member().mute(30) @@ -83,6 +80,7 @@ suspend fun main() { } } + // 订阅来自这个 bot 的消息事件, 可以是群消息也可以是好友消息 bot.subscribeMessages { always { }