xtb_client/schema/
messages.rs

1use derive_setters::Setters;
2use serde::{Deserialize, Serialize};
3use serde_json::Value;
4use crate::schema::api_errors::XtbErrorCode;
5
6
7/// Message sent to XTB servers
8#[derive(Clone, Default, Debug, Serialize, Setters)]
9#[serde(rename_all = "camelCase")]
10#[setters(into, prefix = "with_", strip_option)]
11pub struct Request {
12    /// The command name
13    pub command: String,
14    /// Data (payload) send with a command
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub arguments: Option<Value>,
17    /// Custom tag for message identification
18    pub custom_tag: Option<String>,
19}
20
21
22impl Request {
23
24    /// Correctly set arguments.
25    ///
26    /// The arguments can be:
27    ///
28    /// * None - set payload to None
29    /// * Some(Value::Null) - set payload to None
30    /// * Some(Value::Object) - set payload to given value
31    ///
32    /// # Panics
33    ///
34    /// Any other payload configuration than supported one
35    pub fn with_maybe_arguments(mut self, arguments: Option<Value>) -> Self {
36        match arguments {
37            None | Some(Value::Null) => self.arguments = None,
38            Some(Value::Object(obj)) => self.arguments = Some(Value::Object(obj)),
39            _ => panic!("Unsupported argument type. RTFM")
40        }
41        self
42    }
43}
44
45
46/// Response message returned from server when operation succeeds.
47#[derive(Clone, Default, Debug, Deserialize)]
48#[serde(rename_all = "camelCase")]
49pub struct Response {
50    /// Response status is always TRUE
51    pub status: bool,
52    /// This is set only for response to the "login" request
53    pub stream_session_id: Option<String>,
54    /// Returning data.
55    pub return_data: Option<Value>,
56    /// Custom tag from original message
57    pub custom_tag: Option<String>,
58}
59
60
61/// Subscribe for stream of data
62///
63/// # Note
64///
65/// This struct does not carry any arguments itself. The arguments are merged into serialized object
66/// before the send operation is done.
67#[derive(Clone, Default, Debug, Serialize, Setters)]
68#[serde(rename_all = "camelCase")]
69#[setters(into, prefix = "with_", strip_option)]
70pub struct SubscribeRequest {
71    /// The command name
72    pub command: String,
73    /// The stream session id (identify the connection)
74    pub stream_session_id: String
75}
76
77
78/// Unsubscribe from stream of data
79///
80/// # Note
81///
82/// This struct does not carry any arguments itself. The arguments are merged into serialized object
83/// before the send operation is done.
84#[derive(Clone, Default, Debug, Serialize, Setters)]
85#[serde(rename_all = "camelCase")]
86#[setters(into, prefix = "with_", strip_option)]
87pub struct UnsubscribeRequest {
88    /// Command to be unsubscribed from
89    pub command: String,
90}
91
92
93/// Data stream item representation
94#[derive(Clone, Default, Debug, Deserialize)]
95#[serde(rename_all = "camelCase")]
96pub struct StreamDataMessage {
97    /// Source command
98    pub command: String,
99    /// Payload
100    pub data: Value
101}
102
103
104/// Response message returned from server when operation fails.
105#[derive(Clone, Default, Debug, Deserialize)]
106#[serde(rename_all = "camelCase")]
107pub struct ErrorResponse {
108    /// Error response status is always FALSE
109    pub status: bool,
110    /// The machine-readable error code
111    pub error_code: XtbErrorCode,
112    /// The human-readable error code
113    pub error_descr: Option<String>,
114    /// Custom tag from original message
115    pub custom_tag: Option<String>,
116}
117
118
119#[cfg(test)]
120mod tests {
121    use rstest::rstest;
122    use serde_json::{from_str, to_value, Value};
123    use crate::schema::Request;
124
125    #[rstest]
126    #[case(Request::default().with_command("command").with_arguments("argument").with_custom_tag("tag"), "{\"command\": \"command\", \"arguments\": \"argument\", \"customTag\": \"tag\"}")]
127    fn serialize_request(#[case] request: Request, #[case] expected_json: &str) {
128        let request_value = to_value(request).unwrap();
129        let expected_value: Value = from_str(expected_json).unwrap();
130        assert_eq!(request_value, expected_value)
131    }
132}