diff --git a/src/device.rs b/src/device.rs index 9b384ee23..f9044f123 100644 --- a/src/device.rs +++ b/src/device.rs @@ -453,6 +453,11 @@ struct Runtime { /// Some of the events are time based, so just poll the whole state from time to time polling_interval: Interval, + /// Store most recent reported event to the apps per node + /// + /// TODO: This is planned to be refactored into a bit better solution in https://github.com/NordSecurity/libtelio/pull/1021 + last_transmitted_event: HashMap, + #[cfg(test)] /// MockedAdapter (tests) test_env: telio_wg::tests::Env, @@ -1275,6 +1280,7 @@ impl Runtime { derp_events_publisher: derp_events.tx, }, polling_interval, + last_transmitted_event: Default::default(), #[cfg(test)] test_env: wg::tests::Env { analytics: analytics_ch, @@ -2302,6 +2308,21 @@ impl Runtime { } } } + + fn is_dublicated_event(&mut self, node: &Node) -> bool { + match self.last_transmitted_event.get(&node.public_key) { + None => node.state == PeerState::Disconnected, + Some(last_node) => *node == *last_node, + } + } + + fn remember_last_transmitted_node_event(&mut self, node: Node) { + if node.state == PeerState::Disconnected { + self.last_transmitted_event.remove(&node.public_key); + } else { + self.last_transmitted_event.insert(node.public_key, node); + } + } } #[async_trait] @@ -2364,11 +2385,13 @@ impl TaskRuntime for Runtime { if let Some(node) = node { // Publish WG event to app - let event = Event::builder::().set(node).build(); - if let Some(event) = event { - let _ = self.event_publishers.libtelio_event_publisher.send( - Box::new(event) - ); + if let Some(event) = Event::builder::().set(node.clone()).build() { + if !self.is_dublicated_event(&node) { + let _ = self.event_publishers.libtelio_event_publisher.send( + Box::new(event) + ); + self.remember_last_transmitted_node_event(node); + } } } @@ -2418,26 +2441,36 @@ impl TaskRuntime for Runtime { match (&pq_event, &self.requested_state.exit_node, &self.requested_state.last_exit_node) { (telio_pq::Event::Connecting(pubkey), Some(exit), _) if exit.public_key == *pubkey => { - let body = Node { + let node = Node { state: PeerState::Connecting, link_state: Some(LinkState::Down), ..node_from_exit_node(exit) }; - let _ = self.event_publishers.libtelio_event_publisher.send( - Box::new(Event::Node { body }) - ); + if let Some(event) = Event::builder::().set(node.clone()).build() { + if !self.is_dublicated_event(&node) { + let _ = self.event_publishers.libtelio_event_publisher.send( + Box::new(event) + ); + self.remember_last_transmitted_node_event(node); + } + } }, (telio_pq::Event::Disconnected(pubkey), _, Some(last_exit)) if last_exit.public_key == *pubkey => { - let body = Node { + let node = Node { state: PeerState::Disconnected, link_state: Some(LinkState::Down), ..node_from_exit_node(last_exit) }; - let _ = self.event_publishers.libtelio_event_publisher.send( - Box::new(Event::Node { body }) - ); + if let Some(event) = Event::builder::().set(node.clone()).build() { + if !self.is_dublicated_event(&node) { + let _ = self.event_publishers.libtelio_event_publisher.send( + Box::new(event) + ); + self.remember_last_transmitted_node_event(node); + } + } }, _ => (), }