add api cache cleanup

This commit is contained in:
2026-08-17 14:47:29 +03:00
parent ea67ed80a5
commit 0243466cf1
5 changed files with 58 additions and 43 deletions
@@ -0,0 +1,40 @@
package ru.shadowsparky.vbox.shared.data.api
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import org.koin.core.annotation.Factory
import ru.shadowsparky.domain.DispatcherProvider
import ru.shadowsparky.vbox.domain.ApiCacheQueries
import ru.shadowsparky.vbox.shared.data.AppDatabaseProvider
@Factory
class ApiCache(
val dbProvider: AppDatabaseProvider,
val json: Json,
val dispatcherProvider: DispatcherProvider
) {
suspend inline fun <reified T> writeByKey(key: String, value: T) =
withContext(dispatcherProvider.io) {
getCache().insert(
key,
json.encodeToString(value)
)
}
suspend fun clear() {
getCache().clear()
}
suspend inline fun <reified T> getByKey(key: String): T? {
val value = getCache().selectByKey(key)
.awaitAsOneOrNull()?.cache_value
?: return null
return json.decodeFromString(value)
}
suspend fun getCache(): ApiCacheQueries {
return dbProvider.get().apiCacheQueries
}
}
@@ -1,31 +1,23 @@
package ru.shadowsparky.vbox.shared.data.api
import app.cash.sqldelight.async.coroutines.awaitAsOneOrNull
import kotlinx.coroutines.withContext
import kotlinx.serialization.json.Json
import ru.shadowsparky.domain.DispatcherProvider
import ru.shadowsparky.vbox.domain.ApiCacheQueries
import ru.shadowsparky.vbox.shared.data.AppDatabaseProvider
import ru.shadowsparky.vbox.shared.domain.VideoApi
import ru.shadowsparky.vbox.shared.domain.model.VideoDetails
import ru.shadowsparky.vbox.shared.domain.model.VideoLinksResponse
import ru.shadowsparky.vbox.shared.domain.model.VideosResponse
class FallbackVideoApi(
private val dbProvider: AppDatabaseProvider,
private val wrapper: VideoApi,
private val json: Json,
private val dispatcherProvider: DispatcherProvider
private val cache: ApiCache,
private val wrapper: VideoApi
) : VideoApi {
override suspend fun fetchNewVideos(query: String?): VideosResponse {
val key = "fetchNewVideos_${query};1;date;"
return try {
wrapper.fetchNewVideos(query).apply {
writeByKey(key, this)
cache.writeByKey(key, this)
}
} catch (e: Exception) {
getByKey(key) ?: throw e
cache.getByKey(key) ?: throw e
}
}
@@ -33,10 +25,10 @@ class FallbackVideoApi(
val key = "fetchDetails_${id};"
return try {
wrapper.fetchDetails(id).apply {
writeByKey(key, this)
cache.writeByKey(key, this)
}
} catch (e: Exception) {
getByKey(key) ?: throw e
cache.getByKey(key) ?: throw e
}
}
@@ -44,29 +36,10 @@ class FallbackVideoApi(
val key = "fetchVideoLinks_${id};$seasonId;"
return try {
wrapper.fetchVideoLinks(id, seasonId).apply {
writeByKey(key, this)
cache.writeByKey(key, this)
}
} catch (e: Exception) {
getByKey(key) ?: throw e
cache.getByKey(key) ?: throw e
}
}
private suspend fun getCache(): ApiCacheQueries {
return dbProvider.get().apiCacheQueries
}
private suspend inline fun <reified T> getByKey(key: String): T? {
val value = getCache().selectByKey(key)
.awaitAsOneOrNull()?.cache_value
?: return null
return json.decodeFromString(value)
}
private suspend inline fun <reified T> writeByKey(key: String, value: T) =
withContext(dispatcherProvider.io) {
getCache().insert(
key,
json.encodeToString(value)
)
}
}
@@ -1,11 +1,9 @@
package ru.shadowsparky.vbox.shared.di
import io.ktor.client.HttpClient
import kotlinx.serialization.json.Json
import org.koin.core.annotation.Module
import org.koin.core.annotation.Single
import ru.shadowsparky.domain.DispatcherProvider
import ru.shadowsparky.vbox.shared.data.AppDatabaseProvider
import ru.shadowsparky.vbox.shared.data.api.ApiCache
import ru.shadowsparky.vbox.shared.data.api.FallbackVideoApi
import ru.shadowsparky.vbox.shared.data.api.PosterWithoutSuffixVideoApi
import ru.shadowsparky.vbox.shared.data.api.VideoApiImpl
@@ -19,13 +17,11 @@ class HttpModule {
fun provideVideoApi(
httpClient: HttpClient,
serverConfigurationProvider: ServerConfigurationRepository,
json: Json,
dbProvider: AppDatabaseProvider,
dispatcherProvider: DispatcherProvider
apiCache: ApiCache
): VideoApi {
val impl = VideoApiImpl(httpClient, serverConfigurationProvider)
return PosterWithoutSuffixVideoApi(
FallbackVideoApi(dbProvider, impl, json, dispatcherProvider)
FallbackVideoApi(apiCache, impl)
)
}
}
@@ -6,6 +6,7 @@ import org.koin.core.annotation.Factory
import org.koin.core.annotation.Named
import ru.shadowsparky.http.domain.LogoutAction
import ru.shadowsparky.http.domain.TokenStorage
import ru.shadowsparky.vbox.shared.data.api.ApiCache
import ru.shadowsparky.vbox.shared.di.DbType
import ru.shadowsparky.vbox.shared.domain.tag.MovieTagRepository
import ru.shadowsparky.vbox.shared.domain.tag.UserTagRepository
@@ -21,7 +22,8 @@ class LogoutUseCase(
private val bearerAuthProvider: BearerAuthProvider,
private val tokenStorage: TokenStorage,
private val authTokenRepository: AuthTokenRepository,
private val pendingOperationRepository: PendingOperationRepository
private val pendingOperationRepository: PendingOperationRepository,
private val apiCache: ApiCache
) : LogoutAction {
override suspend fun logout() {
@@ -37,5 +39,6 @@ class LogoutUseCase(
localUserTagRepository.clear()
AggregateType.entries.forEach { syncRepository.set(it, false) }
pendingOperationRepository.clear()
apiCache.clear()
}
}
@@ -12,3 +12,6 @@ deleteByKey:
selectByKey:
SELECT * FROM ApiCache WHERE cache_key = ?;
clear:
DELETE FROM ApiCache;