fe2o3_amqp/lib.rs
1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![deny(missing_docs, missing_debug_implementations)]
3#![warn(clippy::unused_async)]
4
5//! A rust implementation of AMQP 1.0 protocol based on serde and tokio.
6//!
7//! [](https://crates.io/crates/fe2o3-amqp)
8//! [](https://docs.rs/fe2o3-amqp/latest/fe2o3_amqp/)
9//! [](https://discord.gg/YMkaETwnFW)
10//!
11//! - [Quick Start](#quick-start)
12//! - [Documentation](https://docs.rs/fe2o3-amqp)
13//! - [Changelog](https://github.com/minghuaw/fe2o3-amqp/blob/main/fe2o3-amqp/Changelog.md)
14//! - [Examples](https://github.com/minghuaw/fe2o3-amqp/tree/main/examples)
15//!
16//! # Feature flags
17//!
18//! ```toml
19//! default = []
20//! ```
21//!
22//! | Feature | Description |
23//! |---------|-------------|
24//! |`"rustls"`| enables TLS integration with `tokio-rustls` and `rustls` |
25//! |`"native-tls"`| enables TLS integration with `tokio-native-tls` and `native-tls`|
26//! |`"acceptor"`| enables `ConnectionAcceptor`, `SessionAcceptor`, and `LinkAcceptor`|
27//! |`"transaction"`| enables `Controller`, `Transaction`, `OwnedTransaction` and `control_link_acceptor` |
28//! |`"scram"`| enables SCRAM auth |
29//! |`"tracing"`| enables logging with `tracing` |
30//! |`"log"`| enables logging with `log` |
31//!
32//! ## The crypto provider for `"rustls"`
33//!
34//! This crate does not name a crypto provider. It takes the default features of
35//! `rustls`, so the provider follows the `rustls` default. That default is
36//! `aws-lc-rs`.
37//!
38//! To use a different provider, install it with
39//! `rustls::crypto::CryptoProvider::install_default` and supply your own
40//! `tokio_rustls::TlsConnector` to the connection builder.
41//!
42//! When both the `"rustls"` and `"native-tls"` features are enabled, `"native-tls"`
43//! is used as the default TLS connector for `amqps://` when no connector is supplied
44//! to the builder. Pick a specific stack with
45//! [`Connection::builder().rustls_connector(..)`] / `native_tls_connector(..)`.
46//!
47//! The default features also include `prefer-post-quantum`. A client therefore
48//! sends an `X25519MLKEM768` key share in the first ClientHello. To send an
49//! `X25519` key share instead, build the config with
50//! `ClientConfig::builder_with_provider` and pass a `CryptoProvider` whose
51//! `kx_groups` field starts with `X25519`. A plain `ClientConfig::builder()` does
52//! not change the order, because it takes the order from the default provider.
53//!
54//! Neither TLS feature does anything on a `wasm32` target. See [WebAssembly
55//! support](#webassembly-support).
56//!
57//! # Quick start
58//!
59//! 1. [Client](#client)
60//! 2. [Listener](#listener)
61//! 3. [WebSocket binding](#websocket)
62//!
63//! More examples including one showing how to use it with Azure Service Bus can be found on the
64//! [GitHub repo](https://github.com/minghuaw/fe2o3-amqp/tree/main/examples).
65//!
66//! ## Client
67//!
68//! Below is an example with a local broker
69//! ([`TestAmqpBroker`](https://github.com/Azure/amqpnetlite/releases/download/test_broker.1609/TestAmqpBroker.zip))
70//! listening on the localhost. The broker is executed with the following command
71//!
72//! ```powershell
73//! ./TestAmqpBroker.exe amqp://localhost:5672 /creds:guest:guest /queues:q1
74//! ```
75//!
76//! The following code requires the [`tokio`] async runtime added to the dependencies.
77//!
78//! ```rust,no_run
79//! use fe2o3_amqp::{Connection, Session, Sender, Receiver};
80//! use fe2o3_amqp::types::messaging::Outcome;
81//!
82//! #[tokio::main]
83//! async fn main() {
84//! let mut connection = Connection::open(
85//! "connection-1", // container id
86//! "amqp://guest:guest@localhost:5672" // url
87//! ).await.unwrap();
88//!
89//! let mut session = Session::begin(&mut connection).await.unwrap();
90//!
91//! // Create a sender
92//! let mut sender = Sender::attach(
93//! &mut session, // Session
94//! "rust-sender-link-1", // link name
95//! "q1" // target address
96//! ).await.unwrap();
97//!
98//! // Create a receiver
99//! let mut receiver = Receiver::attach(
100//! &mut session,
101//! "rust-receiver-link-1", // link name
102//! "q1" // source address
103//! ).await.unwrap();
104//!
105//! // Send a message to the broker and wait for outcome (Disposition)
106//! let outcome: Outcome = sender.send("hello AMQP").await.unwrap();
107//! outcome.accepted_or_else(|state| state).unwrap(); // Handle delivery outcome
108//!
109//! // Send a message with batchable field set to true
110//! let fut = sender.send_batchable("hello batchable AMQP").await.unwrap();
111//! let outcome: Outcome = fut.await.unwrap(); // Wait for outcome (Disposition)
112//! outcome.accepted_or_else(|state| state).unwrap(); // Handle delivery outcome
113//!
114//! // Receive the message from the broker
115//! let delivery = receiver.recv::<String>().await.unwrap();
116//! receiver.accept(&delivery).await.unwrap();
117//!
118//! sender.close().await.unwrap(); // Detach sender with closing Detach performatives
119//! receiver.close().await.unwrap(); // Detach receiver with closing Detach performatives
120//! session.end().await.unwrap(); // End the session
121//! connection.close().await.unwrap(); // Close the connection
122//! }
123//! ```
124//!
125//! ## Listener
126//!
127//! ```rust,no_run
128//! use tokio::net::TcpListener;
129//! use fe2o3_amqp::acceptor::{ConnectionAcceptor, SessionAcceptor, LinkAcceptor, LinkEndpoint};
130//!
131//! #[tokio::main]
132//! async fn main() {
133//! let tcp_listener = TcpListener::bind("localhost:5672").await.unwrap();
134//! let connection_acceptor = ConnectionAcceptor::new("example-listener");
135//!
136//! while let Ok((stream, addr)) = tcp_listener.accept().await {
137//! let mut connection = connection_acceptor.accept(stream).await.unwrap();
138//! let handle = tokio::spawn(async move {
139//! let session_acceptor = SessionAcceptor::new();
140//! while let Ok(mut session) = session_acceptor.accept(&mut connection).await{
141//! let handle = tokio::spawn(async move {
142//! let link_acceptor = LinkAcceptor::new();
143//! match link_acceptor.accept(&mut session).await.unwrap() {
144//! LinkEndpoint::Sender(sender) => { },
145//! LinkEndpoint::Receiver(recver) => { },
146//! }
147//! });
148//! }
149//! });
150//! }
151//! }
152//! ```
153//!
154//! ## WebSocket
155//!
156//! [`fe2o3-amqp-ws`](https://crates.io/crates/fe2o3-amqp-ws) is needed for WebSocket binding
157//!
158//! ```rust,ignore
159//! use fe2o3_amqp::{
160//! types::{messaging::Outcome, primitives::Value},
161//! Connection, Delivery, Receiver, Sender, Session,
162//! };
163//! use fe2o3_amqp_ws::WebSocketStream;
164//!
165//! #[tokio::main]
166//! async fn main() {
167//! let (ws_stream, _response) = WebSocketStream::connect("ws://localhost:5673")
168//! .await
169//! .unwrap();
170//! let mut connection = Connection::builder()
171//! .container_id("connection-1")
172//! .open_with_stream(ws_stream)
173//! .await
174//! .unwrap();
175//!
176//! connection.close().await.unwrap();
177//! }
178//! ```
179//!
180//! # More examples
181//!
182//! More examples of sending and receiving can be found on the [GitHub
183//! repo](https://github.com/minghuaw/fe2o3-amqp/tree/main/examples/). Please note that most
184//! examples requires a local broker running. One broker that can be used on Windows is
185//! [TestAmqpBroker](https://azure.github.io/amqpnetlite/articles/hello_amqp.html).
186//!
187//! # WebAssembly support
188//!
189//! Experimental support for `wasm32-unknown-unknown` target is added since "0.8.11" and requires use of
190//! `fe2o3-amqp-ws` to establish WebSocket connection to the broker. An example of sending and
191//! receiving message in a browser tab can be found
192//! [examples/wasm32-in-browser](https://github.com/minghuaw/fe2o3-amqp/tree/main/examples/wasm32-in-browser).
193//!
194//! The `"rustls"` and `"native-tls"` features do nothing on a `wasm32` target. A browser
195//! cannot open a raw socket, so it terminates TLS itself. Use a `wss://` URL with
196//! `fe2o3-amqp-ws` to get an encrypted connection. If you enable a TLS feature and then
197//! open an `amqps://` URL on `wasm32`, the call returns
198//! [`connection::OpenError::TlsConnectorNotFound`].
199//!
200//! # Components
201//!
202//! | Name | Description |
203//! |------|-------------|
204//! |`serde_amqp_derive`| Custom derive macro for described types as defined in AMQP1.0 protocol |
205//! |`serde_amqp`| AMQP1.0 serializer and deserializer as well as primitive types |
206//! |`fe2o3-amqp-types`| AMQP1.0 data types |
207//! |`fe2o3-amqp`| Implementation of AMQP1.0 `Connection`, `Session`, and `Link` |
208//! |`fe2o3-amqp-ext`| Extension types and implementations |
209//! |`fe2o3-amqp-ws` | WebSocket binding for `fe2o3-amqp` transport |
210//! |`fe2o3-amqp-management`| Experimental implementation of AMQP1.0 management |
211//! |`fe2o3-amqp-cbs`| Experimental implementation of AMQP1.0 CBS |
212//!
213//! # Minimum rust version supported
214//!
215//! 1.85.0
216
217#[macro_use]
218mod macros;
219
220pub(crate) mod control;
221pub(crate) mod endpoint;
222pub(crate) mod util;
223
224pub mod auth;
225pub mod connection;
226pub mod frames;
227pub mod link;
228pub mod sasl_profile;
229pub mod session;
230pub mod transport;
231
232cfg_acceptor! {
233 pub mod acceptor;
234}
235
236cfg_transaction! {
237 pub mod transaction;
238}
239
240pub mod types {
241 //! Re-exporting `fe2o3-amqp-types`
242 pub use fe2o3_amqp_types::*;
243}
244
245pub use connection::Connection;
246pub use link::{
247 delivery::{Delivery, Sendable},
248 Receiver, ReceiverDisposer, Sender,
249};
250pub use session::Session;
251
252type Payload = bytes::Bytes;
253
254cfg_not_wasm32! {
255 /// A marker trait to indicate that the type is `Send` bound in non-wasm32 targets
256 pub trait SendBound: Send {}
257 impl<T> SendBound for T where T: Send {}
258}
259
260cfg_wasm32! {
261 /// A marker trait that is implemented for all types in wasm32 targets
262 pub trait SendBound {}
263 impl<T> SendBound for T {}
264}