Marcel Märtens 33085f1645 COMPLETE REDESIGN of network crate
- Implementing a async non-io protocol crate
    a) no tokio / no channels
    b) I/O is based on abstraction Sink/Drain
    c) different Protocols can have a different Drain Type
       This allow MPSC to send its content without splitting up messages at all!
       It allows UDP to have internal extra frames to care for security
       It allows better abstraction for tests
       Allows benchmarks on the mpsc variant
       Custom Handshakes to allow sth like Quic protocol easily
 - reduce the participant managers to 4: channel creations, send, recv and shutdown.
   keeping the `mut data` in one manager removes the need for all RwLocks.
   reducing complexity and parallel access problems
 - more strategic participant shutdown. first send. then wait for remote side to notice recv stop, then remote side will stop send, then local side can stop recv.
 - metrics are internally abstracted to fit protocol and network layer
 - in this commit network/protocol tests work and network tests work someway, veloren compiles but does not work
 - handshake compatible to async_std
2021-02-17 12:39:47 +01:00

114 lines
4.4 KiB
Rust

#![deny(unsafe_code)]
#![cfg_attr(test, deny(rust_2018_idioms))]
#![cfg_attr(test, deny(warnings))]
#![deny(clippy::clone_on_ref_ptr)]
#![feature(try_trait)]
//! Crate to handle high level networking of messages with different
//! requirements and priorities over a number of protocols
//!
//! To start with the `veloren_network` crate you should focus on the 3
//! elementar structs [`Network`], [`Participant`] and [`Stream`].
//!
//! Say you have an application that wants to communicate with other application
//! over a Network or on the same computer. Now each application instances the
//! struct [`Network`] once with a new [`Pid`]. The Pid is necessary to identify
//! other [`Networks`] over the network protocols (e.g. TCP, UDP)
//!
//! To connect to another application, you must know it's [`ProtocolAddr`]. One
//! side will call [`connect`], the other [`connected`]. If successful both
//! applications will now get a [`Participant`].
//!
//! This [`Participant`] represents the connection between those 2 applications.
//! over the respective [`ProtocolAddr`] and with it the chosen network
//! protocol. However messages can't be send directly via [`Participants`],
//! instead you must open a [`Stream`] on it. Like above, one side has to call
//! [`open`], the other [`opened`]. [`Streams`] can have a different priority
//! and [`Promises`].
//!
//! You can now use the [`Stream`] to [`send`] and [`recv`] in both directions.
//! You can send all kind of messages that implement [`serde`].
//! As the receiving side needs to know the format, it sometimes is useful to
//! always send a specific Enum and then handling it with a big `match`
//! statement This create makes heavily use of `async`, except for [`send`]
//! which returns always directly.
//!
//! For best practices see the `examples` folder of this crate containing useful
//! code snippets, a simple client/server below. Of course due to the async
//! nature, no strict client server separation is necessary
//!
//! # Examples
//! ```rust
//! use futures::{executor::block_on, join};
//! use tokio::task::sleep;
//! use veloren_network::{Network, Pid, Promises, ProtocolAddr};
//!
//! // Client
//! async fn client() -> std::result::Result<(), Box<dyn std::error::Error>> {
//! sleep(std::time::Duration::from_secs(1)).await; // `connect` MUST be after `listen`
//! let (client_network, f) = Network::new(Pid::new());
//! std::thread::spawn(f);
//! let server = client_network
//! .connect(ProtocolAddr::Tcp("127.0.0.1:12345".parse().unwrap()))
//! .await?;
//! let mut stream = server
//! .open(10, Promises::ORDERED | Promises::CONSISTENCY)
//! .await?;
//! stream.send("Hello World")?;
//! Ok(())
//! }
//!
//! // Server
//! async fn server() -> std::result::Result<(), Box<dyn std::error::Error>> {
//! let (server_network, f) = Network::new(Pid::new());
//! std::thread::spawn(f);
//! server_network
//! .listen(ProtocolAddr::Tcp("127.0.0.1:12345".parse().unwrap()))
//! .await?;
//! let client = server_network.connected().await?;
//! let mut stream = client.opened().await?;
//! let msg: String = stream.recv().await?;
//! println!("Got message: {}", msg);
//! assert_eq!(msg, "Hello World");
//! Ok(())
//! }
//!
//! fn main() -> std::result::Result<(), Box<dyn std::error::Error>> {
//! block_on(async {
//! let (result_c, result_s) = join!(client(), server(),);
//! result_c?;
//! result_s?;
//! Ok(())
//! })
//! }
//! ```
//!
//! [`Network`]: crate::api::Network
//! [`Networks`]: crate::api::Network
//! [`connect`]: crate::api::Network::connect
//! [`connected`]: crate::api::Network::connected
//! [`Participant`]: crate::api::Participant
//! [`Participants`]: crate::api::Participant
//! [`open`]: crate::api::Participant::open
//! [`opened`]: crate::api::Participant::opened
//! [`Stream`]: crate::api::Stream
//! [`Streams`]: crate::api::Stream
//! [`send`]: crate::api::Stream::send
//! [`recv`]: crate::api::Stream::recv
//! [`Pid`]: crate::types::Pid
//! [`ProtocolAddr`]: crate::api::ProtocolAddr
//! [`Promises`]: crate::types::Promises
mod api;
mod channel;
mod message;
#[cfg(feature = "metrics")] mod metrics;
mod participant;
mod scheduler;
pub use api::{
Network, NetworkError, Participant, ParticipantError, ProtocolAddr, Stream, StreamError,
};
pub use message::Message;
pub use network_protocol::{Pid, Promises};