mirror of
https://github.com/mamoe/mirai.git
synced 2025-02-02 04:30:25 +08:00
Use BotConfiguration
This commit is contained in:
parent
885ae7806b
commit
a47ea07feb
@ -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) {
|
||||
|
||||
}
|
||||
configuration: BotConfiguration
|
||||
) : QQAndroidBotBase(account, configuration)
|
@ -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<QQAndroidBotNetworkHandler>(account, logger, context) {
|
||||
configuration: BotConfiguration
|
||||
) : BotImpl<QQAndroidBotNetworkHandler>(account, configuration) {
|
||||
override val qqs: ContactList<QQ>
|
||||
get() = TODO("not implemented")
|
||||
|
||||
|
@ -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()
|
||||
}
|
@ -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()
|
||||
}
|
@ -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))
|
||||
}
|
@ -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<TIMPCBotNetworkHandler>(account, logger ?: DefaultLogger("Bot(" + account.id + ")"), context) {
|
||||
configuration: BotConfiguration
|
||||
) : BotImpl<TIMPCBotNetworkHandler>(account, configuration) {
|
||||
|
||||
@UseExperimental(ExperimentalUnsignedTypes::class)
|
||||
companion object {
|
||||
|
@ -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)
|
||||
|
@ -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() }
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
}
|
@ -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 号
|
||||
|
@ -14,16 +14,16 @@ import kotlin.coroutines.CoroutineContext
|
||||
@MiraiInternalAPI
|
||||
abstract class BotImpl<N : BotNetworkHandler> 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<N : BotNetworkHandler> 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<N : BotNetworkHandler> 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<N : BotNetworkHandler> 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()
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
|
@ -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<BotConfiguration> {
|
||||
companion object {
|
||||
/**
|
||||
* 默认的配置实例
|
||||
*/
|
||||
@JvmStatic
|
||||
val Default = BotConfiguration()
|
||||
}
|
||||
|
||||
override val key: CoroutineContext.Key<*> get() = Key
|
||||
}
|
||||
|
||||
suspend inline fun currentBotConfiguration(): BotConfiguration = coroutineContext[BotConfiguration] ?: error("No BotConfiguration found")
|
@ -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) }
|
||||
fun Bot(qq: Long, password: String, configuration: (BotConfiguration.() -> Unit)? = null): Bot =
|
||||
factory.Bot(qq, password, configuration)
|
@ -43,10 +43,10 @@ suspend fun main() {
|
||||
id = 1994701121,
|
||||
password = "123456"
|
||||
)
|
||||
).alsoLogin {
|
||||
) {
|
||||
// 覆盖默认的配置
|
||||
randomDeviceName = false
|
||||
}
|
||||
}.alsoLogin()
|
||||
|
||||
bot.messageDSL()
|
||||
directlySubscribe(bot)
|
||||
|
@ -49,29 +49,26 @@ suspend fun main() {
|
||||
id = 913366033,
|
||||
password = "a18260132383"
|
||||
)
|
||||
).alsoLogin()
|
||||
) {
|
||||
// override config here.
|
||||
}.alsoLogin()
|
||||
|
||||
/**
|
||||
* 监听所有事件
|
||||
*/
|
||||
// 任何可以监听的对象都继承 Subscribable, 因此这个订阅会订阅全部的事件.
|
||||
GlobalScope.subscribeAlways<Subscribable> {
|
||||
//bot.logger.verbose("收到了一个事件: $this")
|
||||
}
|
||||
|
||||
// 全局范围订阅事件, 不受 bot 实例影响
|
||||
GlobalScope.subscribeAlways<ReceiveFriendAddRequestEvent> {
|
||||
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 {
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user