tokio_stomp_2/
lib.rs

1//! tokio-stomp - A library for asynchronous streaming of STOMP messages
2
3#[macro_use]
4extern crate nom;
5
6use custom_debug_derive::CustomDebug;
7use frame::Frame;
8
9pub mod client;
10mod frame;
11
12pub(crate) type Result<T> = std::result::Result<T, anyhow::Error>;
13
14/// A representation of a STOMP frame
15#[derive(Debug)]
16pub struct Message<T> {
17    /// The message content
18    pub content: T,
19    /// Headers present in the frame which were not required by the content
20    pub extra_headers: Vec<(Vec<u8>, Vec<u8>)>,
21}
22
23fn pretty_bytes(b: &Option<Vec<u8>>, f: &mut std::fmt::Formatter) -> std::fmt::Result {
24    if let Some(v) = b {
25        write!(f, "{}", String::from_utf8_lossy(v))
26    } else {
27        write!(f, "None")
28    }
29}
30
31/// A STOMP message sent from the server
32/// See the [Spec](https://stomp.github.io/stomp-specification-1.2.html) for more information
33#[derive(CustomDebug, Clone)]
34pub enum FromServer {
35    #[doc(hidden)] // The user shouldn't need to know about this one
36    Connected {
37        version: String,
38        session: Option<String>,
39        server: Option<String>,
40        heartbeat: Option<String>,
41    },
42    /// Conveys messages from subscriptions to the client
43    Message {
44        destination: String,
45        message_id: String,
46        subscription: String,
47        headers: Vec<(String, String)>,
48        #[debug(with = "pretty_bytes")]
49        body: Option<Vec<u8>>,
50    },
51    /// Sent from the server to the client once a server has successfully
52    /// processed a client frame that requests a receipt
53    Receipt { receipt_id: String },
54    /// Something went wrong. After sending an Error, the server will close the connection
55    Error {
56        message: Option<String>,
57        #[debug(with = "pretty_bytes")]
58        body: Option<Vec<u8>>,
59    },
60}
61
62// TODO tidy this lot up with traits?
63impl Message<FromServer> {
64    // fn to_frame<'a>(&'a self) -> Frame<'a> {
65    //     unimplemented!()
66    // }
67
68    // TODO make this undead
69    fn from_frame(frame: Frame) -> Result<Message<FromServer>> {
70        frame.to_server_msg()
71    }
72}
73
74/// A STOMP message sent by the client.
75/// See the [Spec](https://stomp.github.io/stomp-specification-1.2.html) for more information
76#[derive(Debug, Clone)]
77pub enum ToServer {
78    #[doc(hidden)] // The user shouldn't need to know about this one
79    Connect {
80        accept_version: String,
81        host: String,
82        login: Option<String>,
83        passcode: Option<String>,
84        heartbeat: Option<(u32, u32)>,
85    },
86    /// Send a message to a destination in the messaging system
87    Send {
88        destination: String,
89        transaction: Option<String>,
90        headers: Option<Vec<(String, String)>>,
91        body: Option<Vec<u8>>,
92    },
93    /// Register to listen to a given destination
94    Subscribe {
95        destination: String,
96        id: String,
97        ack: Option<AckMode>,
98    },
99    /// Remove an existing subscription
100    Unsubscribe { id: String },
101    /// Acknowledge consumption of a message from a subscription using
102    /// 'client' or 'client-individual' acknowledgment.
103    Ack {
104        // TODO ack and nack should be automatic?
105        id: String,
106        transaction: Option<String>,
107    },
108    /// Notify the server that the client did not consume the message
109    Nack {
110        id: String,
111        transaction: Option<String>,
112    },
113    /// Start a transaction
114    Begin { transaction: String },
115    /// Commit an in-progress transaction
116    Commit { transaction: String },
117    /// Roll back an in-progress transaction
118    Abort { transaction: String },
119    /// Gracefully disconnect from the server
120    /// Clients MUST NOT send any more frames after the DISCONNECT frame is sent.
121    Disconnect { receipt: Option<String> },
122}
123
124#[derive(Debug, Clone, Copy)]
125pub enum AckMode {
126    Auto,
127    Client,
128    ClientIndividual,
129}
130
131impl Message<ToServer> {
132    fn to_frame(&self) -> Frame {
133        self.content.to_frame()
134    }
135    #[allow(dead_code)]
136    fn from_frame(frame: Frame) -> Result<Message<ToServer>> {
137        frame.to_client_msg()
138    }
139}
140
141impl From<ToServer> for Message<ToServer> {
142    fn from(content: ToServer) -> Message<ToServer> {
143        Message {
144            content,
145            extra_headers: vec![],
146        }
147    }
148}