mirror of
https://github.com/Suwayomi/Tachidesk.git
synced 2026-01-20 10:42:37 +01:00
Feature/gql improve webui update status (#783)
* Remove "updateAvailable" from webui update info Doesn't add anything * Extract status creation into function * Optionally emit status immediately Otherwise, some emissions can get lost due to the 1s sample period * Rename "STOPPED" state to "IDLE" * Reset webui update status Currently, the update status never gets reset. Thus, it will be "FINISHED" or "ERROR" until the next update gets triggered. Due to this, the client won't know that the update result was already handled and will handle it again the next time it gets the update status. To prevent this, the client has to be able to tell the server that it has handled the update result and that it can be resetted
This commit is contained in:
@@ -4,11 +4,9 @@ import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.withTimeout
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.DOWNLOADING
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.ERROR
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.STOPPED
|
||||
import suwayomi.tachidesk.graphql.types.WebUIUpdateInfo
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.IDLE
|
||||
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
|
||||
import suwayomi.tachidesk.server.JavalinSetup.future
|
||||
import suwayomi.tachidesk.server.serverConfig
|
||||
import suwayomi.tachidesk.server.util.WebInterfaceManager
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import kotlin.time.Duration.Companion.seconds
|
||||
@@ -37,16 +35,7 @@ class InfoMutation {
|
||||
|
||||
return@withTimeout WebUIUpdatePayload(
|
||||
input.clientMutationId,
|
||||
WebUIUpdateStatus(
|
||||
info =
|
||||
WebUIUpdateInfo(
|
||||
channel = serverConfig.webUIChannel.value,
|
||||
tag = version,
|
||||
updateAvailable,
|
||||
),
|
||||
state = if (didUpdateCheckFail) ERROR else STOPPED,
|
||||
progress = 0,
|
||||
),
|
||||
WebInterfaceManager.getStatus(version, if (didUpdateCheckFail) ERROR else IDLE),
|
||||
)
|
||||
}
|
||||
try {
|
||||
@@ -62,4 +51,19 @@ class InfoMutation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun resetWebUIUpdateStatus(): CompletableFuture<WebUIUpdateStatus> {
|
||||
return future {
|
||||
withTimeout(30.seconds) {
|
||||
val isUpdateFinished = WebInterfaceManager.status.value.state != DOWNLOADING
|
||||
if (!isUpdateFinished) {
|
||||
throw Exception("Status reset is not allowed during status \"$DOWNLOADING\"")
|
||||
}
|
||||
|
||||
WebInterfaceManager.resetStatus()
|
||||
|
||||
WebInterfaceManager.status.first { it.state == IDLE }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,10 @@ data class WebUIUpdateCheck(
|
||||
data class WebUIUpdateInfo(
|
||||
val channel: String,
|
||||
val tag: String,
|
||||
val updateAvailable: Boolean,
|
||||
)
|
||||
|
||||
enum class UpdateState {
|
||||
STOPPED,
|
||||
IDLE,
|
||||
DOWNLOADING,
|
||||
FINISHED,
|
||||
ERROR,
|
||||
|
||||
@@ -41,7 +41,7 @@ import suwayomi.tachidesk.graphql.types.UpdateState
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.DOWNLOADING
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.ERROR
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.FINISHED
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.STOPPED
|
||||
import suwayomi.tachidesk.graphql.types.UpdateState.IDLE
|
||||
import suwayomi.tachidesk.graphql.types.WebUIUpdateInfo
|
||||
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
|
||||
import suwayomi.tachidesk.server.ApplicationDirs
|
||||
@@ -137,25 +137,22 @@ object WebInterfaceManager {
|
||||
private val notifyFlow =
|
||||
MutableSharedFlow<WebUIUpdateStatus>(extraBufferCapacity = 1, onBufferOverflow = DROP_OLDEST)
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
private val statusFlow = MutableSharedFlow<WebUIUpdateStatus>()
|
||||
val status =
|
||||
notifyFlow.sample(1.seconds)
|
||||
.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
WebUIUpdateStatus(
|
||||
info =
|
||||
WebUIUpdateInfo(
|
||||
channel = serverConfig.webUIChannel.value,
|
||||
tag = "",
|
||||
updateAvailable = false,
|
||||
),
|
||||
state = STOPPED,
|
||||
progress = 0,
|
||||
),
|
||||
)
|
||||
statusFlow.stateIn(
|
||||
scope,
|
||||
SharingStarted.Eagerly,
|
||||
getStatus(),
|
||||
)
|
||||
|
||||
init {
|
||||
scope.launch {
|
||||
@OptIn(FlowPreview::class)
|
||||
notifyFlow.sample(1.seconds).collect {
|
||||
statusFlow.emit(it)
|
||||
}
|
||||
}
|
||||
|
||||
serverConfig.subscribeTo(
|
||||
combine(serverConfig.webUIUpdateCheckInterval, serverConfig.webUIFlavor) { interval, flavor ->
|
||||
Pair(
|
||||
@@ -168,7 +165,7 @@ object WebInterfaceManager {
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getAboutInfo(): AboutWebUI {
|
||||
fun getAboutInfo(): AboutWebUI {
|
||||
val currentVersion = getLocalVersion()
|
||||
|
||||
val failedToGetVersion = currentVersion === "r-1"
|
||||
@@ -182,6 +179,26 @@ object WebInterfaceManager {
|
||||
)
|
||||
}
|
||||
|
||||
fun getStatus(
|
||||
version: String = "",
|
||||
state: UpdateState = IDLE,
|
||||
progress: Int = 0,
|
||||
): WebUIUpdateStatus {
|
||||
return WebUIUpdateStatus(
|
||||
info =
|
||||
WebUIUpdateInfo(
|
||||
channel = serverConfig.webUIChannel.value,
|
||||
tag = version,
|
||||
),
|
||||
state,
|
||||
progress,
|
||||
)
|
||||
}
|
||||
|
||||
fun resetStatus() {
|
||||
emitStatus("", IDLE, 0, immediate = true)
|
||||
}
|
||||
|
||||
private var serveWebUI: () -> Unit = {}
|
||||
|
||||
fun setServeWebUI(serveWebUI: () -> Unit) {
|
||||
@@ -535,20 +552,17 @@ object WebInterfaceManager {
|
||||
version: String,
|
||||
state: UpdateState,
|
||||
progress: Int,
|
||||
immediate: Boolean = false,
|
||||
) {
|
||||
scope.launch {
|
||||
notifyFlow.emit(
|
||||
WebUIUpdateStatus(
|
||||
info =
|
||||
WebUIUpdateInfo(
|
||||
channel = serverConfig.webUIChannel.value,
|
||||
tag = version,
|
||||
updateAvailable = true,
|
||||
),
|
||||
state,
|
||||
progress,
|
||||
),
|
||||
)
|
||||
val status = getStatus(version, state, progress)
|
||||
|
||||
if (immediate) {
|
||||
statusFlow.emit(status)
|
||||
return@launch
|
||||
}
|
||||
|
||||
notifyFlow.emit(status)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -559,7 +573,7 @@ object WebInterfaceManager {
|
||||
}
|
||||
|
||||
suspend fun downloadVersion(version: String) {
|
||||
emitStatus(version, DOWNLOADING, 0)
|
||||
emitStatus(version, DOWNLOADING, 0, immediate = true)
|
||||
|
||||
try {
|
||||
val webUIZip = "${WebUIFlavor.WEBUI.baseFileName}-$version.zip"
|
||||
@@ -586,11 +600,11 @@ object WebInterfaceManager {
|
||||
extractDownload(webUIZipPath, applicationDirs.webUIRoot)
|
||||
log.info { "Extracting WebUI zip Done." }
|
||||
|
||||
emitStatus(version, FINISHED, 100)
|
||||
emitStatus(version, FINISHED, 100, immediate = true)
|
||||
|
||||
serveWebUI()
|
||||
} catch (e: Exception) {
|
||||
emitStatus(version, ERROR, 0)
|
||||
emitStatus(version, ERROR, 0, immediate = true)
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user