[package]
name = "connect"
-version = "0.2.1"
+version = "0.2.2"
edition = "2018"
authors = ["Sachandhan Ganesh <sachan.ganesh@gmail.com>"]
description = "message queue abstraction over async network streams"
[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<u8> = 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<u8>`), 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<u8>` 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 |
// 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?;
-//! 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<u8> = 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<u8>`), 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<u8>` 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)]
/// 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
///
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();
/// 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
///
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
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.closed = true;
+ debug!("Closing the sink for connection with {}", self.peer_addr);
match self.write_pending_bytes(cx) {
Poll::Pending => Poll::Pending,