Files
social-app/apps/lib/app/services/app_prewarm_orchestrator.dart
T

119 lines
3.5 KiB
Dart

import 'dart:async';
import 'package:flutter/foundation.dart';
import '../../features/calendar/data/repositories/calendar_repository.dart';
import '../../features/messages/data/repositories/inbox_repository.dart';
import '../../features/chat/data/repositories/chat_history_repository.dart';
enum AppPrewarmStatus { idle, running, completed, timedOut, failed }
class AppPrewarmOrchestrator extends ChangeNotifier {
AppPrewarmOrchestrator({
required CalendarRepository calendarRepository,
required InboxRepository inboxRepository,
required ChatHistoryRepository chatHistoryRepository,
this.bootBudget = const Duration(milliseconds: 1200),
Future<void> Function()? prewarmChatHistory,
Future<void> Function()? prewarmCalendarToday,
Future<void> Function()? prewarmUnreadInbox,
}) : _calendarRepository = calendarRepository,
_inboxRepository = inboxRepository,
_chatHistoryRepository = chatHistoryRepository,
_prewarmChatHistory = prewarmChatHistory,
_prewarmCalendarToday = prewarmCalendarToday,
_prewarmUnreadInbox = prewarmUnreadInbox;
final CalendarRepository _calendarRepository;
final InboxRepository _inboxRepository;
final ChatHistoryRepository _chatHistoryRepository;
final Duration bootBudget;
final Future<void> Function()? _prewarmChatHistory;
final Future<void> Function()? _prewarmCalendarToday;
final Future<void> Function()? _prewarmUnreadInbox;
AppPrewarmStatus _status = AppPrewarmStatus.idle;
AppPrewarmStatus get status => _status;
String? _userId;
Future<void>? _running;
bool get isBootBlocking => _status == AppPrewarmStatus.running;
Future<void> ensureStartedFor(String userId) {
if (_userId == userId &&
(_status == AppPrewarmStatus.completed ||
_status == AppPrewarmStatus.timedOut)) {
return Future<void>.value();
}
if (_userId == userId && _running != null) {
return _running!;
}
_userId = userId;
_status = AppPrewarmStatus.running;
notifyListeners();
final tasks = Future.wait<void>([
_runPrewarmChatHistory(),
_runPrewarmCalendarToday(),
_runPrewarmUnreadInbox(),
]);
final running = _runWithBudget(tasks);
_running = running;
return running.whenComplete(() {
if (identical(_running, running)) {
_running = null;
}
});
}
Future<void> _runPrewarmChatHistory() {
final override = _prewarmChatHistory;
if (override != null) {
return override();
}
return _chatHistoryRepository.loadHistory();
}
Future<void> _runPrewarmCalendarToday() {
final override = _prewarmCalendarToday;
if (override != null) {
return override();
}
return _calendarRepository.getDayEvents(DateTime.now());
}
Future<void> _runPrewarmUnreadInbox() {
final override = _prewarmUnreadInbox;
if (override != null) {
return override();
}
return _inboxRepository.getMessages(isRead: false);
}
Future<void> _runWithBudget(Future<void> tasks) async {
try {
await tasks.timeout(bootBudget);
_status = AppPrewarmStatus.completed;
notifyListeners();
} on TimeoutException {
_status = AppPrewarmStatus.timedOut;
notifyListeners();
} catch (_) {
_status = AppPrewarmStatus.failed;
notifyListeners();
}
}
void reset() {
_userId = null;
_running = null;
if (_status != AppPrewarmStatus.idle) {
_status = AppPrewarmStatus.idle;
notifyListeners();
}
}
}