mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-16 23:12:12 +00:00
Revert "feat: implement manifest caching for addons"
This reverts commit 018e1e50a8.
This commit is contained in:
parent
db7baf11e3
commit
21793b8ac7
5 changed files with 76 additions and 201 deletions
|
|
@ -19,7 +19,6 @@ import java.util.concurrent.TimeUnit
|
||||||
actual object AddonStorage {
|
actual object AddonStorage {
|
||||||
private const val preferencesName = "nuvio_addons"
|
private const val preferencesName = "nuvio_addons"
|
||||||
private const val addonUrlsKey = "installed_manifest_urls"
|
private const val addonUrlsKey = "installed_manifest_urls"
|
||||||
private const val manifestCacheKey = "manifest_cache_payload"
|
|
||||||
|
|
||||||
private var preferences: SharedPreferences? = null
|
private var preferences: SharedPreferences? = null
|
||||||
|
|
||||||
|
|
@ -42,19 +41,7 @@ actual object AddonStorage {
|
||||||
?.putString("${addonUrlsKey}_$profileId", urls.joinToString(separator = "\n"))
|
?.putString("${addonUrlsKey}_$profileId", urls.joinToString(separator = "\n"))
|
||||||
?.apply()
|
?.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun loadManifestCachePayload(profileId: Int): String? =
|
|
||||||
preferences?.getString("${manifestCacheKey}_$profileId", null)
|
|
||||||
|
|
||||||
actual fun saveManifestCachePayload(profileId: Int, payload: String) {
|
|
||||||
preferences
|
|
||||||
?.edit()
|
|
||||||
?.putString("${manifestCacheKey}_$profileId", payload)
|
|
||||||
?.apply()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal actual fun addonEpochMs(): Long = System.currentTimeMillis()
|
|
||||||
|
|
||||||
private val addonHttpClient = OkHttpClient.Builder()
|
private val addonHttpClient = OkHttpClient.Builder()
|
||||||
.dns(IPv4FirstDns())
|
.dns(IPv4FirstDns())
|
||||||
|
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
package com.nuvio.app.features.addons
|
|
||||||
|
|
||||||
import kotlinx.serialization.Serializable
|
|
||||||
import kotlinx.serialization.json.Json
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class AddonManifestCachePayload(
|
|
||||||
val entries: List<AddonManifestCacheEntry> = emptyList(),
|
|
||||||
)
|
|
||||||
|
|
||||||
@Serializable
|
|
||||||
internal data class AddonManifestCacheEntry(
|
|
||||||
val manifestUrl: String,
|
|
||||||
val payload: String,
|
|
||||||
val fetchedAtEpochMs: Long,
|
|
||||||
)
|
|
||||||
|
|
||||||
internal object AddonManifestCacheCodec {
|
|
||||||
private val json = Json { ignoreUnknownKeys = true; encodeDefaults = true }
|
|
||||||
|
|
||||||
fun decode(payload: String): List<AddonManifestCacheEntry>? =
|
|
||||||
runCatching {
|
|
||||||
json.decodeFromString(AddonManifestCachePayload.serializer(), payload).entries
|
|
||||||
}.getOrNull()
|
|
||||||
|
|
||||||
fun encode(entries: Collection<AddonManifestCacheEntry>): String =
|
|
||||||
json.encodeToString(
|
|
||||||
AddonManifestCachePayload.serializer(),
|
|
||||||
AddonManifestCachePayload(entries = entries.toList()),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
@ -3,12 +3,8 @@ package com.nuvio.app.features.addons
|
||||||
internal expect object AddonStorage {
|
internal expect object AddonStorage {
|
||||||
fun loadInstalledAddonUrls(profileId: Int): List<String>
|
fun loadInstalledAddonUrls(profileId: Int): List<String>
|
||||||
fun saveInstalledAddonUrls(profileId: Int, urls: List<String>)
|
fun saveInstalledAddonUrls(profileId: Int, urls: List<String>)
|
||||||
fun loadManifestCachePayload(profileId: Int): String?
|
|
||||||
fun saveManifestCachePayload(profileId: Int, payload: String)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal expect fun addonEpochMs(): Long
|
|
||||||
|
|
||||||
data class RawHttpResponse(
|
data class RawHttpResponse(
|
||||||
val status: Int,
|
val status: Int,
|
||||||
val statusText: String,
|
val statusText: String,
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,6 @@ object AddonRepository {
|
||||||
private var pulledFromServer = false
|
private var pulledFromServer = false
|
||||||
private var currentProfileId: Int = 1
|
private var currentProfileId: Int = 1
|
||||||
private val activeRefreshJobs = mutableMapOf<String, Job>()
|
private val activeRefreshJobs = mutableMapOf<String, Job>()
|
||||||
private var manifestCacheByUrl: Map<String, AddonManifestCacheEntry> = emptyMap()
|
|
||||||
|
|
||||||
fun initialize() {
|
fun initialize() {
|
||||||
val effectiveProfileId = resolveEffectiveProfileId(ProfileRepository.activeProfileId)
|
val effectiveProfileId = resolveEffectiveProfileId(ProfileRepository.activeProfileId)
|
||||||
|
|
@ -62,12 +61,21 @@ object AddonRepository {
|
||||||
|
|
||||||
val storedUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
val storedUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
||||||
log.d { "initialize() — local addon count: ${storedUrls.size}" }
|
log.d { "initialize() — local addon count: ${storedUrls.size}" }
|
||||||
if (storedUrls.isEmpty()) {
|
if (storedUrls.isEmpty()) return
|
||||||
manifestCacheByUrl = emptyMap()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
applyAddonsFromUrls(storedUrls)
|
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||||
|
_uiState.value = AddonsUiState(
|
||||||
|
addons = storedUrls.map { manifestUrl ->
|
||||||
|
existingByUrl[manifestUrl].toPendingAddon(manifestUrl)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
storedUrls.forEach { manifestUrl ->
|
||||||
|
val existing = existingByUrl[manifestUrl]
|
||||||
|
if (existing == null || (existing.manifest == null && !existing.isRefreshing)) {
|
||||||
|
refreshAddon(manifestUrl)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onProfileChanged(profileId: Int) {
|
fun onProfileChanged(profileId: Int) {
|
||||||
|
|
@ -77,15 +85,11 @@ object AddonRepository {
|
||||||
currentProfileId = effectiveProfileId
|
currentProfileId = effectiveProfileId
|
||||||
initialized = false
|
initialized = false
|
||||||
pulledFromServer = false
|
pulledFromServer = false
|
||||||
manifestCacheByUrl = emptyMap()
|
|
||||||
_uiState.value = AddonsUiState()
|
_uiState.value = AddonsUiState()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun clearLocalState() {
|
fun clearLocalState() {
|
||||||
val profileToClear = currentProfileId
|
|
||||||
cancelActiveRefreshes()
|
cancelActiveRefreshes()
|
||||||
manifestCacheByUrl = emptyMap()
|
|
||||||
AddonStorage.saveManifestCachePayload(profileToClear, AddonManifestCacheCodec.encode(emptyList()))
|
|
||||||
currentProfileId = 1
|
currentProfileId = 1
|
||||||
initialized = false
|
initialized = false
|
||||||
pulledFromServer = false
|
pulledFromServer = false
|
||||||
|
|
@ -145,16 +149,38 @@ object AddonRepository {
|
||||||
val localUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
val localUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
||||||
if (localUrls.isNotEmpty()) {
|
if (localUrls.isNotEmpty()) {
|
||||||
log.w { "pullFromServer() — remote empty while local has ${localUrls.size} addons; preserving local addons" }
|
log.w { "pullFromServer() — remote empty while local has ${localUrls.size} addons; preserving local addons" }
|
||||||
applyAddonsFromUrls(localUrls)
|
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||||
|
_uiState.value = AddonsUiState(
|
||||||
|
addons = localUrls.map { url ->
|
||||||
|
existingByUrl[url].toPendingAddon(url)
|
||||||
|
},
|
||||||
|
)
|
||||||
persist()
|
persist()
|
||||||
|
localUrls.forEach { url ->
|
||||||
|
val existing = existingByUrl[url]
|
||||||
|
if (existing == null || (existing.manifest == null && !existing.isRefreshing)) {
|
||||||
|
refreshAddon(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
pulledFromServer = true
|
pulledFromServer = true
|
||||||
initialized = true
|
initialized = true
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
applyAddonsFromUrls(urls, namesByUrl)
|
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||||
|
_uiState.value = AddonsUiState(
|
||||||
|
addons = urls.map { url ->
|
||||||
|
existingByUrl[url].toPendingAddon(url, namesByUrl[url])
|
||||||
|
},
|
||||||
|
)
|
||||||
persist()
|
persist()
|
||||||
|
urls.forEach { url ->
|
||||||
|
val existing = existingByUrl[url]
|
||||||
|
if (existing == null || (existing.manifest == null && !existing.isRefreshing)) {
|
||||||
|
refreshAddon(url)
|
||||||
|
}
|
||||||
|
}
|
||||||
pulledFromServer = true
|
pulledFromServer = true
|
||||||
initialized = true
|
initialized = true
|
||||||
log.i { "pullFromServer() — applied ${urls.size} addons to state" }
|
log.i { "pullFromServer() — applied ${urls.size} addons to state" }
|
||||||
|
|
@ -185,19 +211,17 @@ object AddonRepository {
|
||||||
return AddAddonResult.Error("That addon is already installed.")
|
return AddAddonResult.Error("That addon is already installed.")
|
||||||
}
|
}
|
||||||
|
|
||||||
val fetched = try {
|
val manifest = try {
|
||||||
withContext(Dispatchers.Default) {
|
withContext(Dispatchers.Default) {
|
||||||
val payload = httpGetText(manifestUrl)
|
val payload = httpGetText(manifestUrl)
|
||||||
val manifest = AddonManifestParser.parse(
|
AddonManifestParser.parse(
|
||||||
manifestUrl = manifestUrl,
|
manifestUrl = manifestUrl,
|
||||||
payload = payload,
|
payload = payload,
|
||||||
)
|
)
|
||||||
payload to manifest
|
|
||||||
}
|
}
|
||||||
} catch (error: Throwable) {
|
} catch (error: Throwable) {
|
||||||
return AddAddonResult.Error(error.message ?: "Unable to load manifest")
|
return AddAddonResult.Error(error.message ?: "Unable to load manifest")
|
||||||
}
|
}
|
||||||
val (payload, manifest) = fetched
|
|
||||||
|
|
||||||
_uiState.update { current ->
|
_uiState.update { current ->
|
||||||
current.copy(
|
current.copy(
|
||||||
|
|
@ -209,7 +233,6 @@ object AddonRepository {
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
updateManifestCache(manifestUrl, payload)
|
|
||||||
persist()
|
persist()
|
||||||
pushToServer()
|
pushToServer()
|
||||||
return AddAddonResult.Success(manifest)
|
return AddAddonResult.Success(manifest)
|
||||||
|
|
@ -218,16 +241,11 @@ object AddonRepository {
|
||||||
fun removeAddon(manifestUrl: String) {
|
fun removeAddon(manifestUrl: String) {
|
||||||
if (isUsingPrimaryAddonsFromSecondaryProfile()) return
|
if (isUsingPrimaryAddonsFromSecondaryProfile()) return
|
||||||
log.i { "removeAddon() — $manifestUrl" }
|
log.i { "removeAddon() — $manifestUrl" }
|
||||||
val normalizedUrl = ensureManifestSuffix(manifestUrl)
|
|
||||||
_uiState.update { current ->
|
_uiState.update { current ->
|
||||||
current.copy(
|
current.copy(
|
||||||
addons = current.addons.filterNot { it.manifestUrl == normalizedUrl },
|
addons = current.addons.filterNot { it.manifestUrl == manifestUrl },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (manifestCacheByUrl.containsKey(normalizedUrl)) {
|
|
||||||
manifestCacheByUrl = manifestCacheByUrl - normalizedUrl
|
|
||||||
persistManifestCache()
|
|
||||||
}
|
|
||||||
persist()
|
persist()
|
||||||
pushToServer()
|
pushToServer()
|
||||||
}
|
}
|
||||||
|
|
@ -239,34 +257,29 @@ object AddonRepository {
|
||||||
}
|
}
|
||||||
|
|
||||||
fun refreshAddon(manifestUrl: String) {
|
fun refreshAddon(manifestUrl: String) {
|
||||||
val normalizedUrl = ensureManifestSuffix(manifestUrl)
|
val existingJob = activeRefreshJobs[manifestUrl]
|
||||||
val existingJob = activeRefreshJobs[normalizedUrl]
|
|
||||||
if (existingJob?.isActive == true) return
|
if (existingJob?.isActive == true) return
|
||||||
|
|
||||||
markRefreshing(normalizedUrl)
|
markRefreshing(manifestUrl)
|
||||||
var refreshJob: Job? = null
|
var refreshJob: Job? = null
|
||||||
refreshJob = scope.launch {
|
refreshJob = scope.launch {
|
||||||
try {
|
try {
|
||||||
val result = runCatching {
|
val result = runCatching {
|
||||||
val payload = httpGetText(normalizedUrl)
|
val payload = httpGetText(manifestUrl)
|
||||||
val manifest = AddonManifestParser.parse(
|
AddonManifestParser.parse(
|
||||||
manifestUrl = normalizedUrl,
|
manifestUrl = manifestUrl,
|
||||||
payload = payload,
|
payload = payload,
|
||||||
)
|
)
|
||||||
payload to manifest
|
|
||||||
}
|
|
||||||
result.onSuccess { (payload, _) ->
|
|
||||||
updateManifestCache(normalizedUrl, payload)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_uiState.update { current ->
|
_uiState.update { current ->
|
||||||
current.copy(
|
current.copy(
|
||||||
addons = current.addons.map { addon ->
|
addons = current.addons.map { addon ->
|
||||||
if (addon.manifestUrl != normalizedUrl) {
|
if (addon.manifestUrl != manifestUrl) {
|
||||||
addon
|
addon
|
||||||
} else {
|
} else {
|
||||||
result.fold(
|
result.fold(
|
||||||
onSuccess = { (_, manifest) ->
|
onSuccess = { manifest ->
|
||||||
addon.copy(
|
addon.copy(
|
||||||
manifest = manifest,
|
manifest = manifest,
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
|
|
@ -276,7 +289,7 @@ object AddonRepository {
|
||||||
onFailure = { error ->
|
onFailure = { error ->
|
||||||
addon.copy(
|
addon.copy(
|
||||||
isRefreshing = false,
|
isRefreshing = false,
|
||||||
errorMessage = error.message ?: addon.errorMessage ?: "Unable to load manifest",
|
errorMessage = error.message ?: "Unable to load manifest",
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -285,111 +298,12 @@ object AddonRepository {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
if (activeRefreshJobs[normalizedUrl] === refreshJob) {
|
if (activeRefreshJobs[manifestUrl] === refreshJob) {
|
||||||
activeRefreshJobs.remove(normalizedUrl)
|
activeRefreshJobs.remove(manifestUrl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
activeRefreshJobs[normalizedUrl] = refreshJob
|
activeRefreshJobs[manifestUrl] = refreshJob
|
||||||
}
|
|
||||||
|
|
||||||
private fun applyAddonsFromUrls(
|
|
||||||
urls: List<String>,
|
|
||||||
namesByUrl: Map<String, String> = emptyMap(),
|
|
||||||
) {
|
|
||||||
val normalizedUrls = dedupeManifestUrls(urls)
|
|
||||||
val normalizedUrlSet = normalizedUrls.toSet()
|
|
||||||
val now = addonEpochMs()
|
|
||||||
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
|
||||||
val loadedCache = loadManifestCacheByUrl()
|
|
||||||
val nextCache = loadedCache.filterKeys { key -> key in normalizedUrlSet }.toMutableMap()
|
|
||||||
|
|
||||||
val addons = normalizedUrls.map { manifestUrl ->
|
|
||||||
val existing = existingByUrl[manifestUrl]
|
|
||||||
val cachedEntry = nextCache[manifestUrl]
|
|
||||||
val cachedManifest = cachedEntry
|
|
||||||
?.takeIf { it.payload.isNotBlank() }
|
|
||||||
?.let { entry ->
|
|
||||||
runCatching {
|
|
||||||
AddonManifestParser.parse(
|
|
||||||
manifestUrl = manifestUrl,
|
|
||||||
payload = entry.payload,
|
|
||||||
)
|
|
||||||
}.getOrNull()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cachedEntry != null && cachedManifest == null) {
|
|
||||||
nextCache.remove(manifestUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
val manifest = existing?.manifest ?: cachedManifest
|
|
||||||
val shouldRefresh = when {
|
|
||||||
manifest == null -> true
|
|
||||||
existing?.manifest != null && !existing.isRefreshing -> false
|
|
||||||
cachedEntry == null -> true
|
|
||||||
cachedEntry.fetchedAtEpochMs <= 0L -> true
|
|
||||||
now - cachedEntry.fetchedAtEpochMs >= MANIFEST_CACHE_TTL_MS -> true
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
|
|
||||||
ManagedAddon(
|
|
||||||
manifestUrl = manifestUrl,
|
|
||||||
manifest = manifest,
|
|
||||||
userSetName = namesByUrl[manifestUrl] ?: existing?.userSetName,
|
|
||||||
isRefreshing = shouldRefresh,
|
|
||||||
errorMessage = if (manifest != null) null else existing?.errorMessage,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
manifestCacheByUrl = nextCache.toMap()
|
|
||||||
persistManifestCache()
|
|
||||||
|
|
||||||
_uiState.value = AddonsUiState(addons = addons)
|
|
||||||
addons.filter { it.isRefreshing }.forEach { addon ->
|
|
||||||
refreshAddon(addon.manifestUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun loadManifestCacheByUrl(): Map<String, AddonManifestCacheEntry> {
|
|
||||||
val payload = AddonStorage.loadManifestCachePayload(currentProfileId).orEmpty()
|
|
||||||
if (payload.isBlank()) {
|
|
||||||
manifestCacheByUrl = emptyMap()
|
|
||||||
return manifestCacheByUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
val decoded = AddonManifestCacheCodec.decode(payload)
|
|
||||||
?.mapNotNull { entry ->
|
|
||||||
val normalizedUrl = ensureManifestSuffix(entry.manifestUrl)
|
|
||||||
if (entry.payload.isBlank()) {
|
|
||||||
null
|
|
||||||
} else {
|
|
||||||
entry.copy(manifestUrl = normalizedUrl)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
?.associateBy(AddonManifestCacheEntry::manifestUrl)
|
|
||||||
.orEmpty()
|
|
||||||
manifestCacheByUrl = decoded
|
|
||||||
return decoded
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun updateManifestCache(manifestUrl: String, payload: String) {
|
|
||||||
if (payload.isBlank()) return
|
|
||||||
val normalizedUrl = ensureManifestSuffix(manifestUrl)
|
|
||||||
manifestCacheByUrl = manifestCacheByUrl + (
|
|
||||||
normalizedUrl to AddonManifestCacheEntry(
|
|
||||||
manifestUrl = normalizedUrl,
|
|
||||||
payload = payload,
|
|
||||||
fetchedAtEpochMs = addonEpochMs(),
|
|
||||||
)
|
|
||||||
)
|
|
||||||
persistManifestCache()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun persistManifestCache() {
|
|
||||||
AddonStorage.saveManifestCachePayload(
|
|
||||||
profileId = currentProfileId,
|
|
||||||
payload = AddonManifestCacheCodec.encode(manifestCacheByUrl.values),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun pushToServer() {
|
private fun pushToServer() {
|
||||||
|
|
@ -462,6 +376,30 @@ object AddonRepository {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ManagedAddon?.toPendingAddon(manifestUrl: String, userSetName: String? = null): ManagedAddon =
|
||||||
|
when {
|
||||||
|
this == null -> ManagedAddon(
|
||||||
|
manifestUrl = manifestUrl,
|
||||||
|
isRefreshing = true,
|
||||||
|
userSetName = userSetName,
|
||||||
|
)
|
||||||
|
manifest != null -> copy(
|
||||||
|
manifestUrl = manifestUrl,
|
||||||
|
isRefreshing = false,
|
||||||
|
userSetName = userSetName ?: this.userSetName,
|
||||||
|
)
|
||||||
|
isRefreshing -> copy(
|
||||||
|
manifestUrl = manifestUrl,
|
||||||
|
userSetName = userSetName ?: this.userSetName,
|
||||||
|
)
|
||||||
|
else -> copy(
|
||||||
|
manifestUrl = manifestUrl,
|
||||||
|
isRefreshing = true,
|
||||||
|
errorMessage = null,
|
||||||
|
userSetName = userSetName ?: this.userSetName,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun dedupeManifestUrls(urls: List<String>): List<String> =
|
private fun dedupeManifestUrls(urls: List<String>): List<String> =
|
||||||
urls.map(::ensureManifestSuffix).distinct()
|
urls.map(::ensureManifestSuffix).distinct()
|
||||||
|
|
||||||
|
|
@ -493,5 +431,3 @@ private fun normalizeManifestUrl(rawUrl: String): String {
|
||||||
|
|
||||||
return if (query.isEmpty()) manifestPath else "$manifestPath?$query"
|
return if (query.isEmpty()) manifestPath else "$manifestPath?$query"
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val MANIFEST_CACHE_TTL_MS = 12L * 60L * 60L * 1000L
|
|
||||||
|
|
|
||||||
|
|
@ -15,13 +15,10 @@ import io.ktor.http.ContentType
|
||||||
import io.ktor.http.HttpHeaders
|
import io.ktor.http.HttpHeaders
|
||||||
import io.ktor.http.HttpMethod
|
import io.ktor.http.HttpMethod
|
||||||
import io.ktor.http.isSuccess
|
import io.ktor.http.isSuccess
|
||||||
import platform.Foundation.NSDate
|
|
||||||
import platform.Foundation.NSUserDefaults
|
import platform.Foundation.NSUserDefaults
|
||||||
import platform.Foundation.timeIntervalSince1970
|
|
||||||
|
|
||||||
actual object AddonStorage {
|
actual object AddonStorage {
|
||||||
private const val addonUrlsKey = "installed_manifest_urls"
|
private const val addonUrlsKey = "installed_manifest_urls"
|
||||||
private const val manifestCacheKey = "manifest_cache_payload"
|
|
||||||
|
|
||||||
actual fun loadInstalledAddonUrls(profileId: Int): List<String> =
|
actual fun loadInstalledAddonUrls(profileId: Int): List<String> =
|
||||||
NSUserDefaults.standardUserDefaults
|
NSUserDefaults.standardUserDefaults
|
||||||
|
|
@ -38,17 +35,7 @@ actual object AddonStorage {
|
||||||
forKey = "${addonUrlsKey}_$profileId",
|
forKey = "${addonUrlsKey}_$profileId",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual fun loadManifestCachePayload(profileId: Int): String? =
|
|
||||||
NSUserDefaults.standardUserDefaults.stringForKey("${manifestCacheKey}_$profileId")
|
|
||||||
|
|
||||||
actual fun saveManifestCachePayload(profileId: Int, payload: String) {
|
|
||||||
NSUserDefaults.standardUserDefaults.setObject(payload, forKey = "${manifestCacheKey}_$profileId")
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
internal actual fun addonEpochMs(): Long =
|
|
||||||
(NSDate().timeIntervalSince1970 * 1000.0).toLong()
|
|
||||||
|
|
||||||
private val addonHttpClient = HttpClient(Darwin) {
|
private val addonHttpClient = HttpClient(Darwin) {
|
||||||
install(HttpTimeout) {
|
install(HttpTimeout) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue