Implement configuration of server settings during runtime

This commit is contained in:
Syer10
2024-03-30 16:22:50 -04:00
parent a04762842b
commit 52ea0f1c37
34 changed files with 1544 additions and 289 deletions

View File

@@ -1,46 +1,146 @@
fragment SettingsTypeFragment on SettingsType {
autoDownloadNewChapters
autoDownloadNewChaptersLimit
backupInterval
backupPath
backupTTL
backupTime
basicAuthEnabled
basicAuthPassword
basicAuthUsername
debugLogsEnabled
downloadAsCbz
downloadsPath
electronPath
excludeCompleted
excludeEntryWithUnreadChapters
excludeNotStarted
excludeUnreadChapters
extensionRepos
flareSolverrEnabled
flareSolverrSessionName
flareSolverrSessionTtl
flareSolverrTimeout
flareSolverrUrl
globalUpdateInterval
gqlDebugLogsEnabled
initialOpenInBrowserEnabled
ip
localSourcePath
maxSourcesInParallel
port
socksProxyEnabled
socksProxyHost
socksProxyPassword
socksProxyPort
socksProxyUsername
socksProxyVersion
systemTrayEnabled
updateMangas
webUIChannel
webUIFlavor
webUIInterface
webUIUpdateCheckInterval
}
query AllSettings {
settings {
autoDownloadNewChapters
autoDownloadNewChaptersLimit
backupInterval
backupPath
backupTTL
backupTime
basicAuthEnabled
basicAuthPassword
basicAuthUsername
debugLogsEnabled
downloadAsCbz
downloadsPath
electronPath
excludeCompleted
excludeEntryWithUnreadChapters
excludeNotStarted
excludeUnreadChapters
extensionRepos
flareSolverrEnabled
flareSolverrSessionName
flareSolverrSessionTtl
flareSolverrTimeout
flareSolverrUrl
globalUpdateInterval
gqlDebugLogsEnabled
initialOpenInBrowserEnabled
ip
localSourcePath
maxSourcesInParallel
port
socksProxyEnabled
socksProxyHost
socksProxyPassword
socksProxyPort
socksProxyUsername
socksProxyVersion
systemTrayEnabled
updateMangas
webUIChannel
webUIFlavor
webUIInterface
webUIUpdateCheckInterval
...SettingsTypeFragment
}
}
mutation SetSettings(
$autoDownloadNewChapters: Boolean = null,
$autoDownloadNewChaptersLimit: Int = null,
$backupInterval: Int = null,
$backupPath: String = null,
$backupTTL: Int = null,
$backupTime: String = null,
$basicAuthEnabled: Boolean = null,
$basicAuthPassword: String = null,
$basicAuthUsername: String = null,
$debugLogsEnabled: Boolean = null,
$downloadAsCbz: Boolean = null,
$downloadsPath: String = null,
$electronPath: String = null,
$excludeCompleted: Boolean = null,
$excludeEntryWithUnreadChapters: Boolean = null,
$excludeNotStarted: Boolean = null,
$excludeUnreadChapters: Boolean = null,
$extensionRepos: [String!] = null,
$flareSolverrEnabled: Boolean = null,
$flareSolverrSessionName: String = null,
$flareSolverrSessionTtl: Int = null,
$flareSolverrTimeout: Int = null,
$flareSolverrUrl: String = null,
$globalUpdateInterval: Float = null,
$gqlDebugLogsEnabled: Boolean = null,
$initialOpenInBrowserEnabled: Boolean = null,
$ip: String = null,
$localSourcePath: String = null,
$maxSourcesInParallel: Int = null,
$port: Int = null,
$socksProxyEnabled: Boolean = null,
$socksProxyHost: String = null,
$socksProxyPassword: String = null,
$socksProxyPort: String = null,
$socksProxyUsername: String = null,
$socksProxyVersion: Int = null,
$systemTrayEnabled: Boolean = null,
$updateMangas: Boolean = null,
$webUIChannel: WebUIChannel = null,
$webUIFlavor: WebUIFlavor = null,
$webUIInterface: WebUIInterface = null,
$webUIUpdateCheckInterval: Float = null
) {
setSettings(
input: {
settings: {
autoDownloadNewChapters: $autoDownloadNewChapters,
autoDownloadNewChaptersLimit: $autoDownloadNewChaptersLimit,
backupInterval: $backupInterval,
backupPath: $backupPath,
backupTTL: $backupTTL,
backupTime: $backupTime,
basicAuthEnabled: $basicAuthEnabled,
basicAuthPassword: $basicAuthPassword,
basicAuthUsername: $basicAuthUsername,
debugLogsEnabled: $debugLogsEnabled,
downloadAsCbz: $downloadAsCbz,
downloadsPath: $downloadsPath,
electronPath: $electronPath,
excludeCompleted: $excludeCompleted,
excludeEntryWithUnreadChapters: $excludeEntryWithUnreadChapters,
excludeNotStarted: $excludeNotStarted,
excludeUnreadChapters: $excludeUnreadChapters,
extensionRepos: $extensionRepos,
flareSolverrEnabled: $flareSolverrEnabled,
flareSolverrSessionName: $flareSolverrSessionName,
flareSolverrSessionTtl: $flareSolverrSessionTtl,
flareSolverrTimeout: $flareSolverrTimeout,
flareSolverrUrl: $flareSolverrUrl,
globalUpdateInterval: $globalUpdateInterval,
gqlDebugLogsEnabled: $gqlDebugLogsEnabled,
initialOpenInBrowserEnabled: $initialOpenInBrowserEnabled,
ip: $ip,
localSourcePath: $localSourcePath,
maxSourcesInParallel: $maxSourcesInParallel,
port: $port,
socksProxyEnabled: $socksProxyEnabled,
socksProxyHost: $socksProxyHost,
socksProxyPassword: $socksProxyPassword,
socksProxyPort: $socksProxyPort,
socksProxyUsername: $socksProxyUsername,
socksProxyVersion: $socksProxyVersion,
systemTrayEnabled: $systemTrayEnabled,
updateMangas: $updateMangas,
webUIChannel: $webUIChannel,
webUIFlavor: $webUIFlavor,
webUIInterface: $webUIInterface,
webUIUpdateCheckInterval: $webUIUpdateCheckInterval
}
}
) {
clientMutationId
}
}

