stop forwarding data to remote when no friend is online

This commit is contained in:
2026-09-05 02:09:15 +08:00
parent 8a80bf5f59
commit 295ba679dd
3 changed files with 89 additions and 3 deletions
+71
View File
@@ -14,6 +14,16 @@ pub(super) struct Change {
pub(super) struct FriendPresence(Mutex<HashMap<String, HashSet<String>>>);
impl FriendPresence {
pub(super) fn active_remotes(&self) -> Result<HashSet<String>, String> {
let by_remote = self.0.lock().map_err(|error| error.to_string())?;
Ok(by_remote.keys().cloned().collect())
}
pub(super) fn has_online_friends(&self, remote_id: &str) -> Result<bool, String> {
let by_remote = self.0.lock().map_err(|error| error.to_string())?;
Ok(by_remote.contains_key(remote_id))
}
pub(super) fn remotes_for(&self, friend_id: &str) -> Result<HashSet<String>, String> {
let by_remote = self.0.lock().map_err(|error| error.to_string())?;
Ok(by_remote
@@ -128,6 +138,67 @@ fn diff(
mod tests {
use super::{Change, FriendPresence};
#[test]
fn live_data_routes_follow_each_remotes_online_friends() {
let presence = FriendPresence::default();
assert!(presence.active_remotes().unwrap().is_empty());
assert!(!presence.has_online_friends("remote-a").unwrap());
presence
.replace("remote-a", vec!["friend-a".into(), "friend-b".into()])
.unwrap();
presence.replace("remote-b", Vec::new()).unwrap();
assert_eq!(
presence.active_remotes().unwrap(),
["remote-a".to_owned()].into()
);
assert!(!presence.has_online_friends("remote-b").unwrap());
presence
.update("remote-a", "friend-a".into(), false)
.unwrap();
assert!(presence.has_online_friends("remote-a").unwrap());
presence
.update("remote-a", "friend-b".into(), false)
.unwrap();
assert!(!presence.has_online_friends("remote-a").unwrap());
assert!(presence.active_remotes().unwrap().is_empty());
let change = presence
.update("remote-b", "friend-a".into(), true)
.unwrap()
.unwrap();
assert!(
change.route_added,
"resuming must trigger current-state publication"
);
assert!(presence.has_online_friends("remote-b").unwrap());
assert!(!presence.has_online_friends("remote-a").unwrap());
}
#[test]
fn disconnect_snapshot_and_friend_removal_disable_live_data_routes() {
let presence = FriendPresence::default();
for remote in ["disconnected", "empty-snapshot", "removed-friend"] {
presence.update(remote, "friend".into(), true).unwrap();
}
presence.remove("disconnected").unwrap();
presence.replace("empty-snapshot", Vec::new()).unwrap();
assert!(!presence.has_online_friends("disconnected").unwrap());
assert!(!presence.has_online_friends("empty-snapshot").unwrap());
assert!(presence.has_online_friends("removed-friend").unwrap());
presence.retain(&[]).unwrap();
assert!(presence.active_remotes().unwrap().is_empty());
assert!(!presence.has_online_friends("removed-friend").unwrap());
let change = presence
.replace("disconnected", vec!["friend".into()])
.unwrap()
.unwrap();
assert!(change.route_added);
assert!(presence.has_online_friends("disconnected").unwrap());
}
#[test]
fn friend_stays_online_while_any_remote_reports_presence() {
let presence = FriendPresence::default();