//! tokio-stomp - A library for asynchronous streaming of STOMP messages #[macro_use] extern crate nom; use custom_debug_derive::CustomDebug; use frame::Frame; pub mod client; mod frame; pub(crate) type Result = std::result::Result; /// A representation of a STOMP frame #[derive(Debug)] pub struct Message { /// The message content pub content: T, /// Headers present in the frame which were not required by the content pub extra_headers: Vec<(Vec, Vec)>, } fn pretty_bytes(b: &Option>, f: &mut std::fmt::Formatter) -> std::fmt::Result { if let Some(v) = b { write!(f, "{}", String::from_utf8_lossy(v)) } else { write!(f, "None") } } /// A STOMP message sent from the server /// See the [Spec](https://stomp.github.io/stomp-specification-1.2.html) for more information #[derive(CustomDebug, Clone)] pub enum FromServer { #[doc(hidden)] // The user shouldn't need to know about this one Connected { version: String, session: Option, server: Option, heartbeat: Option, }, /// Conveys messages from subscriptions to the client Message { destination: String, message_id: String, subscription: String, headers: Vec<(String, String)>, #[debug(with = "pretty_bytes")] body: Option>, }, /// Sent from the server to the client once a server has successfully /// processed a client frame that requests a receipt Receipt { receipt_id: String }, /// Something went wrong. After sending an Error, the server will close the connection Error { message: Option, #[debug(with = "pretty_bytes")] body: Option>, }, } // TODO tidy this lot up with traits? impl Message { // fn to_frame<'a>(&'a self) -> Frame<'a> { // unimplemented!() // } // TODO make this undead fn from_frame(frame: Frame) -> Result> { frame.to_server_msg() } } /// A STOMP message sent by the client. /// See the [Spec](https://stomp.github.io/stomp-specification-1.2.html) for more information #[derive(Debug, Clone)] pub enum ToServer { #[doc(hidden)] // The user shouldn't need to know about this one Connect { accept_version: String, host: String, login: Option, passcode: Option, heartbeat: Option<(u32, u32)>, }, /// Send a message to a destination in the messaging system Send { destination: String, transaction: Option, headers: Option>, body: Option>, }, /// Register to listen to a given destination Subscribe { destination: String, id: String, ack: Option, }, /// Remove an existing subscription Unsubscribe { id: String }, /// Acknowledge consumption of a message from a subscription using /// 'client' or 'client-individual' acknowledgment. Ack { // TODO ack and nack should be automatic? id: String, transaction: Option, }, /// Notify the server that the client did not consume the message Nack { id: String, transaction: Option, }, /// Start a transaction Begin { transaction: String }, /// Commit an in-progress transaction Commit { transaction: String }, /// Roll back an in-progress transaction Abort { transaction: String }, /// Gracefully disconnect from the server /// Clients MUST NOT send any more frames after the DISCONNECT frame is sent. Disconnect { receipt: Option }, } #[derive(Debug, Clone, Copy)] pub enum AckMode { Auto, Client, ClientIndividual, } impl Message { fn to_frame(&self) -> Frame { self.content.to_frame() } #[allow(dead_code)] fn from_frame(frame: Frame) -> Result> { frame.to_client_msg() } } impl From for Message { fn from(content: ToServer) -> Message { Message { content, extra_headers: vec![], } } }