View File

@@ -7,6 +7,7 @@
package ca.gosyer.jui.data
import ca.gosyer.jui.core.lang.addSuffix
import ca.gosyer.jui.data.settings.SettingsRepositoryImpl
import ca.gosyer.jui.domain.backup.service.BackupRepository
import ca.gosyer.jui.domain.category.service.CategoryRepository
import ca.gosyer.jui.domain.chapter.service.ChapterRepository
@@ -18,6 +19,7 @@ import ca.gosyer.jui.domain.manga.service.MangaRepository
import ca.gosyer.jui.domain.server.Http
import ca.gosyer.jui.domain.server.service.ServerPreferences
import ca.gosyer.jui.domain.settings.service.SettingsRepository
import ca.gosyer.jui.domain.settings.service.SettingsRepositoryOld
import ca.gosyer.jui.domain.source.service.SourceRepository
import ca.gosyer.jui.domain.updates.service.UpdatesRepository
import com.apollographql.apollo3.ApolloClient
@@ -79,11 +81,15 @@ interface DataComponent {
fun mangaRepository(ktorfit: Ktorfit) = ktorfit.create<MangaRepository>()
@Provides
fun settingsRepository(ktorfit: Ktorfit) = ktorfit.create<SettingsRepository>()
fun settingsRepositoryOld(ktorfit: Ktorfit) = ktorfit.create<SettingsRepositoryOld>()
@Provides
fun sourceRepository(ktorfit: Ktorfit) = ktorfit.create<SourceRepository>()
@Provides
fun updatesRepository(ktorfit: Ktorfit) = ktorfit.create<UpdatesRepository>()
@Provides
fun settingsRepository(apolloClient: ApolloClient): SettingsRepository =
SettingsRepositoryImpl(apolloClient)
}

View File

