feat: Add startup cleanup for stale markers and orphans
This commit introduces a new startup cleanup routine for the Doctate client. The cleanup process reaps stale markers and orphaned audio files to adhere to data minimization principles and maintain client efficiency. Specifically, it performs the following actions: - Removes markers that are older than 72 hours and have been confirmed by the server. This ensures that old, irrelevant metadata is purged. - Cleans up orphaned audio files (e.g., `.m4a` without corresponding `.meta.json` or vice-versa) that are older than 24 hours. This prevents the accumulation of audio data that will never be uploaded, as such files are silently ignored by the uploader. - Removes any temporary files (`.tmp`) left over from interrupted writes, as these are considered invalid at startup. The `filetime` crate is added as a dependency to facilitate setting modification times for testing purposes.
This commit is contained in:
@@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use doctate_client_core::{
|
||||
CaseMarker, CaseStore, OnelinerPoller, PollerConfig, SnapshotCache,
|
||||
cleanup_orphan_audio, CaseMarker, CaseStore, OnelinerPoller, PollerConfig, SnapshotCache,
|
||||
};
|
||||
use doctate_common::timestamp::{now_rfc3339, recorded_at_to_filename_stem};
|
||||
use eframe::egui;
|
||||
@@ -86,6 +86,32 @@ impl DoctateApp {
|
||||
let snapshot_cache = Arc::new(SnapshotCache::new(snapshot_cache_path));
|
||||
let http_client = Arc::new(reqwest::Client::new());
|
||||
|
||||
// Startup cleanup — runs once, before the poller and uploader
|
||||
// spawn. Keeps the client a lean ephemeral microphone:
|
||||
// - markers older than 72 h (and server-confirmed) drop out,
|
||||
// - orphan audio older than 24 h is reaped (patient-data
|
||||
// minimization; a file that never found its sidecar will
|
||||
// never be uploaded).
|
||||
{
|
||||
let store = case_store.clone();
|
||||
let pending = pending_dir.clone();
|
||||
runtime.block_on(async move {
|
||||
let marker_cutoff =
|
||||
time::OffsetDateTime::now_utc() - time::Duration::hours(72);
|
||||
match store.cleanup_stale(marker_cutoff).await {
|
||||
Ok(n) if n > 0 => info!(count = n, "startup cleanup: stale markers removed"),
|
||||
Ok(_) => {}
|
||||
Err(e) => warn!(error = %e, "startup cleanup: marker sweep failed"),
|
||||
}
|
||||
let audio_cutoff = std::time::SystemTime::now()
|
||||
- std::time::Duration::from_secs(24 * 3600);
|
||||
let n = cleanup_orphan_audio(&pending, audio_cutoff).await;
|
||||
if n > 0 {
|
||||
info!(count = n, "startup cleanup: orphan audio removed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let (state, uploader, upload_events, poller) = if let Some(cfg) = &config {
|
||||
let (up, rx, pol) = spawn_background(
|
||||
&runtime,
|
||||
|
||||
Reference in New Issue
Block a user