Feature/support different webui flavors (#863)

* Run functions for specific webui flavor

* Set default flavor of WebUIFlavor enum

* Consider flavor of served webUI when checking for update

In case the flavor was changed and the served webui files are still for the previous flavor, the update check could incorrectly detect no update

* Skip validation during initial setup

In case initial setup is triggered because of an invalid local webUI, doing a validation again is unnecessary

* Handle changed flavor on startup
This commit is contained in:
schroda
2024-02-17 17:23:01 +01:00
committed by GitHub
parent 8aa75be0d3
commit 9edbc7f1d7
3 changed files with 139 additions and 66 deletions

View File

@@ -8,6 +8,7 @@ import suwayomi.tachidesk.graphql.types.UpdateState.IDLE
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.JavalinSetup.future import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.util.WebInterfaceManager import suwayomi.tachidesk.server.util.WebInterfaceManager
import suwayomi.tachidesk.server.util.WebUIFlavor
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import kotlin.time.Duration.Companion.seconds import kotlin.time.Duration.Companion.seconds
@@ -28,7 +29,9 @@ class InfoMutation {
return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value) return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value)
} }
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable() val flavor = WebUIFlavor.current
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(flavor)
if (!updateAvailable) { if (!updateAvailable) {
val didUpdateCheckFail = version.isEmpty() val didUpdateCheckFail = version.isEmpty()
@@ -39,7 +42,7 @@ class InfoMutation {
) )
} }
try { try {
WebInterfaceManager.startDownloadInScope(version) WebInterfaceManager.startDownloadInScope(flavor, version)
} catch (e: Exception) { } catch (e: Exception) {
// ignore since we use the status anyway // ignore since we use the status anyway
} }

View File

