write method
Writes bytes to uri atomically. With expected, refuses with a
TomFileConflict when the file is no longer that revision. Answers
the revision written.
Implementation
@override
Future<TomFileRevision> write(
Uri uri,
Uint8List bytes, {
TomFileRevision? expected,
}) async {
final target = File(localPathOf(uri));
final existed = target.existsSync();
if (expected != null) {
final current = existed
? TomFileRevision.of(
await target.readAsBytes(),
await target.lastModified(),
)
: null;
if (current != expected) throw TomFileConflict(absolute(uri), current);
}
// Atomic: a sibling temporary file, flushed, renamed over the target. A
// crash leaves either the old file or the new one, never half of one.
final temp = File(
p.join(
target.parent.path,
'.${p.basename(target.path)}.tom-'
'${DateTime.now().microsecondsSinceEpoch}.tmp',
),
);
final handle = await temp.open(mode: FileMode.writeOnly);
try {
await handle.writeFrom(bytes);
await handle.flush();
} finally {
await handle.close();
}
await temp.rename(target.path);
emitChange(
uri,
existed ? TomFileChangeType.modified : TomFileChangeType.created,
);
return TomFileRevision.of(bytes, await target.lastModified());
}