BotConfiguration.common.kt 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. /*
  2. * Copyright 2019-2020 Mamoe Technologies and contributors.
  3. *
  4. * 此源代码的使用受 GNU AFFERO GENERAL PUBLIC LICENSE version 3 许可证的约束, 可以在以下链接找到该许可证.
  5. * Use of this source code is governed by the GNU AGPLv3 license that can be found through the following link.
  6. *
  7. * https://github.com/mamoe/mirai/blob/master/LICENSE
  8. */
  9. @file:Suppress("unused", "DEPRECATION_ERROR", "EXPOSED_SUPER_CLASS")
  10. package net.mamoe.mirai.utils
  11. import kotlinx.coroutines.Job
  12. import kotlinx.coroutines.SupervisorJob
  13. import kotlinx.serialization.UnstableDefault
  14. import kotlinx.serialization.json.Json
  15. import net.mamoe.mirai.Bot
  16. import net.mamoe.mirai.utils.BotConfiguration.MiraiProtocol
  17. import kotlin.coroutines.CoroutineContext
  18. import kotlin.coroutines.EmptyCoroutineContext
  19. import kotlin.coroutines.coroutineContext
  20. import kotlin.jvm.JvmStatic
  21. import kotlin.jvm.JvmSynthetic
  22. /**
  23. * [Bot] 配置.
  24. *
  25. * Kotlin 使用方法:
  26. * ```
  27. * val bot = Bot(...) {
  28. * // 在这里配置 Bot
  29. *
  30. * bogLoggerSupplier = { bot -> ... }
  31. * fileBasedDeviceInfo()
  32. * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job
  33. * }
  34. * ```
  35. */
  36. public expect open class BotConfiguration() : BotConfigurationBase {
  37. /**
  38. * 设备信息覆盖. 在没有手动指定时将会通过日志警告, 并使用随机设备信息.
  39. * @see randomDeviceInfo 使用随机设备信息
  40. */
  41. public var deviceInfo: ((Context) -> DeviceInfo)?
  42. /**
  43. * 使用随机设备信息.
  44. *
  45. * @see deviceInfo
  46. */
  47. @ConfigurationDsl
  48. public fun randomDeviceInfo()
  49. /**
  50. * 使用特定由 [DeviceInfo] 序列化产生的 JSON 的设备信息
  51. *
  52. * @see deviceInfo
  53. */
  54. @SinceMirai("1.2.0")
  55. public fun loadDeviceInfoJson(json: String)
  56. /**
  57. * 协议类型, 服务器仅允许使用不同协议同时登录.
  58. */
  59. public enum class MiraiProtocol {
  60. /**
  61. * Android 手机.
  62. */
  63. ANDROID_PHONE,
  64. /**
  65. * Android 平板.
  66. */
  67. ANDROID_PAD,
  68. /**
  69. * Android 手表.
  70. * */
  71. @SinceMirai("1.1.0")
  72. ANDROID_WATCH;
  73. internal val id: Long
  74. }
  75. public companion object {
  76. /** 默认的配置实例. 可以进行修改 */
  77. @JvmStatic
  78. public val Default: BotConfiguration
  79. }
  80. public fun copy(): BotConfiguration
  81. }
  82. @SinceMirai("1.1.0")
  83. public open class BotConfigurationBase internal constructor() {
  84. /**
  85. * 日志记录器
  86. *
  87. * - 默认打印到标准输出, 通过 [DefaultLogger]
  88. * - 忽略所有日志: [noBotLog]
  89. * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
  90. * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
  91. *
  92. * @see MiraiLogger
  93. */
  94. public var botLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Bot ${it.id}") }
  95. /**
  96. * 网络层日志构造器
  97. *
  98. * - 默认打印到标准输出, 通过 [DefaultLogger]
  99. * - 忽略所有日志: [noNetworkLog]
  100. * - 重定向到一个目录: `networkLoggerSupplier = { DirectoryLogger("Net ${it.id}") }`
  101. * - 重定向到一个文件: `networkLoggerSupplier = { SingleFileLogger("Net ${it.id}") }`
  102. *
  103. * @see MiraiLogger
  104. */
  105. public var networkLoggerSupplier: ((Bot) -> MiraiLogger) = { DefaultLogger("Net ${it.id}") }
  106. /** 父 [CoroutineContext]. [Bot] 创建后会使用 [SupervisorJob] 覆盖其 [Job], 但会将这个 [Job] 作为父 [Job] */
  107. public var parentCoroutineContext: CoroutineContext = EmptyCoroutineContext
  108. /** 心跳周期. 过长会导致被服务器断开连接. */
  109. public var heartbeatPeriodMillis: Long = 60.secondsToMillis
  110. /**
  111. * 每次心跳时等待结果的时间.
  112. * 一旦心跳超时, 整个网络服务将会重启 (将消耗约 1s). 除正在进行的任务 (如图片上传) 会被中断外, 事件和插件均不受影响.
  113. */
  114. public var heartbeatTimeoutMillis: Long = 5.secondsToMillis
  115. /** 心跳失败后的第一次重连前的等待时间. */
  116. public var firstReconnectDelayMillis: Long = 5.secondsToMillis
  117. /** 重连失败后, 继续尝试的每次等待时间 */
  118. public var reconnectPeriodMillis: Long = 5.secondsToMillis
  119. /** 最多尝试多少次重连 */
  120. public var reconnectionRetryTimes: Int = Int.MAX_VALUE
  121. /** 验证码处理器 */
  122. public var loginSolver: LoginSolver = LoginSolver.Default
  123. /** 使用协议类型 */
  124. public var protocol: MiraiProtocol = MiraiProtocol.ANDROID_PAD
  125. /** 缓存策略 */
  126. @SinceMirai("1.0.0")
  127. @MiraiExperimentalApi
  128. public var fileCacheStrategy: FileCacheStrategy = FileCacheStrategy.PlatformDefault
  129. /**
  130. * Json 序列化器, 使用 'kotlinx.serialization'
  131. */
  132. @SinceMirai("1.1.0")
  133. @MiraiExperimentalApi
  134. public var json: Json = kotlin.runCatching {
  135. @OptIn(UnstableDefault::class)
  136. Json {
  137. isLenient = true
  138. ignoreUnknownKeys = true
  139. }
  140. }.getOrElse { Json {} }
  141. /**
  142. * 不显示网络日志. 不推荐.
  143. * @see networkLoggerSupplier 更多日志处理方式
  144. */
  145. @ConfigurationDsl
  146. public fun noNetworkLog() {
  147. networkLoggerSupplier = { _ -> SilentLogger }
  148. }
  149. /**
  150. * 不显示 [Bot] 日志. 不推荐.
  151. * @see botLoggerSupplier 更多日志处理方式
  152. */
  153. @ConfigurationDsl
  154. public fun noBotLog() {
  155. botLoggerSupplier = { _ -> SilentLogger }
  156. }
  157. /**
  158. * 使用当前协程的 [coroutineContext] 作为 [parentCoroutineContext].
  159. *
  160. * Bot 将会使用一个 [SupervisorJob] 覆盖 [coroutineContext] 当前协程的 [Job], 并使用当前协程的 [Job] 作为父 [Job]
  161. *
  162. * 用例:
  163. * ```
  164. * coroutineScope {
  165. * val bot = Bot(...) {
  166. * inheritCoroutineContext()
  167. * }
  168. * bot.login()
  169. * } // coroutineScope 会等待 Bot 退出
  170. * ```
  171. *
  172. *
  173. * **注意**: `bot.cancel` 时将会让父 [Job] 也被 cancel.
  174. * ```
  175. * coroutineScope { // this: CoroutineScope
  176. * launch {
  177. * while(isActive) {
  178. * delay(500)
  179. * println("I'm alive")
  180. * }
  181. * }
  182. *
  183. * val bot = Bot(...) {
  184. * inheritCoroutineContext() // 使用 `coroutineScope` 的 Job 作为父 Job
  185. * }
  186. * bot.login()
  187. * bot.cancel() // 取消了整个 `coroutineScope`, 因此上文不断打印 `"I'm alive"` 的协程也会被取消.
  188. * }
  189. * ```
  190. *
  191. * 因此, 此函数尤为适合在 `suspend fun main()` 中使用, 它能阻止主线程退出:
  192. * ```
  193. * suspend fun main() {
  194. * val bot = Bot() {
  195. * inheritCoroutineContext()
  196. * }
  197. * bot.subscribe { ... }
  198. *
  199. * // 主线程不会退出, 直到 Bot 离线.
  200. * }
  201. * ```
  202. *
  203. * 简言之,
  204. * - 若想让 [Bot] 作为 '守护进程' 运行, 则无需调用 [inheritCoroutineContext].
  205. * - 若想让 [Bot] 依赖于当前协程, 让当前协程等待 [Bot] 运行, 则使用 [inheritCoroutineContext]
  206. *
  207. * @see parentCoroutineContext
  208. */
  209. @JvmSynthetic
  210. @ConfigurationDsl
  211. public suspend inline fun inheritCoroutineContext() {
  212. parentCoroutineContext = coroutineContext
  213. }
  214. /** 标注一个配置 DSL 函数 */
  215. @Target(AnnotationTarget.FUNCTION)
  216. @DslMarker
  217. public annotation class ConfigurationDsl
  218. }
  219. internal val deviceInfoStub: (Context) -> DeviceInfo = {
  220. @Suppress("DEPRECATION")
  221. MiraiLogger.warning("未指定设备信息, 已使用随机设备信息. 请查看 BotConfiguration.deviceInfo 以获取更多信息.")
  222. @Suppress("DEPRECATION")
  223. MiraiLogger.warning("Device info isn't specified. Please refer to BotConfiguration.deviceInfo for more information")
  224. DeviceInfo.random()
  225. }