diff --git a/src/ironforce.rs b/src/ironforce.rs index f5f4ad8..bb482b9 100644 --- a/src/ironforce.rs +++ b/src/ironforce.rs @@ -1,5 +1,74 @@ +use alloc::vec::Vec; +use alloc::vec; +use crate::crypto::PublicKey; +use crate::message::{Message, MessageType, ServiceMessageType}; +use crate::res::{IFError, IFResult}; use crate::transport::Transport; +use crate::tunnel::Tunnel; + +/// Main worker pub struct IronForce { - transport: Transport + /// the struct that manages communicating with neighbor nodes + transport: Transport, + /// Tunnels that are known to this node + tunnels: Vec, + /// Additional modules that may be plugged in later, + /// for example internet access (like Tor) + /// and some kind of decentralized storage + additional_modules: Vec<()>, + /// Non-service messages to give outside + messages: Vec, +} + +impl IronForce { + /// Create new worker + pub fn new() -> Self { + Self { + transport: Transport::new(crate::interfaces::get_interfaces()), + tunnels: vec![], + additional_modules: vec![], + messages: vec![], + } + } + + /// Create a new tunnel to another node + fn create_new_tunnel(&mut self, _destination: PublicKey) -> IFResult { + todo!() + } + + /// Send a message through tunnel + fn send_through_tunnel(&mut self, _tunnel_id: u64, _message: Message, _direction: Option) -> IFResult<()> { + todo!() + } + + /// Send a message to another node, + /// creating a new tunnel if needed + pub fn send_message(&mut self, message: Message, destination: PublicKey) -> IFResult<()> { + if let Some(Some(tunnel_id)) = self.tunnels.iter() + .find(|t| t.target_node.as_ref() == Some(&destination) || t.nodes_in_tunnel.as_ref().map(|nodes| nodes.contains(&destination)) == Some(true)) + .map(|tunnel| tunnel.id) { + self.send_through_tunnel(tunnel_id, message, None) + } else { + Err(IFError::TunnelNotFound) + } + } + + /// Process a message: if it's a service message, act accordingly. + /// Otherwise, add to `self.messages` + fn process_message(&mut self, message: Message) { + match message.message_type { + MessageType::Service(msg_type) => match msg_type { + ServiceMessageType::TunnelBuilding(_tunnel) => { + todo!() + } + } + MessageType::SingleCast | MessageType::Broadcast => { self.messages.push(message) } + } + } + + /// Get a message from `self.messages` + pub fn read_message(&mut self) -> Option { + self.messages.pop() + } } diff --git a/src/lib.rs b/src/lib.rs index 56859e4..80d2577 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ extern crate alloc; extern crate rand; extern crate rsa; +extern crate serde; extern crate core_error; mod crypto; diff --git a/src/message.rs b/src/message.rs index 359a961..8a5cc34 100644 --- a/src/message.rs +++ b/src/message.rs @@ -1,13 +1,16 @@ +use alloc::string::String; use alloc::vec::Vec; use crate::crypto::{Keys, PublicKey}; use crate::res::IFResult; use crate::tunnel::TunnelPublic; +use serde::{Serialize, Deserialize}; /// A serialized message pub(crate) type MessageBytes = Vec; - +/// Signature of the message: optional and optionally encrypted sender's key and signed hash +#[derive(Serialize, Deserialize, Clone)] pub enum Signature { /// The message is signed. Author is unknown NotSigned, @@ -20,19 +23,35 @@ pub enum Signature { SignedPrivately { sender_encrypted: Vec, signature: Vec, + }, +} + +/// Network name and version +#[derive(Serialize, Deserialize, Clone)] +struct NetworkInfo { + network_name: String, + version: String, +} + +impl Default for NetworkInfo { + fn default() -> Self { + Self { version: String::from("0.1.0"), network_name: String::from("test") } } } +#[derive(Serialize, Deserialize, Clone)] pub enum MessageType { SingleCast, Broadcast, Service(ServiceMessageType), } +#[derive(Serialize, Deserialize, Clone)] pub enum ServiceMessageType { TunnelBuilding(TunnelPublic) } +#[derive(Serialize, Deserialize, Clone)] pub enum MessageContent { /// Just plaintext message content Plain(Vec), @@ -40,13 +59,14 @@ pub enum MessageContent { Encrypted(Vec), } +#[derive(Serialize, Deserialize, Clone)] pub struct Message { /// Content of the message (not to be confused with the bytes that we are sending through interfaces) - content: MessageContent, + pub content: MessageContent, /// The type of this message - message_type: MessageType, + pub message_type: MessageType, /// Sender's signature - signature: Signature, + pub signature: Signature, /// A random number that is used in hash together with the content salt: u64, /// Hash of message content and the salt @@ -55,6 +75,8 @@ pub struct Message { recipient_verification: Option>, /// ID of the tunnel that is used tunnel_id: u64, + /// Network info + network_info: NetworkInfo, } impl Message { diff --git a/src/res.rs b/src/res.rs index 0b282c6..f06648d 100644 --- a/src/res.rs +++ b/src/res.rs @@ -7,6 +7,8 @@ use core::fmt::Debug; pub enum IFError { /// An error that was created in some dependency and then converted to `IFError` General(String), + /// A tunnel satisfying some conditions has not been found + TunnelNotFound, } diff --git a/src/transport.rs b/src/transport.rs index ab5e3c1..89d5dea 100644 --- a/src/transport.rs +++ b/src/transport.rs @@ -134,7 +134,7 @@ impl Transport { self.interfaces.par_iter_mut().map(|interface| interface.main_loop_iteration()).collect::>()?; #[cfg(not(std))] { - self.interfaces.iter_mut().map(|interface| if !interface.has_blocking_main() { interface.main_loop_iteration() } else { Ok(()) }).collect::>()?; + self.interfaces.iter_mut().try_for_each(|interface| if !interface.has_blocking_main() { interface.main_loop_iteration() } else { Ok(()) })?; let blocking_interface_index = self.interfaces.iter().position(|interface| interface.has_blocking_main()); if let Some(ind) = blocking_interface_index { self.interfaces[ind].main_loop_iteration()?; diff --git a/src/tunnel.rs b/src/tunnel.rs index ac44110..db5be37 100644 --- a/src/tunnel.rs +++ b/src/tunnel.rs @@ -1,30 +1,36 @@ use alloc::vec::Vec; use crate::crypto::PublicKey; +use serde::{Serialize, Deserialize}; /// A tunnel that is used for communication +#[derive(Serialize, Clone, Deserialize)] pub struct Tunnel { - /// Tunnel's id - id: Option, - /// Ids that are - local_ids: Vec, + /// Tunnel's id. + /// By the way, this id is `None` until the tunnel is validated in the backward movement + pub id: Option, + /// Ids, each of them is just for local storage on each node until a final global id is created + pub local_ids: Vec, /// Ids of peers (in transport) by which we can send a message - one for backward direction, another for forward - peer_ids: (u64, u64), + pub peer_ids: (u64, u64), /// Time at which this tunnel should be destroyed (UNIX epoch) - ttd: u64, - /// Public keys of nodes - nodes_in_tunnel: Option>, + pub ttd: u64, + /// Public keys of nodes in the tunnel + pub nodes_in_tunnel: Option>, /// Is this tunnel used for multicast? - is_multicast: bool, + pub is_multicast: bool, + /// If we created this tunnel, then this is the node that it's used to communicate with + pub target_node: Option, } /// Tunnel, but only the fields that are ok to share +#[derive(Serialize, Clone, Deserialize)] pub struct TunnelPublic { /// Tunnel's id id: Option, - /// Ids that are + /// Ids, each of them is just for local storage on each node until a final global id is created local_ids: Vec, /// Time at which this tunnel should be destroyed (UNIX epoch) ttd: u64, - /// Public keys of nodes + /// Public keys of nodes in the tunnel nodes_in_tunnel: Option>, }