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