@@ -8,6 +8,7 @@ import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.generated.BuildConfig import suwayomi.tachidesk.server.generated.BuildConfig
import suwayomi.tachidesk.server.serverConfig import suwayomi.tachidesk.server.serverConfig
import suwayomi.tachidesk.server.util.WebInterfaceManager import suwayomi.tachidesk.server.util.WebInterfaceManager
import suwayomi.tachidesk.server.util.WebUIFlavor
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
class InfoQuery { class InfoQuery {
@@ -60,7 +61,7 @@ class InfoQuery {
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> { fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateCheck> {
return future { return future {
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(raiseError = true) val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable(WebUIFlavor.current, raiseError = true)
WebUIUpdateCheck( WebUIUpdateCheck(
channel = serverConfig.webUIChannel.value, channel = serverConfig.webUIChannel.value,
tag = version, tag = version,

View File

@@ -119,7 +119,12 @@ enum class WebUIFlavor(
; ;
companion object { companion object {
fun from(value: String): WebUIFlavor = entries.find { it.uiName == value } ?: WEBUI val default: WebUIFlavor = WEBUI
fun from(value: String): WebUIFlavor = entries.find { it.uiName == value } ?: default
val current: WebUIFlavor
get() = from(serverConfig.webUIFlavor.value)
} }
} }
@@ -128,6 +133,7 @@ object WebInterfaceManager {
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default) private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
private const val LAST_WEBUI_UPDATE_CHECK_KEY = "lastWebUIUpdateCheck" private const val LAST_WEBUI_UPDATE_CHECK_KEY = "lastWebUIUpdateCheck"
private const val SERVED_WEBUI_FLAVOR_KEY = "servedWebUIFlavor"
private val preferences = Injekt.get<Application>().getSharedPreferences("server_util", Context.MODE_PRIVATE) private val preferences = Injekt.get<Application>().getSharedPreferences("server_util", Context.MODE_PRIVATE)
private var currentUpdateTaskId: String = "" private var currentUpdateTaskId: String = ""
@@ -206,6 +212,14 @@ object WebInterfaceManager {
this.serveWebUI = serveWebUI this.serveWebUI = serveWebUI
} }
private fun setServedWebUIFlavor(flavor: WebUIFlavor) {
preferences.edit().putString(SERVED_WEBUI_FLAVOR_KEY, flavor.uiName).apply()
}
private fun getServedWebUIFlavor(): WebUIFlavor {
return WebUIFlavor.from(preferences.getString(SERVED_WEBUI_FLAVOR_KEY, WebUIFlavor.default.uiName)!!)
}
private fun isAutoUpdateEnabled(): Boolean { private fun isAutoUpdateEnabled(): Boolean {
return serverConfig.webUIUpdateCheckInterval.value.toInt() != 0 return serverConfig.webUIUpdateCheckInterval.value.toInt() != 0
} }
@@ -224,6 +238,7 @@ object WebInterfaceManager {
val task = { val task = {
logger.debug { logger.debug {
"Checking for webUI update (" + "Checking for webUI update (" +
"flavor= ${WebUIFlavor.current.uiName}, " +
"channel= ${serverConfig.webUIChannel.value}, " + "channel= ${serverConfig.webUIChannel.value}, " +
"interval= ${serverConfig.webUIUpdateCheckInterval.value}h, " + "interval= ${serverConfig.webUIUpdateCheckInterval.value}h, " +
"lastAutomatedUpdate= ${ "lastAutomatedUpdate= ${
@@ -234,7 +249,7 @@ object WebInterfaceManager {
} }
runBlocking { runBlocking {
checkForUpdate() checkForUpdate(WebUIFlavor.current)
} }
} }
@@ -253,49 +268,66 @@ object WebInterfaceManager {
return return
} }
val flavor = WebUIFlavor.current
val servedFlavor = getServedWebUIFlavor()
val log =
KotlinLogging.logger("${logger.name} setupWebUI(flavor= ${flavor.uiName}, servedFlavor= ${servedFlavor.uiName})")
if (doesLocalWebUIExist(applicationDirs.webUIRoot)) { if (doesLocalWebUIExist(applicationDirs.webUIRoot)) {
val currentVersion = getLocalVersion() val currentVersion = getLocalVersion()
logger.info { "setupWebUI: found webUI files - flavor= ${serverConfig.webUIFlavor.value}, version= $currentVersion" } log.info { "found webUI files - version= $currentVersion" }
if (!isLocalWebUIValid(applicationDirs.webUIRoot)) { val hasFlavorChanged = flavor.uiName != servedFlavor.uiName
if (hasFlavorChanged) {
try { try {
doInitialSetup() doInitialSetup(flavor)
return
} catch (e: Exception) { } catch (e: Exception) {
logger.warn(e) { "WebUI is invalid and failed to install a valid version, proceeding with invalid version" } log.warn(e) { "Failed to install the version of the new flavor, proceeding with version of previous flavor" }
}
}
val flavorToValidate = if (hasFlavorChanged) servedFlavor else flavor
if (!isLocalWebUIValid(flavorToValidate, applicationDirs.webUIRoot)) {
try {
doInitialSetup(flavorToValidate, isInvalid = true)
} catch (e: Exception) {
log.warn(e) { "WebUI is invalid and failed to install a valid version, proceeding with invalid version" }
} }
return return
} }
if (isAutoUpdateEnabled()) { if (isAutoUpdateEnabled()) {
checkForUpdate() checkForUpdate(flavor)
} }
// check if the bundled webUI version is a newer version than the current used version // check if the bundled webUI version is a newer version than the current used version
// this could be the case in case no compatible webUI version is available and a newer server version was installed // this could be the case in case no compatible webUI version is available and a newer server version was installed
val shouldUpdateToBundledVersion = val shouldUpdateToBundledVersion =
serverConfig.webUIFlavor.value == WebUIFlavor.WEBUI.uiName && extractVersion(getLocalVersion()) < flavor.uiName == WebUIFlavor.default.uiName && extractVersion(getLocalVersion()) <
extractVersion( extractVersion(
BuildConfig.WEBUI_TAG, BuildConfig.WEBUI_TAG,
) )
if (shouldUpdateToBundledVersion) { if (shouldUpdateToBundledVersion) {
logger.debug { "setupWebUI: update to bundled version \"${BuildConfig.WEBUI_TAG}\"" } log.debug { "update to bundled version \"${BuildConfig.WEBUI_TAG}\"" }
try { try {
setupBundledWebUI() setupBundledWebUI()
} catch (e: Exception) { } catch (e: Exception) {
logger.error(e) { "setupWebUI: failed the update to the bundled webUI" } log.error(e) { "failed the update to the bundled webUI" }
} }
} }
return return
} }
logger.warn { "setupWebUI: no webUI files found, starting download..." } log.warn { "no webUI files found, starting download..." }
try { try {
doInitialSetup() doInitialSetup(flavor)
} catch (e: Exception) { } catch (e: Exception) {
logger.error(e) { log.error(e) {
"Failed to setup the webUI. Unable to start the server with a served webUI, change the settings to start" + "Failed to setup the webUI. Unable to start the server with a served webUI, change the settings to start" +
"without one. Stopping the server now..." "without one. Stopping the server now..."
} }
@@ -306,8 +338,14 @@ object WebInterfaceManager {
/** /**
* Tries to download the latest compatible version for the selected webUI and falls back to the default webUI in case of errors. * Tries to download the latest compatible version for the selected webUI and falls back to the default webUI in case of errors.
*/ */
private suspend fun doInitialSetup() { private suspend fun doInitialSetup(
val isLocalWebUIValid = isLocalWebUIValid(applicationDirs.webUIRoot) flavor: WebUIFlavor,
isInvalid: Boolean = false,
) {
val log =
KotlinLogging.logger("${logger.name} doInitialSetup(flavor= ${flavor.uiName})")
val isLocalWebUIValid = !isInvalid && isLocalWebUIValid(flavor, applicationDirs.webUIRoot)
/** /**
* Performs the download and returns if the download was successful. * Performs the download and returns if the download was successful.
@@ -316,7 +354,7 @@ object WebInterfaceManager {
*/ */
val doDownload: suspend (getVersion: suspend () -> String) -> Boolean = { getVersion -> val doDownload: suspend (getVersion: suspend () -> String) -> Boolean = { getVersion ->
try { try {
downloadVersion(getVersion()) downloadVersion(flavor, getVersion())
true true
} catch (e: Exception) { } catch (e: Exception) {
false false
@@ -324,23 +362,23 @@ object WebInterfaceManager {
} }
// download the latest compatible version for the current selected webUI // download the latest compatible version for the current selected webUI
val fallbackToDefaultWebUI = !doDownload { getLatestCompatibleVersion() } val fallbackToDefaultWebUI = !doDownload { getLatestCompatibleVersion(flavor) }
if (!fallbackToDefaultWebUI) { if (!fallbackToDefaultWebUI) {
return return
} }
if (serverConfig.webUIFlavor.value != WebUIFlavor.WEBUI.uiName) { if (flavor.uiName != WebUIFlavor.default.uiName) {
logger.warn { "doInitialSetup: fallback to default webUI \"${WebUIFlavor.WEBUI.uiName}\"" } log.warn { "fallback to default webUI \"${WebUIFlavor.default.uiName}\"" }
serverConfig.webUIFlavor.value = WebUIFlavor.WEBUI.uiName serverConfig.webUIFlavor.value = WebUIFlavor.default.uiName
val fallbackToBundledVersion = !doDownload { getLatestCompatibleVersion() } val fallbackToBundledVersion = !doDownload { getLatestCompatibleVersion(flavor) }
if (!fallbackToBundledVersion) { if (!fallbackToBundledVersion) {
return return
} }
} }
logger.warn { "doInitialSetup: fallback to bundled default webUI \"${WebUIFlavor.WEBUI.uiName}\"" } log.warn { "fallback to bundled default webUI \"${WebUIFlavor.default.uiName}\"" }
try { try {
setupBundledWebUI() setupBundledWebUI()
@@ -352,12 +390,13 @@ object WebInterfaceManager {
private suspend fun setupBundledWebUI() { private suspend fun setupBundledWebUI() {
try { try {
extractBundledWebUI() extractBundledWebUI()
setServedWebUIFlavor(WebUIFlavor.default)
return return
} catch (e: BundledWebUIMissing) { } catch (e: BundledWebUIMissing) {
logger.warn(e) { "setupBundledWebUI: fallback to downloading the version of the bundled webUI" } logger.warn(e) { "setupBundledWebUI: fallback to downloading the version of the bundled webUI" }
} }
downloadVersion(BuildConfig.WEBUI_TAG) downloadVersion(WebUIFlavor.default, BuildConfig.WEBUI_TAG)
} }
private fun extractBundledWebUI() { private fun extractBundledWebUI() {
@@ -366,7 +405,7 @@ object WebInterfaceManager {
logger.info { "extractBundledWebUI: Using the bundled WebUI zip..." } logger.info { "extractBundledWebUI: Using the bundled WebUI zip..." }
val webUIZip = WebUIFlavor.WEBUI.baseFileName val webUIZip = WebUIFlavor.default.baseFileName
val webUIZipPath = "$tmpDir/$webUIZip" val webUIZipPath = "$tmpDir/$webUIZip"
val webUIZipFile = File(webUIZipPath) val webUIZipFile = File(webUIZipPath)
resourceWebUI.use { input -> resourceWebUI.use { input ->
@@ -379,25 +418,31 @@ object WebInterfaceManager {
extractDownload(webUIZipPath, applicationDirs.webUIRoot) extractDownload(webUIZipPath, applicationDirs.webUIRoot)
} }
private suspend fun checkForUpdate() { private suspend fun checkForUpdate(flavor: WebUIFlavor) {
preferences.edit().putLong(LAST_WEBUI_UPDATE_CHECK_KEY, System.currentTimeMillis()).apply() preferences.edit().putLong(LAST_WEBUI_UPDATE_CHECK_KEY, System.currentTimeMillis()).apply()
val localVersion = getLocalVersion() val localVersion = getLocalVersion()
if (!isUpdateAvailable(localVersion).second) { val log =
logger.debug { "checkForUpdate(${serverConfig.webUIFlavor.value}, $localVersion): local version is the latest one" } KotlinLogging.logger("${logger.name} checkForUpdate(flavor= ${flavor.uiName}, localVersion= $localVersion)")
if (!isUpdateAvailable(flavor, localVersion).second) {
log.debug { "local version is the latest one" }
return return
} }
logger.info { "checkForUpdate(${serverConfig.webUIFlavor.value}, $localVersion): An update is available, starting download..." } log.info { "An update is available, starting download..." }
try { try {
downloadVersion(getLatestCompatibleVersion()) downloadVersion(flavor, getLatestCompatibleVersion(flavor))
} catch (e: Exception) { } catch (e: Exception) {
logger.warn(e) { "checkForUpdate: failed due to" } log.warn(e) { "failed due to" }
} }
} }
private fun getDownloadUrlFor(version: String): String { private fun getDownloadUrlFor(
val baseReleasesUrl = "${WebUIFlavor.WEBUI.repoUrl}/releases" flavor: WebUIFlavor,
version: String,
): String {
val baseReleasesUrl = "${flavor.repoUrl}/releases"
val downloadSpecificVersionBaseUrl = "$baseReleasesUrl/download" val downloadSpecificVersionBaseUrl = "$baseReleasesUrl/download"
return "$downloadSpecificVersionBaseUrl/$version" return "$downloadSpecificVersionBaseUrl/$version"
@@ -417,20 +462,25 @@ object WebInterfaceManager {
return webUIRevisionFile.exists() return webUIRevisionFile.exists()
} }
private suspend fun isLocalWebUIValid(path: String): Boolean { private suspend fun isLocalWebUIValid(
flavor: WebUIFlavor,
path: String,
): Boolean {
if (!doesLocalWebUIExist(path)) { if (!doesLocalWebUIExist(path)) {
return false return false
} }
logger.info { "isLocalWebUIValid: Verifying WebUI files..." } val log =
KotlinLogging.logger("${logger.name} isLocalWebUIValid(flavor= ${flavor.uiName}, path= $path)")
log.info { "Verifying WebUI files..." }
val currentVersion = getLocalVersion(path) val currentVersion = getLocalVersion(path)
val localMD5Sum = getLocalMD5Sum(path) val localMD5Sum = getLocalMD5Sum(path)
val currentVersionMD5Sum = fetchMD5SumFor(currentVersion) val currentVersionMD5Sum = fetchMD5SumFor(flavor, currentVersion)
val validationSucceeded = currentVersionMD5Sum == localMD5Sum val validationSucceeded = currentVersionMD5Sum == localMD5Sum
logger.info { log.info {
"isLocalWebUIValid: Validation " + "Validation " +
"${if (validationSucceeded) "succeeded" else "failed"} - " + "${if (validationSucceeded) "succeeded" else "failed"} - " +
"md5: local= $localMD5Sum; expected= $currentVersionMD5Sum" "md5: local= $localMD5Sum; expected= $currentVersionMD5Sum"
} }
@@ -474,10 +524,13 @@ object WebInterfaceManager {
} }
} }
private suspend fun fetchMD5SumFor(version: String): String { private suspend fun fetchMD5SumFor(
flavor: WebUIFlavor,
version: String,
): String {
return try { return try {
executeWithRetry(KotlinLogging.logger("${logger.name} fetchMD5SumFor($version)"), { executeWithRetry(KotlinLogging.logger("${logger.name} fetchMD5SumFor(flavor= ${flavor.uiName}, version= $version)"), {
network.client.newCall(GET("${getDownloadUrlFor(version)}/md5sum")).awaitSuccess().body.string().trim() network.client.newCall(GET("${getDownloadUrlFor(flavor, version)}/md5sum")).awaitSuccess().body.string().trim()
}) })
} catch (e: Exception) { } catch (e: Exception) {
"" ""
@@ -489,36 +542,37 @@ object WebInterfaceManager {
return versionString.substring(1).toInt() return versionString.substring(1).toInt()
} }
private suspend fun fetchPreviewVersion(): String { private suspend fun fetchPreviewVersion(flavor: WebUIFlavor): String {
return executeWithRetry(KotlinLogging.logger("${logger.name} fetchPreviewVersion"), { return executeWithRetry(KotlinLogging.logger("${logger.name} fetchPreviewVersion(${flavor.uiName})"), {
val releaseInfoJson = network.client.newCall(GET(WebUIFlavor.WEBUI.latestReleaseInfoUrl)).awaitSuccess().body.string() val releaseInfoJson = network.client.newCall(GET(flavor.latestReleaseInfoUrl)).awaitSuccess().body.string()
Json.decodeFromString<JsonObject>(releaseInfoJson)["tag_name"]?.jsonPrimitive?.content Json.decodeFromString<JsonObject>(releaseInfoJson)["tag_name"]?.jsonPrimitive?.content
?: throw Exception("Failed to get the preview version tag") ?: throw Exception("Failed to get the preview version tag")
}) })
} }
private suspend fun fetchServerMappingFile(): JsonArray { private suspend fun fetchServerMappingFile(flavor: WebUIFlavor): JsonArray {
return executeWithRetry( return executeWithRetry(
KotlinLogging.logger("$logger fetchServerMappingFile"), KotlinLogging.logger("$logger fetchServerMappingFile(${flavor.uiName})"),
{ {
json.parseToJsonElement( json.parseToJsonElement(
network.client.newCall(GET(WebUIFlavor.WEBUI.versionMappingUrl)).awaitSuccess().body.string(), network.client.newCall(GET(flavor.versionMappingUrl)).awaitSuccess().body.string(),
).jsonArray ).jsonArray
}, },
) )
} }
private suspend fun getLatestCompatibleVersion(): String { private suspend fun getLatestCompatibleVersion(flavor: WebUIFlavor): String {
if (WebUIChannel.doesConfigChannelEqual(WebUIChannel.BUNDLED)) { if (WebUIChannel.doesConfigChannelEqual(WebUIChannel.BUNDLED)) {
logger.debug { "getLatestCompatibleVersion: Channel is \"${WebUIChannel.BUNDLED}\", do not check for update" } logger.debug { "getLatestCompatibleVersion: Channel is \"${WebUIChannel.BUNDLED}\", do not check for update" }
return BuildConfig.WEBUI_TAG return BuildConfig.WEBUI_TAG
} }
val currentServerVersionNumber = extractVersion(BuildConfig.REVISION) val currentServerVersionNumber = extractVersion(BuildConfig.REVISION)
val webUIToServerVersionMappings = fetchServerMappingFile() val webUIToServerVersionMappings = fetchServerMappingFile(flavor)
logger.debug { logger.debug {
"getLatestCompatibleVersion: " + "getLatestCompatibleVersion: " +
"flavor= ${flavor.uiName}, " +
"webUIChannel= ${serverConfig.webUIChannel.value}, " + "webUIChannel= ${serverConfig.webUIChannel.value}, " +
"currentServerVersion= ${BuildConfig.REVISION}, " + "currentServerVersion= ${BuildConfig.REVISION}, " +
"mappingFile= $webUIToServerVersionMappings" "mappingFile= $webUIToServerVersionMappings"
@@ -545,7 +599,7 @@ object WebInterfaceManager {
} }
if (webUIVersion == WebUIChannel.PREVIEW.name) { if (webUIVersion == WebUIChannel.PREVIEW.name) {
webUIVersion = fetchPreviewVersion() webUIVersion = fetchPreviewVersion(flavor)
} }
val isCompatibleVersion = val isCompatibleVersion =
@@ -579,26 +633,32 @@ object WebInterfaceManager {
} }
} }
fun startDownloadInScope(version: String) { fun startDownloadInScope(
flavor: WebUIFlavor,
version: String,
) {
scope.launch { scope.launch {
downloadVersion(version) downloadVersion(flavor, version)
} }
} }
suspend fun downloadVersion(version: String) { suspend fun downloadVersion(
flavor: WebUIFlavor,
version: String,
) {
emitStatus(version, DOWNLOADING, 0, immediate = true) emitStatus(version, DOWNLOADING, 0, immediate = true)
try { try {
val webUIZip = "${WebUIFlavor.WEBUI.baseFileName}-$version.zip" val webUIZip = "${flavor.baseFileName}-$version.zip"
val webUIZipPath = "$tmpDir/$webUIZip" val webUIZipPath = "$tmpDir/$webUIZip"
val webUIZipURL = "${getDownloadUrlFor(version)}/$webUIZip" val webUIZipURL = "${getDownloadUrlFor(flavor, version)}/$webUIZip"
val log = val log =
KotlinLogging.logger("${logger.name} downloadVersion(version= $version, flavor= ${serverConfig.webUIFlavor.value})") KotlinLogging.logger("${logger.name} downloadVersion(version= $version, flavor= ${flavor.uiName})")
log.info { "Downloading WebUI zip from the Internet..." } log.info { "Downloading WebUI zip from the Internet..." }
executeWithRetry(log, { executeWithRetry(log, {
downloadVersionZipFile(webUIZipURL, webUIZipPath) { progress -> downloadVersionZipFile(flavor, webUIZipURL, webUIZipPath) { progress ->
emitStatus( emitStatus(
version, version,
DOWNLOADING, DOWNLOADING,
@@ -613,6 +673,8 @@ object WebInterfaceManager {
extractDownload(webUIZipPath, applicationDirs.webUIRoot) extractDownload(webUIZipPath, applicationDirs.webUIRoot)
log.info { "Extracting WebUI zip Done." } log.info { "Extracting WebUI zip Done." }
setServedWebUIFlavor(flavor)
emitStatus(version, FINISHED, 100, immediate = true) emitStatus(version, FINISHED, 100, immediate = true)
serveWebUI() serveWebUI()
@@ -623,6 +685,7 @@ object WebInterfaceManager {
} }
private suspend fun downloadVersionZipFile( private suspend fun downloadVersionZipFile(
flavor: WebUIFlavor,
url: String, url: String,
filePath: String, filePath: String,
updateProgress: (progress: Int) -> Unit, updateProgress: (progress: Int) -> Unit,
@@ -641,7 +704,7 @@ object WebInterfaceManager {
connection.inputStream.buffered().use { inp -> connection.inputStream.buffered().use { inp ->
var totalCount = 0 var totalCount = 0
print("downloadVersionZipFile: Download progress: % 00") print("downloadVersionZipFile(${flavor.uiName}): Download progress: % 00")
while (true) { while (true) {
val count = inp.read(data, 0, 1024) val count = inp.read(data, 0, 1024)
@@ -659,21 +722,24 @@ object WebInterfaceManager {
updateProgress(percentage) updateProgress(percentage)
} }
println() println()
logger.info { "downloadVersionZipFile: Downloading WebUI Done." } logger.info { "downloadVersionZipFile(${flavor.uiName}): Downloading WebUI Done." }
} }
} }
if (!isDownloadValid(filePath)) { if (!isDownloadValid(flavor, filePath)) {
throw Exception("Download is invalid") throw Exception("Download is invalid")
} }
} }
private suspend fun isDownloadValid(zipFilePath: String): Boolean { private suspend fun isDownloadValid(
flavor: WebUIFlavor,
zipFilePath: String,
): Boolean {
val tempUnzippedWebUIFolderPath = zipFilePath.replace(".zip", "") val tempUnzippedWebUIFolderPath = zipFilePath.replace(".zip", "")
extractDownload(zipFilePath, tempUnzippedWebUIFolderPath) extractDownload(zipFilePath, tempUnzippedWebUIFolderPath)
val isDownloadValid = isLocalWebUIValid(tempUnzippedWebUIFolderPath) val isDownloadValid = isLocalWebUIValid(flavor, tempUnzippedWebUIFolderPath)
File(tempUnzippedWebUIFolderPath).deleteRecursively() File(tempUnzippedWebUIFolderPath).deleteRecursively()
@@ -689,13 +755,16 @@ object WebInterfaceManager {
} }
suspend fun isUpdateAvailable( suspend fun isUpdateAvailable(
flavor: WebUIFlavor,
currentVersion: String = getLocalVersion(), currentVersion: String = getLocalVersion(),
raiseError: Boolean = false, raiseError: Boolean = false,
): Pair<String, Boolean> { ): Pair<String, Boolean> {
return try { return try {
val latestCompatibleVersion = getLatestCompatibleVersion() val isServedWebUIForCurrentFlavor = flavor.uiName == getServedWebUIFlavor().uiName
val isUpdateAvailable = latestCompatibleVersion != currentVersion val latestCompatibleVersion = getLatestCompatibleVersion(flavor)
val isVersionUpdateAvailable = latestCompatibleVersion != currentVersion
val isUpdateAvailable = !isServedWebUIForCurrentFlavor || isVersionUpdateAvailable
Pair(latestCompatibleVersion, isUpdateAvailable) Pair(latestCompatibleVersion, isUpdateAvailable)
} catch (e: Exception) { } catch (e: Exception) {
logger.warn(e) { "isUpdateAvailable: check failed due to" } logger.warn(e) { "isUpdateAvailable: check failed due to" }