Skip to content

Commit

Permalink
[runtime] Change NetworkMonitor to expose a StateFlow directly (#6119)
Browse files Browse the repository at this point in the history
* Change NetworkMonitor to expose a StateFlow directly

* add .close() to docs
  • Loading branch information
martinbonnin authored Aug 14, 2024
1 parent 98562e7 commit 19fc22b
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 25 deletions.
3 changes: 3 additions & 0 deletions docs/source/advanced/network-connectivity.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ val apolloClient = ApolloClient.Builder()
.serverUrl("https://example.com/graphql")
.retryOnErrorInterceptor(RetryOnErrorInterceptor(networkMonitor))
.build()

// once you're done with your `ApolloClient`
networkMonitor.close()
```

### `failFastIfOffline`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.apollographql.apollo.exception.ApolloException
import com.apollographql.apollo.exception.ApolloNetworkException
import com.apollographql.apollo.exception.OfflineException
import com.apollographql.apollo.network.NetworkMonitor
import com.apollographql.apollo.network.waitForNetwork
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emitAll
Expand Down Expand Up @@ -60,7 +61,7 @@ private class DefaultRetryOnErrorInterceptorImpl(private val networkMonitor: Net
val downStream = chain.proceed(request)

return flow {
if (failFastIfOffline && networkMonitor?.isOnline() == false) {
if (failFastIfOffline && networkMonitor?.isOnline?.value == false) {
emit((ApolloResponse.Builder(request.operation, request.requestUuid).exception(OfflineApolloException).build()))
} else {
emitAll(downStream)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ package com.apollographql.apollo.network

import com.apollographql.apollo.annotations.ApolloExperimental
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.mapNotNull
import kotlinx.coroutines.flow.takeWhile
import okio.Closeable
import kotlin.js.JsName
import kotlin.jvm.JvmMultifileClass
import kotlin.jvm.JvmName

Expand All @@ -20,35 +23,35 @@ import kotlin.jvm.JvmName
@ApolloExperimental
interface NetworkMonitor : Closeable {
/**
* The current state of the network
* Emits the current network state. May emit null during initialization
* when the current state is not known yet.
*/
suspend fun isOnline(): Boolean
val isOnline: StateFlow<Boolean?>
}

/**
* Waits until [isOnline] is true
*/
suspend fun waitForNetwork()
internal suspend fun NetworkMonitor.waitForNetwork() {
isOnline.takeWhile { it != true }.collect()
}

/**
* @param networkObserverFactory a factory for a [NetworkObserver]. [networkObserverFactory] is called from a
* background thread.
*/
internal class DefaultNetworkMonitor(private val networkObserverFactory: () -> NetworkObserver) : NetworkMonitor, NetworkObserver.Listener {
private val _isOnline: MutableStateFlow<Boolean?> = MutableStateFlow(null)

override val isOnline: StateFlow<Boolean?>
get() {
networkObserver
return _isOnline.asStateFlow()
}

private val networkObserver by lazy {
networkObserverFactory().also {
it.setListener(this)
}
}

override suspend fun isOnline(): Boolean {
networkObserver
return _isOnline.mapNotNull { it }.first()
}

override suspend fun waitForNetwork() {
networkObserver
_isOnline.takeWhile { it != true }.collect()
}

override fun close() {
networkObserver.close()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,14 @@ import com.apollographql.mockserver.MockServer
import com.apollographql.mockserver.assertNoRequest
import com.apollographql.mockserver.enqueueString
import com.apollographql.apollo.network.NetworkMonitor
import com.apollographql.apollo.network.waitForNetwork
import test.FooQuery
import com.apollographql.apollo.testing.internal.runTest
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.emitAll
import kotlinx.coroutines.flow.first
Expand Down Expand Up @@ -91,15 +94,10 @@ class NetworkMonitorTest {
class FakeNetworkMonitor: NetworkMonitor {
val _isOnline = MutableStateFlow(false)

override fun close() {}

override suspend fun waitForNetwork() {
_isOnline.takeWhile { !it }.collect()
}
override val isOnline: StateFlow<Boolean?>
get() = _isOnline.asStateFlow()

override suspend fun isOnline(): Boolean {
return _isOnline.mapNotNull { it }.first()
}
override fun close() {}
}

class NetworkMonitorInterceptor(private val networkMonitor: NetworkMonitor): ApolloInterceptor {
Expand Down

0 comments on commit 19fc22b

Please sign in to comment.