Feature/graphql web UI (#649)

* Add "server" to "checkForUpdate" logic names

* Use "webUIRoot" as default path for "getLocalVersion"

* Use local version as default version for "isUpdateAvailable"

* Return the version with the webUI update check

* Update WebinterfaceManager to be async

* Add query, mutation and subscription for webUI update

* Catch error and return default error value for missing local WebUI version
This commit is contained in:
schroda
2023-08-10 02:46:48 +02:00
committed by GitHub
parent 684bb1875c
commit 74ff112e7a
7 changed files with 308 additions and 61 deletions

View File

@@ -0,0 +1,62 @@
package suwayomi.tachidesk.graphql.mutations
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.withTimeout
import suwayomi.tachidesk.graphql.types.UpdateState.DOWNLOADING
import suwayomi.tachidesk.graphql.types.UpdateState.FINISHED
import suwayomi.tachidesk.graphql.types.UpdateState.STOPPED
import suwayomi.tachidesk.graphql.types.WebUIUpdateInfo
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
class InfoMutation {
data class WebUIUpdateInput(
val clientMutationId: String? = null
)
data class WebUIUpdatePayload(
val clientMutationId: String?,
val updateStatus: WebUIUpdateStatus
)
fun updateWebUI(input: WebUIUpdateInput): CompletableFuture<WebUIUpdatePayload> {
return future {
withTimeout(30.seconds) {
if (WebInterfaceManager.status.value.state === DOWNLOADING) {
return@withTimeout WebUIUpdatePayload(input.clientMutationId, WebInterfaceManager.status.value)
}
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable()
if (!updateAvailable) {
return@withTimeout WebUIUpdatePayload(
input.clientMutationId,
WebUIUpdateStatus(
info = WebUIUpdateInfo(
channel = serverConfig.webUIChannel,
tag = version,
updateAvailable
),
state = STOPPED,
progress = 0
)
)
}
try {
WebInterfaceManager.startDownloadInScope(version)
} catch (e: Exception) {
// ignore since we use the status anyway
}
WebUIUpdatePayload(
input.clientMutationId,
updateStatus = WebInterfaceManager.status.first { it.state == DOWNLOADING }
)
}
}
}
}

View File

@@ -1,8 +1,12 @@
package suwayomi.tachidesk.graphql.queries
import suwayomi.tachidesk.global.impl.AppUpdate
import suwayomi.tachidesk.graphql.types.WebUIUpdateInfo
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.BuildConfig
import suwayomi.tachidesk.server.JavalinSetup.future
import suwayomi.tachidesk.server.serverConfig
import suwayomi.tachidesk.server.util.WebInterfaceManager
import java.util.concurrent.CompletableFuture
class InfoQuery {
@@ -28,17 +32,17 @@ class InfoQuery {
)
}
data class CheckForUpdatesPayload(
data class CheckForServerUpdatesPayload(
/** [channel] mirrors [suwayomi.tachidesk.server.BuildConfig.BUILD_TYPE] */
val channel: String,
val tag: String,
val url: String
)
fun checkForUpdates(): CompletableFuture<List<CheckForUpdatesPayload>> {
fun checkForServerUpdates(): CompletableFuture<List<CheckForServerUpdatesPayload>> {
return future {
AppUpdate.checkUpdate().map {
CheckForUpdatesPayload(
CheckForServerUpdatesPayload(
channel = it.channel,
tag = it.tag,
url = it.url
@@ -46,4 +50,19 @@ class InfoQuery {
}
}
}
fun checkForWebUIUpdate(): CompletableFuture<WebUIUpdateInfo> {
return future {
val (version, updateAvailable) = WebInterfaceManager.isUpdateAvailable()
WebUIUpdateInfo(
channel = serverConfig.webUIChannel,
tag = version,
updateAvailable
)
}
}
fun getWebUIUpdateStatus(): WebUIUpdateStatus {
return WebInterfaceManager.status.value
}
}

View File

@@ -18,6 +18,7 @@ import suwayomi.tachidesk.graphql.mutations.CategoryMutation
import suwayomi.tachidesk.graphql.mutations.ChapterMutation
import suwayomi.tachidesk.graphql.mutations.DownloadMutation
import suwayomi.tachidesk.graphql.mutations.ExtensionMutation
import suwayomi.tachidesk.graphql.mutations.InfoMutation
import suwayomi.tachidesk.graphql.mutations.MangaMutation
import suwayomi.tachidesk.graphql.mutations.MetaMutation
import suwayomi.tachidesk.graphql.mutations.SourceMutation
@@ -37,6 +38,7 @@ import suwayomi.tachidesk.graphql.server.primitives.GraphQLCursor
import suwayomi.tachidesk.graphql.server.primitives.GraphQLLongAsString
import suwayomi.tachidesk.graphql.server.primitives.GraphQLUpload
import suwayomi.tachidesk.graphql.subscriptions.DownloadSubscription
import suwayomi.tachidesk.graphql.subscriptions.InfoSubscription
import suwayomi.tachidesk.graphql.subscriptions.UpdateSubscription
import kotlin.reflect.KClass
import kotlin.reflect.KType
@@ -74,6 +76,7 @@ val schema = toSchema(
TopLevelObject(ChapterMutation()),
TopLevelObject(DownloadMutation()),
TopLevelObject(ExtensionMutation()),
TopLevelObject(InfoMutation()),
TopLevelObject(MangaMutation()),
TopLevelObject(MetaMutation()),
TopLevelObject(SourceMutation()),
@@ -81,6 +84,7 @@ val schema = toSchema(
),
subscriptions = listOf(
TopLevelObject(DownloadSubscription()),
TopLevelObject(InfoSubscription()),
TopLevelObject(UpdateSubscription())
)
)

View File

@@ -0,0 +1,11 @@
package suwayomi.tachidesk.graphql.subscriptions
import kotlinx.coroutines.flow.Flow
import suwayomi.tachidesk.graphql.types.WebUIUpdateStatus
import suwayomi.tachidesk.server.util.WebInterfaceManager
class InfoSubscription {
fun webUIUpdateStatusChange(): Flow<WebUIUpdateStatus> {
return WebInterfaceManager.status
}
}

View File

@@ -0,0 +1,20 @@
package suwayomi.tachidesk.graphql.types
data class WebUIUpdateInfo(
val channel: String,
val tag: String,
val updateAvailable: Boolean
)
enum class UpdateState {
STOPPED,
DOWNLOADING,
FINISHED,
ERROR
}
data class WebUIUpdateStatus(
val info: WebUIUpdateInfo,
val state: UpdateState,
val progress: Int
)