Browse Source

Write Interface trait and Transport

interface-2
Lev 3 years ago
parent
commit
790e471b69
  1. 110
      Cargo.lock
  2. 3
      Cargo.toml
  3. 1
      src/crypto.rs
  4. 42
      src/interface.rs
  5. 6
      src/interfaces/mod.rs
  6. 6
      src/lib.rs
  7. 5
      src/message.rs
  8. 19
      src/res.rs
  9. 94
      src/transport.rs

110
Cargo.lock generated

@ -65,6 +65,50 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d6f2aa4d0537bcc1c74df8755072bd31c1ef1a3a1b85a68e8404a8c353b7b8b"
[[package]]
name = "crossbeam-channel"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4"
dependencies = [
"cfg-if",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-deque"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e"
dependencies = [
"cfg-if",
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd"
dependencies = [
"cfg-if",
"crossbeam-utils",
"lazy_static",
"memoffset",
"scopeguard",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db"
dependencies = [
"cfg-if",
"lazy_static",
]
[[package]]
name = "crypto-bigint"
version = "0.2.11"
@ -104,6 +148,12 @@ dependencies = [
"generic-array 0.14.4",
]
[[package]]
name = "either"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "fake-simd"
version = "0.1.2"
@ -151,12 +201,22 @@ dependencies = [
"wasi 0.10.2+wasi-snapshot-preview1",
]
[[package]]
name = "hermit-abi"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
dependencies = [
"libc",
]
[[package]]
name = "ironforce"
version = "0.1.0"
dependencies = [
"rand",
"rand_os",
"rayon",
"rsa",
"serde",
"sha2",
@ -183,6 +243,15 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]]
name = "memoffset"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9"
dependencies = [
"autocfg 1.0.1",
]
[[package]]
name = "num-bigint-dig"
version = "0.7.0"
@ -233,6 +302,16 @@ dependencies = [
"libm",
]
[[package]]
name = "num_cpus"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "opaque-debug"
version = "0.2.3"
@ -355,6 +434,31 @@ dependencies = [
"rand_core 0.5.1",
]
[[package]]
name = "rayon"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
dependencies = [
"autocfg 1.0.1",
"crossbeam-deque",
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
dependencies = [
"crossbeam-channel",
"crossbeam-deque",
"crossbeam-utils",
"lazy_static",
"num_cpus",
]
[[package]]
name = "rsa"
version = "0.5.0"
@ -376,6 +480,12 @@ dependencies = [
"zeroize",
]
[[package]]
name = "scopeguard"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "serde"
version = "1.0.130"

3
Cargo.toml

@ -7,7 +7,7 @@ edition = "2018"
[features]
default = []
std = []
std = ["rayon"]
[dependencies]
rand_os = "*"
@ -17,6 +17,7 @@ sha2 = "0.8.1"
rand = "*"
rsa = { version = "0.5", features = ["serde"] }
serde = { version = "1.0", features = ["derive", "alloc"], default-features = false }
rayon = { version = "1.5.1", optional = true }
[profile.dev.package.num-bigint-dig]
opt-level = 3

1
src/crypto.rs

@ -1,7 +1,6 @@
/// This module has wrappers for cryptography with RSA algorithms.
/// Its main structs - `PublicKey` and `Keys` implement all functions for key generation, signatures and asymmetric encryption
use alloc::vec::Vec;
use alloc::vec;
use serde::{Deserialize, Serialize};
use rsa::{RsaPublicKey, RsaPrivateKey, PaddingScheme, PublicKey as RPK};
use rsa::errors::Result as RsaRes;

42
src/interface.rs

@ -1 +1,41 @@
pub trait Interface {}
use alloc::string::String;
use crate::message::MessageBytes;
use crate::res::IFResult;
/// 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(std))]
pub trait InterfaceRequirements {}
#[cfg(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*/)>>;
}

6
src/interfaces/mod.rs

@ -0,0 +1,6 @@
use crate::interface::Interface;
use alloc::vec;
pub fn get_interfaces() -> alloc::vec::Vec<alloc::boxed::Box<dyn Interface>> {
vec![]
}

6
src/lib.rs

@ -10,11 +10,9 @@ mod ironforce;
mod message;
mod transport;
mod interface;
mod interfaces;
mod res;
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}

5
src/message.rs

@ -0,0 +1,5 @@
use alloc::vec::Vec;
/// A serialized message
pub(crate) type MessageBytes = Vec<u8>;

19
src/res.rs

@ -0,0 +1,19 @@
use alloc::format;
use alloc::string::String;
use core::fmt::Debug;
/// An enum for all errors that may occur
pub enum IFError {
/// An error that was created in some dependency and then converted to `IFError`
General(String),
}
impl<T: Debug> From<T> for IFError {
/// Convert from other error
fn from(e: T) -> Self {
Self::General(format!("{:?}", e))
}
}
pub type IFResult<T> = Result<T, IFError>;

94
src/transport.rs

@ -1 +1,95 @@
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))
}
}
}
}

Loading…
Cancel
Save