cyberhybridhub/lib/admin/repositories/sync_run_log_repository.dart
2026-05-31 11:17:12 -05:00

180 lines
5.0 KiB
Dart

import '../models/market_history_admin_config.dart';
import '../models/sync_run_event.dart';
import '../services/market_history_admin_api.dart';
abstract class SyncRunLogController {
SyncRunLogRepositoryState get state;
Future<SyncRunLogRepositoryState> loadInitial({int limit = 50});
Future<SyncRunLogRepositoryState> refresh({int limit = 50});
Future<SyncRunLogRepositoryState> loadMore({int limit = 50});
Future<SyncRunLogRepositoryState> triggerResync();
Future<SyncRunLogRepositoryState> triggerCleanup({bool archive = false});
}
class SyncRunLogRepositoryState {
const SyncRunLogRepositoryState({
required this.pinned,
required this.history,
required this.nextBefore,
required this.isLoading,
required this.errorMessage,
this.config = const MarketHistoryAdminConfig(
archiveEnabled: false,
windowDays: 7,
retentionDays: 7,
syncEnabled: false,
),
});
final List<SyncRunEvent> pinned;
final List<SyncRunEvent> history;
final DateTime? nextBefore;
final bool isLoading;
final String? errorMessage;
final MarketHistoryAdminConfig config;
bool get hasMore => nextBefore != null;
bool get hasInProgressRun {
bool inProgress(SyncRunEvent event) =>
event.status == SyncRunStatus.inProgress;
return pinned.any(inProgress) || history.any(inProgress);
}
}
class SyncRunLogRepository implements SyncRunLogController {
SyncRunLogRepository({required MarketHistoryAdminApi api}) : _api = api;
final MarketHistoryAdminApi _api;
List<SyncRunEvent> _pinned = <SyncRunEvent>[];
List<SyncRunEvent> _history = <SyncRunEvent>[];
DateTime? _nextBefore;
bool _isLoading = false;
String? _errorMessage;
MarketHistoryAdminConfig _config = const MarketHistoryAdminConfig(
archiveEnabled: false,
windowDays: 7,
retentionDays: 7,
syncEnabled: false,
);
SyncRunLogRepositoryState get state => SyncRunLogRepositoryState(
pinned: List<SyncRunEvent>.unmodifiable(_pinned),
history: List<SyncRunEvent>.unmodifiable(_history),
nextBefore: _nextBefore,
isLoading: _isLoading,
errorMessage: _errorMessage,
config: _config,
);
Future<SyncRunLogRepositoryState> loadInitial({int limit = 50}) async {
_isLoading = true;
_errorMessage = null;
try {
final SyncRunLogPage page = await _api.fetchSyncRuns(limit: limit);
_pinned = _dedupeById(page.pinned);
_history = _dedupeById(_sortedNewestFirst(page.runs));
_nextBefore = page.nextBefore;
_config = page.config;
} on MarketHistoryAdminApiException catch (e) {
_errorMessage = e.message;
} catch (e) {
_errorMessage = e.toString();
} finally {
_isLoading = false;
}
return state;
}
Future<SyncRunLogRepositoryState> refresh({int limit = 50}) async {
return loadInitial(limit: limit);
}
Future<SyncRunLogRepositoryState> loadMore({int limit = 50}) async {
if (_isLoading || _nextBefore == null) {
return state;
}
_isLoading = true;
_errorMessage = null;
try {
final SyncRunLogPage page = await _api.fetchSyncRuns(
limit: limit,
before: _nextBefore,
);
_pinned = _dedupeById(page.pinned);
final List<SyncRunEvent> merged = <SyncRunEvent>[
..._history,
...page.runs,
];
_history = _dedupeById(_sortedNewestFirst(merged));
_nextBefore = page.nextBefore;
_config = page.config;
} on MarketHistoryAdminApiException catch (e) {
_errorMessage = e.message;
} catch (e) {
_errorMessage = e.toString();
} finally {
_isLoading = false;
}
return state;
}
@override
Future<SyncRunLogRepositoryState> triggerResync() async {
_isLoading = true;
_errorMessage = null;
try {
await _api.triggerResync();
return refresh();
} on MarketHistoryAdminApiException catch (e) {
_errorMessage = e.message;
_isLoading = false;
return state;
} catch (e) {
_errorMessage = e.toString();
_isLoading = false;
return state;
}
}
@override
Future<SyncRunLogRepositoryState> triggerCleanup({bool archive = false}) async {
_isLoading = true;
_errorMessage = null;
try {
await _api.triggerCleanup(archive: archive);
return refresh();
} on MarketHistoryAdminApiException catch (e) {
_errorMessage = e.message;
_isLoading = false;
return state;
} catch (e) {
_errorMessage = e.toString();
_isLoading = false;
return state;
}
}
static List<SyncRunEvent> _dedupeById(List<SyncRunEvent> events) {
final Map<int, SyncRunEvent> byId = <int, SyncRunEvent>{};
for (final SyncRunEvent event in events) {
byId[event.id] = event;
}
return byId.values.toList();
}
static List<SyncRunEvent> _sortedNewestFirst(List<SyncRunEvent> events) {
final List<SyncRunEvent> sorted = List<SyncRunEvent>.from(events);
sorted.sort(
(SyncRunEvent a, SyncRunEvent b) => b.startedAt.compareTo(a.startedAt),
);
return sorted;
}
}