Skip to main content

rio_rs/
protocol.rs

1//! Client/Server communication protocol
2
3use super::errors::HandlerError;
4use serde::{de::DeserializeOwned, Deserialize, Serialize};
5use thiserror::Error;
6
7/// This is the struct that we serialize and send to the server serialized
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct RequestEnvelope {
10    pub handler_type: String,
11    pub handler_id: String,
12    pub message_type: String,
13    pub payload: Vec<u8>,
14}
15
16impl RequestEnvelope {
17    pub fn new(
18        handler_type: String,
19        handler_id: String,
20        message_type: String,
21        payload: Vec<u8>,
22    ) -> RequestEnvelope {
23        RequestEnvelope {
24            handler_type,
25            handler_id,
26            message_type,
27            payload,
28        }
29    }
30}
31
32/// This is the struct that we serialize and send back to the client
33///
34/// ```rust
35/// # use rio_rs::protocol::*;
36///
37/// // Success case
38/// let response = ResponseEnvelope::new(vec![1, 2, 3]);
39/// assert!(response.body.is_ok());
40///
41/// // Error case
42/// let response_error = ResponseError::Unknown("something went wrong".to_string());
43/// let response = ResponseEnvelope::err(response_error);
44/// assert!(response.body.is_err());
45/// ```
46#[derive(Debug, Serialize, Deserialize)]
47pub struct ResponseEnvelope {
48    pub body: Result<Vec<u8>, ResponseError>,
49}
50
51impl ResponseEnvelope {
52    /// New `ResponseEnvelope`. `Ok` Variant
53    pub fn new(body: Vec<u8>) -> ResponseEnvelope {
54        ResponseEnvelope { body: Ok(body) }
55    }
56
57    /// New `ResponseEnvelope`. `Err` Variant
58    pub fn err(error: ResponseError) -> ResponseEnvelope {
59        ResponseEnvelope { body: Err(error) }
60    }
61}
62
63/// Convert a `HandlerError` into a `ResponseEnvelope`.
64///
65/// This is used to convert errors that occur during handler execution
66/// into a response envelope that can be sent back to the client.
67impl From<HandlerError> for ResponseEnvelope {
68    fn from(error: HandlerError) -> Self {
69        let response_err = ResponseError::from(error);
70        ResponseEnvelope {
71            body: Err(response_err),
72        }
73    }
74}
75
76/// Error that we serialize back inside of the [ResponseEnvelope]
77#[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)]
78pub enum ResponseError {
79    #[error("ServiceObject is in another server")]
80    Redirect(String),
81
82    #[error("ServiceObject had to be deallocated")]
83    DeallocateServiceObject,
84
85    #[error("ServiceObject could not be allocated")]
86    Allocate,
87
88    #[error("ServiceObject not supported")]
89    NotSupported(String),
90
91    #[error("unknown execution error")]
92    Unknown(String),
93
94    #[error("handler error")]
95    HandlerError(String),
96
97    #[error("error deserializing response")]
98    DeseralizationError(String),
99
100    #[error("error serializing message")]
101    SeralizationError(String),
102
103    #[error("Error caused by the application, serialized in bincode")]
104    ApplicationError(Vec<u8>),
105}
106
107/// Convert a `HandlerError` into a `ResponseError`.
108///
109/// This is used to convert errors that occur during handler execution
110/// into a response error that can be serialized and sent back to the client.
111impl From<HandlerError> for ResponseError {
112    fn from(error: HandlerError) -> Self {
113        match error {
114            HandlerError::ApplicationError(v) => ResponseError::ApplicationError(v),
115            inner_err => ResponseError::Unknown(inner_err.to_string()),
116        }
117    }
118}
119
120/// Errors that might occur while building or using the client,
121/// but that are not related to any behaviour on the server
122#[derive(Error, Debug, PartialEq, Eq)]
123pub enum ClientError {
124    #[error("no servers available")]
125    NoServersAvailable,
126
127    #[error("the requested server is not available")]
128    ServerNotAvailable(String),
129
130    #[error("client was disconnected from the server (no more items on the TCP stream)")]
131    Disconnect,
132
133    #[error("rendenvouz is not available")]
134    RendevouzUnavailable,
135
136    #[error("connectivity error")]
137    Connectivity,
138
139    #[error("unknown client error")]
140    Unknown(String),
141
142    #[error("unknown PlacementLock error")]
143    PlacementLock,
144
145    #[error("error deserializing response")]
146    DeseralizationError(String),
147
148    #[error("error serializing message")]
149    SeralizationError(String),
150
151    #[error("std::io::Error")]
152    IoError(String),
153}
154
155impl From<::std::io::Error> for ClientError {
156    fn from(error: ::std::io::Error) -> Self {
157        ClientError::IoError(error.to_string())
158    }
159}
160
161/// This error can be used with [RequestError] when you don't care
162/// about the possible application errors
163#[derive(Debug, Clone, PartialEq, Eq, Error, Serialize, Deserialize)]
164pub enum NoopError {}
165
166/// Union of types for actions that bundle client logic and response handling
167#[derive(Error, Debug, PartialEq, Eq)]
168pub enum RequestError<E: std::error::Error> {
169    #[error("error in the service response")]
170    ResponseError(ResponseError),
171
172    #[error("client error")]
173    ClientError(ClientError),
174
175    #[error("application error")]
176    ApplicationError(E),
177}
178
179impl<E: std::error::Error> From<::std::io::Error> for RequestError<E> {
180    fn from(error: ::std::io::Error) -> Self {
181        Into::<ClientError>::into(error).into()
182    }
183}
184
185/// Convert a `ClientError` into a `RequestError`.
186///
187/// This is useful because client-side operations can fail for reasons that are not
188/// related to the server's response (e.g., network connectivity issues,
189/// deserialization errors on the client-side, etc.).
190///
191/// By implementing `From<ClientError> for RequestError`, we can easily propagate
192/// client-side errors up to the request handling layer, where they can be
193/// treated as part of the overall request error scenario, without needing to
194/// explicitly convert them everywhere they might occur.
195impl<E: std::error::Error> From<ClientError> for RequestError<E> {
196    fn from(err: ClientError) -> Self {
197        RequestError::ClientError(err)
198    }
199}
200
201impl<E: std::error::Error + DeserializeOwned> From<ResponseError> for RequestError<E> {
202    fn from(err: ResponseError) -> Self {
203        match err {
204            ResponseError::ApplicationError(ser_error) => {
205                //
206                let des_result: Result<E, _> = bincode::deserialize(&ser_error);
207                match des_result {
208                    Ok(err) => Self::ApplicationError(err),
209                    Err(bincode_err) => {
210                        let error_message =
211                            format!("Application error deserialization issue: {}", bincode_err);
212                        let des_error = ResponseError::DeseralizationError(error_message);
213                        Self::ResponseError(des_error)
214                    }
215                }
216            }
217            rest => RequestError::ResponseError(rest),
218        }
219    }
220}
221
222pub mod pubsub {
223    use super::*;
224
225    /// This is the struct that we serialize and send to the server serialized to request a new
226    /// subscription
227    #[derive(Debug, Serialize, Deserialize)]
228    pub struct SubscriptionRequest {
229        pub handler_type: String,
230        pub handler_id: String,
231    }
232
233    /// Item that is streamed serialized from the server to the client
234    #[derive(Debug, Clone, Serialize, Deserialize)]
235    pub struct SubscriptionResponse {
236        pub body: Result<Vec<u8>, ResponseError>,
237    }
238
239    impl SubscriptionResponse {
240        /// New `Ok` variant
241        pub fn new(body: Vec<u8>) -> Self {
242            SubscriptionResponse { body: Ok(body) }
243        }
244
245        /// New `Err` Variant
246        pub fn err(error: ResponseError) -> Self {
247            SubscriptionResponse { body: Err(error) }
248        }
249    }
250}