Skip to content

Commit 2adbdfe

Browse files
committed
DataConnectCredentialsTokenManager.kt: clean up State sealed interface
1 parent e0feba9 commit 2adbdfe

File tree

2 files changed

+39
-47
lines changed

2 files changed

+39
-47
lines changed

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectCredentialsTokenManager.kt

Lines changed: 38 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
4848
import kotlinx.coroutines.flow.StateFlow
4949
import kotlinx.coroutines.flow.asStateFlow
5050
import kotlinx.coroutines.launch
51-
import kotlinx.coroutines.yield
5251

5352
/** Base class that shares logic for managing the Auth token and AppCheck token. */
5453
internal sealed class DataConnectCredentialsTokenManager<T : Any>(
@@ -86,49 +85,39 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
8685
}
8786
}
8887

89-
private interface ProviderProvider<T> {
90-
val provider: T?
91-
}
92-
9388
private sealed interface State<out T> {
9489

9590
/** State indicating that [close] has been invoked. */
9691
object Closed : State<Nothing>
9792

98-
/** State indicating that there is no outstanding "get token" request. */
99-
class Idle<T>(
100-
101-
/**
102-
* The [InternalAuthProvider] or [InteropAppCheckTokenProvider]; may be null if the deferred
103-
* has not yet given us a provider.
104-
*/
105-
override val provider: T?,
106-
93+
sealed interface StateWithForceTokenRefresh<out T> : State<T> {
10794
/** The value to specify for `forceRefresh` on the next invocation of [getToken]. */
10895
val forceTokenRefresh: Boolean
109-
) : State<T>, ProviderProvider<T>
96+
}
11097

111-
/** State indicating that there _is_ an outstanding "get token" request. */
112-
class Active<T>(
98+
/** State indicating that the token provider is not (yet?) available. */
99+
data class New(override val forceTokenRefresh: Boolean) : StateWithForceTokenRefresh<Nothing>
100+
101+
sealed interface StateWithProvider<out T> : State<T> {
102+
/** The token provider, [InternalAuthProvider] or [InteropAppCheckTokenProvider] */
103+
val provider: T
104+
}
105+
106+
/** State indicating that there is no outstanding "get token" request. */
107+
data class Idle<T>(override val provider: T, override val forceTokenRefresh: Boolean) :
108+
StateWithProvider<T>, StateWithForceTokenRefresh<T>
113109

114-
/**
115-
* The [InternalAuthProvider] or [InteropAppCheckTokenProvider] that is performing the "get
116-
* token" request.
117-
*/
110+
/** State indicating that there _is_ an outstanding "get token" request. */
111+
data class Active<out T>(
118112
override val provider: T,
119113

120114
/** The job that is performing the "get token" request. */
121115
val job: Deferred<SequencedReference<Result<GetTokenResult>>>
122-
) : State<T>, ProviderProvider<T>
116+
) : StateWithProvider<T>
123117
}
124118

125-
/**
126-
* The current state of this object. The value should only be changed in a compare-and-swap loop
127-
* in order to be thread-safe. Such a loop should call `yield()` on each iteration to allow other
128-
* coroutines to run on the thread.
129-
*/
130-
private val state =
131-
MutableStateFlow<State<T>>(State.Idle(provider = null, forceTokenRefresh = false))
119+
/** The current state of this object. */
120+
private val state = MutableStateFlow<State<T>>(State.New(forceTokenRefresh = false))
132121

133122
/**
134123
* Adds the token listener to the given provider.
@@ -171,15 +160,16 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
171160
private fun setClosedState() {
172161
while (true) {
173162
val oldState = state.value
174-
val providerProvider: ProviderProvider<T> =
163+
val provider: T? =
175164
when (oldState) {
176165
is State.Closed -> return
177-
is State.Idle -> oldState
178-
is State.Active -> oldState
166+
is State.New -> null
167+
is State.Idle -> oldState.provider
168+
is State.Active -> oldState.provider
179169
}
180170

181171
if (state.compareAndSet(oldState, State.Closed)) {
182-
providerProvider.provider?.let { removeTokenListener(it) }
172+
provider?.let { removeTokenListener(it) }
183173
break
184174
}
185175
}
@@ -190,27 +180,28 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
190180
*
191181
* If [close] has been called, this method does nothing.
192182
*/
193-
suspend fun forceRefresh() {
183+
fun forceRefresh() {
194184
logger.debug { "forceRefresh()" }
195185
while (true) {
196186
val oldState = state.value
197-
val oldStateProviderProvider =
187+
val newState: State.StateWithForceTokenRefresh<T> =
198188
when (oldState) {
199189
is State.Closed -> return
200-
is State.Idle -> oldState
190+
is State.New -> oldState.copy(forceTokenRefresh = true)
191+
is State.Idle -> oldState.copy(forceTokenRefresh = true)
201192
is State.Active -> {
202193
val message = "needs token refresh (wgrwbrvjxt)"
203194
oldState.job.cancel(message, ForceRefresh(message))
204-
oldState
195+
State.Idle(oldState.provider, forceTokenRefresh = true)
205196
}
206197
}
207198

208-
val newState = State.Idle(oldStateProviderProvider.provider, forceTokenRefresh = true)
199+
check(newState.forceTokenRefresh) {
200+
"newState.forceTokenRefresh should be true (error code gnvr2wx7nz)"
201+
}
209202
if (state.compareAndSet(oldState, newState)) {
210203
break
211204
}
212-
213-
yield()
214205
}
215206
}
216207

@@ -256,13 +247,13 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
256247
}
257248
throw CredentialsTokenManagerClosedException(this)
258249
}
259-
is State.Idle -> {
260-
if (oldState.provider === null) {
261-
logger.debug {
262-
"$invocationId getToken() returns null (token provider is not (yet?) available)"
263-
}
264-
return null
250+
is State.New -> {
251+
logger.debug {
252+
"$invocationId getToken() returns null (token provider is not (yet?) available)"
265253
}
254+
return null
255+
}
256+
is State.Idle -> {
266257
newActiveState(invocationId, oldState.provider, oldState.forceTokenRefresh)
267258
}
268259
is State.Active -> {
@@ -352,6 +343,7 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
352343
removeTokenListener(newProvider)
353344
break
354345
}
346+
is State.New -> State.Idle(newProvider, oldState.forceTokenRefresh)
355347
is State.Idle -> State.Idle(newProvider, oldState.forceTokenRefresh)
356348
is State.Active -> {
357349
val newProviderClassName = newProvider::class.qualifiedName

firebase-dataconnect/src/main/kotlin/com/google/firebase/dataconnect/core/DataConnectGrpcClient.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,7 @@ internal class DataConnectGrpcClient(
102102
)
103103
}
104104

105-
private suspend inline fun <T, R> T.retryOnGrpcUnauthenticatedError(
105+
private inline fun <T, R> T.retryOnGrpcUnauthenticatedError(
106106
requestId: String,
107107
kotlinMethodName: String,
108108
block: T.() -> R

0 commit comments

Comments
 (0)