feat(launch): 延后 BotConfig 的反序列化时机.

通过将 BotConfig 的反序列化时机延后到启动机器人的时候, 可以避免因某个机器人配置错误导致所有机器人都无法启动的问题.
注意, 语法错误还是会在启动时报错, 只是说部分序列化器会检查字段值是否有误, 通过延后反序列化来防止全反序列化的时候一个配置炸了影响全部而已.
This commit is contained in:
LamGC 2022-07-04 16:40:17 +08:00
parent 3c54c33364
commit 51d036c4c6
Signed by: LamGC
GPG Key ID: 6C5AE2A913941E1D
2 changed files with 30 additions and 12 deletions

View File

@ -3,7 +3,7 @@ package net.lamgc.scalabot
import ch.qos.logback.core.PropertyDefinerBase import ch.qos.logback.core.PropertyDefinerBase
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.GsonBuilder import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken import com.google.gson.JsonArray
import mu.KotlinLogging import mu.KotlinLogging
import net.lamgc.scalabot.config.* import net.lamgc.scalabot.config.*
import net.lamgc.scalabot.config.serializer.* import net.lamgc.scalabot.config.serializer.*
@ -221,8 +221,8 @@ internal fun initialFiles() {
} }
} }
private object GsonConst { internal object GsonConst {
val baseGson: Gson = GsonBuilder() private val baseGson: Gson = GsonBuilder()
.setPrettyPrinting() .setPrettyPrinting()
.serializeNulls() .serializeNulls()
.create() .create()
@ -253,10 +253,10 @@ internal fun loadAppConfig(configFile: File = AppPaths.CONFIG_APPLICATION.file):
} }
} }
internal fun loadBotConfig(botConfigFile: File = AppPaths.CONFIG_BOT.file): Set<BotConfig>? { internal fun loadBotConfigJson(botConfigFile: File = AppPaths.CONFIG_BOT.file): JsonArray? {
try { try {
botConfigFile.bufferedReader(StandardCharsets.UTF_8).use { botConfigFile.bufferedReader(StandardCharsets.UTF_8).use {
return GsonConst.botConfigGson.fromJson(it, object : TypeToken<Set<BotConfig>>() {}.type)!! return GsonConst.botConfigGson.fromJson(it, JsonArray::class.java)!!
} }
} catch (e: Exception) { } catch (e: Exception) {
log.error(e) { "读取 Bot 配置文件 (bot.json) 时发生错误, 请检查配置格式是否正确." } log.error(e) { "读取 Bot 配置文件 (bot.json) 时发生错误, 请检查配置格式是否正确." }

View File

@ -1,5 +1,6 @@
package net.lamgc.scalabot package net.lamgc.scalabot
import com.google.gson.JsonParseException
import io.prometheus.client.exporter.HTTPServer import io.prometheus.client.exporter.HTTPServer
import kotlinx.coroutines.runBlocking import kotlinx.coroutines.runBlocking
import mu.KotlinLogging import mu.KotlinLogging
@ -110,22 +111,39 @@ internal class Launcher(private val config: AppConfig = Const.config) : AutoClos
@Synchronized @Synchronized
fun launch(): Boolean { fun launch(): Boolean {
val botConfigs = loadBotConfig() ?: return false val botConfigs = loadBotConfigJson() ?: return false
if (botConfigs.isEmpty()) { if (botConfigs.isEmpty) {
log.warn { "尚未配置任何机器人, 请先配置机器人后再启动本程序." } log.warn { "尚未配置任何机器人, 请先配置机器人后再启动本程序." }
return false return false
} else if (botConfigs.none { it.enabled }) {
log.warn { "配置文件中没有已启用的机器人, 请至少启用一个机器人." }
return false
} }
for (botConfig in botConfigs) { var launchedCounts = 0
for (botConfigJson in botConfigs) {
val botConfig = try {
GsonConst.botConfigGson.fromJson(botConfigJson, BotConfig::class.java)
} catch (e: JsonParseException) {
val botName = try {
botConfigJson.asJsonObject.get("account")?.asJsonObject?.get("name")?.asString ?: "Unknown"
} catch (e: Exception) {
"Unknown"
}
log.error(e) { "机器人 `$botName` 配置有误, 跳过该机器人的启动." }
continue
}
try { try {
launchBot(botConfig) launchBot(botConfig)
launchedCounts++
} catch (e: Exception) { } catch (e: Exception) {
log.error(e) { "机器人 `${botConfig.account.name}` 启动时发生错误." } log.error(e) { "机器人 `${botConfig.account.name}` 启动时发生错误." }
} }
} }
return true return if (launchedCounts != 0) {
log.info { "已启动 $launchedCounts 个机器人." }
true
} else {
log.warn { "未启动任何机器人, 请检查配置并至少启用一个机器人." }
false
}
} }
private fun launchBot(botConfig: BotConfig) { private fun launchBot(botConfig: BotConfig) {