Use BotConfiguration

This commit is contained in:
Him188 2019-12-24 14:48:07 +08:00
parent 885ae7806b
commit a47ea07feb
17 changed files with 101 additions and 294 deletions

View File

@ -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)

View File

@ -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")

View File

@ -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()
}

View File

@ -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()
}

View File

@ -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))
}

View File

@ -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 {

View File

@ -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)

View File

@ -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() }

View File

@ -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

View File

@ -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)
}

View File

@ -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

View File

@ -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()
}

View File

@ -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))
}

View File

@ -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")

View File

@ -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)

View File

@ -43,10 +43,10 @@ suspend fun main() {
id = 1994701121,
password = "123456"
)
).alsoLogin {
) {
// 覆盖默认的配置
randomDeviceName = false
}
}.alsoLogin()
bot.messageDSL()
directlySubscribe(bot)

View File

@ -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 {
}