Skip to content

Commit

Permalink
Feature/graphql web UI (#649)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
schroda authored Aug 10, 2023
1 parent 684bb18 commit 74ff112
Show file tree
Hide file tree
Showing 7 changed files with 305 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -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 }
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -28,22 +32,37 @@ 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
)
}
}
}

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
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -74,13 +76,15 @@ val schema = toSchema(
TopLevelObject(ChapterMutation()),
TopLevelObject(DownloadMutation()),
TopLevelObject(ExtensionMutation()),
TopLevelObject(InfoMutation()),
TopLevelObject(MangaMutation()),
TopLevelObject(MetaMutation()),
TopLevelObject(SourceMutation()),
TopLevelObject(UpdateMutation())
),
subscriptions = listOf(
TopLevelObject(DownloadSubscription()),
TopLevelObject(InfoSubscription()),
TopLevelObject(UpdateSubscription())
)
)
Original file line number Diff line number Diff line change
@@ -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
}
}
Original file line number Diff line number Diff line change
@@ -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
)
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.future.future
import kotlinx.coroutines.runBlocking
import mu.KotlinLogging
import org.kodein.di.DI
import org.kodein.di.conf.global
Expand Down Expand Up @@ -47,7 +48,9 @@ object JavalinSetup {
fun javalinSetup() {
val app = Javalin.create { config ->
if (serverConfig.webUIEnabled) {
WebInterfaceManager.setupWebUI()
runBlocking {
WebInterfaceManager.setupWebUI()
}

logger.info { "Serving web static files for ${serverConfig.webUIFlavor}" }
config.addStaticFiles(applicationDirs.webUIRoot, Location.EXTERNAL)
Expand Down
Loading

0 comments on commit 74ff112

Please sign in to comment.