[core] Commonize BotConfiguration, simplify MPP hierarchy: (#2583)

* [core] Commonize BotConfiguration, simplify MPP hierarchy:

Move platform specific API to `AbstractBotConfiguration`

* Updates docs for AbstractBotConfiguration

* Add @since for AbstractBotConfiguration

* Mark AbstractBotConfiguration as not stable for inheritance
This commit is contained in:
Him188 2023-03-21 23:06:27 +00:00 committed by GitHub
parent dca39f9b60
commit b9ee2a8931
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 266 additions and 1131 deletions

View File

@ -5425,6 +5425,41 @@ public final class net/mamoe/mirai/network/UnsupportedSmsLoginException : net/ma
public final class net/mamoe/mirai/network/WrongPasswordException : net/mamoe/mirai/network/LoginFailedException {
}
public abstract class net/mamoe/mirai/utils/AbstractBotConfiguration {
public fun <init> ()V
public final fun fileBasedDeviceInfo ()V
public final fun fileBasedDeviceInfo (Ljava/lang/String;)V
public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V
protected abstract fun getBotLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getCacheDir ()Ljava/io/File;
protected abstract fun getDeviceInfo ()Lkotlin/jvm/functions/Function1;
protected abstract fun getNetworkLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getWorkingDir ()Ljava/io/File;
public final fun redirectBotLogToDirectory ()V
public final fun redirectBotLogToDirectory (Ljava/io/File;)V
public final fun redirectBotLogToDirectory (Ljava/io/File;J)V
public final fun redirectBotLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToDirectory$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectBotLogToFile ()V
public final fun redirectBotLogToFile (Ljava/io/File;)V
public final fun redirectBotLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToFile$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToDirectory ()V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;J)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToDirectory$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToFile ()V
public final fun redirectNetworkLogToFile (Ljava/io/File;)V
public final fun redirectNetworkLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToFile$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
protected abstract fun setBotLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setCacheDir (Ljava/io/File;)V
protected abstract fun setDeviceInfo (Lkotlin/jvm/functions/Function1;)V
protected abstract fun setNetworkLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setWorkingDir (Ljava/io/File;)V
}
public abstract class net/mamoe/mirai/utils/AbstractExternalResource : net/mamoe/mirai/utils/ExternalResource {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
@ -5448,7 +5483,7 @@ public abstract interface class net/mamoe/mirai/utils/AbstractExternalResource$R
public abstract fun cleanup ()V
}
public class net/mamoe/mirai/utils/BotConfiguration {
public class net/mamoe/mirai/utils/BotConfiguration : net/mamoe/mirai/utils/AbstractBotConfiguration {
public static final field Companion Lnet/mamoe/mirai/utils/BotConfiguration$Companion;
public fun <init> ()V
public final fun autoReconnectOnForceOffline ()V
@ -5457,12 +5492,8 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun disableAccountSecretes ()V
public final fun disableContactCache ()V
public final fun enableContactCache ()V
public final fun fileBasedDeviceInfo ()V
public final fun fileBasedDeviceInfo (Ljava/lang/String;)V
public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V
public final fun getAutoReconnectOnForceOffline ()Z
public final fun getBotLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getCacheDir ()Ljava/io/File;
public final fun getContactListCache ()Lnet/mamoe/mirai/utils/BotConfiguration$ContactListCache;
public static final fun getDefault ()Lnet/mamoe/mirai/utils/BotConfiguration;
public final fun getDeviceInfo ()Lkotlin/jvm/functions/Function1;
@ -5479,7 +5510,6 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final synthetic fun getReconnectPeriodMillis ()J
public final fun getReconnectionRetryTimes ()I
public final fun getStatHeartbeatPeriodMillis ()J
public final fun getWorkingDir ()Ljava/io/File;
public final synthetic fun inheritCoroutineContext (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun isConvertLineSeparator ()Z
public final fun isShowingVerboseEventLog ()Z
@ -5487,27 +5517,8 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun noBotLog ()V
public final fun noNetworkLog ()V
public final fun randomDeviceInfo ()V
public final fun redirectBotLogToDirectory ()V
public final fun redirectBotLogToDirectory (Ljava/io/File;)V
public final fun redirectBotLogToDirectory (Ljava/io/File;J)V
public final fun redirectBotLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToDirectory$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectBotLogToFile ()V
public final fun redirectBotLogToFile (Ljava/io/File;)V
public final fun redirectBotLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToFile$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToDirectory ()V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;J)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToDirectory$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToFile ()V
public final fun redirectNetworkLogToFile (Ljava/io/File;)V
public final fun redirectNetworkLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToFile$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun setAutoReconnectOnForceOffline (Z)V
public final fun setBotLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setCacheDir (Ljava/io/File;)V
public final fun setContactListCache (Lnet/mamoe/mirai/utils/BotConfiguration$ContactListCache;)V
public final fun setConvertLineSeparator (Z)V
public final fun setDeviceInfo (Lkotlin/jvm/functions/Function1;)V
@ -5525,7 +5536,6 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun setReconnectionRetryTimes (I)V
public final fun setShowingVerboseEventLog (Z)V
public final fun setStatHeartbeatPeriodMillis (J)V
public final fun setWorkingDir (Ljava/io/File;)V
}
public final class net/mamoe/mirai/utils/BotConfiguration$Companion {

View File

@ -5425,6 +5425,41 @@ public final class net/mamoe/mirai/network/UnsupportedSmsLoginException : net/ma
public final class net/mamoe/mirai/network/WrongPasswordException : net/mamoe/mirai/network/LoginFailedException {
}
public abstract class net/mamoe/mirai/utils/AbstractBotConfiguration {
public fun <init> ()V
public final fun fileBasedDeviceInfo ()V
public final fun fileBasedDeviceInfo (Ljava/lang/String;)V
public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V
protected abstract fun getBotLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getCacheDir ()Ljava/io/File;
protected abstract fun getDeviceInfo ()Lkotlin/jvm/functions/Function1;
protected abstract fun getNetworkLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getWorkingDir ()Ljava/io/File;
public final fun redirectBotLogToDirectory ()V
public final fun redirectBotLogToDirectory (Ljava/io/File;)V
public final fun redirectBotLogToDirectory (Ljava/io/File;J)V
public final fun redirectBotLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToDirectory$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectBotLogToFile ()V
public final fun redirectBotLogToFile (Ljava/io/File;)V
public final fun redirectBotLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToFile$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToDirectory ()V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;J)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToDirectory$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToFile ()V
public final fun redirectNetworkLogToFile (Ljava/io/File;)V
public final fun redirectNetworkLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToFile$default (Lnet/mamoe/mirai/utils/AbstractBotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
protected abstract fun setBotLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setCacheDir (Ljava/io/File;)V
protected abstract fun setDeviceInfo (Lkotlin/jvm/functions/Function1;)V
protected abstract fun setNetworkLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setWorkingDir (Ljava/io/File;)V
}
public abstract class net/mamoe/mirai/utils/AbstractExternalResource : net/mamoe/mirai/utils/ExternalResource {
public fun <init> ()V
public fun <init> (Ljava/lang/String;)V
@ -5448,7 +5483,7 @@ public abstract interface class net/mamoe/mirai/utils/AbstractExternalResource$R
public abstract fun cleanup ()V
}
public class net/mamoe/mirai/utils/BotConfiguration {
public class net/mamoe/mirai/utils/BotConfiguration : net/mamoe/mirai/utils/AbstractBotConfiguration {
public static final field Companion Lnet/mamoe/mirai/utils/BotConfiguration$Companion;
public fun <init> ()V
public final fun autoReconnectOnForceOffline ()V
@ -5457,12 +5492,8 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun disableAccountSecretes ()V
public final fun disableContactCache ()V
public final fun enableContactCache ()V
public final fun fileBasedDeviceInfo ()V
public final fun fileBasedDeviceInfo (Ljava/lang/String;)V
public static synthetic fun fileBasedDeviceInfo$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/lang/String;ILjava/lang/Object;)V
public final fun getAutoReconnectOnForceOffline ()Z
public final fun getBotLoggerSupplier ()Lkotlin/jvm/functions/Function1;
public final fun getCacheDir ()Ljava/io/File;
public final fun getContactListCache ()Lnet/mamoe/mirai/utils/BotConfiguration$ContactListCache;
public static final fun getDefault ()Lnet/mamoe/mirai/utils/BotConfiguration;
public final fun getDeviceInfo ()Lkotlin/jvm/functions/Function1;
@ -5479,7 +5510,6 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final synthetic fun getReconnectPeriodMillis ()J
public final fun getReconnectionRetryTimes ()I
public final fun getStatHeartbeatPeriodMillis ()J
public final fun getWorkingDir ()Ljava/io/File;
public final synthetic fun inheritCoroutineContext (Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public final fun isConvertLineSeparator ()Z
public final fun isShowingVerboseEventLog ()Z
@ -5487,27 +5517,8 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun noBotLog ()V
public final fun noNetworkLog ()V
public final fun randomDeviceInfo ()V
public final fun redirectBotLogToDirectory ()V
public final fun redirectBotLogToDirectory (Ljava/io/File;)V
public final fun redirectBotLogToDirectory (Ljava/io/File;J)V
public final fun redirectBotLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToDirectory$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectBotLogToFile ()V
public final fun redirectBotLogToFile (Ljava/io/File;)V
public final fun redirectBotLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectBotLogToFile$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToDirectory ()V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;J)V
public final fun redirectNetworkLogToDirectory (Ljava/io/File;JLkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToDirectory$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;JLkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun redirectNetworkLogToFile ()V
public final fun redirectNetworkLogToFile (Ljava/io/File;)V
public final fun redirectNetworkLogToFile (Ljava/io/File;Lkotlin/jvm/functions/Function1;)V
public static synthetic fun redirectNetworkLogToFile$default (Lnet/mamoe/mirai/utils/BotConfiguration;Ljava/io/File;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)V
public final fun setAutoReconnectOnForceOffline (Z)V
public final fun setBotLoggerSupplier (Lkotlin/jvm/functions/Function1;)V
public final fun setCacheDir (Ljava/io/File;)V
public final fun setContactListCache (Lnet/mamoe/mirai/utils/BotConfiguration$ContactListCache;)V
public final fun setConvertLineSeparator (Z)V
public final fun setDeviceInfo (Lkotlin/jvm/functions/Function1;)V
@ -5525,7 +5536,6 @@ public class net/mamoe/mirai/utils/BotConfiguration {
public final fun setReconnectionRetryTimes (I)V
public final fun setShowingVerboseEventLog (Z)V
public final fun setStatHeartbeatPeriodMillis (J)V
public final fun setWorkingDir (Ljava/io/File;)V
}
public final class net/mamoe/mirai/utils/BotConfiguration$Companion {

View File

@ -0,0 +1,38 @@
/*
* Copyright 2019-2023 Mamoe Technologies and contributors.
*
* 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
* Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
*
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
package net.mamoe.mirai.utils
import net.mamoe.mirai.Bot
import kotlin.jvm.JvmOverloads
/**
* [BotConfiguration] 的平台特别配置
* @since 2.15
*/
@NotStableForInheritance
public expect abstract class AbstractBotConfiguration @MiraiInternalApi protected constructor() {
protected abstract var deviceInfo: ((Bot) -> DeviceInfo)?
protected abstract var networkLoggerSupplier: ((Bot) -> MiraiLogger)
protected abstract var botLoggerSupplier: ((Bot) -> MiraiLogger)
/**
* 使用文件存储设备信息.
*
* 此函数只在 JVM Android 有效. 在其他平台将会抛出异常.
* @param filepath 文件路径. 默认是相对于 `workingDir` 的文件 "device.json".
* @see BotConfiguration.deviceInfo
*/
@JvmOverloads
@BotConfiguration.ConfigurationDsl
public fun fileBasedDeviceInfo(filepath: String = "device.json")
internal fun applyMppCopy(new: BotConfiguration)
}

View File

@ -17,17 +17,22 @@ package net.mamoe.mirai.utils
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.serialization.json.Json
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotFactory
import net.mamoe.mirai.event.events.BotOfflineEvent
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.jvm.*
import kotlin.native.CName
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* [Bot] 配置. 用于 [BotFactory.newBot]
* [Bot] 配置. 用于 [BotFactory.newBot].
*
* 部分平台相关配置位于 [AbstractBotConfiguration], 例如 `fileBasedDeviceInfo`.
*
* Kotlin 使用方法:
* ```
@ -50,13 +55,13 @@ import kotlin.time.Duration
* ```
*/
@Suppress("PropertyName")
public expect open class BotConfiguration() { // open for Java
public open class BotConfiguration : AbstractBotConfiguration() { // open for Java
///////////////////////////////////////////////////////////////////////////
// Coroutines
///////////////////////////////////////////////////////////////////////////
/** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */
public var parentCoroutineContext: CoroutineContext
public var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
/**
* 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext].
@ -112,7 +117,9 @@ public expect open class BotConfiguration() { // open for Java
*/
@JvmSynthetic
@ConfigurationDsl
public suspend inline fun inheritCoroutineContext()
public suspend inline fun inheritCoroutineContext() {
parentCoroutineContext = coroutineContext
}
///////////////////////////////////////////////////////////////////////////
@ -120,7 +127,7 @@ public expect open class BotConfiguration() { // open for Java
///////////////////////////////////////////////////////////////////////////
/** 连接心跳包周期. 过长会导致被服务器断开连接. */
public var heartbeatPeriodMillis: Long
public var heartbeatPeriodMillis: Long = 60.secondsToMillis
/**
* 状态心跳包周期. 过长会导致掉线.
@ -128,13 +135,13 @@ public expect open class BotConfiguration() { // open for Java
* @since 2.6
* @see heartbeatStrategy
*/
public var statHeartbeatPeriodMillis: Long
public var statHeartbeatPeriodMillis: Long = 300.secondsToMillis
/**
* 心跳策略.
* @since 2.6.3
*/
public var heartbeatStrategy: HeartbeatStrategy
public var heartbeatStrategy: HeartbeatStrategy = HeartbeatStrategy.STAT_HB
/**
* 心跳策略.
@ -168,7 +175,7 @@ public expect open class BotConfiguration() { // open for Java
* 每次心跳时等待结果的时间.
* 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
*/
public var heartbeatTimeoutMillis: Long
public var heartbeatTimeoutMillis: Long = 5.secondsToMillis
/** 心跳失败后的第一次重连前的等待时间. */
@Deprecated(
@ -176,7 +183,7 @@ public expect open class BotConfiguration() { // open for Java
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public var firstReconnectDelayMillis: Long
public var firstReconnectDelayMillis: Long = 5.secondsToMillis
/** 重连失败后, 继续尝试的每次等待时间 */
@Deprecated(
@ -184,10 +191,10 @@ public expect open class BotConfiguration() { // open for Java
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public var reconnectPeriodMillis: Long
public var reconnectPeriodMillis: Long = 5.secondsToMillis
/** 最多尝试多少次重连 */
public var reconnectionRetryTimes: Int
public var reconnectionRetryTimes: Int = Int.MAX_VALUE
/**
* 在被挤下线时 ([BotOfflineEvent.Force]) 自动重连. 默认为 `false`.
@ -196,7 +203,7 @@ public expect open class BotConfiguration() { // open for Java
*
* @since 2.1
*/
public var autoReconnectOnForceOffline: Boolean
public var autoReconnectOnForceOffline: Boolean = false
/**
* 验证码处理器
@ -208,10 +215,10 @@ public expect open class BotConfiguration() { // open for Java
*
* @see LoginSolver
*/
public var loginSolver: LoginSolver?
public var loginSolver: LoginSolver? = LoginSolver.Default
/** 使用协议类型 */
public var protocol: MiraiProtocol
public var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PHONE
public enum class MiraiProtocol {
/**
@ -251,25 +258,27 @@ public expect open class BotConfiguration() { // open for Java
* Highway 通道上传图片, 语音, 文件等资源时的协程数量.
*
* 每个协程的速度约为 200KB/s. 协程数量越多越快, 同时也更要求性能.
* 默认 [CPU 核心数][Runtime.availableProcessors].
* 默认 CPU 核心数.
*
* @since 2.2
*/
public var highwayUploadCoroutineCount: Int
public var highwayUploadCoroutineCount: Int = availableProcessors()
/**
* 设置 [autoReconnectOnForceOffline] `true`, 即在被挤下线时自动重连.
* @since 2.1
*/
@ConfigurationDsl
public fun autoReconnectOnForceOffline()
public fun autoReconnectOnForceOffline() {
autoReconnectOnForceOffline = true
}
///////////////////////////////////////////////////////////////////////////
// Device
///////////////////////////////////////////////////////////////////////////
@JvmField
internal var accountSecrets: Boolean
internal var accountSecrets: Boolean = true
/**
* 禁止保存 `account.secrets`.
@ -279,14 +288,16 @@ public expect open class BotConfiguration() { // open for Java
*
* @since 2.11
*/
public fun disableAccountSecretes()
public fun disableAccountSecretes() {
accountSecrets = false
}
/**
* 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息.
* @see fileBasedDeviceInfo 使用指定文件存储设备信息
* @see randomDeviceInfo 使用随机设备信息
*/
public var deviceInfo: ((Bot) -> DeviceInfo)?
public final override var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually.
/**
* 使用随机设备信息.
@ -294,7 +305,9 @@ public expect open class BotConfiguration() { // open for Java
* @see deviceInfo
*/
@ConfigurationDsl
public fun randomDeviceInfo()
public fun randomDeviceInfo() {
deviceInfo = null
}
/**
* 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
@ -302,18 +315,11 @@ public expect open class BotConfiguration() { // open for Java
* @see deviceInfo
*/
@ConfigurationDsl
public fun loadDeviceInfoJson(json: String)
/**
* 使用文件存储设备信息.
*
* 此函数只在 JVM Android 有效. 在其他平台将会抛出异常.
* @param filepath 文件路径. 默认是相对于 [workingDir] 的文件 "device.json".
* @see deviceInfo
*/
@JvmOverloads
@ConfigurationDsl
public fun fileBasedDeviceInfo(filepath: String = "device.json")
public fun loadDeviceInfoJson(json: String) {
deviceInfo = {
DeviceInfoManager.deserialize(json, Companion.json)
}
}
///////////////////////////////////////////////////////////////////////////
// Logging
@ -322,33 +328,39 @@ public expect open class BotConfiguration() { // open for Java
/**
* 日志记录器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 默认打印到标准输出, 通过 [MiraiLogger.Factory.create]
* - 忽略所有日志: [noBotLog]
* - 重定向到一个目录: `botLoggerSupplier = { DirectoryLogger("Bot ${it.id}") }`
* - 重定向到一个文件: `botLoggerSupplier = { SingleFileLogger("Bot ${it.id}") }`
*
* @see MiraiLogger
*/
public var botLoggerSupplier: ((Bot) -> MiraiLogger)
public final override var botLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Bot ${it.id}")
}
/**
* 网络层日志构造器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 默认打印到标准输出, 通过 [MiraiLogger.Factory.create]
* - 忽略所有日志: [noNetworkLog]
* - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
* - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
*
* @see MiraiLogger
*/
public var networkLoggerSupplier: ((Bot) -> MiraiLogger)
public final override var networkLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Net ${it.id}")
}
/**
* 不显示网络日志. 不推荐.
* @see networkLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public fun noNetworkLog()
public fun noNetworkLog() {
networkLoggerSupplier = { _ -> SilentLogger }
}
/**
@ -356,7 +368,10 @@ public expect open class BotConfiguration() { // open for Java
* @see botLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public fun noBotLog()
public fun noBotLog() {
botLoggerSupplier = { _ -> SilentLogger }
}
/**
* 是否显示过于冗长的事件日志
@ -365,17 +380,17 @@ public expect open class BotConfiguration() { // open for Java
*
* @since 2.8
*/
public var isShowingVerboseEventLog: Boolean
public var isShowingVerboseEventLog: Boolean = false
///////////////////////////////////////////////////////////////////////////
// Cache
//////////////////////////////////////////////////////////////////////////
/**
* 联系人信息缓存配置. 将会保存在 [cacheDir] `contacts` 目录
* 联系人信息缓存配置. 将会保存在 `cacheDir` `contacts` 目录
* @since 2.4
*/
public var contactListCache: ContactListCache
public var contactListCache: ContactListCache = ContactListCache()
/**
* 联系人信息缓存配置
@ -388,24 +403,29 @@ public expect open class BotConfiguration() { // open for Java
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/
public var saveIntervalMillis: Long
public var saveIntervalMillis: Long = 60_000
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/ // was @ExperimentalTime before 2.9
public var saveInterval: Duration
public inline var saveInterval: Duration
@JvmSynthetic inline get() = saveIntervalMillis.milliseconds
@JvmSynthetic inline set(v) {
saveIntervalMillis = v.inWholeMilliseconds
}
/**
* 开启好友列表缓存.
*/
public var friendListCacheEnabled: Boolean
public var friendListCacheEnabled: Boolean = false
/**
* 开启群成员列表缓存.
*/
public var groupMemberListCacheEnabled: Boolean
public var groupMemberListCacheEnabled: Boolean = false
}
/**
* 配置 [ContactListCache]
* ```
@ -417,21 +437,31 @@ public expect open class BotConfiguration() { // open for Java
* @since 2.4
*/
@JvmSynthetic
public inline fun contactListCache(action: ContactListCache.() -> Unit)
public inline fun contactListCache(action: ContactListCache.() -> Unit) {
action.invoke(this.contactListCache)
}
/**
* 禁用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public fun disableContactCache()
public fun disableContactCache() {
contactListCache.friendListCacheEnabled = false
contactListCache.groupMemberListCacheEnabled = false
}
/**
* 启用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public fun enableContactCache()
public fun enableContactCache() {
contactListCache.friendListCacheEnabled = true
contactListCache.groupMemberListCacheEnabled = true
}
/**
* 登录缓存.
@ -445,14 +475,37 @@ public expect open class BotConfiguration() { // open for Java
*
* @since 2.6
*/
public var loginCacheEnabled: Boolean
public var loginCacheEnabled: Boolean = true
///////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////
@Suppress("DuplicatedCode")
public fun copy(): BotConfiguration
public fun copy(): BotConfiguration {
return BotConfiguration().also { new ->
// To structural order
new.parentCoroutineContext = parentCoroutineContext
new.heartbeatPeriodMillis = heartbeatPeriodMillis
new.heartbeatTimeoutMillis = heartbeatTimeoutMillis
new.statHeartbeatPeriodMillis = statHeartbeatPeriodMillis
new.heartbeatStrategy = heartbeatStrategy
new.reconnectionRetryTimes = reconnectionRetryTimes
new.autoReconnectOnForceOffline = autoReconnectOnForceOffline
new.loginSolver = loginSolver
new.protocol = protocol
new.highwayUploadCoroutineCount = highwayUploadCoroutineCount
new.accountSecrets = accountSecrets
new.deviceInfo = deviceInfo
new.botLoggerSupplier = botLoggerSupplier
new.networkLoggerSupplier = networkLoggerSupplier
new.contactListCache = contactListCache
new.convertLineSeparator = convertLineSeparator
new.isShowingVerboseEventLog = isShowingVerboseEventLog
applyMppCopy(new)
}
}
/**
* 是否处理接受到的特殊换行符, 默认为 `true`
@ -463,17 +516,31 @@ public expect open class BotConfiguration() { // open for Java
* @since 2.4
*/
@get:JvmName("isConvertLineSeparator")
public var convertLineSeparator: Boolean
public var convertLineSeparator: Boolean = true
/** 标注一个配置 DSL 函数 */
@Target(AnnotationTarget.FUNCTION)
@DslMarker
public annotation class ConfigurationDsl()
public annotation class ConfigurationDsl
public companion object {
/** 默认的配置实例. 可以进行修改 */
@JvmStatic
public val Default: BotConfiguration
public val Default: BotConfiguration = BotConfiguration()
/**
* Json 序列化器, 使用 'kotlinx.serialization'
*/
internal val json: Json = kotlin.runCatching {
Json {
isLenient = true
ignoreUnknownKeys = true
prettyPrint = true
}
}.getOrElse {
@Suppress("JSON_FORMAT_REDUNDANT_DEFAULT") // compatible for older versions
(Json {})
}
}
}

View File

@ -7,324 +7,33 @@
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("unused", "DEPRECATION_ERROR", "EXPOSED_SUPER_CLASS", "MemberVisibilityCanBePrivate")
@file:JvmMultifileClass
@file:JvmName("Utils")
package net.mamoe.mirai.utils
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.serialization.json.Json
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotFactory
import net.mamoe.mirai.event.events.BotOfflineEvent
import net.mamoe.mirai.utils.DeviceInfo.Companion.loadAsDeviceInfo
import java.io.File
import java.io.InputStream
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* [Bot] 配置. 用于 [BotFactory.newBot]
*
* Kotlin 使用方法:
* ```
* val bot = BotFactory.newBot(...) {
* // 在这里配置 Bot
*
* bogLoggerSupplier = { bot -> ... }
* fileBasedDeviceInfo()
* inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job
* }
* ```
*
* Java 使用方法:
* ```java
* Bot bot = BotFactory.newBot(..., new BotConfiguration() {{
* setBogLoggerSupplier((Bot bot) -> { ... })
* fileBasedDeviceInfo()
* ...
* }})
* ```
* [BotConfiguration] JVM 平台特别配置
* @since 2.15
*/
@Suppress("PropertyName")
public actual open class BotConfiguration { // open for Java
@NotStableForInheritance
public actual abstract class AbstractBotConfiguration { // open for Java
protected actual abstract var deviceInfo: ((Bot) -> DeviceInfo)?
protected actual abstract var networkLoggerSupplier: ((Bot) -> MiraiLogger)
protected actual abstract var botLoggerSupplier: ((Bot) -> MiraiLogger)
/**
* 工作目录. 默认为 "."
*/
public var workingDir: File = File(".")
///////////////////////////////////////////////////////////////////////////
// Coroutines
///////////////////////////////////////////////////////////////////////////
/** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */
public actual 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.eventChannel.subscribe { ... }
*
* // 主线程不会退出, 直到 Bot 离线.
* }
* ```
*
* 简言之,
* - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext].
* - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext]
*
* @see parentCoroutineContext
*/
@JvmSynthetic
@ConfigurationDsl
public actual suspend inline fun inheritCoroutineContext() {
parentCoroutineContext = coroutineContext
}
///////////////////////////////////////////////////////////////////////////
// Connection
///////////////////////////////////////////////////////////////////////////
/** 连接心跳包周期. 过长会导致被服务器断开连接. */
public actual var heartbeatPeriodMillis: Long = 60.secondsToMillis
/**
* 状态心跳包周期. 过长会导致掉线.
* 该值会在登录时根据服务器下发的配置自动进行更新.
* @since 2.6
* @see heartbeatStrategy
*/
public actual var statHeartbeatPeriodMillis: Long = 300.secondsToMillis
/**
* 心跳策略.
* @since 2.6.3
*/
public actual var heartbeatStrategy: HeartbeatStrategy = HeartbeatStrategy.STAT_HB
/**
* 心跳策略.
* @since 2.6.3
*/
public actual enum class HeartbeatStrategy {
/**
* 使用 2.6.0 增加的*状态心跳* (Stat Heartbeat). 通常推荐这个模式.
*
* 该模式大多数情况下更稳定. 但有些账号使用这个模式时会遇到一段时间后发送消息成功但客户端不可见的问题.
*/
STAT_HB,
/**
* 不发送状态心跳, 而是发送*切换在线状态* (可能会导致频繁的好友或客户端上线提示, 也可能产生短暂 (几秒) 发送消息不可见的问题).
*
* 建议在 [STAT_HB] 不可用时使用 [REGISTER].
*/
REGISTER,
/**
* 不主动维护会话. 多数账号会每 16 分钟掉线然后重连. 则会有短暂的不可用时间.
*
* 仅当 [STAT_HB] [REGISTER] 都造成无法接收等问题时使用.
* 同时请在 [https://github.com/mamoe/mirai/issues/1209] 提交问题.
*/
NONE;
}
/**
* 每次心跳时等待结果的时间.
* 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
*/
public actual var heartbeatTimeoutMillis: Long = 5.secondsToMillis
/** 心跳失败后的第一次重连前的等待时间. */
@Deprecated(
"Useless since new network. Please just remove this.",
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public actual var firstReconnectDelayMillis: Long = 5.secondsToMillis
/** 重连失败后, 继续尝试的每次等待时间 */
@Deprecated(
"Useless since new network. Please just remove this.",
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public actual var reconnectPeriodMillis: Long = 5.secondsToMillis
/** 最多尝试多少次重连 */
public actual var reconnectionRetryTimes: Int = Int.MAX_VALUE
/**
* 在被挤下线时 ([BotOfflineEvent.Force]) 自动重连. 默认为 `false`.
*
* 其他情况掉线都默认会自动重连, 详见 [BotOfflineEvent.reconnect]
*
* @since 2.1
*/
public actual var autoReconnectOnForceOffline: Boolean = false
/**
* 验证码处理器
*
* - Android 需要手动提供 [LoginSolver]
* - JVM, Mirai 会根据环境支持情况选择 Swing/CLI 实现
*
* 详见 [LoginSolver.Default]
*
* @see LoginSolver
*/
public actual var loginSolver: LoginSolver? = LoginSolver.Default
/** 使用协议类型 */
public actual var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PHONE
public actual enum class MiraiProtocol {
/**
* Android 手机. 所有功能都支持.
*/
ANDROID_PHONE,
/**
* Android 平板.
*/
ANDROID_PAD,
/**
* Android 手表.
*
* 注意: 不支持戳一戳事件解析
*/
ANDROID_WATCH,
/**
* iPad - 来自MiraiGo
*
* @since 2.8
*/
IPAD,
/**
* MacOS - 来自MiraiGo
*
* @since 2.8
*/
MACOS,
}
/**
* Highway 通道上传图片, 语音, 文件等资源时的协程数量.
*
* 每个协程的速度约为 200KB/s. 协程数量越多越快, 同时也更要求性能.
* 默认 [CPU 核心数][Runtime.availableProcessors].
*
* @since 2.2
*/
public actual var highwayUploadCoroutineCount: Int = Runtime.getRuntime().availableProcessors()
/**
* 设置 [autoReconnectOnForceOffline] `true`, 即在被挤下线时自动重连.
* @since 2.1
*/
@ConfigurationDsl
public actual fun autoReconnectOnForceOffline() {
autoReconnectOnForceOffline = true
}
///////////////////////////////////////////////////////////////////////////
// Device
///////////////////////////////////////////////////////////////////////////
@JvmField
internal actual var accountSecrets: Boolean = true
/**
* 禁止保存 `account.secrets`.
*
* `account.secrets` 保存账号的会话信息
* 它可加速登录过程也可能可以减少出现验证码的次数如果遇到一段时间后无法接收消息通知等同步问题时可尝试禁用
*
* @since 2.11
*/
public actual fun disableAccountSecretes() {
accountSecrets = false
}
/**
* 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息.
* @see fileBasedDeviceInfo 使用指定文件存储设备信息
* @see randomDeviceInfo 使用随机设备信息
*/
public actual var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually.
/**
* 使用随机设备信息.
*
* @see deviceInfo
*/
@ConfigurationDsl
public actual fun randomDeviceInfo() {
deviceInfo = null
}
/**
* 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
*
* @see deviceInfo
*/
@ConfigurationDsl
public actual fun loadDeviceInfoJson(json: String) {
deviceInfo = {
DeviceInfoManager.deserialize(json, Companion.json)
}
}
/**
* 使用文件存储设备信息.
*
@ -333,43 +42,17 @@ public actual open class BotConfiguration { // open for Java
* @see deviceInfo
*/
@JvmOverloads
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public actual fun fileBasedDeviceInfo(filepath: String) {
deviceInfo = getFileBasedDeviceInfoSupplier { workingDir.resolve(filepath) }
deviceInfo = {
workingDir.resolve(filepath).loadAsDeviceInfo(BotConfiguration.json)
}
}
///////////////////////////////////////////////////////////////////////////
// Logging
///////////////////////////////////////////////////////////////////////////
/**
* 日志记录器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 忽略所有日志: [noBotLog]
* - 重定向到一个目录: `botLoggerSupplier = { DirectoryLogger("Bot ${it.id}") }`
* - 重定向到一个文件: `botLoggerSupplier = { SingleFileLogger("Bot ${it.id}") }`
*
* @see MiraiLogger
*/
public actual var botLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Bot ${it.id}")
}
/**
* 网络层日志构造器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 忽略所有日志: [noNetworkLog]
* - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
* - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
*
* @see MiraiLogger
*/
public actual var networkLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Net ${it.id}")
}
/**
* 重定向 [网络日志][networkLoggerSupplier] 到指定目录. 若目录不存在将会自动创建 ([File.mkdirs])
@ -378,7 +61,7 @@ public actual open class BotConfiguration { // open for Java
* @see redirectNetworkLogToDirectory
*/
@JvmOverloads
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public fun redirectNetworkLogToDirectory(
dir: File = File("logs"),
retain: Long = 1.weeksToMillis,
@ -395,7 +78,7 @@ public actual open class BotConfiguration { // open for Java
* @see redirectNetworkLogToDirectory
*/
@JvmOverloads
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public fun redirectNetworkLogToFile(
file: File = File("mirai.log"),
identity: (bot: Bot) -> String = { "Net ${it.id}" }
@ -411,7 +94,7 @@ public actual open class BotConfiguration { // open for Java
* @see redirectBotLogToDirectory
*/
@JvmOverloads
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public fun redirectBotLogToFile(
file: File = File("mirai.log"),
identity: (bot: Bot) -> String = { "Bot ${it.id}" }
@ -427,7 +110,7 @@ public actual open class BotConfiguration { // open for Java
* @see redirectBotLogToFile
*/
@JvmOverloads
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public fun redirectBotLogToDirectory(
dir: File = File("logs"),
retain: Long = 1.weeksToMillis,
@ -437,33 +120,6 @@ public actual open class BotConfiguration { // open for Java
botLoggerSupplier = { DirectoryLogger(identity(it), workingDir.resolve(dir), retain) }
}
/**
* 不显示网络日志. 不推荐.
* @see networkLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public actual fun noNetworkLog() {
networkLoggerSupplier = { _ -> SilentLogger }
}
/**
* 不显示 [Bot] 日志. 不推荐.
* @see botLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public actual fun noBotLog() {
botLoggerSupplier = { _ -> SilentLogger }
}
/**
* 是否显示过于冗长的事件日志
*
* 默认为 `false`
*
* @since 2.8
*/
public actual var isShowingVerboseEventLog: Boolean = false
///////////////////////////////////////////////////////////////////////////
// Cache
//////////////////////////////////////////////////////////////////////////
@ -485,165 +141,12 @@ public actual open class BotConfiguration { // open for Java
*/
public var cacheDir: File = File("cache")
/**
* 联系人信息缓存配置. 将会保存在 [cacheDir] `contacts` 目录
* @since 2.4
*/
public actual var contactListCache: ContactListCache = ContactListCache()
/**
* 联系人信息缓存配置
* @see contactListCache
* @see enableContactCache
* @see disableContactCache
* @since 2.4
*/
public actual class ContactListCache {
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/
public actual var saveIntervalMillis: Long = 60_000
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/ // was @ExperimentalTime before 2.9
public actual inline var saveInterval: Duration
@JvmSynthetic inline get() = saveIntervalMillis.milliseconds
@JvmSynthetic inline set(v) {
saveIntervalMillis = v.inWholeMilliseconds
}
/**
* 开启好友列表缓存.
*/
public actual var friendListCacheEnabled: Boolean = false
/**
* 开启群成员列表缓存.
*/
public actual var groupMemberListCacheEnabled: Boolean = false
}
/**
* 配置 [ContactListCache]
* ```
* contactListCache {
* saveIntervalMillis = 30_000
* friendListCacheEnabled = true
* }
* ```
* @since 2.4
*/
@JvmSynthetic
public actual inline fun contactListCache(action: ContactListCache.() -> Unit) {
action.invoke(this.contactListCache)
}
/**
* 禁用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public actual fun disableContactCache() {
contactListCache.friendListCacheEnabled = false
contactListCache.groupMemberListCacheEnabled = false
}
/**
* 启用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public actual fun enableContactCache() {
contactListCache.friendListCacheEnabled = true
contactListCache.groupMemberListCacheEnabled = true
}
/**
* 登录缓存.
*
* 开始后在密码登录成功时会保存秘钥等信息, 在下次启动时通过这些信息登录, 而不提交密码.
* 可以减少验证码出现的频率.
*
* 秘钥信息会由密码加密保存. 如果秘钥过期, 则会进行普通密码登录.
*
* 默认 `true` (开启).
*
* @since 2.6
*/
public actual var loginCacheEnabled: Boolean = true
///////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////
@Suppress("DuplicatedCode")
public actual fun copy(): BotConfiguration {
return BotConfiguration().also { new ->
// To structural order
new.workingDir = workingDir
@Suppress("DEPRECATION_ERROR")
new.parentCoroutineContext = parentCoroutineContext
new.heartbeatPeriodMillis = heartbeatPeriodMillis
new.heartbeatTimeoutMillis = heartbeatTimeoutMillis
new.statHeartbeatPeriodMillis = statHeartbeatPeriodMillis
new.heartbeatStrategy = heartbeatStrategy
new.reconnectionRetryTimes = reconnectionRetryTimes
new.autoReconnectOnForceOffline = autoReconnectOnForceOffline
new.loginSolver = loginSolver
new.protocol = protocol
new.highwayUploadCoroutineCount = highwayUploadCoroutineCount
new.accountSecrets = accountSecrets
new.deviceInfo = deviceInfo
new.botLoggerSupplier = botLoggerSupplier
new.networkLoggerSupplier = networkLoggerSupplier
new.cacheDir = cacheDir
new.contactListCache = contactListCache
new.convertLineSeparator = convertLineSeparator
new.isShowingVerboseEventLog = isShowingVerboseEventLog
}
internal actual fun applyMppCopy(new: BotConfiguration) {
new.workingDir = workingDir
new.cacheDir = cacheDir
}
/**
* 是否处理接受到的特殊换行符, 默认为 `true`
*
* - 若为 `true`, 会将收到的 `CRLF(\r\n)` `CR(\r)` 替换为 `LF(\n)`
* - 若为 `false`, 则不做处理
*
* @since 2.4
*/
@get:JvmName("isConvertLineSeparator")
public actual var convertLineSeparator: Boolean = true
/** 标注一个配置 DSL 函数 */
@Target(AnnotationTarget.FUNCTION)
@DslMarker
public actual annotation class ConfigurationDsl
public actual companion object {
/** 默认的配置实例. 可以进行修改 */
@JvmStatic
public actual val Default: BotConfiguration = BotConfiguration()
/**
* Json 序列化器, 使用 'kotlinx.serialization'
*/
internal val json: Json = kotlin.runCatching {
Json {
isLenient = true
ignoreUnknownKeys = true
prettyPrint = true
}
}.getOrElse {
@Suppress("JSON_FORMAT_REDUNDANT_DEFAULT") // compatible for older versions
Json {}
}
internal fun BotConfiguration.getFileBasedDeviceInfoSupplier(file: () -> File): (Bot) -> DeviceInfo {
return {
@Suppress("DEPRECATION_ERROR")
file().loadAsDeviceInfo(json)
}
}
}
}
}

View File

@ -7,317 +7,26 @@
* https://github.com/mamoe/mirai/blob/dev/LICENSE
*/
@file:Suppress("RedundantVisibilityModifier")
package net.mamoe.mirai.utils
import io.ktor.utils.io.core.*
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.serialization.json.Json
import net.mamoe.mirai.Bot
import net.mamoe.mirai.BotFactory
import net.mamoe.mirai.event.events.BotOfflineEvent
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlin.coroutines.coroutineContext
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
/**
* [Bot] 配置. 用于 [BotFactory.newBot]
*
* Kotlin 使用方法:
* ```
* val bot = BotFactory.newBot(...) {
* // 在这里配置 Bot
*
* bogLoggerSupplier = { bot -> ... }
* fileBasedDeviceInfo()
* inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job
* }
* ```
*
* Java 使用方法:
* ```java
* Bot bot = BotFactory.newBot(..., new BotConfiguration() {{
* setBogLoggerSupplier((Bot bot) -> { ... })
* fileBasedDeviceInfo()
* ...
* }})
* ```
* [BotConfiguration] Native 平台特别配置
* @since 2.15
*/
@Suppress("PropertyName")
public actual open class BotConfiguration { // open for Java
@NotStableForInheritance
public actual abstract class AbstractBotConfiguration { // open for Java
protected actual abstract var deviceInfo: ((Bot) -> DeviceInfo)?
protected actual abstract var networkLoggerSupplier: ((Bot) -> MiraiLogger)
protected actual abstract var botLoggerSupplier: ((Bot) -> MiraiLogger)
/**
* 工作目录. 默认为当前目录
*/
public var workingDir: String = "."
///////////////////////////////////////////////////////////////////////////
// Coroutines
///////////////////////////////////////////////////////////////////////////
/** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */
public actual 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.eventChannel.subscribe { ... }
*
* // 主线程不会退出, 直到 Bot 离线.
* }
* ```
*
* 简言之,
* - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext].
* - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext]
*
* @see parentCoroutineContext
*/
@ConfigurationDsl
public actual suspend inline fun inheritCoroutineContext() {
parentCoroutineContext = coroutineContext
}
///////////////////////////////////////////////////////////////////////////
// Connection
///////////////////////////////////////////////////////////////////////////
/** 连接心跳包周期. 过长会导致被服务器断开连接. */
public actual var heartbeatPeriodMillis: Long = 60.secondsToMillis
/**
* 状态心跳包周期. 过长会导致掉线.
* 该值会在登录时根据服务器下发的配置自动进行更新.
* @since 2.6
* @see heartbeatStrategy
*/
public actual var statHeartbeatPeriodMillis: Long = 300.secondsToMillis
/**
* 心跳策略.
* @since 2.6.3
*/
public actual var heartbeatStrategy: HeartbeatStrategy = HeartbeatStrategy.STAT_HB
/**
* 心跳策略.
* @since 2.6.3
*/
public actual enum class HeartbeatStrategy {
/**
* 使用 2.6.0 增加的*状态心跳* (Stat Heartbeat). 通常推荐这个模式.
*
* 该模式大多数情况下更稳定. 但有些账号使用这个模式时会遇到一段时间后发送消息成功但客户端不可见的问题.
*/
STAT_HB,
/**
* 不发送状态心跳, 而是发送*切换在线状态* (可能会导致频繁的好友或客户端上线提示, 也可能产生短暂 (几秒) 发送消息不可见的问题).
*
* 建议在 [STAT_HB] 不可用时使用 [REGISTER].
*/
REGISTER,
/**
* 不主动维护会话. 多数账号会每 16 分钟掉线然后重连. 则会有短暂的不可用时间.
*
* 仅当 [STAT_HB] [REGISTER] 都造成无法接收等问题时使用.
* 同时请在 [https://github.com/mamoe/mirai/issues/1209] 提交问题.
*/
NONE;
}
/**
* 每次心跳时等待结果的时间.
* 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
*/
public actual var heartbeatTimeoutMillis: Long = 5.secondsToMillis
/** 心跳失败后的第一次重连前的等待时间. */
@Deprecated(
"Useless since new network. Please just remove this.",
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public actual var firstReconnectDelayMillis: Long = 5.secondsToMillis
/** 重连失败后, 继续尝试的每次等待时间 */
@Deprecated(
"Useless since new network. Please just remove this.",
level = DeprecationLevel.HIDDEN
) // deprecated since 2.7, error since 2.8
@DeprecatedSinceMirai(warningSince = "2.7", errorSince = "2.8", hiddenSince = "2.10")
public actual var reconnectPeriodMillis: Long = 5.secondsToMillis
/** 最多尝试多少次重连 */
public actual var reconnectionRetryTimes: Int = Int.MAX_VALUE
/**
* 在被挤下线时 ([BotOfflineEvent.Force]) 自动重连. 默认为 `false`.
*
* 其他情况掉线都默认会自动重连, 详见 [BotOfflineEvent.reconnect]
*
* @since 2.1
*/
public actual var autoReconnectOnForceOffline: Boolean = false
/**
* 验证码处理器
*
* - Android 需要手动提供 [LoginSolver]
* - JVM, Mirai 会根据环境支持情况选择 Swing/CLI 实现
*
* 详见 [LoginSolver.Default]
*
* @see LoginSolver
*/
public actual var loginSolver: LoginSolver? = LoginSolver.Default
/** 使用协议类型 */
public actual var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PHONE
public actual enum class MiraiProtocol {
/**
* Android 手机. 所有功能都支持.
*/
ANDROID_PHONE,
/**
* Android 平板.
*/
ANDROID_PAD,
/**
* Android 手表.
*
* 注意: 不支持戳一戳事件解析
*/
ANDROID_WATCH,
/**
* iPad - 来自MiraiGo
*
* @since 2.8
*/
IPAD,
/**
* MacOS - 来自MiraiGo
*
* @since 2.8
*/
MACOS,
}
/**
* Highway 通道上传图片, 语音, 文件等资源时的协程数量.
*
* 每个协程的速度约为 200KB/s. 协程数量越多越快, 同时也更要求性能.
* 默认: CPU 核心数.
*
* @since 2.2
*/
public actual var highwayUploadCoroutineCount: Int = availableProcessors()
/**
* 设置 [autoReconnectOnForceOffline] `true`, 即在被挤下线时自动重连.
* @since 2.1
*/
@ConfigurationDsl
public actual fun autoReconnectOnForceOffline() {
autoReconnectOnForceOffline = true
}
///////////////////////////////////////////////////////////////////////////
// Device
///////////////////////////////////////////////////////////////////////////
internal actual var accountSecrets: Boolean = true
/**
* 禁止保存 `account.secrets`.
*
* `account.secrets` 保存账号的会话信息
* 它可加速登录过程也可能可以减少出现验证码的次数如果遇到一段时间后无法接收消息通知等同步问题时可尝试禁用
*
* @since 2.11
*/
public actual fun disableAccountSecretes() {
accountSecrets = false
}
/**
* 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息.
* @see fileBasedDeviceInfo 使用指定文件存储设备信息
* @see randomDeviceInfo 使用随机设备信息
*/
public actual var deviceInfo: ((Bot) -> DeviceInfo)? = deviceInfoStub // allows user to set `null` manually.
/**
* 使用随机设备信息.
*
* @see deviceInfo
*/
@ConfigurationDsl
public actual fun randomDeviceInfo() {
deviceInfo = null
}
/**
* 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
*
* @see deviceInfo
*/
@ConfigurationDsl
public actual fun loadDeviceInfoJson(json: String) {
deviceInfo = {
DeviceInfoManager.deserialize(json, Companion.json)
}
}
/**
* 使用文件存储设备信息.
*
@ -325,80 +34,17 @@ public actual open class BotConfiguration { // open for Java
* @param filepath 文件路径. 默认是相对于 [workingDir] 的文件 "device.json".
* @see deviceInfo
*/
@ConfigurationDsl
@BotConfiguration.ConfigurationDsl
public actual fun fileBasedDeviceInfo(filepath: String) {
deviceInfo = {
val file = MiraiFile.create(workingDir).resolve(filepath)
if (!file.exists()) {
file.writeText(DeviceInfoManager.serialize(DeviceInfo.random(), json))
file.writeText(DeviceInfoManager.serialize(DeviceInfo.random(), BotConfiguration.json))
}
DeviceInfoManager.deserialize(file.readText(), json)
DeviceInfoManager.deserialize(file.readText(), BotConfiguration.json)
}
}
///////////////////////////////////////////////////////////////////////////
// Logging
///////////////////////////////////////////////////////////////////////////
/**
* 日志记录器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 忽略所有日志: [noBotLog]
* - 重定向到一个目录: `botLoggerSupplier = { DirectoryLogger("Bot ${it.id}") }`
* - 重定向到一个文件: `botLoggerSupplier = { SingleFileLogger("Bot ${it.id}") }`
*
* @see MiraiLogger
*/
public actual var botLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Bot ${it.id}")
}
/**
* 网络层日志构造器
*
* - 默认打印到标准输出, 通过 [MiraiLogger.create]
* - 忽略所有日志: [noNetworkLog]
* - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
* - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
*
* @see MiraiLogger
*/
public actual var networkLoggerSupplier: ((Bot) -> MiraiLogger) = {
MiraiLogger.Factory.create(Bot::class, "Net ${it.id}")
}
/**
* 不显示网络日志. 不推荐.
* @see networkLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public actual fun noNetworkLog() {
networkLoggerSupplier = { _ -> SilentLogger }
}
/**
* 不显示 [Bot] 日志. 不推荐.
* @see botLoggerSupplier 更多日志处理方式
*/
@ConfigurationDsl
public actual fun noBotLog() {
botLoggerSupplier = { _ -> SilentLogger }
}
/**
* 是否显示过于冗长的事件日志
*
* 默认为 `false`
*
* @since 2.8
*/
public actual var isShowingVerboseEventLog: Boolean = false
///////////////////////////////////////////////////////////////////////////
// Cache
//////////////////////////////////////////////////////////////////////////
/**
* 缓存数据目录路径. [cacheDir] 为绝对路径, 将解析该绝对路径, 否则作为相对于 [workingDir] 的路径解析.
* 例如, `cache` 将会解析为 `$workingDir/cache`, `/Users/Chisato/Desktop/bot/cache` 指代绝对路径, 将解析为绝对路径.
@ -417,147 +63,8 @@ public actual open class BotConfiguration { // open for Java
*/
public var cacheDir: String = "cache"
/**
* 联系人信息缓存配置. 将会保存在 [cacheDir] `contacts` 目录
* @since 2.4
*/
public actual var contactListCache: ContactListCache = ContactListCache()
/**
* 联系人信息缓存配置
* @see contactListCache
* @see enableContactCache
* @see disableContactCache
* @since 2.4
*/
public actual class ContactListCache {
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/
public actual var saveIntervalMillis: Long = 60_000
/**
* 在有修改时自动保存间隔. 默认 60 . 在每次登录完成后有修改时都会立即保存一次.
*/ // was @ExperimentalTime before 2.9
public actual inline var saveInterval: Duration
inline get() = saveIntervalMillis.milliseconds
inline set(v) {
saveIntervalMillis = v.inWholeMilliseconds
}
/**
* 开启好友列表缓存.
*/
public actual var friendListCacheEnabled: Boolean = false
/**
* 开启群成员列表缓存.
*/
public actual var groupMemberListCacheEnabled: Boolean = false
}
/**
* 配置 [ContactListCache]
* ```
* contactListCache {
* saveIntervalMillis = 30_000
* friendListCacheEnabled = true
* }
* ```
* @since 2.4
*/
public actual inline fun contactListCache(action: ContactListCache.() -> Unit) {
action.invoke(this.contactListCache)
}
/**
* 禁用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public actual fun disableContactCache() {
contactListCache.friendListCacheEnabled = false
contactListCache.groupMemberListCacheEnabled = false
}
/**
* 启用好友列表和群成员列表的缓存.
* @since 2.4
*/
@ConfigurationDsl
public actual fun enableContactCache() {
contactListCache.friendListCacheEnabled = true
contactListCache.groupMemberListCacheEnabled = true
}
/**
* 登录缓存.
*
* 开始后在密码登录成功时会保存秘钥等信息, 在下次启动时通过这些信息登录, 而不提交密码.
* 可以减少验证码出现的频率.
*
* 秘钥信息会由密码加密保存. 如果秘钥过期, 则会进行普通密码登录.
*
* 默认 `true` (开启).
*
* @since 2.6
*/
public actual var loginCacheEnabled: Boolean = true
///////////////////////////////////////////////////////////////////////////
// Misc
///////////////////////////////////////////////////////////////////////////
@Suppress("DuplicatedCode")
public actual fun copy(): BotConfiguration {
return BotConfiguration().also { new ->
// To structural order
new.workingDir = workingDir
new.parentCoroutineContext = parentCoroutineContext
new.heartbeatPeriodMillis = heartbeatPeriodMillis
new.heartbeatTimeoutMillis = heartbeatTimeoutMillis
new.statHeartbeatPeriodMillis = statHeartbeatPeriodMillis
new.heartbeatStrategy = heartbeatStrategy
new.reconnectionRetryTimes = reconnectionRetryTimes
new.autoReconnectOnForceOffline = autoReconnectOnForceOffline
new.loginSolver = loginSolver
new.protocol = protocol
new.highwayUploadCoroutineCount = highwayUploadCoroutineCount
new.accountSecrets = accountSecrets
new.deviceInfo = deviceInfo
new.botLoggerSupplier = botLoggerSupplier
new.networkLoggerSupplier = networkLoggerSupplier
new.cacheDir = cacheDir
new.contactListCache = contactListCache
new.convertLineSeparator = convertLineSeparator
new.isShowingVerboseEventLog = isShowingVerboseEventLog
}
}
/**
* 是否处理接受到的特殊换行符, 默认为 `true`
*
* - 若为 `true`, 会将收到的 `CRLF(\r\n)` `CR(\r)` 替换为 `LF(\n)`
* - 若为 `false`, 则不做处理
*
* @since 2.4
*/
public actual var convertLineSeparator: Boolean = true
/** 标注一个配置 DSL 函数 */
@Target(AnnotationTarget.FUNCTION)
@DslMarker
public actual annotation class ConfigurationDsl
public actual companion object {
/** 默认的配置实例. 可以进行修改 */
public actual val Default: BotConfiguration = BotConfiguration()
private val json = Json {
isLenient = true
ignoreUnknownKeys = true
prettyPrint = true
}
internal actual fun applyMppCopy(new: BotConfiguration) {
new.workingDir = workingDir
new.cacheDir = cacheDir
}
}