IronForce is a decentralized network, Degeon is a messenger built on it
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

95 lines
3.4 KiB

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<Box<dyn Interface>>,
peers: Vec<PeerInfo>,
}
impl Transport {
/// Find a peer in `self.peers` by its id
fn get_peer_by_id(&self, peer_id: u64) -> Option<PeerInfo> {
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<u64>) -> 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))
}
}
}
}