@@ -0,0 +1,179 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.data.settings
import ca.gosyer.jui.data.graphql.AllSettingsQuery
import ca.gosyer.jui.data.graphql.SetSettingsMutation
import ca.gosyer.jui.data.graphql.fragment.SettingsTypeFragment
import ca.gosyer.jui.data.graphql.type.WebUIChannel
import ca.gosyer.jui.data.graphql.type.WebUIFlavor
import ca.gosyer.jui.data.graphql.type.WebUIInterface
import ca.gosyer.jui.data.util.toOptional
import ca.gosyer.jui.domain.settings.model.SetSettingsInput
import ca.gosyer.jui.domain.settings.model.Settings
import ca.gosyer.jui.domain.settings.service.SettingsRepository
import com.apollographql.apollo3.ApolloClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import ca.gosyer.jui.domain.settings.model.WebUIChannel as DomainWebUIChannel
import ca.gosyer.jui.domain.settings.model.WebUIFlavor as DomainWebUIFlavor
import ca.gosyer.jui.domain.settings.model.WebUIInterface as DomainWebUIInterface
class SettingsRepositoryImpl(private val apolloClient: ApolloClient) : SettingsRepository {
private fun SettingsTypeFragment.toSettings() = Settings(
autoDownloadNewChapters = autoDownloadNewChapters,
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit,
backupInterval = backupInterval,
backupPath = backupPath,
backupTTL = backupTTL,
backupTime = backupTime,
basicAuthEnabled = basicAuthEnabled,
basicAuthPassword = basicAuthPassword,
basicAuthUsername = basicAuthUsername,
debugLogsEnabled = debugLogsEnabled,
downloadAsCbz = downloadAsCbz,
downloadsPath = downloadsPath,
electronPath = electronPath,
excludeCompleted = excludeCompleted,
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters,
excludeNotStarted = excludeNotStarted,
excludeUnreadChapters = excludeUnreadChapters,
extensionRepos = extensionRepos,
flareSolverrEnabled = flareSolverrEnabled,
flareSolverrSessionName = flareSolverrSessionName,
flareSolverrSessionTtl = flareSolverrSessionTtl,
flareSolverrTimeout = flareSolverrTimeout,
flareSolverrUrl = flareSolverrUrl,
globalUpdateInterval = globalUpdateInterval,
gqlDebugLogsEnabled = gqlDebugLogsEnabled,
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled,
ip = ip,
localSourcePath = localSourcePath,
maxSourcesInParallel = maxSourcesInParallel,
port = port,
socksProxyEnabled = socksProxyEnabled,
socksProxyHost = socksProxyHost,
socksProxyPassword = socksProxyPassword,
socksProxyPort = socksProxyPort,
socksProxyUsername = socksProxyUsername,
socksProxyVersion = socksProxyVersion,
systemTrayEnabled = systemTrayEnabled,
updateMangas = updateMangas,
webUIChannel = webUIChannel.toDomain(),
webUIFlavor = webUIFlavor.toDomain(),
webUIInterface = webUIInterface.toDomain(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval
)
private fun WebUIChannel.toDomain() = when (this) {
WebUIChannel.BUNDLED -> DomainWebUIChannel.BUNDLED
WebUIChannel.STABLE -> DomainWebUIChannel.STABLE
WebUIChannel.PREVIEW -> DomainWebUIChannel.PREVIEW
WebUIChannel.UNKNOWN__ -> DomainWebUIChannel.UNKNOWN__
}
private fun WebUIFlavor.toDomain() = when (this) {
WebUIFlavor.WEBUI -> DomainWebUIFlavor.WEBUI
WebUIFlavor.VUI -> DomainWebUIFlavor.VUI
WebUIFlavor.CUSTOM -> DomainWebUIFlavor.CUSTOM
WebUIFlavor.UNKNOWN__ -> DomainWebUIFlavor.UNKNOWN__
}
private fun WebUIInterface.toDomain() = when (this) {
WebUIInterface.BROWSER -> DomainWebUIInterface.BROWSER
WebUIInterface.ELECTRON -> DomainWebUIInterface.ELECTRON
WebUIInterface.UNKNOWN__ -> DomainWebUIInterface.UNKNOWN__
}
private fun DomainWebUIChannel.toGraphQL() = when (this) {
DomainWebUIChannel.BUNDLED -> WebUIChannel.BUNDLED
DomainWebUIChannel.STABLE -> WebUIChannel.STABLE
DomainWebUIChannel.PREVIEW -> WebUIChannel.PREVIEW
DomainWebUIChannel.UNKNOWN__ -> WebUIChannel.UNKNOWN__
}
private fun DomainWebUIFlavor.toGraphQL() = when (this) {
DomainWebUIFlavor.WEBUI -> WebUIFlavor.WEBUI
DomainWebUIFlavor.VUI -> WebUIFlavor.VUI
DomainWebUIFlavor.CUSTOM -> WebUIFlavor.CUSTOM
DomainWebUIFlavor.UNKNOWN__ -> WebUIFlavor.UNKNOWN__
}
private fun DomainWebUIInterface.toGraphQL() = when (this) {
DomainWebUIInterface.BROWSER -> WebUIInterface.BROWSER
DomainWebUIInterface.ELECTRON -> WebUIInterface.ELECTRON
DomainWebUIInterface.UNKNOWN__ -> WebUIInterface.UNKNOWN__
}
override fun getSettings(): Flow<Settings> {
return apolloClient.query(AllSettingsQuery()).toFlow()
.map {
it.dataOrThrow().settings.settingsTypeFragment.toSettings()
}
.flowOn(Dispatchers.IO)
}
private fun SetSettingsInput.toMutation() = SetSettingsMutation(
autoDownloadNewChapters = autoDownloadNewChapters.toOptional(),
autoDownloadNewChaptersLimit = autoDownloadNewChaptersLimit.toOptional(),
backupInterval = backupInterval.toOptional(),
backupPath = backupPath.toOptional(),
backupTTL = backupTTL.toOptional(),
backupTime = backupTime.toOptional(),
basicAuthEnabled = basicAuthEnabled.toOptional(),
basicAuthPassword = basicAuthPassword.toOptional(),
basicAuthUsername = basicAuthUsername.toOptional(),
debugLogsEnabled = debugLogsEnabled.toOptional(),
downloadAsCbz = downloadAsCbz.toOptional(),
downloadsPath = downloadsPath.toOptional(),
electronPath = electronPath.toOptional(),
excludeCompleted = excludeCompleted.toOptional(),
excludeEntryWithUnreadChapters = excludeEntryWithUnreadChapters.toOptional(),
excludeNotStarted = excludeNotStarted.toOptional(),
excludeUnreadChapters = excludeUnreadChapters.toOptional(),
extensionRepos = extensionRepos.toOptional(),
flareSolverrEnabled = flareSolverrEnabled.toOptional(),
flareSolverrSessionName = flareSolverrSessionName.toOptional(),
flareSolverrSessionTtl = flareSolverrSessionTtl.toOptional(),
flareSolverrTimeout = flareSolverrTimeout.toOptional(),
flareSolverrUrl = flareSolverrUrl.toOptional(),
globalUpdateInterval = globalUpdateInterval.toOptional(),
gqlDebugLogsEnabled = gqlDebugLogsEnabled.toOptional(),
initialOpenInBrowserEnabled = initialOpenInBrowserEnabled.toOptional(),
ip = ip.toOptional(),
localSourcePath = localSourcePath.toOptional(),
maxSourcesInParallel = maxSourcesInParallel.toOptional(),
port = port.toOptional(),
socksProxyEnabled = socksProxyEnabled.toOptional(),
socksProxyHost = socksProxyHost.toOptional(),
socksProxyPassword = socksProxyPassword.toOptional(),
socksProxyPort = socksProxyPort.toOptional(),
socksProxyUsername = socksProxyUsername.toOptional(),
socksProxyVersion = socksProxyVersion.toOptional(),
systemTrayEnabled = systemTrayEnabled.toOptional(),
updateMangas = updateMangas.toOptional(),
webUIChannel = webUIChannel?.toGraphQL().toOptional(),
webUIFlavor = webUIFlavor?.toGraphQL().toOptional(),
webUIInterface = webUIInterface?.toGraphQL().toOptional(),
webUIUpdateCheckInterval = webUIUpdateCheckInterval.toOptional(),
)
override fun setSettings(input: SetSettingsInput): Flow<Unit> {
return apolloClient.mutation(input.toMutation())
.toFlow()
.map {
it.dataOrThrow()
Unit
}
.flowOn(Dispatchers.IO)
}
}

View File

@@ -0,0 +1,11 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
package ca.gosyer.jui.data.util
import com.apollographql.apollo3.api.Optional
internal fun <T> T?.toOptional() = Optional.presentIfNotNull(this)