stop forwarding data to remote when no friend is online
This commit is contained in:
@@ -173,7 +173,9 @@ async fn connect(
|
||||
changed = cursor_data.changed() => {
|
||||
changed.map_err(|_| "cursor sender closed")?;
|
||||
let payload = { cursor_data.borrow_and_update().clone() };
|
||||
if let Some(payload) = payload {
|
||||
if let Some(payload) = payload
|
||||
&& friend_presence.has_online_friends(&remote.id)?
|
||||
{
|
||||
send(&mut writer, &ClientMessage::Signed {
|
||||
signature: keypair.sign(&message_bytes(&payload)),
|
||||
payload,
|
||||
@@ -183,7 +185,9 @@ async fn connect(
|
||||
changed = foreground_app_data.changed() => {
|
||||
changed.map_err(|_| "foreground-app sender closed")?;
|
||||
let payload = { foreground_app_data.borrow_and_update().clone() };
|
||||
if let Some(payload) = payload {
|
||||
if let Some(payload) = payload
|
||||
&& friend_presence.has_online_friends(&remote.id)?
|
||||
{
|
||||
send(&mut writer, &ClientMessage::Signed {
|
||||
signature: keypair.sign(&message_bytes(&payload)),
|
||||
payload,
|
||||
|
||||
@@ -95,6 +95,14 @@ impl Network {
|
||||
}
|
||||
|
||||
pub fn send_live_data(&self, data: LiveData) {
|
||||
let active_remotes = match self.friend_presence.active_remotes() {
|
||||
Ok(remotes) if remotes.is_empty() => return,
|
||||
Ok(remotes) => remotes,
|
||||
Err(error) => {
|
||||
eprintln!("failed to read friend presence for live data: {error}");
|
||||
return;
|
||||
}
|
||||
};
|
||||
let sequence = match data.kind() {
|
||||
LiveDataKind::Cursor => self.next_cursor_sequence.fetch_add(1, Ordering::Relaxed),
|
||||
LiveDataKind::ForegroundApp => self
|
||||
@@ -114,7 +122,10 @@ impl Network {
|
||||
eprintln!("failed to lock remote connections for live data");
|
||||
return;
|
||||
};
|
||||
for connection in connections.values() {
|
||||
for (remote_id, connection) in connections.iter() {
|
||||
if !active_remotes.contains(remote_id) {
|
||||
continue;
|
||||
}
|
||||
match envelope.kind() {
|
||||
LiveDataKind::Cursor => {
|
||||
connection.cursor_sender.send_replace(Some(payload.clone()));
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user