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.
 
 

175 lines
5.8 KiB

use crate::message::MessageBytes;
use crate::res::IFResult;
use alloc::string::String;
/// Some data that can be provided to the interface to send the message to a target.
///
/// For IP this might be `IP:port`.
/// Radio interface, for example, may not have the functionality of targeting, but that's fine
pub(crate) type TargetingData = String;
/// In an std environment we require that the interface can be send safely between threads
#[cfg(not(feature = "std"))]
pub trait InterfaceRequirements {}
#[cfg(feature = "std")]
pub trait InterfaceRequirements: Send + Sync {}
/// An interface that can be used to
pub trait Interface: InterfaceRequirements {
/// Run one main loop iteration.
/// On platforms that support concurrency, these functions will be run simultaneously for all interfaces.
/// Most likely, this function will accept messages and save them somewhere internally to give out later in `Interface.receive()`.
///
/// For systems that don't support concurrency, there can be only one interface in this function waits for a message (to avoid blocking).
/// That's why it's necessary to check if it is the case for this interface, and it's done using function `Interface::has_blocking_main()`
fn main_loop_iteration(&mut self) -> IFResult<()>;
/// Check if `main_loop_iteration` stops execution and waits for a message
fn has_blocking_main(&self) -> bool {
false // hopefully...
}
/// Get some way of identification for this interface
fn id(&self) -> &str;
/// Send a message. If no `interface_data` is provided, we should consider it to be a broadcast.
/// If, on the other hand, `interface_data` is not `None`, it should be used to send the message to the target.
fn send(
&mut self,
message: &[u8], /*MessageBytes*/
interface_data: Option<TargetingData>,
) -> IFResult<()>;
/// Receive a message through this interface. Returns a result with an option of (message bytes, target).
/// `None` means there is no message available at the time.
/// The implementations of this function shouldn't wait for new messages, but
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData /*interface data*/)>>;
/// Dump the interface to string
fn get_dump_data(&self) -> String;
/// Create the interface from dumped data
fn from_dump(data: String) -> IFResult<Self> where Self: Sized;
}
#[cfg(test)]
pub mod test_interface {
use crate::interface::{Interface, InterfaceRequirements, TargetingData};
use crate::message::MessageBytes;
use crate::res::IFResult;
use alloc::string::String;
use alloc::string::ToString;
use alloc::sync::Arc;
use alloc::vec;
use alloc::vec::Vec;
use spin::Mutex;
#[derive(Default)]
pub struct SimpleTestInterface {
messages: Vec<(Vec<u8>, TargetingData)>,
}
impl InterfaceRequirements for SimpleTestInterface {}
impl Interface for SimpleTestInterface {
fn main_loop_iteration(&mut self) -> IFResult<()> {
Ok(())
}
fn id(&self) -> &str {
"test_interface"
}
fn send(&mut self, message: &[u8], interface_data: Option<TargetingData>) -> IFResult<()> {
self.messages
.push((Vec::from(message), interface_data.unwrap_or_default()));
Ok(())
}
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData)>> {
Ok(self.messages.pop())
}
fn get_dump_data(&self) -> String {
"".to_string()
}
fn from_dump(_data: String) -> IFResult<Self> {
Ok(Default::default())
}
}
pub type Storage = Vec<(Vec<u8>, TargetingData)>;
#[derive(Default)]
pub struct TestInterface {
this_peer_id: String,
storage: Arc<Mutex<Storage>>,
messages: Vec<(Vec<u8>, TargetingData)>,
}
impl Interface for TestInterface {
fn main_loop_iteration(&mut self) -> IFResult<()> {
let mut storage_locked = self.storage.lock();
while let Some(i) = storage_locked
.iter()
.position(|msg| msg.1 == self.this_peer_id || msg.1.is_empty())
{
self.messages.push(storage_locked.remove(i));
}
Ok(())
}
fn id(&self) -> &str {
"test_interface"
}
fn send(&mut self, message: &[u8], target: Option<TargetingData>) -> IFResult<()> {
self.storage
.lock()
.push((Vec::from(message), target.unwrap_or_default()));
Ok(())
}
fn receive(&mut self) -> IFResult<Option<(MessageBytes, TargetingData)>> {
Ok(self.messages.pop())
}
fn get_dump_data(&self) -> String {
"".to_string()
}
fn from_dump(_data: String) -> IFResult<Self> {
Ok(TestInterface {
this_peer_id: "".to_string(),
storage: Arc::new(Default::default()),
messages: vec![],
})
}
}
impl InterfaceRequirements for TestInterface {}
pub fn create_test_interfaces(n: usize) -> Vec<TestInterface> {
let storage_mutex = Arc::new(Mutex::new(vec![]));
(0..n)
.map(|i| TestInterface {
this_peer_id: i.to_string(),
storage: storage_mutex.clone(),
messages: vec![],
})
.collect()
}
#[test]
fn test_test_interface() {
let mut interfaces = create_test_interfaces(2);
interfaces[0].send(b"123", Some("1".to_string())).unwrap();
interfaces[1].main_loop_iteration().unwrap();
assert_eq!(
interfaces[1].receive().unwrap().unwrap().0.as_slice(),
b"123"
);
}
}