65 lines
2.0 KiB
Dart
65 lines
2.0 KiB
Dart
import 'dart:async';
|
|
|
|
import '../../l10n/tr.dart';
|
|
|
|
/// 무거운 작업 (AI 자막 · 자막 번역 · MKV 만들기 - CPU · 메모리를 많이 써서 하나씩) 의 대기열.
|
|
/// 약속: [enqueue] 는 작업 중이면 대기열에 넣고 아니면 바로 실행한다. 끝나면 다음 작업을 이어서 실행.
|
|
/// 돌려주는 Future 는 그 작업이 실제로 끝날 때 (대기 중에 [cancelPending] 으로 빠지면 바로) 끝난다.
|
|
/// 상태가 바뀔 때마다 [onChanged], 대기열에 넣을 때 [log].
|
|
class JobQueue {
|
|
final void Function() onChanged;
|
|
final void Function(String msg) log;
|
|
JobQueue({required this.onChanged, required this.log});
|
|
|
|
/// 작업 중인지 (화면 시험은 직접 정하기도 한다)
|
|
bool busy = false;
|
|
|
|
/// 실행 중인 작업 이름 (없으면 null)
|
|
String? current;
|
|
|
|
/// 대기 중인 작업 이름 (차례대로)
|
|
final List<String> pending = [];
|
|
final List<(Future<void> Function(), Completer<void>)> _runs = [];
|
|
|
|
Future<void> enqueue(String label, Future<void> Function() job) {
|
|
if (busy) {
|
|
final done = Completer<void>();
|
|
pending.add(label);
|
|
_runs.add((job, done));
|
|
log(trf('대기열에 추가: {0} (대기 {1}개)', [label, pending.length]));
|
|
onChanged();
|
|
return done.future;
|
|
}
|
|
return _run(label, job);
|
|
}
|
|
|
|
Future<void> _run(String label, Future<void> Function() job) async {
|
|
busy = true;
|
|
current = label;
|
|
onChanged();
|
|
try {
|
|
await job();
|
|
} finally {
|
|
busy = false;
|
|
current = null;
|
|
onChanged();
|
|
if (_runs.isNotEmpty) {
|
|
final (next, done) = _runs.removeAt(0);
|
|
final nextLabel = pending.removeAt(0);
|
|
unawaited(_run(nextLabel, next).then((_) => done.complete(), onError: done.completeError));
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 대기 중인 작업을 모두 뺀다 (지금 작업은 그대로). 뺀 수
|
|
int cancelPending() {
|
|
final n = pending.length;
|
|
pending.clear();
|
|
for (final (_, done) in _runs) {
|
|
done.complete();
|
|
}
|
|
_runs.clear();
|
|
return n;
|
|
}
|
|
}
|