diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/ApiCache.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/ApiCache.kt new file mode 100644 index 0000000..8e778ae --- /dev/null +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/ApiCache.kt @@ -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 writeByKey(key: String, value: T) = + withContext(dispatcherProvider.io) { + getCache().insert( + key, + json.encodeToString(value) + ) + } + + suspend fun clear() { + getCache().clear() + } + + suspend inline fun 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 + } +} diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/FallbackVideoApi.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/FallbackVideoApi.kt index f212266..bc427ad 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/FallbackVideoApi.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/data/api/FallbackVideoApi.kt @@ -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 getByKey(key: String): T? { - val value = getCache().selectByKey(key) - .awaitAsOneOrNull()?.cache_value - ?: return null - return json.decodeFromString(value) - } - - private suspend inline fun writeByKey(key: String, value: T) = - withContext(dispatcherProvider.io) { - getCache().insert( - key, - json.encodeToString(value) - ) - } } diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/di/HttpModule.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/di/HttpModule.kt index 7f1426f..8b3b86c 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/di/HttpModule.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/di/HttpModule.kt @@ -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) ) } } diff --git a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/domain/LogoutUseCase.kt b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/domain/LogoutUseCase.kt index 76aaaab..25c3aab 100644 --- a/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/domain/LogoutUseCase.kt +++ b/apps/vbox/client/shared/src/commonMain/kotlin/ru/shadowsparky/vbox/shared/domain/LogoutUseCase.kt @@ -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() } } diff --git a/apps/vbox/client/shared/src/commonMain/sqldelight/ru/shadowsparky/vbox/domain/ApiCache.sq b/apps/vbox/client/shared/src/commonMain/sqldelight/ru/shadowsparky/vbox/domain/ApiCache.sq index 2dddfa4..301c905 100644 --- a/apps/vbox/client/shared/src/commonMain/sqldelight/ru/shadowsparky/vbox/domain/ApiCache.sq +++ b/apps/vbox/client/shared/src/commonMain/sqldelight/ru/shadowsparky/vbox/domain/ApiCache.sq @@ -12,3 +12,6 @@ deleteByKey: selectByKey: SELECT * FROM ApiCache WHERE cache_key = ?; + +clear: + DELETE FROM ApiCache;