use alloc::boxed::Box; use alloc::string::String; use alloc::vec::Vec; use crate::interface::{Interface, TargetingData}; use crate::message::MessageBytes; use crate::res::IFResult; #[cfg(std)] use rayon::prelude::*; /// An identification of a peer - something that we can use to send a message to id #[derive(Clone, Debug)] pub struct PeerInfo { /// Something to locally identify this peer pub peer_id: u64, /// ID of the interface through which we communicate with this peer pub interface_id: String, /// Data that should be passed to the interface to send a message to this peer pub interface_targeting_data: TargetingData, } impl PeerInfo { fn new(interface_id: String, interface_targeting_data: TargetingData) -> Self { Self { peer_id: rand::random(), interface_id, interface_targeting_data, } } } /// The struct that manages all the communication with peers pub struct Transport { pub interfaces: Vec>, peers: Vec, } impl Transport { /// Find a peer in `self.peers` by its id fn get_peer_by_id(&self, peer_id: u64) -> Option { self.peers.iter().find(|peer| peer.peer_id == peer_id).cloned() } /// Try to find a peer in `self.peers` by interface_id and targeting data fn get_peer_by_parameters(&self, interface_id: &str, data: &str /*&TargetingData*/) -> Option<&PeerInfo> { self.peers.iter().find(|peer| peer.interface_id == interface_id && peer.interface_targeting_data == data) } /// Insert a new peer into out database and return its id or find an existing one with these parameters fn find_or_add_peer(&mut self, interface_id: String, data: TargetingData) -> u64 { match self.get_peer_by_parameters(interface_id.as_str(), &data) { None => { let new_peer = PeerInfo::new(interface_id, data); let peer_id = new_peer.peer_id; self.peers.push(new_peer); peer_id } Some(peer) => peer.peer_id } } /// Get interface index by its ID fn interface_index_by_id(&self, interface_id: &str) -> usize { self.interfaces.iter().position(|interface| interface.id() == interface_id).unwrap_or_else(|| panic!("Invalid interface id")) } /// Send message bytes to a peer if data is provided or broadcast the data if `peer == None` pub fn send_message(&mut self, message: MessageBytes, peer_id: Option) -> IFResult<()> { let peer = if let Some(peer_id) = peer_id { self.get_peer_by_id(peer_id) } else { None }; match peer { // Broadcast None => { #[cfg(not(std))] { for interface in &mut self.interfaces { interface.send(&message, None)?; } } // If we have concurrency, we will do it concurrently #[cfg(std)] { self.interfaces.par_iter_mut().map(|interface| interface.send(&message, None)).for_each(drop); } Ok(()) } // Singlecast Some(peer) => { let interface_ind = self.interface_index_by_id(peer.interface_id.as_str()); self.interfaces[interface_ind].send(&message, Some(peer.interface_targeting_data)) } } } }