From fd6ab3e962b8cc1810b1a27914713632ede33a62 Mon Sep 17 00:00:00 2001 From: Aly Raffauf Date: Sun, 2 Aug 2026 21:28:57 -0400 Subject: [PATCH] isolate sync state persistence --- src/storage.rs | 51 +---------------------------------- src/storage/sync_state.rs | 56 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 src/storage/sync_state.rs diff --git a/src/storage.rs b/src/storage.rs index ede6729..3494ad6 100644 --- a/src/storage.rs +++ b/src/storage.rs @@ -19,6 +19,7 @@ use crate::{ mod manifests; mod paths; +mod sync_state; pub use manifests::ManifestRevision; pub use paths::AppPaths; @@ -421,56 +422,6 @@ impl StateStore { u64::try_from(count).map_err(Into::into) } - pub fn record_successful_sync(&self, folder_id: FolderId) -> anyhow::Result<()> { - let completed_at = OffsetDateTime::now_utc().format(&Rfc3339)?; - self.connection.execute( - "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, ?2, NULL) ON CONFLICT(folder_id) DO UPDATE SET last_successful_sync = excluded.last_successful_sync, last_error = NULL", - params![folder_id.to_string(), completed_at], - )?; - Ok(()) - } - - pub fn record_sync_failure( - &self, - folder_id: FolderId, - error: &anyhow::Error, - ) -> anyhow::Result<()> { - self.connection.execute( - "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, NULL, ?2) ON CONFLICT(folder_id) DO UPDATE SET last_error = excluded.last_error", - params![folder_id.to_string(), error.to_string()], - )?; - Ok(()) - } - - pub fn last_successful_sync( - &self, - folder_id: FolderId, - ) -> anyhow::Result> { - let timestamp: Option = self - .connection - .query_row( - "SELECT last_successful_sync FROM sync_state WHERE folder_id = ?1", - params![folder_id.to_string()], - |row| row.get(0), - ) - .optional()?; - timestamp - .map(|value| OffsetDateTime::parse(&value, &Rfc3339).map_err(Into::into)) - .transpose() - } - - pub fn last_sync_error(&self, folder_id: FolderId) -> anyhow::Result> { - self.connection - .query_row( - "SELECT last_error FROM sync_state WHERE folder_id = ?1", - params![folder_id.to_string()], - |row| row.get(0), - ) - .optional() - .map(|value| value.flatten()) - .map_err(Into::into) - } - fn initialize_schema(&self) -> anyhow::Result<()> { self.connection.execute_batch("CREATE TABLE IF NOT EXISTS folders (id TEXT PRIMARY KEY NOT NULL, name TEXT NOT NULL, path TEXT NOT NULL UNIQUE, capability TEXT NOT NULL, mode TEXT NOT NULL DEFAULT '\"send_receive\"'); CREATE TABLE IF NOT EXISTS peers (folder_id TEXT NOT NULL, endpoint TEXT NOT NULL, PRIMARY KEY (folder_id, endpoint)); CREATE TABLE IF NOT EXISTS known_peers (folder_id TEXT NOT NULL, device_id TEXT NOT NULL, endpoint TEXT NOT NULL, last_seen TEXT NOT NULL, PRIMARY KEY (folder_id, device_id)); CREATE TABLE IF NOT EXISTS join_invites (folder_id TEXT PRIMARY KEY NOT NULL, invite TEXT NOT NULL); CREATE TABLE IF NOT EXISTS members (folder_id TEXT NOT NULL, device_id TEXT NOT NULL, label TEXT, is_active BOOLEAN NOT NULL, PRIMARY KEY (folder_id, device_id)); CREATE TABLE IF NOT EXISTS folder_rosters (folder_id TEXT PRIMARY KEY NOT NULL, epoch INTEGER NOT NULL, roster TEXT NOT NULL); CREATE TABLE IF NOT EXISTS previous_capabilities (folder_id TEXT PRIMARY KEY NOT NULL, capability TEXT NOT NULL); CREATE TABLE IF NOT EXISTS settings (key TEXT PRIMARY KEY NOT NULL, value TEXT NOT NULL); CREATE TABLE IF NOT EXISTS manifests (folder_id TEXT PRIMARY KEY NOT NULL, manifest TEXT NOT NULL); CREATE TABLE IF NOT EXISTS manifest_history (revision INTEGER PRIMARY KEY AUTOINCREMENT, folder_id TEXT NOT NULL, saved_at TEXT NOT NULL, manifest TEXT NOT NULL); CREATE TABLE IF NOT EXISTS counters (folder_id TEXT NOT NULL, device_id TEXT NOT NULL, counter INTEGER NOT NULL, PRIMARY KEY (folder_id, device_id)); CREATE TABLE IF NOT EXISTS sync_state (folder_id TEXT PRIMARY KEY NOT NULL, last_successful_sync TEXT, last_error TEXT);")?; Ok(()) diff --git a/src/storage/sync_state.rs b/src/storage/sync_state.rs new file mode 100644 index 0000000..42abab8 --- /dev/null +++ b/src/storage/sync_state.rs @@ -0,0 +1,56 @@ +use rusqlite::{OptionalExtension, params}; +use time::{OffsetDateTime, format_description::well_known::Rfc3339}; + +use crate::{domain::FolderId, storage::StateStore}; + +impl StateStore { + pub fn record_successful_sync(&self, folder_id: FolderId) -> anyhow::Result<()> { + let completed_at = OffsetDateTime::now_utc().format(&Rfc3339)?; + self.connection.execute( + "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, ?2, NULL) ON CONFLICT(folder_id) DO UPDATE SET last_successful_sync = excluded.last_successful_sync, last_error = NULL", + params![folder_id.to_string(), completed_at], + )?; + Ok(()) + } + + pub fn record_sync_failure( + &self, + folder_id: FolderId, + error: &anyhow::Error, + ) -> anyhow::Result<()> { + self.connection.execute( + "INSERT INTO sync_state (folder_id, last_successful_sync, last_error) VALUES (?1, NULL, ?2) ON CONFLICT(folder_id) DO UPDATE SET last_error = excluded.last_error", + params![folder_id.to_string(), error.to_string()], + )?; + Ok(()) + } + + pub fn last_successful_sync( + &self, + folder_id: FolderId, + ) -> anyhow::Result> { + let timestamp: Option = self + .connection + .query_row( + "SELECT last_successful_sync FROM sync_state WHERE folder_id = ?1", + params![folder_id.to_string()], + |row| row.get(0), + ) + .optional()?; + timestamp + .map(|value| OffsetDateTime::parse(&value, &Rfc3339).map_err(Into::into)) + .transpose() + } + + pub fn last_sync_error(&self, folder_id: FolderId) -> anyhow::Result> { + self.connection + .query_row( + "SELECT last_error FROM sync_state WHERE folder_id = ?1", + params![folder_id.to_string()], + |row| row.get(0), + ) + .optional() + .map(|value| value.flatten()) + .map_err(Into::into) + } +} -- 2.51.2