Commit a47ea07f authored by Him188's avatar Him188

Use BotConfiguration

parent 885ae780
package net.mamoe.mirai.qqandroid package net.mamoe.mirai.qqandroid
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.BotConfiguration
import kotlin.coroutines.CoroutineContext
internal actual class QQAndroidBot actual constructor( internal actual class QQAndroidBot actual constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : QQAndroidBotBase(account, configuration)
) : QQAndroidBotBase(account, logger, context) { \ No newline at end of file
}
\ No newline at end of file
...@@ -9,21 +9,18 @@ import net.mamoe.mirai.message.data.Image ...@@ -9,21 +9,18 @@ import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler import net.mamoe.mirai.qqandroid.network.QQAndroidBotNetworkHandler
import net.mamoe.mirai.utils.BotConfiguration import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiInternalAPI import net.mamoe.mirai.utils.MiraiInternalAPI
import net.mamoe.mirai.utils.MiraiLogger
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
internal expect class QQAndroidBot( internal expect class QQAndroidBot(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext
) : QQAndroidBotBase ) : QQAndroidBotBase
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
internal abstract class QQAndroidBotBase constructor( internal abstract class QQAndroidBotBase constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) {
) : BotImpl<QQAndroidBotNetworkHandler>(account, logger, context) {
override val qqs: ContactList<QQ> override val qqs: ContactList<QQ>
get() = TODO("not implemented") get() = TODO("not implemented")
......
package net.mamoe.mirai.qqandroid package net.mamoe.mirai.qqandroid
import kotlinx.coroutines.GlobalScope
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.alsoLogin import net.mamoe.mirai.alsoLogin
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.BotConfiguration
import kotlin.coroutines.CoroutineContext
internal actual class QQAndroidBot actual constructor( internal actual class QQAndroidBot actual constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : QQAndroidBotBase(account, configuration)
) : QQAndroidBotBase(account, logger, context)
suspend fun main() { suspend fun main() {
val bot = QQAndroidBot(BotAccount(1, ""), null, GlobalScope.coroutineContext).alsoLogin() val bot = QQAndroidBot(BotAccount(1, ""), BotConfiguration()).alsoLogin()
bot.network.awaitDisconnection() bot.network.awaitDisconnection()
} }
\ No newline at end of file
...@@ -6,13 +6,11 @@ import kotlinx.io.InputStream ...@@ -6,13 +6,11 @@ import kotlinx.io.InputStream
import kotlinx.io.streams.inputStream import kotlinx.io.streams.inputStream
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.BotConfiguration
import kotlin.coroutines.CoroutineContext
internal actual class TIMPCBot actual constructor( internal actual class TIMPCBot actual constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : TIMPCBotBase(account, configuration) {
) : TIMPCBotBase(account, logger, context) {
suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream()
} }
\ No newline at end of file
...@@ -2,75 +2,19 @@ ...@@ -2,75 +2,19 @@
package net.mamoe.mirai.timpc package net.mamoe.mirai.timpc
import kotlinx.coroutines.CoroutineScope
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.BotFactory import net.mamoe.mirai.BotFactory
import net.mamoe.mirai.timpc.TIMPC.Bot import net.mamoe.mirai.timpc.TIMPC.Bot
import net.mamoe.mirai.utils.MiraiLogger import net.mamoe.mirai.utils.BotConfiguration
import kotlin.coroutines.coroutineContext
/** /**
* TIM PC 协议的 [Bot] 构造器. * TIM PC 协议的 [Bot] 构造器.
*/ */
object TIMPC : BotFactory { object TIMPC : BotFactory {
/** /**
* 在当前 CoroutineScope 下构造 Bot 实例 * 使用指定的 [配置][configuration] 构造 [Bot] 实例
* 该 Bot 实例的生命周期将会跟随这个 CoroutineScope.
* 这个 CoroutineScope 也会等待 Bot 的结束才会结束.
*
* ```kotlin
* suspend fun myProcess(){
* TIMPC.Bot(account, logger)
* }
* ```
*/ */
override suspend fun Bot(account: BotAccount, logger: MiraiLogger?): Bot = override fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)?): Bot =
TIMPCBot(account, logger, coroutineContext) TIMPCBot(account, if (configuration == null) BotConfiguration.Default else BotConfiguration().apply(configuration))
/**
* 在当前 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)
} }
\ No newline at end of file
...@@ -37,16 +37,14 @@ import kotlin.jvm.JvmSynthetic ...@@ -37,16 +37,14 @@ import kotlin.jvm.JvmSynthetic
internal expect class TIMPCBot constructor( internal expect class TIMPCBot constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext
) : TIMPCBotBase ) : TIMPCBotBase
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
internal abstract class TIMPCBotBase constructor( internal abstract class TIMPCBotBase constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : BotImpl<TIMPCBotNetworkHandler>(account, configuration) {
) : BotImpl<TIMPCBotNetworkHandler>(account, logger ?: DefaultLogger("Bot(" + account.id + ")"), context) {
@UseExperimental(ExperimentalUnsignedTypes::class) @UseExperimental(ExperimentalUnsignedTypes::class)
companion object { companion object {
......
...@@ -20,8 +20,11 @@ import net.mamoe.mirai.timpc.TIMPCBot ...@@ -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.DataPacketSocketAdapter
import net.mamoe.mirai.timpc.network.handler.TemporaryPacketHandler import net.mamoe.mirai.timpc.network.handler.TemporaryPacketHandler
import net.mamoe.mirai.timpc.network.packet.login.* 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.io.*
import net.mamoe.mirai.utils.unsafeWeakRef
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.random.Random import kotlin.random.Random
...@@ -90,8 +93,8 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -90,8 +93,8 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
heartbeatJob?.join() heartbeatJob?.join()
} }
override fun close(cause: Throwable?) { override fun dispose(cause: Throwable?) {
super.close(cause) super.dispose(cause)
this.heartbeatJob?.cancel(CancellationException("handler closed")) this.heartbeatJob?.cancel(CancellationException("handler closed"))
this.heartbeatJob = null this.heartbeatJob = null
...@@ -186,7 +189,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -186,7 +189,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
try { try {
launch { processReceive() } launch { processReceive() }
launch { launch {
if (withTimeoutOrNull(currentBotConfiguration().touchTimeoutMillis) { expectingTouchResponse!!.join() } == null) { if (withTimeoutOrNull(bot.configuration.touchTimeoutMillis) { expectingTouchResponse!!.join() } == null) {
loginResult.complete(LoginResult.TIMEOUT) loginResult.complete(LoginResult.TIMEOUT)
} }
} }
...@@ -252,7 +255,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -252,7 +255,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
if (e.cause !is CancellationException) { if (e.cause !is CancellationException) {
bot.logger.error("Caught SendPacketInternalException: ${e.cause?.message}") bot.logger.error("Caught SendPacketInternalException: ${e.cause?.message}")
} }
val configuration = currentBotConfiguration() val configuration = bot.configuration
delay(configuration.firstReconnectDelayMillis) delay(configuration.firstReconnectDelayMillis)
bot.tryReinitializeNetworkHandler(configuration, e) bot.tryReinitializeNetworkHandler(configuration, e)
return@withContext return@withContext
...@@ -340,7 +343,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -340,7 +343,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
privateKey = privateKey, privateKey = privateKey,
token0825 = token0825, token0825 = token0825,
token00BA = null, token00BA = null,
randomDeviceName = currentBotConfiguration().randomDeviceName randomDeviceName = bot.configuration.randomDeviceName
) )
) )
} }
...@@ -370,7 +373,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -370,7 +373,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
privateKey = privateKey, privateKey = privateKey,
token0825 = token0825, token0825 = token0825,
token00BA = packet.token00BA, token00BA = packet.token00BA,
randomDeviceName = currentBotConfiguration().randomDeviceName randomDeviceName = bot.configuration.randomDeviceName
) )
) )
} }
...@@ -395,7 +398,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -395,7 +398,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
this.captchaCache!!.writeFully(packet.captchaSectionN) this.captchaCache!!.writeFully(packet.captchaSectionN)
this.token00BA = packet.token00BA this.token00BA = packet.token00BA
val configuration = currentBotConfiguration() val configuration = bot.configuration
if (packet.transmissionCompleted) { if (packet.transmissionCompleted) {
if (configuration.failOnCaptcha) { if (configuration.failOnCaptcha) {
loginResult.complete(LoginResult.CAPTCHA) loginResult.complete(LoginResult.CAPTCHA)
...@@ -435,7 +438,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -435,7 +438,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
privateKey = privateKey, privateKey = privateKey,
token0825 = token0825, token0825 = token0825,
token00BA = packet.tokenUnknown ?: token00BA, token00BA = packet.tokenUnknown ?: token00BA,
randomDeviceName = currentBotConfiguration().randomDeviceName, randomDeviceName = bot.configuration.randomDeviceName,
tlv0006 = packet.tlv0006 tlv0006 = packet.tlv0006
) )
) )
...@@ -451,7 +454,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor ...@@ -451,7 +454,7 @@ internal class TIMPCBotNetworkHandler internal constructor(coroutineContext: Cor
is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> { is ChangeOnlineStatusPacket.ChangeOnlineStatusResponse -> {
BotLoginSucceedEvent(bot).broadcast() BotLoginSucceedEvent(bot).broadcast()
val configuration = currentBotConfiguration() val configuration = bot.configuration
heartbeatJob = this@TIMPCBotNetworkHandler.launch { heartbeatJob = this@TIMPCBotNetworkHandler.launch {
while (socket.isOpen) { while (socket.isOpen) {
delay(configuration.heartbeatPeriodMillis) delay(configuration.heartbeatPeriodMillis)
......
...@@ -9,19 +9,17 @@ import kotlinx.io.core.use ...@@ -9,19 +9,17 @@ import kotlinx.io.core.use
import kotlinx.io.streams.inputStream import kotlinx.io.streams.inputStream
import net.mamoe.mirai.BotAccount import net.mamoe.mirai.BotAccount
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.ExternalImage import net.mamoe.mirai.utils.ExternalImage
import net.mamoe.mirai.utils.MiraiLogger
import net.mamoe.mirai.utils.toExternalImage import net.mamoe.mirai.utils.toExternalImage
import java.awt.image.BufferedImage import java.awt.image.BufferedImage
import java.io.File import java.io.File
import javax.imageio.ImageIO import javax.imageio.ImageIO
import kotlin.coroutines.CoroutineContext
internal actual class TIMPCBot actual constructor( internal actual class TIMPCBot actual constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, configuration: BotConfiguration
context: CoroutineContext ) : TIMPCBotBase(account, configuration) {
) : TIMPCBotBase(account, logger, context) {
suspend inline fun Image.downloadAsStream(): InputStream = download().inputStream() 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.downloadAsBufferedImage(): BufferedImage = withContext(IO) { downloadAsStream().use { ImageIO.read(it) } }
suspend inline fun Image.downloadAsExternalImage(): ExternalImage = download().use { it.toExternalImage() } suspend inline fun Image.downloadAsExternalImage(): ExternalImage = download().use { it.toExternalImage() }
......
...@@ -12,9 +12,11 @@ import net.mamoe.mirai.data.AddFriendResult ...@@ -12,9 +12,11 @@ import net.mamoe.mirai.data.AddFriendResult
import net.mamoe.mirai.data.ImageLink import net.mamoe.mirai.data.ImageLink
import net.mamoe.mirai.message.data.Image import net.mamoe.mirai.message.data.Image
import net.mamoe.mirai.network.BotNetworkHandler 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 net.mamoe.mirai.utils.io.transferTo
import kotlin.coroutines.CoroutineContext
/** /**
* Mirai 的机器人. 一个机器人实例登录一个 QQ 账号. * Mirai 的机器人. 一个机器人实例登录一个 QQ 账号.
...@@ -40,8 +42,6 @@ abstract class Bot : CoroutineScope { ...@@ -40,8 +42,6 @@ abstract class Bot : CoroutineScope {
*/ */
abstract val logger: MiraiLogger abstract val logger: MiraiLogger
abstract override val coroutineContext: CoroutineContext
// region contacts // region contacts
/** /**
...@@ -87,20 +87,11 @@ abstract class Bot : CoroutineScope { ...@@ -87,20 +87,11 @@ abstract class Bot : CoroutineScope {
abstract val network: BotNetworkHandler abstract val network: BotNetworkHandler
/** /**
* 使用在默认配置基础上修改的配置进行登录 * 登录
*
* @throws LoginFailedException
*/
suspend inline fun login(configuration: BotConfiguration.() -> Unit) {
return this.login(BotConfiguration().apply(configuration))
}
/**
* 使用特定配置进行登录
* *
* @throws LoginFailedException * @throws LoginFailedException
*/ */
abstract suspend fun login(configuration: BotConfiguration = BotConfiguration.Default) abstract suspend fun login()
// endregion // endregion
...@@ -127,7 +118,7 @@ abstract class Bot : CoroutineScope { ...@@ -127,7 +118,7 @@ abstract class Bot : CoroutineScope {
// endregion // endregion
abstract fun close(throwable: Throwable?) abstract fun dispose(throwable: Throwable?)
// region extensions // region extensions
......
...@@ -3,7 +3,11 @@ ...@@ -3,7 +3,11 @@
package net.mamoe.mirai package net.mamoe.mirai
import kotlinx.coroutines.CoroutineScope 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 net.mamoe.mirai.utils.MiraiLogger
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
/** /**
* 构造 [Bot] 的工厂. * 构造 [Bot] 的工厂.
...@@ -14,58 +18,13 @@ import net.mamoe.mirai.utils.MiraiLogger ...@@ -14,58 +18,13 @@ import net.mamoe.mirai.utils.MiraiLogger
*/ */
interface BotFactory { interface BotFactory {
/** /**
* 在当前 CoroutineScope 下构造 Bot 实例 * 使用指定的 [配置][configuration] 构造 [Bot] 实例
* 该 Bot 实例的生命周期将会跟随这个 CoroutineScope.
* 这个 CoroutineScope 也会等待 Bot 的结束才会结束.
*
* ```kotlin
* suspend fun myProcess(){
* TIMPC.Bot(account, logger)
* }
* ```
*/ */
suspend fun Bot(account: BotAccount, logger: MiraiLogger? = null): Bot fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)? = null) : Bot
/** /**
* 在当前 CoroutineScope 下构造 Bot 实例 * 使用指定的 [配置][configuration] 构造 [Bot] 实例
* 该 Bot 实例的生命周期将会跟随这个 CoroutineScope.
* 这个 CoroutineScope 也会等待 Bot 的结束才会结束.
*
* ```kotlin
* suspend fun myProcess(){
* TIMPC.Bot(account, logger)
* }
* ```
*/ */
suspend fun Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)? = null): Bot =
this.Bot(BotAccount(qq, password), configuration)
/**
* 在特定的 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
} }
\ No newline at end of file
...@@ -4,11 +4,7 @@ ...@@ -4,11 +4,7 @@
package net.mamoe.mirai package net.mamoe.mirai
import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.LoginFailedException 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.JvmMultifileClass
import kotlin.jvm.JvmName import kotlin.jvm.JvmName
...@@ -18,26 +14,11 @@ import kotlin.jvm.JvmName ...@@ -18,26 +14,11 @@ import kotlin.jvm.JvmName
//Contacts //Contacts
/** /**
* 使用默认的配置 ([BotConfiguration.Default]) 登录, 返回 [this] * 登录, 返回 [this]
* *
* @throws LoginFailedException * @throws LoginFailedException
*/ */
suspend inline fun Bot.alsoLogin(configuration: BotConfiguration = BotConfiguration.Default): Bot = suspend inline fun Bot.alsoLogin(): Bot = also { login() }
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
}
/** /**
* 取得机器人的 QQ 号 * 取得机器人的 QQ 号
......
...@@ -14,16 +14,16 @@ import kotlin.coroutines.CoroutineContext ...@@ -14,16 +14,16 @@ import kotlin.coroutines.CoroutineContext
@MiraiInternalAPI @MiraiInternalAPI
abstract class BotImpl<N : BotNetworkHandler> constructor( abstract class BotImpl<N : BotNetworkHandler> constructor(
account: BotAccount, account: BotAccount,
logger: MiraiLogger?, val configuration: BotConfiguration
context: CoroutineContext
) : Bot(), CoroutineScope { ) : Bot(), CoroutineScope {
private val supervisorJob = SupervisorJob(context[Job]) private val botJob = SupervisorJob(configuration.parentCoroutineContext[Job])
override val coroutineContext: CoroutineContext = 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 @Suppress("CanBePrimaryConstructorProperty") // for logger
override val account: BotAccount = account 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 { init {
@Suppress("LeakingThis") @Suppress("LeakingThis")
...@@ -54,17 +54,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -54,17 +54,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
private lateinit var _network: N private lateinit var _network: N
override suspend fun login(configuration: BotConfiguration) = override suspend fun login() = reinitializeNetworkHandler(null)
reinitializeNetworkHandler(configuration, null)
// shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close // shouldn't be suspend!! This function MUST NOT inherit the context from the caller because the caller(NetworkHandler) is going to close
fun tryReinitializeNetworkHandler( fun tryReinitializeNetworkHandler(
configuration: BotConfiguration,
cause: Throwable? cause: Throwable?
): Job = launch { ): Job = launch {
repeat(configuration.reconnectionRetryTimes) { repeat(configuration.reconnectionRetryTimes) {
try { try {
reinitializeNetworkHandler(configuration, cause) reinitializeNetworkHandler(cause)
logger.info("Reconnected successfully") logger.info("Reconnected successfully")
return@launch return@launch
} catch (e: LoginFailedException) { } catch (e: LoginFailedException) {
...@@ -74,19 +72,18 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -74,19 +72,18 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
} }
private suspend fun reinitializeNetworkHandler( private suspend fun reinitializeNetworkHandler(
configuration: BotConfiguration,
cause: Throwable? cause: Throwable?
) { ) {
logger.info("BotAccount: $qqAccount") logger.info("BotAccount: $qqAccount")
logger.info("Initializing BotNetworkHandler") logger.info("Initializing BotNetworkHandler")
try { try {
if (::_network.isInitialized) { if (::_network.isInitialized) {
_network.close(cause) _network.dispose(cause)
} }
} catch (e: Exception) { } catch (e: Exception) {
logger.error("Cannot close network handler", e) logger.error("Cannot close network handler", e)
} }
_network = createNetworkHandler(this.coroutineContext + configuration) _network = createNetworkHandler(this.coroutineContext)
_network.login() _network.login()
} }
...@@ -96,15 +93,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor( ...@@ -96,15 +93,15 @@ abstract class BotImpl<N : BotNetworkHandler> constructor(
// endregion // endregion
@UseExperimental(MiraiInternalAPI::class) @UseExperimental(MiraiInternalAPI::class)
override fun close(throwable: Throwable?) { override fun dispose(throwable: Throwable?) {
if (throwable == null) { if (throwable == null) {
network.close() network.dispose()
this.supervisorJob.complete() this.botJob.complete()
groups.delegate.clear() groups.delegate.clear()
qqs.delegate.clear() qqs.delegate.clear()
} else { } else {
network.close(throwable) network.dispose(throwable)
this.supervisorJob.completeExceptionally(throwable) this.botJob.completeExceptionally(throwable)
groups.delegate.clear() groups.delegate.clear()
qqs.delegate.clear() qqs.delegate.clear()
} }
......
...@@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel ...@@ -22,7 +22,7 @@ import net.mamoe.mirai.utils.io.PlatformDatagramChannel
* - SKey 刷新 [RequestSKeyPacket] * - SKey 刷新 [RequestSKeyPacket]
* - 所有数据包处理和发送 * - 所有数据包处理和发送
* *
* [BotNetworkHandler.close] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程 * [BotNetworkHandler.dispose] 时将会 [取消][kotlin.coroutines.CoroutineContext.cancelChildren] 所有此作用域下的协程
* *
* A BotNetworkHandler is used to connect with Tencent servers. * A BotNetworkHandler is used to connect with Tencent servers.
*/ */
...@@ -46,7 +46,7 @@ abstract class BotNetworkHandler : CoroutineScope { ...@@ -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)) supervisor.cancel(CancellationException("handler closed", cause))
} }
......
...@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils ...@@ -3,6 +3,7 @@ package net.mamoe.mirai.utils
import kotlinx.io.core.IoBuffer import kotlinx.io.core.IoBuffer
import net.mamoe.mirai.Bot import net.mamoe.mirai.Bot
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext import kotlin.coroutines.coroutineContext
import kotlin.jvm.JvmStatic import kotlin.jvm.JvmStatic
...@@ -21,7 +22,17 @@ expect var DefaultCaptchaSolver: CaptchaSolver ...@@ -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 { ...@@ -68,15 +79,11 @@ class BotConfiguration : CoroutineContext.Element {
*/ */
var logPreviousMessages: Boolean = false var logPreviousMessages: Boolean = false
companion object Key : CoroutineContext.Key<BotConfiguration> { companion object {
/** /**
* 默认的配置实例 * 默认的配置实例
*/ */
@JvmStatic @JvmStatic
val Default = BotConfiguration() val Default = BotConfiguration()
} }
}
override val key: CoroutineContext.Key<*> get() = Key \ No newline at end of file
}
suspend inline fun currentBotConfiguration(): BotConfiguration = coroutineContext[BotConfiguration] ?: error("No BotConfiguration found")
\ No newline at end of file
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
package net.mamoe.mirai package net.mamoe.mirai
import kotlinx.coroutines.CoroutineScope import net.mamoe.mirai.utils.BotConfiguration
import net.mamoe.mirai.utils.MiraiLogger
// Do not use ServiceLoader. Probably not working on MPP // Do not use ServiceLoader. Probably not working on MPP
private val factory = run { private val factory = run {
...@@ -22,69 +21,13 @@ private val factory = run { ...@@ -22,69 +21,13 @@ private val factory = run {
) )
/** /**
* 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] * 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
*
* 在当前 CoroutineScope 下构造 Bot 实例
* 该 Bot 实例的生命周期将会跟随这个 CoroutineScope.
* 这个 CoroutineScope 也会等待 Bot 的结束才会结束.
*
* ```kotlin
* suspend fun myProcess(){
* TIMPC.Bot(account, logger)
* }
* ```
*/ */
suspend fun Bot(account: BotAccount, logger: MiraiLogger? = null): Bot = fun Bot(account: BotAccount, configuration: (BotConfiguration.() -> Unit)? = null): Bot =
factory.Bot(account, logger) factory.Bot(account, configuration)
/** /**
* 加载现有协议的 [BotFactory], 并调用其 [BotFactory.Bot] * 加载现有协议的 [BotFactory], 并使用指定的 [配置][configuration] 构造 [Bot] 实例
*
* 在当前 CoroutineScope 下构造 Bot 实例
* 该 Bot 实例的生命周期将会跟随这个 CoroutineScope.
* 这个 CoroutineScope 也会等待 Bot 的结束才会结束.
*
* ```kotlin
* suspend fun myProcess(){
* TIMPC.Bot(account, logger)
* }
* ```
*/ */
suspend fun Bot(qq: Long, password: String, logger: MiraiLogger? = null): Bot = fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)? = null): Bot =
factory.Bot(qq, password, logger) factory.Bot(qq, password, configuration)
\ No newline at end of file
/**
* 加载现有协议的 [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
...@@ -43,10 +43,10 @@ suspend fun main() { ...@@ -43,10 +43,10 @@ suspend fun main() {
id = 1994701121, id = 1994701121,
password = "123456" password = "123456"
) )
).alsoLogin { ) {
// 覆盖默认的配置 // 覆盖默认的配置
randomDeviceName = false randomDeviceName = false
} }.alsoLogin()
bot.messageDSL() bot.messageDSL()
directlySubscribe(bot) directlySubscribe(bot)
......
...@@ -49,29 +49,26 @@ suspend fun main() { ...@@ -49,29 +49,26 @@ suspend fun main() {
id = 913366033, id = 913366033,
password = "a18260132383" password = "a18260132383"
) )
).alsoLogin() ) {
// override config here.
}.alsoLogin()
/** // 任何可以监听的对象都继承 Subscribable, 因此这个订阅会订阅全部的事件.
* 监听所有事件
*/
GlobalScope.subscribeAlways<Subscribable> { GlobalScope.subscribeAlways<Subscribable> {
//bot.logger.verbose("收到了一个事件: $this") //bot.logger.verbose("收到了一个事件: $this")
} }
// 全局范围订阅事件, 不受 bot 实例影响
GlobalScope.subscribeAlways<ReceiveFriendAddRequestEvent> { GlobalScope.subscribeAlways<ReceiveFriendAddRequestEvent> {
it.approve() it.approve()
} }
GlobalScope.subscribeGroupMessages { // 订阅来自这个 bot 的群消息事件
bot.subscribeGroupMessages {
"群资料" reply { "群资料" reply {
group.updateGroupInfo().toString().reply() group.updateGroupInfo().toString().reply()
} }
startsWith("mt2months") {
val at: At by message
at.member().mute(1)
}
startsWith("mute") { startsWith("mute") {
val at: At by message val at: At by message
at.member().mute(30) at.member().mute(30)
...@@ -83,6 +80,7 @@ suspend fun main() { ...@@ -83,6 +80,7 @@ suspend fun main() {
} }
} }
// 订阅来自这个 bot 的消息事件, 可以是群消息也可以是好友消息
bot.subscribeMessages { bot.subscribeMessages {
always { always {
} }
......
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