use std::net::SocketAddr; use std::net::ToSocketAddrs; use std::pin::Pin; use log::info; use serde::Serialize; use futures::Stream; use tokio::sync::watch; use crate::message::SerializeMessage; /// A node's identifier, which is also its public cryptographic key pub type NodeID = sodiumoxide::crypto::sign::ed25519::PublicKey; /// A node's secret key pub type NodeKey = sodiumoxide::crypto::sign::ed25519::SecretKey; /// A network key pub type NetworkKey = sodiumoxide::crypto::auth::Key; /// A stream of associated data. /// /// The Stream can continue after receiving an error. /// When sent through Netapp, the Vec may be split in smaller chunk in such a way /// consecutive Vec may get merged, but Vec and error code may not be reordered /// /// Error code 255 means the stream was cut before its end. Other codes have no predefined /// meaning, it's up to your application to define their semantic. pub type ByteStream = Pin + Send>>; pub type Packet = Result, u8>; /// Utility function: encodes any serializable value in MessagePack binary format /// using the RMP library. /// /// Field names and variant names are included in the serialization. /// This is used internally by the netapp communication protocol. pub fn rmp_to_vec_all_named( val: &T, ) -> Result<(Vec, Option), rmp_serde::encode::Error> where T: SerializeMessage + ?Sized, { let mut wr = Vec::with_capacity(128); let mut se = rmp_serde::Serializer::new(&mut wr) .with_struct_map() .with_string_variants(); let (val, stream) = val.serialize_msg(); val.serialize(&mut se)?; Ok((wr, stream)) } /// This async function returns only when a true signal was received /// from a watcher that tells us when to exit. /// /// Usefull in a select statement to interrupt another /// future: /// ```ignore /// select!( /// _ = a_long_task() => Success, /// _ = await_exit(must_exit) => Interrupted, /// ) /// ``` pub async fn await_exit(mut must_exit: watch::Receiver) { while !*must_exit.borrow_and_update() { if must_exit.changed().await.is_err() { break; } } } /// Creates a watch that contains `false`, and that changes /// to `true` when a Ctrl+C signal is received. pub fn watch_ctrl_c() -> watch::Receiver { let (send_cancel, watch_cancel) = watch::channel(false); tokio::spawn(async move { tokio::signal::ctrl_c() .await .expect("failed to install CTRL+C signal handler"); info!("Received CTRL+C, shutting down."); send_cancel.send(true).unwrap(); }); watch_cancel } /// Parse a peer's address including public key, written in the format: /// `@:` pub fn parse_peer_addr(peer: &str) -> Option<(NodeID, SocketAddr)> { let delim = peer.find('@')?; let (key, ip) = peer.split_at(delim); let pubkey = NodeID::from_slice(&hex::decode(&key).ok()?)?; let ip = ip[1..].parse::().ok()?; Some((pubkey, ip)) } /// Parse and resolve a peer's address including public key, written in the format: /// `@:` pub fn parse_and_resolve_peer_addr(peer: &str) -> Option<(NodeID, Vec)> { let delim = peer.find('@')?; let (key, host) = peer.split_at(delim); let pubkey = NodeID::from_slice(&hex::decode(&key).ok()?)?; let hosts = host[1..].to_socket_addrs().ok()?.collect::>(); if hosts.is_empty() { return None; } Some((pubkey, hosts)) }