Skip to content

Commit

Permalink
Refactor PackageSearchApiPackageCache for offline support
Browse files Browse the repository at this point in the history
The PackageSearchApiPackageCache now accepts an "isOnline" flag which is used to skip network requests when offline. This restructuring facilitates optimized package searching and provides more refined control over network activities. Search parameters were also updated to use this new cache system.

(cherry picked from commit 3afd4a0)
  • Loading branch information
lamba92 committed Jan 29, 2024
1 parent 9eddddd commit 876804c
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 27 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ import kotlin.io.path.div
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.future.future
import kotlinx.coroutines.launch
Expand Down Expand Up @@ -91,11 +93,16 @@ class PackageSearchApplicationCachesService(private val coroutineScope: Coroutin
val isOnlineFlow = apiClient.isOnlineFlow()
.stateIn(coroutineScope, SharingStarted.WhileSubscribed(), true)

val apiPackageCache = PackageSearchApiPackageCache(
apiPackageCache = packagesRepository,
searchCache = searchesRepository,
apiClient = apiClient
)
val apiPackageCache = isOnlineFlow
.map {
PackageSearchApiPackageCache(
apiPackageCache = packagesRepository,
searchCache = searchesRepository,
apiClient = apiClient,
isOnline = it
)
}
.shareIn(coroutineScope, SharingStarted.WhileSubscribed(), 1)

private suspend fun createIndexes() {
searchesRepository.createIndex(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,17 +65,20 @@ class PackageSearchProjectService(
// Todo SAVE
internal val stableOnlyStateFlow = MutableStateFlow(true)

val knownRepositoriesStateFlow = timer(12.hours) {
val knownRepositoriesStateFlow =
IntelliJApplication.PackageSearchApplicationCachesService
.apiPackageCache
.getKnownRepositories()
.associateBy { it.id }
}
.retry {
logWarn("${this::class.simpleName}#knownRepositoriesStateFlow", throwable = it)
true
}
.stateIn(coroutineScope, SharingStarted.Eagerly, emptyMap())
.flatMapLatest { caches ->
timer(12.hours) {
caches.getKnownRepositories()
.associateBy { it.id }
}
}
.retry {
logWarn("${this::class.simpleName}#knownRepositoriesStateFlow", throwable = it)
true
}
.stateIn(coroutineScope, SharingStarted.Eagerly, emptyMap())

override val knownRepositories: Map<String, ApiRepository>
get() = knownRepositoriesStateFlow.value
Expand All @@ -85,11 +88,14 @@ class PackageSearchProjectService(
.stateIn(coroutineScope, SharingStarted.Eagerly, false)

private val contextFlow
get() = knownRepositoriesStateFlow.map { repositories ->
get() = combine(
knownRepositoriesStateFlow,
IntelliJApplication.PackageSearchApplicationCachesService.apiPackageCache
) { repositories, cache ->
WindowedModuleBuilderContext(
project = project,
knownRepositories = repositories,
packagesCache = IntelliJApplication.PackageSearchApplicationCachesService.apiPackageCache,
packagesCache = cache,
coroutineScope = coroutineScope,
projectCaches = project.PackageSearchProjectCachesService.cache,
applicationCaches = IntelliJApplication.PackageSearchApplicationCachesService.cache,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import com.jetbrains.packagesearch.plugin.ui.model.hasUpdates
import com.jetbrains.packagesearch.plugin.ui.model.infopanel.InfoPanelViewModel
import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.SetHeaderState.TargetState
import com.jetbrains.packagesearch.plugin.ui.model.packageslist.PackageListItemEvent.SetHeaderState.TargetState.OPEN
import com.jetbrains.packagesearch.plugin.utils.PackageSearchApiPackageCache
import com.jetbrains.packagesearch.plugin.utils.PackageSearchApplicationCachesService
import com.jetbrains.packagesearch.plugin.utils.PackageSearchProjectService
import com.jetbrains.packagesearch.plugin.utils.logTODO
Expand All @@ -58,6 +59,7 @@ import kotlinx.coroutines.flow.retry
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.flow.zip
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.serialization.encodeToString
Expand Down Expand Up @@ -145,15 +147,19 @@ class PackageListViewModel(
else -> null
}
}
.mapLatest { data ->
.zip(IntelliJApplication.PackageSearchApplicationCachesService.apiPackageCache) { a, b -> a to b }
.mapLatest { (data, apis) ->
when (data) {
null -> emptyMap()
else -> {
isLoadingChannel.send(true)
delay(250.milliseconds) // debounce for mapLatest!
when (data.selectedModule) {
is PackageSearchModule.Base -> data.selectedModule.getSearchQuery(data.searchQuery)
is PackageSearchModule.WithVariants -> data.selectedModule.getSearchQueries(data.searchQuery)
is PackageSearchModule.Base -> data.selectedModule.getSearchQuery(data.searchQuery, apis)
is PackageSearchModule.WithVariants -> data.selectedModule.getSearchQueries(
data.searchQuery,
apis
)
}
}
}
Expand Down Expand Up @@ -212,11 +218,11 @@ class PackageListViewModel(

private suspend fun PackageSearchModule.Base.getSearchQuery(
searchQuery: String,
apis: PackageSearchApiPackageCache,
): Map<PackageListItem.Header.Id.Remote, Search.Results.Base> {
val headerId = PackageListItem.Header.Id.Remote.Base(identity)
val results = Search.Results.Base(
packages = IntelliJApplication.PackageSearchApplicationCachesService.apiPackageCache
.searchPackages(buildSearchParameters {
packages = apis.searchPackages(buildSearchParameters {
this.searchQuery = searchQuery
packagesType = compatiblePackageTypes
}),
Expand All @@ -232,6 +238,7 @@ class PackageListViewModel(

private suspend fun PackageSearchModule.WithVariants.getSearchQueries(
searchQuery: String,
apis: PackageSearchApiPackageCache,
): Map<PackageListItem.Header.Id.Remote, Search> =
variants.groupByCompatiblePackageTypes()
.entries
Expand All @@ -241,17 +248,16 @@ class PackageListViewModel(
in variants.map { it.name } -> 0
else -> 1
}
}.associate { (packagesType, variants) ->
}
.associate { (packagesType, variants) ->
val headerId = PackageListItem.Header.Id.Remote.WithVariant(identity, variants.map { it.name })
val primaryVariantName = variants.first { it.isPrimary }.name
val attributes = variants.first().attributes.map { it.value }
val additionalVariants = variants.map { it.name } - primaryVariantName
val search: Search = when (mainVariantName) {
in variants.map { it.name } -> {
val results = Search.Results.WithVariants(
packages = IntelliJApplication.PackageSearchApplicationCachesService
.apiPackageCache
.searchPackages {
packages = apis.searchPackages {
this.searchQuery = searchQuery
this.packagesType = packagesType
},
Expand All @@ -274,7 +280,7 @@ class PackageListViewModel(
this.searchQuery = searchQuery
this.packagesType = packagesType
},
apis = IntelliJApplication.PackageSearchApplicationCachesService.apiPackageCache,
apis = apis,
attributes = attributes,
primaryVariantName = primaryVariantName,
additionalVariants = additionalVariants,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class PackageSearchApiPackageCache(
private val searchCache: CoroutineObjectRepository<ApiSearchEntry>,
private val apiClient: PackageSearchApi,
private val maxAge: Duration = Random.nextDouble(0.5, 1.0).days,
private val isOnline: Boolean,
) : PackageSearchApi by apiClient {

private val cachesMutex = Mutex()
Expand Down Expand Up @@ -74,7 +75,7 @@ class PackageSearchApiPackageCache(
.toList()
.associateBy { it.id }
val missingIds = ids - localDatabaseResults.keys
if (missingIds.isNotEmpty()) {
if (missingIds.isNotEmpty() && isOnline) {
val networkResults = apiCall(missingIds)
// TODO cache also miss in network to avoid pointless empty query
if (networkResults.isNotEmpty()) {
Expand Down

0 comments on commit 876804c

Please sign in to comment.