JJ_MKVMaker/lib/platform/windows/session_marker.dart

59 lines
2.0 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
/// 지난 실행이 정상으로 끝났는지 알아내는 표시 (설정 폴더의 session.json).
///
/// 켤 때 "실행 중" 으로 적고 30초마다 살아 있는 시각을 고쳐 적는다. 종료 버튼 · 트레이 종료로 끝나면
/// "정상 종료" 로 바꾼다. 다음에 켤 때 "실행 중" 인 채로 남아 있으면 지난번은 비정상으로 끝난 것이다
/// (프로그램 오류 · 강제 종료 · 전원 꺼짐 등).
class SessionMarker {
final String file;
Timer? _beat;
DateTime _start = DateTime.now();
SessionMarker(this.file);
/// 지난 실행이 비정상으로 끝났으면 (시작 시각, 마지막으로 살아 있던 시각), 아니면 null.
/// 그리고 이번 실행을 "실행 중" 으로 적기 시작한다.
(DateTime, DateTime)? start() {
(DateTime, DateTime)? crashed;
try {
final f = File(file);
if (f.existsSync()) {
final j = jsonDecode(f.readAsStringSync()) as Map<String, dynamic>;
if (j['clean'] != true) {
final s = DateTime.tryParse(j['start'] as String? ?? '');
final seen = DateTime.tryParse(j['lastSeen'] as String? ?? '');
if (s != null && seen != null) crashed = (s, seen);
}
}
} catch (_) {}
_start = DateTime.now();
_write(clean: false);
_beat?.cancel();
_beat = Timer.periodic(const Duration(seconds: 30), (_) => _write(clean: false));
return crashed;
}
/// 정상 종료로 표시 (종료 진행 창의 저장 단계에서)
void markClean() {
_beat?.cancel();
_beat = null;
_write(clean: true);
}
void _write({required bool clean}) {
try {
final tmp = File('$file.$pid.tmp')
..writeAsStringSync(jsonEncode({
'pid': pid,
'start': _start.toIso8601String(),
'lastSeen': DateTime.now().toIso8601String(),
'clean': clean,
}), flush: true);
tmp.renameSync(file);
} catch (_) {}
}
}