From: Sachandhan Ganesh Date: Sun, 14 Feb 2021 20:37:14 +0000 (-0800) Subject: improve documentation and logging X-Git-Url: https://git.lizzy.rs/?a=commitdiff_plain;h=424227abf248ee200ef02b1f4f319f1cb87c2afb;p=connect-rs.git improve documentation and logging --- diff --git a/Cargo.toml b/Cargo.toml index 7e6631d..f970a86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "connect" -version = "0.2.1" +version = "0.2.2" edition = "2018" authors = ["Sachandhan Ganesh "] description = "message queue abstraction over async network streams" diff --git a/README.md b/README.md index 65b42dc..418f5e2 100644 --- a/README.md +++ b/README.md @@ -8,19 +8,75 @@ [docs-badge]: https://docs.rs/connect/badge.svg [docs-url]: https://docs.rs/connect -This Rust crate provides a simple, brokerless message-queue abstraction over asynchronous network -streams. +This Rust crate provides a simple, brokerless message-queue abstraction over asynchronous +network streams. It guarantees ordered message delivery and reception, and both TCP and TLS +transports are supported. ## Examples -Please use the [example programs](https://github.com/sachanganesh/connect-rs/tree/main/examples) -provided to help understand crate usage. + +````rust +// create a client connection to the server +let mut conn = Connection::tcp_client(ip_address).await?; + +// construct a new message +let msg = String::from("Hello world!"); +let envelope: ConnectDatagram = ConnectDatagram::new(65535, msg.into_bytes())?; + +// send a message to the server +conn.writer().send(envelope).await?; + +// wait for the echo-server to reply with an echo +if let Some(mut envelope) = conn.reader().next().await { + // take the message payload from the envelope + let data: Vec = envelope.take_data().unwrap(); + + // reconstruct the original message + let msg = String::from_utf8(data)?; + assert_eq!("Hello world!", msg.as_str()); +} +```` + +In addition to the [crate documentation](https://docs.rs/connect/latest/connect/), please use +the provided [example programs](https://github.com/sachanganesh/connect-rs/tree/main/examples) +as a practical reference for crate usage. + +- TCP + - [TCP Echo Server](https://github.com/sachanganesh/connect-rs/tree/main/examples/tcp-echo-server) + - [TCP Client](https://github.com/sachanganesh/connect-rs/tree/main/examples/tcp-client) +- TLS + - [TLS Echo Server](https://github.com/sachanganesh/connect-rs/tree/main/examples/tls-echo-server) + - [TLS Client](https://github.com/sachanganesh/connect-rs/tree/main/examples/tls-client) ## Why? + When building networked applications, developers shouldn't have to focus on repeatedly solving -the problem of reliable, fault-tolerant message delivery over byte-streams. By using a message +the problem of reliable, ordered message delivery over byte-streams. By using a message queue abstraction, crate users can focus on core application logic and leave the low-level networking and message-queue guarantees to the abstraction. +Connect provides a `ConnectionWriter` and `ConnectionReader` interface to concurrently send +and receive messages over a network connection. Each user-provided message is prefixed by 8 +bytes, containing a size-prefix (4 bytes), version tag (2 bytes), and recipient tag (2 bytes). +The size-prefix and version tag are used internally to deserialize messages received from the +network connection. The recipient tag is intended for crate users to identify the message +recipient, although the library leaves that up to the user's discretion. + +Library users must serialize their custom messages into bytes (`Vec`), prior to +constructing a `ConnectDatagram`, which can then be passed to a `ConnectionWriter`. +Consequently, `ConnectionReader`s will return `ConnectDatagram`s containing the message payload +(`Vec` again) to the user to deserialize. + +Requiring crate users to serialize data before constructing a datagram may appear redundant, but +gives the developer the freedom to use a serialization format of their choosing. This means that +library users can do interesting things such as: + +- Use the recipient tag to signify which serialization format was used for that message +- Use the recipient tag to signify the type of message being sent + +## Contributing + +This crate gladly accepts contributions. Don't hesitate to open issues or PRs. + ## Feature Status | Feature | Status | diff --git a/examples/tcp-client-blaster/src/main.rs b/examples/tcp-client-blaster/src/main.rs index d93b85e..d68ad7a 100644 --- a/examples/tcp-client-blaster/src/main.rs +++ b/examples/tcp-client-blaster/src/main.rs @@ -54,7 +54,7 @@ async fn main() -> anyhow::Result<()> { // send messages to the server for i in 0..NUM_MESSAGES { - // info!("Sending message: {}", i); + info!("Sending message: {}", i); let data = i.to_be_bytes().to_vec(); let envelope = ConnectDatagram::new(i, data)?; writer.send(envelope).await?; diff --git a/src/lib.rs b/src/lib.rs index b3c3232..b99dd98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,16 +1,68 @@ -//! This crate provides a simple, brokerless message-queue abstraction over asynchronous network -//! streams. +//! This Rust crate provides a simple, brokerless message-queue abstraction over asynchronous +//! network streams. It guarantees ordered message delivery and reception, and both TCP and TLS +//! transports are supported. //! //! # Examples -//! Please use the [example programs](https://github.com/sachanganesh/connect-rs/tree/main/examples) -//! provided to help understand crate usage. +//! +//! ````ignore +//! // create a client connection to the server +//! let mut conn = Connection::tcp_client(ip_address).await?; +//! +//! // construct a new message +//! let msg = String::from("Hello world!"); +//! let envelope: ConnectDatagram = ConnectDatagram::new(65535, msg.into_bytes())?; +//! +//! // send a message to the server +//! conn.writer().send(envelope).await?; +//! +//! // wait for the echo-server to reply with an echo +//! if let Some(mut envelope) = conn.reader().next().await { +//! // take the message payload from the envelope +//! let data: Vec = envelope.take_data().unwrap(); +//! +//! // reconstruct the original message +//! let msg = String::from_utf8(data)?; +//! assert_eq!("Hello world!", msg.as_str()); +//! } +//! ```` +//! +//! In addition to the [crate documentation](https://docs.rs/connect/latest/connect/), please use +//! the provided [example programs](https://github.com/sachanganesh/connect-rs/tree/main/examples) +//! as a practical reference for crate usage. +//! +//! - TCP +//! - [TCP Echo Server](https://github.com/sachanganesh/connect-rs/tree/main/examples/tcp-echo-server) +//! - [TCP Client](https://github.com/sachanganesh/connect-rs/tree/main/examples/tcp-client) +//! - TLS +//! - [TLS Echo Server](https://github.com/sachanganesh/connect-rs/tree/main/examples/tls-echo-server) +//! - [TLS Client](https://github.com/sachanganesh/connect-rs/tree/main/examples/tls-client) //! //! # Why? +//! //! When building networked applications, developers shouldn't have to focus on repeatedly solving -//! the problem of reliable, fault-tolerant message delivery over byte-streams. By using a message +//! the problem of reliable, ordered message delivery over byte-streams. By using a message //! queue abstraction, crate users can focus on core application logic and leave the low-level //! networking and message-queue guarantees to the abstraction. //! +//! Connect provides a `ConnectionWriter` and `ConnectionReader` interface to concurrently send +//! and receive messages over a network connection. Each user-provided message is prefixed by 8 +//! bytes, containing a size-prefix (4 bytes), version tag (2 bytes), and recipient tag (2 bytes). +//! The size-prefix and version tag are used internally to deserialize messages received from the +//! network connection. The recipient tag is intended for crate users to identify the message +//! recipient, although the library leaves that up to the user's discretion. +//! +//! Library users must serialize their custom messages into bytes (`Vec`), prior to +//! constructing a `ConnectDatagram`, which can then be passed to a `ConnectionWriter`. +//! Consequently, `ConnectionReader`s will return `ConnectDatagram`s containing the message payload +//! (`Vec` again) to the user to deserialize. +//! +//! Requiring crate users to serialize data before constructing a datagram may appear redundant, but +//! gives the developer the freedom to use a serialization format of their choosing. This means that +//! library users can do interesting things such as: +//! +//! - Use the recipient tag to signify which serialization format was used for that message +//! - Use the recipient tag to signify the type of message being sent +//! #![feature(doc_cfg)] diff --git a/src/reader.rs b/src/reader.rs index 3954c4e..1e9c031 100644 --- a/src/reader.rs +++ b/src/reader.rs @@ -14,7 +14,7 @@ const BUFFER_SIZE: usize = 8192; /// An interface to read messages from the network connection. /// -/// Implements the [`Stream`] trait to asynchronously read messages from the network connection. +/// Implements the `Stream` trait to asynchronously read messages from the network connection. /// /// # Example /// @@ -72,13 +72,13 @@ impl ConnectionReader { self.peer_addr.clone() } - /// Check if the [`Stream`] of messages from the network is closed. + /// Check if the `Stream` of messages from the network is closed. pub fn is_closed(&self) -> bool { self.closed } pub(crate) fn close_stream(&mut self) { - trace!("closing the stream for connection with {}", self.peer_addr); + debug!("Closing the stream for connection with {}", self.peer_addr); self.buffer.take(); self.pending_datagram.take(); self.pending_read.take(); diff --git a/src/writer.rs b/src/writer.rs index 87ad3e6..57dd4a2 100644 --- a/src/writer.rs +++ b/src/writer.rs @@ -36,7 +36,7 @@ impl std::fmt::Display for ConnectionWriteError { /// An interface to write messages to the network connection. /// -/// Implements the [`Sink`] trait to asynchronously write messages to the network connection. +/// Implements the `Sink` trait to asynchronously write messages to the network connection. /// /// # Example /// @@ -84,7 +84,7 @@ impl ConnectionWriter { self.peer_addr.clone() } - /// Check if the [`Sink`] of messages to the network is closed. + /// Check if the `Sink` of messages to the network is closed. pub fn is_closed(&self) -> bool { self.closed } @@ -165,6 +165,7 @@ impl Sink for ConnectionWriter { fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { self.closed = true; + debug!("Closing the sink for connection with {}", self.peer_addr); match self.write_pending_bytes(cx) { Poll::Pending => Poll::Pending,