Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 95 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ libadwaita = { version = "0.9", features = ["v1_5"] }
notify = "8"
rand = "0.10"
roxmltree = "0.21"
rusqlite = { version = "0.32", features = ["bundled"] }
rustls = "0.23"
rustls-native-certs = "0.8"
secret-service = { version = "5", features = ["rt-tokio-crypto-rust"] }
Expand Down
34 changes: 25 additions & 9 deletions src/core/account_runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,19 +167,33 @@ impl WatcherTargets {
}
}

/// A remote file hint triggers a remote-push sync on every folder, like the
/// Python `NotifyPushClient` callback `scheduler.request(REMOTE_PUSH)`.
fn apply_remote_push(targets: &Rc<RefCell<WatcherTargets>>) {
/// Route a remote file hint to the folders that contain the notified files.
///
/// With `notify_file_id` (issue #183) each notified id maps to the folder
/// whose external journal knows that file (`has_file_ids`), so only those
/// folders get a remote-push sync instead of re-syncing every folder of
/// the account. A legacy `notify_file` (empty ids) fans out to every
/// folder, preserving the original `NotifyPushClient` behaviour.
fn apply_remote_push(targets: &Rc<RefCell<WatcherTargets>>, file_ids: Vec<i64>) {
let schedulers = targets.borrow().schedulers.clone();
for scheduler in &schedulers {
scheduler.request(Trigger::RemotePush);
if file_ids.is_empty() || scheduler.has_file_ids(&file_ids) {
scheduler.request(Trigger::RemotePush);
}
}
}

/// Record the latest push state reported by the client (used for the UI).
fn store_push_state(targets: &Rc<RefCell<WatcherTargets>>, state: PushState, message: String) {
if let Ok(mut current) = targets.try_borrow_mut() {
current.push_state = Some((state, message));
// Issue #185: while push is connected it is the real-time source of
// truth, so the periodic remote-interval poll can be skipped. Tell
// every folder scheduler whether to drop `RemoteInterval`.
let ready = state == PushState::Connected;
for scheduler in &current.schedulers {
scheduler.set_remote_push_ready(ready);
}
}
}

Expand Down Expand Up @@ -876,7 +890,7 @@ impl AccountRuntime {
let state_targets = Rc::clone(&self.targets);
Some(NotifyPushClient::new(
self.account.provider,
move || WatcherTargets::apply_remote_push(&file_targets),
move |file_ids| WatcherTargets::apply_remote_push(&file_targets, file_ids),
move || WatcherTargets::apply_server_notification(&notification_targets),
move |state, message| WatcherTargets::store_push_state(&state_targets, state, message),
))
Expand Down Expand Up @@ -1213,9 +1227,11 @@ impl AccountRuntime {
}

/// Drive the notify_push file-notification fan-out (what the client's
/// `on_file_notification` callback runs in production).
pub(crate) fn simulate_remote_push(&self) {
WatcherTargets::apply_remote_push(&self.targets);
/// `on_file_notification` callback runs in production). An empty list is
/// the legacy `notify_file` fan-out; non-empty ids route to the folders
/// that contain them (issue #183).
pub(crate) fn simulate_remote_push(&self, file_ids: Vec<i64>) {
WatcherTargets::apply_remote_push(&self.targets, file_ids);
}

/// Build the push client for the current account (test mirror of
Expand Down Expand Up @@ -1933,7 +1949,7 @@ mod tests {

// `simulate_remote_push` runs exactly what the NotifyPushClient
// `on_file_notification` callback runs in production.
runtime.simulate_remote_push();
runtime.simulate_remote_push(Vec::new());
assert!(source.borrow().pending() >= 1);
}

Expand Down
Loading
Loading