110 lines
3.4 KiB
Dart
110 lines
3.4 KiB
Dart
import 'dart:async';
|
|
import 'package:bloc/bloc.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'session_event.dart';
|
|
import 'session_state.dart';
|
|
|
|
class SessionBloc extends Bloc<SessionEvent, SessionState> {
|
|
Timer? _expiryTimer;
|
|
static const String _tokenKey = 'auth_token';
|
|
static const String _expiryKey = 'auth_expiry';
|
|
|
|
SessionBloc() : super(SessionInitial()) {
|
|
on<SessionStarted>(_onSessionStarted);
|
|
on<SessionExpired>(_onSessionExpired);
|
|
on<SessionRefreshed>(_onSessionRefreshed);
|
|
on<SessionEnded>(_onSessionEnded);
|
|
on<SessionRestored>(_onSessionRestored);
|
|
}
|
|
|
|
void _onSessionStarted(SessionStarted event, Emitter<SessionState> emit) async {
|
|
final expiresAt = DateTime.now().add(
|
|
const Duration(minutes: 15),
|
|
); // Match Go
|
|
|
|
// Save token to persistent storage
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString(_tokenKey, event.token);
|
|
await prefs.setString(_expiryKey, expiresAt.toIso8601String());
|
|
|
|
emit(SessionActive(token: event.token, expiresAt: expiresAt));
|
|
_startExpiryTimer(expiresAt);
|
|
}
|
|
|
|
void _onSessionExpired(SessionExpired event, Emitter<SessionState> emit) {
|
|
_expiryTimer?.cancel();
|
|
_clearStoredSession();
|
|
emit(SessionExpiredState());
|
|
}
|
|
|
|
void _onSessionRefreshed(SessionRefreshed event, Emitter<SessionState> emit) async {
|
|
final expiresAt = DateTime.now().add(const Duration(minutes: 15));
|
|
|
|
// Update stored token
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.setString(_tokenKey, event.newToken);
|
|
await prefs.setString(_expiryKey, expiresAt.toIso8601String());
|
|
|
|
emit(SessionActive(token: event.newToken, expiresAt: expiresAt));
|
|
_startExpiryTimer(expiresAt);
|
|
}
|
|
|
|
void _onSessionEnded(SessionEnded event, Emitter<SessionState> emit) {
|
|
_expiryTimer?.cancel();
|
|
_clearStoredSession();
|
|
emit(SessionInitial());
|
|
}
|
|
|
|
void _onSessionRestored(SessionRestored event, Emitter<SessionState> emit) {
|
|
final expiresAt = event.expiresAt;
|
|
final now = DateTime.now();
|
|
|
|
// Check if token is still valid
|
|
if (expiresAt.isAfter(now)) {
|
|
emit(SessionActive(token: event.token, expiresAt: expiresAt));
|
|
_startExpiryTimer(expiresAt);
|
|
} else {
|
|
// Token expired, clear it
|
|
_clearStoredSession();
|
|
emit(SessionInitial());
|
|
}
|
|
}
|
|
|
|
Future<void> _clearStoredSession() async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
await prefs.remove(_tokenKey);
|
|
await prefs.remove(_expiryKey);
|
|
}
|
|
|
|
static Future<void> restoreSession(SessionBloc bloc) async {
|
|
final prefs = await SharedPreferences.getInstance();
|
|
final token = prefs.getString(_tokenKey);
|
|
final expiryStr = prefs.getString(_expiryKey);
|
|
|
|
if (token != null && expiryStr != null) {
|
|
try {
|
|
final expiresAt = DateTime.parse(expiryStr);
|
|
bloc.add(SessionRestored(token: token, expiresAt: expiresAt));
|
|
} catch (e) {
|
|
// Invalid stored data, clear it
|
|
await prefs.remove(_tokenKey);
|
|
await prefs.remove(_expiryKey);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _startExpiryTimer(DateTime expiresAt) {
|
|
_expiryTimer?.cancel();
|
|
final duration = expiresAt.difference(DateTime.now());
|
|
_expiryTimer = Timer(duration, () {
|
|
add(SessionExpired());
|
|
});
|
|
}
|
|
|
|
@override
|
|
Future<void> close() {
|
|
_expiryTimer?.cancel();
|
|
return super.close();
|
|
}
|
|
}
|