From 5fee9a5b20fb850fe6388bad236797c2c1c46071 Mon Sep 17 00:00:00 2001 From: Brayo Date: Sat, 13 Jun 2026 15:44:02 +0300 Subject: [PATCH 1/3] feat(aw-sync): add --mode option to daemon subcommand The daemon previously hardcoded SyncMode::Both, requiring users to run "aw-sync sync" in a loop to get push-only or pull-only behavior. Adds the same --mode push|pull|both flag already available on the sync subcommand. Closes #485 --- aw-sync/README.md | 4 ++++ aw-sync/src/main.rs | 12 ++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/aw-sync/README.md b/aw-sync/README.md index 5d0f2874..01b43dcc 100644 --- a/aw-sync/README.md +++ b/aw-sync/README.md @@ -24,6 +24,10 @@ aw-sync daemon # Sync daemon with specific buckets only aw-sync daemon --buckets "aw-watcher-window,aw-watcher-afk" --start-date "2024-01-01" +# Sync daemon in push-only or pull-only mode +aw-sync daemon --mode push +aw-sync daemon --mode pull + # Sync all buckets once and exit aw-sync sync --start-date "2024-01-01" ``` diff --git a/aw-sync/src/main.rs b/aw-sync/src/main.rs index d06516f5..dc1773c6 100644 --- a/aw-sync/src/main.rs +++ b/aw-sync/src/main.rs @@ -74,6 +74,11 @@ enum Commands { #[clap(long, value_parser=parse_list)] buckets: Option>, + /// Mode to sync in. Can be "push", "pull", or "both". + /// Defaults to "both". + #[clap(long, default_value = "both")] + mode: sync::SyncMode, + /// Full path to sync db file /// Useful for syncing buckets from a specific db file in the sync directory. /// Must be a valid absolute path to a file in the sync directory. @@ -166,19 +171,21 @@ fn main() -> Result<(), Box> { match opts.command.unwrap_or(Commands::Daemon { start_date: None, buckets: None, + mode: sync::SyncMode::Both, sync_db: None, }) { // Start daemon Commands::Daemon { start_date, buckets, + mode, sync_db, } => { info!("Starting daemon..."); let effective_buckets = buckets; - daemon(&client, start_date, effective_buckets, sync_db)?; + daemon(&client, start_date, effective_buckets, sync_db, mode)?; } // Perform sync Commands::Sync { @@ -251,6 +258,7 @@ fn daemon( start_date: Option>, buckets: Option>, sync_db: Option, + mode: sync::SyncMode, ) -> Result<(), Box> { let (tx, rx) = channel(); @@ -278,7 +286,7 @@ fn daemon( }; loop { - if let Err(e) = sync::sync_run(client, &sync_spec, sync::SyncMode::Both) { + if let Err(e) = sync::sync_run(client, &sync_spec, mode) { error!("Error during sync cycle: {}", e); return Err(e); } From 52a6a53967218335e3e9407acab00920b239452e Mon Sep 17 00:00:00 2001 From: Brayo Date: Sat, 13 Jun 2026 15:44:12 +0300 Subject: [PATCH 2/3] fix(aw-sync): respect --start-date on initial bucket sync SyncSpec.start was parsed from the CLI but never read by sync_one, so --start-date had no effect. Now used as the resume point when a destination bucket has no events yet (first sync), falling back to the last-synced event's end time on subsequent runs as before. --- aw-sync/src/sync.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/aw-sync/src/sync.rs b/aw-sync/src/sync.rs index 64618561..d8dfd5c5 100644 --- a/aw-sync/src/sync.rs +++ b/aw-sync/src/sync.rs @@ -289,7 +289,7 @@ pub fn sync_datastores( for bucket_from in buckets_from { let bucket_to = get_or_create_sync_bucket(&bucket_from, ds_to, is_push); - sync_one(ds_from, ds_to, bucket_from, bucket_to); + sync_one(ds_from, ds_to, bucket_from, bucket_to, sync_spec); } } @@ -299,6 +299,7 @@ fn sync_one( ds_to: &dyn AccessMethod, bucket_from: Bucket, bucket_to: Bucket, + sync_spec: &SyncSpec, ) { let eventcount_to_old = ds_to.get_event_count(bucket_to.id.as_str()).unwrap(); info!(" ⟳ Syncing bucket '{}'", bucket_to.id); @@ -310,7 +311,12 @@ fn sync_one( let most_recent_events = ds_to .get_events(bucket_to.id.as_str(), None, None, Some(1)) .unwrap(); - let resume_sync_at = most_recent_events.first().map(|e| e.timestamp + e.duration); + // If the destination bucket already has events, resume from where it left off. + // Otherwise (first sync of this bucket), fall back to sync_spec.start, if specified. + let resume_sync_at = most_recent_events + .first() + .map(|e| e.timestamp + e.duration) + .or(sync_spec.start); if let Some(resume_time) = resume_sync_at { info!(" + Resuming at {:?}", resume_time); From b064eae16fe8768d66664294d73e58f8c368ab83 Mon Sep 17 00:00:00 2001 From: Brayo Date: Sat, 13 Jun 2026 15:54:39 +0300 Subject: [PATCH 3/3] fix(aw-sync): make --mode take effect on aw-sync sync Previously, "aw-sync sync --mode push" with no other flags fell through to the legacy host-based sync path, which always does both a pull and a push regardless of --mode. Make mode an Option so an explicit --mode opts into the advanced sync path (where it's respected), matching the documented behavior. --- aw-sync/README.md | 1 + aw-sync/src/main.rs | 15 ++++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/aw-sync/README.md b/aw-sync/README.md index 01b43dcc..9e128535 100644 --- a/aw-sync/README.md +++ b/aw-sync/README.md @@ -39,6 +39,7 @@ For more options, see `aw-sync --help`. Some notable options: - `--start-date`: Only sync events after this date (YYYY-MM-DD) - `--sync-db`: Specify a specific database file in the sync directory - `--mode`: Choose sync mode: "push", "pull", or "both" (default: "both") + - For `aw-sync sync`, passing `--mode` (with no other options) is enough to opt into the per-bucket sync path where it's respected; without it, or any of `--buckets`/`--start-date`/`--sync-db`, `aw-sync sync` falls back to the legacy host-based mode, which always does both a pull and a push ### Setting up sync diff --git a/aw-sync/src/main.rs b/aw-sync/src/main.rs index dc1773c6..46a73e03 100644 --- a/aw-sync/src/main.rs +++ b/aw-sync/src/main.rs @@ -108,9 +108,10 @@ enum Commands { buckets: Option>, /// Mode to sync in. Can be "push", "pull", or "both". - /// Defaults to "both". - #[clap(long, default_value = "both")] - mode: sync::SyncMode, + /// Defaults to "both". Implies advanced sync mode (see below), + /// since the simple host-based sync mode always does both. + #[clap(long)] + mode: Option, /// Full path to sync db file /// Useful for syncing buckets from a specific db file in the sync directory. @@ -198,7 +199,11 @@ fn main() -> Result<(), Box> { let effective_buckets = buckets; // If advanced options are provided, use advanced sync mode - if start_date.is_some() || effective_buckets.is_some() || sync_db.is_some() { + if start_date.is_some() + || effective_buckets.is_some() + || sync_db.is_some() + || mode.is_some() + { let sync_dir = dirs::get_sync_dir()?; if let Some(db_path) = &sync_db { info!("Using sync db: {}", &db_path.display()); @@ -218,7 +223,7 @@ fn main() -> Result<(), Box> { start: start_date, }; - sync::sync_run(&client, &sync_spec, mode)? + sync::sync_run(&client, &sync_spec, mode.unwrap_or(sync::SyncMode::Both))? } else { // Simple host-based sync mode (backwards compatibility) // Pull