64 lines
2.1 KiB
Dart
64 lines
2.1 KiB
Dart
import 'dart:io';
|
|
import 'dart:convert';
|
|
|
|
import 'snapshot_store.dart';
|
|
import '../domain/app_snapshot.dart';
|
|
|
|
class FileSnapshotStore extends SnapshotStore {
|
|
FileSnapshotStore(this.directory);
|
|
final Directory directory;
|
|
File get _file => File('${directory.path}/hepan_snapshot.json');
|
|
File get _backup => File('${directory.path}/hepan_snapshot.bak');
|
|
Future<AppSnapshot> _read(File file) async {
|
|
final value = jsonDecode(await file.readAsString());
|
|
if (value is! Map<String, dynamic>) throw const FormatException('保存文件损坏');
|
|
return AppSnapshot.fromJson(value);
|
|
}
|
|
|
|
@override
|
|
Future<AppSnapshot?> load() async =>
|
|
await _file.exists() ? await _read(_file) : null;
|
|
@override
|
|
Future<void> save(AppSnapshot snapshot) async {
|
|
await directory.create(recursive: true);
|
|
final text = jsonEncode(snapshot.toJson());
|
|
// Validate before touching the last successfully saved version.
|
|
AppSnapshot.fromJson(jsonDecode(text) as Map<String, dynamic>);
|
|
if (await _file.exists()) {
|
|
try {
|
|
await _read(_file);
|
|
await _file.copy(_backup.path);
|
|
} on FormatException {
|
|
/* Keep an existing valid backup. */
|
|
}
|
|
}
|
|
final temporary = File('${_file.path}.tmp');
|
|
await temporary.writeAsString(text, flush: true);
|
|
await temporary.rename(_file.path);
|
|
}
|
|
|
|
@override
|
|
Future<AppSnapshot> restoreBackup() async {
|
|
if (!await _backup.exists()) throw StateError('没有可恢复的备份');
|
|
final previous = await _read(_backup);
|
|
final temporary = File('${_file.path}.tmp');
|
|
await temporary.writeAsString(jsonEncode(previous.toJson()), flush: true);
|
|
await temporary.rename(_file.path);
|
|
return previous;
|
|
}
|
|
|
|
@override
|
|
Future<AppSnapshot> startFresh() async {
|
|
await directory.create(recursive: true);
|
|
final stamp = DateTime.now().toUtc().microsecondsSinceEpoch;
|
|
for (final file in [_file, _backup]) {
|
|
if (await file.exists()) {
|
|
await file.rename('${file.path}.damaged-$stamp');
|
|
}
|
|
}
|
|
final fresh = AppSnapshot();
|
|
await save(fresh);
|
|
return fresh;
|
|
}
|
|
}
|