mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2025-12-10 06:42:07 +01:00
Fix/server startup config update failure handling (#1646)
* Catch config value migration exception In case the value did not exist in the config a "ConfigException.Missing" exception was thrown which caused the whole migration to fail. Fixes #1645 * Improve config migration logging * Update user config file after config update The user config file gets reset before the update. This could cause the user settings to get lost on the next server start in case something went wrong during the update and the updated config never got saved to the actual file.
This commit is contained in:
@@ -120,14 +120,16 @@ open class ConfigManager {
|
||||
}
|
||||
}
|
||||
|
||||
fun resetUserConfig(updateInternalConfig: Boolean = true): ConfigDocument {
|
||||
private fun createConfigDocumentFromReference(): ConfigDocument {
|
||||
val serverConfigFileContent = this::class.java.getResource("/server-reference.conf")?.readText()
|
||||
val serverConfigDoc = ConfigDocumentFactory.parseString(serverConfigFileContent)
|
||||
userConfigFile.writeText(serverConfigDoc.render())
|
||||
return ConfigDocumentFactory.parseString(serverConfigFileContent)
|
||||
}
|
||||
|
||||
if (updateInternalConfig) {
|
||||
getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) }
|
||||
}
|
||||
fun resetUserConfig(): ConfigDocument {
|
||||
val serverConfigDoc = createConfigDocumentFromReference()
|
||||
|
||||
userConfigFile.writeText(serverConfigDoc.render())
|
||||
getUserConfig().entrySet().forEach { internalConfig = internalConfig.withValue(it.key, it.value) }
|
||||
|
||||
return serverConfigDoc
|
||||
}
|
||||
@@ -135,8 +137,9 @@ open class ConfigManager {
|
||||
/**
|
||||
* Makes sure the "UserConfig" is up-to-date.
|
||||
*
|
||||
* - adds missing settings
|
||||
* - removes outdated settings
|
||||
* - Adds missing settings
|
||||
* - Migrates deprecated settings
|
||||
* - Removes outdated settings
|
||||
*/
|
||||
fun updateUserConfig(migrate: ConfigDocument.(Config) -> ConfigDocument) {
|
||||
val serverConfig = ConfigFactory.parseResources("server-reference.conf")
|
||||
@@ -149,16 +152,17 @@ open class ConfigManager {
|
||||
}
|
||||
val hasMissingSettings = refKeys.any { !userConfig.hasPath(it) }
|
||||
val hasOutdatedSettings = userConfig.entrySet().any { !refKeys.contains(it.key) && it.key.count { c -> c == '.' } <= 1 }
|
||||
|
||||
val isUserConfigOutdated = hasMissingSettings || hasOutdatedSettings
|
||||
if (!isUserConfigOutdated) {
|
||||
return
|
||||
}
|
||||
|
||||
logger.debug {
|
||||
"user config is out of date, updating... (missingSettings= $hasMissingSettings, outdatedSettings= $hasOutdatedSettings"
|
||||
"user config is out of date, updating... (missingSettings= $hasMissingSettings, outdatedSettings= $hasOutdatedSettings)"
|
||||
}
|
||||
|
||||
var newUserConfigDoc: ConfigDocument = resetUserConfig(false)
|
||||
var newUserConfigDoc: ConfigDocument = createConfigDocumentFromReference()
|
||||
userConfig
|
||||
.entrySet()
|
||||
.filter {
|
||||
|
||||
@@ -19,6 +19,7 @@ import eu.kanade.tachiyomi.App
|
||||
import eu.kanade.tachiyomi.createAppModule
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import eu.kanade.tachiyomi.source.local.LocalSource
|
||||
import io.github.config4k.getValue
|
||||
import io.github.config4k.toConfig
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import io.javalin.json.JavalinJackson
|
||||
@@ -144,7 +145,7 @@ fun setupLogLevelUpdating(
|
||||
)
|
||||
}
|
||||
|
||||
fun migrateConfig(
|
||||
fun migrateConfigValue(
|
||||
configDocument: ConfigDocument,
|
||||
config: Config,
|
||||
configKey: String,
|
||||
@@ -168,6 +169,54 @@ fun migrateConfig(
|
||||
return configDocument
|
||||
}
|
||||
|
||||
fun migrateConfig(
|
||||
configDocument: ConfigDocument,
|
||||
config: Config,
|
||||
): ConfigDocument {
|
||||
var updatedConfig = configDocument
|
||||
|
||||
val settingsRequiringMigration = SettingsRegistry.getAll().filterValues { it.deprecated?.replaceWith != null }
|
||||
settingsRequiringMigration.forEach { (name, data) ->
|
||||
val configKey = "server.$name"
|
||||
val toConfigKey = "server.${data.deprecated!!.replaceWith}"
|
||||
|
||||
try {
|
||||
config.getValue(configKey)
|
||||
} catch (_: ConfigException) {
|
||||
// Ignore, no migration required
|
||||
return@forEach
|
||||
}
|
||||
|
||||
logger.debug { "Migrating config value: $configKey -> $toConfigKey" }
|
||||
|
||||
try {
|
||||
if (data.deprecated!!.migrateConfig != null) {
|
||||
updatedConfig = data.deprecated!!.migrateConfig!!(config.getValue(configKey), updatedConfig)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (data.deprecated!!.migrateConfigValue != null) {
|
||||
updatedConfig =
|
||||
migrateConfigValue(
|
||||
updatedConfig,
|
||||
config,
|
||||
configKey,
|
||||
toConfigKey,
|
||||
data.deprecated!!.migrateConfigValue!!,
|
||||
)
|
||||
return@forEach
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.warn(e) { "Failed to migrate config value: $configKey -> $toConfigKey" }
|
||||
return@forEach
|
||||
}
|
||||
|
||||
shutdownApp(ExitCode.ConfigMigrationMisconfiguredFailure)
|
||||
}
|
||||
|
||||
return updatedConfig
|
||||
}
|
||||
|
||||
fun serverModule(applicationDirs: ApplicationDirs): Module =
|
||||
module {
|
||||
single { applicationDirs }
|
||||
@@ -310,37 +359,7 @@ fun applicationSetup() {
|
||||
}
|
||||
} else {
|
||||
// make sure the user config file is up-to-date
|
||||
GlobalConfigManager.updateUserConfig { config ->
|
||||
var updatedConfig = this
|
||||
|
||||
val settingsRequiringMigration = SettingsRegistry.getAll().filterValues { it.deprecated?.replaceWith != null }
|
||||
settingsRequiringMigration.forEach { (name, data) ->
|
||||
val configKey = "server.$name"
|
||||
val toConfigKey = "server.${data.deprecated!!.replaceWith}"
|
||||
|
||||
if (data.deprecated!!.migrateConfig != null) {
|
||||
logger.debug { "Migrating config value: $configKey -> $toConfigKey" }
|
||||
updatedConfig = data.deprecated!!.migrateConfig!!(config.getValue(configKey), updatedConfig)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
if (data.deprecated!!.migrateConfigValue != null) {
|
||||
updatedConfig =
|
||||
migrateConfig(
|
||||
updatedConfig,
|
||||
config,
|
||||
configKey,
|
||||
toConfigKey,
|
||||
data.deprecated!!.migrateConfigValue!!,
|
||||
)
|
||||
return@forEach
|
||||
}
|
||||
|
||||
shutdownApp(ExitCode.ConfigMigrationMisconfiguredFailure)
|
||||
}
|
||||
|
||||
updatedConfig
|
||||
}
|
||||
GlobalConfigManager.updateUserConfig { migrateConfig(this, it) }
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logger.error(e) { "Exception while creating initial server.conf" }
|
||||
|
||||
Reference in New Issue
Block a user