@@ -48,7 +48,6 @@ import kotlinx.coroutines.flow.MutableStateFlow
48
48
import kotlinx.coroutines.flow.StateFlow
49
49
import kotlinx.coroutines.flow.asStateFlow
50
50
import kotlinx.coroutines.launch
51
- import kotlinx.coroutines.yield
52
51
53
52
/* * Base class that shares logic for managing the Auth token and AppCheck token. */
54
53
internal sealed class DataConnectCredentialsTokenManager <T : Any >(
@@ -86,49 +85,39 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
86
85
}
87
86
}
88
87
89
- private interface ProviderProvider <T > {
90
- val provider: T ?
91
- }
92
-
93
88
private sealed interface State <out T > {
94
89
95
90
/* * State indicating that [close] has been invoked. */
96
91
object Closed : State<Nothing>
97
92
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 > {
107
94
/* * The value to specify for `forceRefresh` on the next invocation of [getToken]. */
108
95
val forceTokenRefresh: Boolean
109
- ) : State<T>, ProviderProvider<T>
96
+ }
110
97
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 >
113
109
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 >(
118
112
override val provider : T ,
119
113
120
114
/* * The job that is performing the "get token" request. */
121
115
val job : Deferred <SequencedReference <Result <GetTokenResult >>>
122
- ) : State<T>, ProviderProvider <T>
116
+ ) : StateWithProvider <T>
123
117
}
124
118
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 ))
132
121
133
122
/* *
134
123
* Adds the token listener to the given provider.
@@ -171,15 +160,16 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
171
160
private fun setClosedState () {
172
161
while (true ) {
173
162
val oldState = state.value
174
- val providerProvider : ProviderProvider < T > =
163
+ val provider : T ? =
175
164
when (oldState) {
176
165
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
179
169
}
180
170
181
171
if (state.compareAndSet(oldState, State .Closed )) {
182
- providerProvider. provider?.let { removeTokenListener(it) }
172
+ provider?.let { removeTokenListener(it) }
183
173
break
184
174
}
185
175
}
@@ -190,27 +180,28 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
190
180
*
191
181
* If [close] has been called, this method does nothing.
192
182
*/
193
- suspend fun forceRefresh () {
183
+ fun forceRefresh () {
194
184
logger.debug { " forceRefresh()" }
195
185
while (true ) {
196
186
val oldState = state.value
197
- val oldStateProviderProvider =
187
+ val newState : State . StateWithForceTokenRefresh < T > =
198
188
when (oldState) {
199
189
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 )
201
192
is State .Active -> {
202
193
val message = " needs token refresh (wgrwbrvjxt)"
203
194
oldState.job.cancel(message, ForceRefresh (message))
204
- oldState
195
+ State . Idle ( oldState.provider, forceTokenRefresh = true )
205
196
}
206
197
}
207
198
208
- val newState = State .Idle (oldStateProviderProvider.provider, forceTokenRefresh = true )
199
+ check(newState.forceTokenRefresh) {
200
+ " newState.forceTokenRefresh should be true (error code gnvr2wx7nz)"
201
+ }
209
202
if (state.compareAndSet(oldState, newState)) {
210
203
break
211
204
}
212
-
213
- yield ()
214
205
}
215
206
}
216
207
@@ -256,13 +247,13 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
256
247
}
257
248
throw CredentialsTokenManagerClosedException (this )
258
249
}
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)"
265
253
}
254
+ return null
255
+ }
256
+ is State .Idle -> {
266
257
newActiveState(invocationId, oldState.provider, oldState.forceTokenRefresh)
267
258
}
268
259
is State .Active -> {
@@ -352,6 +343,7 @@ internal sealed class DataConnectCredentialsTokenManager<T : Any>(
352
343
removeTokenListener(newProvider)
353
344
break
354
345
}
346
+ is State .New -> State .Idle (newProvider, oldState.forceTokenRefresh)
355
347
is State .Idle -> State .Idle (newProvider, oldState.forceTokenRefresh)
356
348
is State .Active -> {
357
349
val newProviderClassName = newProvider::class .qualifiedName
0 commit comments