180 lines
5.0 KiB
Dart
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;
|
|
}
|
|
}
|