1414
1515import 'dart:async' ;
1616
17+ import '../support/completer_manager.dart' ;
1718import 'jwt.dart' ;
1819import 'token_source.dart' ;
1920
@@ -23,11 +24,11 @@ import 'token_source.dart';
2324/// return `true` if the cached credentials are still valid for the given request.
2425///
2526/// The default validator checks JWT expiration using [isResponseExpired] .
26- typedef TokenValidator = bool Function (TokenRequestOptions ? options, TokenSourceResponse response);
27+ typedef TokenValidator = bool Function (TokenRequestOptions options, TokenSourceResponse response);
2728
2829/// A tuple containing the request options and response that were cached.
2930class TokenStoreItem {
30- final TokenRequestOptions ? options;
31+ final TokenRequestOptions options;
3132 final TokenSourceResponse response;
3233
3334 const TokenStoreItem ({
@@ -44,7 +45,7 @@ abstract class TokenStore {
4445 /// Store credentials in the store.
4546 ///
4647 /// This replaces any existing cached credentials with the new ones.
47- Future <void > store (TokenRequestOptions ? options, TokenSourceResponse response);
48+ Future <void > store (TokenRequestOptions options, TokenSourceResponse response);
4849
4950 /// Retrieve the cached credentials.
5051 ///
@@ -63,7 +64,7 @@ class InMemoryTokenStore implements TokenStore {
6364 TokenStoreItem ? _cached;
6465
6566 @override
66- Future <void > store (TokenRequestOptions ? options, TokenSourceResponse response) async {
67+ Future <void > store (TokenRequestOptions options, TokenSourceResponse response) async {
6768 _cached = TokenStoreItem (options: options, response: response);
6869 }
6970
@@ -79,7 +80,7 @@ class InMemoryTokenStore implements TokenStore {
7980}
8081
8182/// Default validator that checks JWT expiration using [isResponseExpired] .
82- bool _defaultValidator (TokenRequestOptions ? options, TokenSourceResponse response) {
83+ bool _defaultValidator (TokenRequestOptions options, TokenSourceResponse response) {
8384 return ! isResponseExpired (response);
8485}
8586
@@ -96,7 +97,7 @@ class CachingTokenSource implements TokenSourceConfigurable {
9697 final TokenSourceConfigurable _wrapped;
9798 final TokenStore _store;
9899 final TokenValidator _validator;
99- Completer < TokenSourceResponse >? _fetchInProgress ;
100+ final Map < TokenRequestOptions , CompleterManager < TokenSourceResponse >> _inflightRequests = {} ;
100101
101102 /// Initialize a caching wrapper around any token source.
102103 ///
@@ -112,31 +113,32 @@ class CachingTokenSource implements TokenSourceConfigurable {
112113 _validator = validator ?? _defaultValidator;
113114
114115 @override
115- Future <TokenSourceResponse > fetch ([TokenRequestOptions ? options]) async {
116- if (_fetchInProgress != null ) {
117- return _fetchInProgress! .future;
116+ Future <TokenSourceResponse > fetch (TokenRequestOptions options) async {
117+ final existingManager = _inflightRequests[options];
118+ if (existingManager != null && existingManager.isActive) {
119+ return existingManager.future;
118120 }
119121
120- _fetchInProgress = Completer <TokenSourceResponse >();
122+ final manager = existingManager ?? CompleterManager <TokenSourceResponse >();
123+ _inflightRequests[options] = manager;
124+ final resultFuture = manager.future;
121125
122126 try {
123- // Check if we have a valid cached token
124127 final cached = await _store.retrieve ();
125128 if (cached != null && cached.options == options && _validator (cached.options, cached.response)) {
126- _fetchInProgress ! .complete (cached.response);
127- return cached.response ;
129+ manager .complete (cached.response);
130+ return resultFuture ;
128131 }
129132
130- final requestOptions = options ?? const TokenRequestOptions ();
131- final response = await _wrapped.fetch (requestOptions);
133+ final response = await _wrapped.fetch (options);
132134 await _store.store (options, response);
133- _fetchInProgress ! .complete (response);
134- return response ;
135- } catch (e) {
136- _fetchInProgress ! .completeError (e);
135+ manager .complete (response);
136+ return resultFuture ;
137+ } catch (e, stackTrace ) {
138+ manager .completeError (e, stackTrace );
137139 rethrow ;
138140 } finally {
139- _fetchInProgress = null ;
141+ _inflightRequests. remove (options) ;
140142 }
141143 }
142144
0 commit comments