Some checks failed
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/chain_gateway Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful
ci/woodpecker/push/bump_version Pipeline failed
103 lines
3.4 KiB
Dart
103 lines
3.4 KiB
Dart
import 'dart:async';
|
|
|
|
import 'package:logging/logging.dart';
|
|
|
|
/// Mutex to prevent concurrent token refresh operations
|
|
/// This ensures only one refresh operation happens at a time,
|
|
/// preventing race conditions during app startup when multiple
|
|
/// providers try to refresh tokens simultaneously.
|
|
class TokenRefreshMutex {
|
|
static final _instance = TokenRefreshMutex._();
|
|
factory TokenRefreshMutex() => _instance;
|
|
TokenRefreshMutex._();
|
|
|
|
static final _logger = Logger('service.authorization.token_mutex');
|
|
|
|
Completer<String>? _currentRefresh;
|
|
Completer<void>? _currentRotation;
|
|
|
|
/// Execute a token refresh operation with mutex protection
|
|
/// If another refresh is in progress, wait for it to complete
|
|
Future<String> executeRefresh(Future<String> Function() refreshOperation) async {
|
|
if (_currentRefresh != null) {
|
|
_logger.fine('Token refresh already in progress, waiting for completion');
|
|
return await _currentRefresh!.future;
|
|
}
|
|
|
|
_logger.fine('Starting new token refresh operation');
|
|
_currentRefresh = Completer<String>();
|
|
|
|
try {
|
|
final result = await refreshOperation();
|
|
if (_currentRefresh != null) {
|
|
_currentRefresh!.complete(result);
|
|
_logger.fine('Token refresh completed successfully');
|
|
}
|
|
return result;
|
|
} catch (e, st) {
|
|
_logger.warning('Token refresh failed', e, st);
|
|
if (_currentRefresh != null) {
|
|
_currentRefresh!.completeError(e, st);
|
|
}
|
|
rethrow;
|
|
} finally {
|
|
_currentRefresh = null;
|
|
}
|
|
}
|
|
|
|
/// Execute a token rotation operation with mutex protection
|
|
/// If another rotation is in progress, wait for it to complete
|
|
Future<void> executeRotation(Future<void> Function() rotationOperation) async {
|
|
if (_currentRotation != null) {
|
|
_logger.fine('Token rotation already in progress, waiting for completion');
|
|
return await _currentRotation!.future;
|
|
}
|
|
|
|
_logger.fine('Starting new token rotation operation');
|
|
_currentRotation = Completer<void>();
|
|
|
|
try {
|
|
await rotationOperation();
|
|
if (_currentRotation != null) {
|
|
_currentRotation!.complete();
|
|
_logger.fine('Token rotation completed successfully');
|
|
}
|
|
} catch (e, st) {
|
|
_logger.warning('Token rotation failed', e, st);
|
|
if (_currentRotation != null) {
|
|
_currentRotation!.completeError(e, st);
|
|
}
|
|
rethrow;
|
|
} finally {
|
|
_currentRotation = null;
|
|
}
|
|
}
|
|
|
|
/// Check if a refresh operation is currently in progress
|
|
bool get isRefreshInProgress => _currentRefresh != null;
|
|
|
|
/// Check if a rotation operation is currently in progress
|
|
bool get isRotationInProgress => _currentRotation != null;
|
|
|
|
/// Get current status for debugging
|
|
Map<String, dynamic> getStatus() {
|
|
return {
|
|
'refreshInProgress': isRefreshInProgress,
|
|
'rotationInProgress': isRotationInProgress,
|
|
'timestamp': DateTime.now().toIso8601String(),
|
|
};
|
|
}
|
|
|
|
/// Force reset the mutex (for testing or emergency situations)
|
|
void forceReset() {
|
|
_logger.warning('Force resetting token refresh mutex');
|
|
if (_currentRefresh != null && !_currentRefresh!.isCompleted) {
|
|
_currentRefresh!.completeError(Exception('Mutex force reset'));
|
|
}
|
|
if (_currentRotation != null && !_currentRotation!.isCompleted) {
|
|
_currentRotation!.completeError(Exception('Mutex force reset'));
|
|
}
|
|
_currentRefresh = null;
|
|
_currentRotation = null;
|
|
}
|
|
} |