diff --git a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt index dffc84cba..6cbd25d17 100644 --- a/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt +++ b/mirai-core-api/src/commonMain/kotlin/utils/BotConfiguration.kt @@ -57,32 +57,87 @@ public open class BotConfiguration { // open for Java public var workingDir: File = File(".") /** - * 日志记录器 - * - * - 默认打印到标准输出, 通过 [MiraiLogger.create] - * - 忽略所有日志: [noBotLog] - * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` - * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` - * - * @see MiraiLogger + * Json 序列化器, 使用 'kotlinx.serialization' */ - public var botLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Bot ${it.id}") } + @MiraiExperimentalApi + public var json: Json = kotlin.runCatching { + Json { + isLenient = true + ignoreUnknownKeys = true + prettyPrint = true + } + }.getOrElse { Json {} } - /** - * 网络层日志构造器 - * - * - 默认打印到标准输出, 通过 [MiraiLogger.create] - * - 忽略所有日志: [noNetworkLog] - * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` - * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` - * - * @see MiraiLogger - */ - public var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Net ${it.id}") } + /////////////////////////////////////////////////////////////////////////// + // Coroutines + /////////////////////////////////////////////////////////////////////////// /** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */ public var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext + /** + * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. + * + * Bot 将会使用一个 [SupervisorJob] 覆盖 [coroutineContext] 当前协程的 [Job], 并使用当前协程的 [Job] 作为父 [Job] + * + * 用例: + * ``` + * coroutineScope { + * val bot = Bot(...) { + * inheritCoroutineContext() + * } + * bot.login() + * } // coroutineScope 会等待 Bot 退出 + * ``` + * + * + * **注意**: `bot.cancel` 时将会让父 [Job] 也被 cancel. + * ``` + * coroutineScope { // this: CoroutineScope + * launch { + * while(isActive) { + * delay(500) + * println("I'm alive") + * } + * } + * + * val bot = Bot(...) { + * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job + * } + * bot.login() + * bot.cancel() // 取消了整个 `coroutineScope`, 因此上文不断打印 `"I'm alive"` 的协程也会被取消. + * } + * ``` + * + * 因此, 此函数尤为适合在 `suspend fun main()` 中使用, 它能阻止主线程退出: + * ``` + * suspend fun main() { + * val bot = Bot() { + * inheritCoroutineContext() + * } + * bot.subscribe { ... } + * + * // 主线程不会退出, 直到 Bot 离线. + * } + * ``` + * + * 简言之, + * - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext]. + * - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext] + * + * @see parentCoroutineContext + */ + @JvmSynthetic + @ConfigurationDsl + public suspend inline fun inheritCoroutineContext() { + parentCoroutineContext = coroutineContext + } + + + /////////////////////////////////////////////////////////////////////////// + // Connection + /////////////////////////////////////////////////////////////////////////// + /** 心跳周期. 过长会导致被服务器断开连接. */ public var heartbeatPeriodMillis: Long = 60.secondsToMillis @@ -125,6 +180,26 @@ public open class BotConfiguration { // open for Java /** 使用协议类型 */ public var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PHONE + public enum class MiraiProtocol { + /** + * Android 手机. 所有功能都支持. + */ + ANDROID_PHONE, + + /** + * Android 平板. + * + * 注意: 不支持戳一戳事件解析 + */ + ANDROID_PAD, + + /** + * Android 手表. + */ + ANDROID_WATCH, + + } + /** * Highway 通道上传图片, 语音, 文件等资源时的协程数量. * @@ -135,25 +210,6 @@ public open class BotConfiguration { // open for Java */ public var highwayUploadCoroutineCount: Int = Runtime.getRuntime().availableProcessors() - /** - * 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息. - * @see fileBasedDeviceInfo 使用指定文件存储设备信息 - * @see randomDeviceInfo 使用随机设备信息 - */ - public var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually. - - /** - * Json 序列化器, 使用 'kotlinx.serialization' - */ - @MiraiExperimentalApi - public var json: Json = kotlin.runCatching { - Json { - isLenient = true - ignoreUnknownKeys = true - prettyPrint = true - } - }.getOrElse { Json {} } - /** * 设置 [autoReconnectOnForceOffline] 为 `true`, 即在被挤下线时自动重连. * @since 2.1 @@ -163,6 +219,17 @@ public open class BotConfiguration { // open for Java autoReconnectOnForceOffline = true } + /////////////////////////////////////////////////////////////////////////// + // Device + /////////////////////////////////////////////////////////////////////////// + + /** + * 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息. + * @see fileBasedDeviceInfo 使用指定文件存储设备信息 + * @see randomDeviceInfo 使用随机设备信息 + */ + public var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually. + /** * 使用随机设备信息. * @@ -198,6 +265,34 @@ public open class BotConfiguration { // open for Java deviceInfo = getFileBasedDeviceInfoSupplier { workingDir.resolve(filepath) } } + /////////////////////////////////////////////////////////////////////////// + // Logging + /////////////////////////////////////////////////////////////////////////// + + /** + * 日志记录器 + * + * - 默认打印到标准输出, 通过 [MiraiLogger.create] + * - 忽略所有日志: [noBotLog] + * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` + * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` + * + * @see MiraiLogger + */ + public var botLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Bot ${it.id}") } + + /** + * 网络层日志构造器 + * + * - 默认打印到标准输出, 通过 [MiraiLogger.create] + * - 忽略所有日志: [noNetworkLog] + * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }` + * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }` + * + * @see MiraiLogger + */ + public var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { MiraiLogger.create("Net ${it.id}") } + /** * 重定向 [网络日志][networkLoggerSupplier] 到指定目录. 若目录不存在将会自动创建 ([File.mkdirs]) @@ -265,33 +360,6 @@ public open class BotConfiguration { // open for Java botLoggerSupplier = { DirectoryLogger(identity(it), workingDir.resolve(dir), retain) } } - public enum class MiraiProtocol { - /** - * Android 手机. 所有功能都支持. - */ - ANDROID_PHONE, - - /** - * Android 平板. - * - * 注意: 不支持戳一戳事件解析 - */ - ANDROID_PAD, - - /** - * Android 手表. - */ - ANDROID_WATCH, - - } - - public companion object { - /** 默认的配置实例. 可以进行修改 */ - @JvmStatic - public val Default: BotConfiguration = BotConfiguration() - } - - /** * 不显示网络日志. 不推荐. * @see networkLoggerSupplier 更多日志处理方式 @@ -342,6 +410,7 @@ public open class BotConfiguration { // open for Java * @since 2.4 * @see BotConfiguration.enableFriendListCache */ + @ConfigurationDsl public fun enableFriendListCache() { friendListCache = FriendListCache() } @@ -375,69 +444,14 @@ public open class BotConfiguration { // open for Java * @since 2.4 * @see BotConfiguration.enableGroupMemberListCache */ + @ConfigurationDsl public fun enableGroupMemberListCache() { friendListCache = FriendListCache() } - - /** - * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext]. - * - * Bot 将会使用一个 [SupervisorJob] 覆盖 [coroutineContext] 当前协程的 [Job], 并使用当前协程的 [Job] 作为父 [Job] - * - * 用例: - * ``` - * coroutineScope { - * val bot = Bot(...) { - * inheritCoroutineContext() - * } - * bot.login() - * } // coroutineScope 会等待 Bot 退出 - * ``` - * - * - * **注意**: `bot.cancel` 时将会让父 [Job] 也被 cancel. - * ``` - * coroutineScope { // this: CoroutineScope - * launch { - * while(isActive) { - * delay(500) - * println("I'm alive") - * } - * } - * - * val bot = Bot(...) { - * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job - * } - * bot.login() - * bot.cancel() // 取消了整个 `coroutineScope`, 因此上文不断打印 `"I'm alive"` 的协程也会被取消. - * } - * ``` - * - * 因此, 此函数尤为适合在 `suspend fun main()` 中使用, 它能阻止主线程退出: - * ``` - * suspend fun main() { - * val bot = Bot() { - * inheritCoroutineContext() - * } - * bot.subscribe { ... } - * - * // 主线程不会退出, 直到 Bot 离线. - * } - * ``` - * - * 简言之, - * - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext]. - * - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext] - * - * @see parentCoroutineContext - */ - @JvmSynthetic - @ConfigurationDsl - public suspend inline fun inheritCoroutineContext() { - parentCoroutineContext = coroutineContext - } - + /////////////////////////////////////////////////////////////////////////// + // Misc + /////////////////////////////////////////////////////////////////////////// public fun copy(): BotConfiguration { return BotConfiguration().also { new -> @@ -455,11 +469,16 @@ public open class BotConfiguration { // open for Java } } - /** 标注一个配置 DSL 函数 */ @Target(AnnotationTarget.FUNCTION) @DslMarker public annotation class ConfigurationDsl + + public companion object { + /** 默认的配置实例. 可以进行修改 */ + @JvmStatic + public val Default: BotConfiguration = BotConfiguration() + } } /**