gl_client/lsps/
json_rpc.rs

1use base64::Engine as _;
2use serde::de::DeserializeOwned;
3use serde::ser::SerializeMap;
4use serde::{Deserialize, Serialize};
5
6use super::error::map_json_rpc_error_code_to_str;
7
8/// Generate a random json_rpc_id string that follows the requirements of LSPS0
9///
10/// - Should be a String
11/// - Should be at generated using at least 80 bits of randomness
12pub fn generate_random_rpc_id() -> String {
13    // The specification requires an id using least 80 random bits of randomness
14    let seed: [u8; 10] = rand::random();
15    base64::engine::general_purpose::URL_SAFE_NO_PAD.encode(seed)
16}
17
18#[derive(Debug, Serialize, Deserialize)]
19pub struct JsonRpcMethod<I, O, E>
20where
21    E: MapErrorCode,
22{
23    pub method: &'static str,
24    #[serde(skip_serializing)]
25    request: std::marker::PhantomData<I>,
26    #[serde(skip_serializing)]
27    return_type: std::marker::PhantomData<O>,
28    #[serde(skip_serializing)]
29    error_type: std::marker::PhantomData<E>,
30}
31
32impl<I, O, E> JsonRpcMethod<I, O, E>
33where
34    E: MapErrorCode,
35{
36    pub const fn new(method: &'static str) -> Self {
37        Self {
38						method,
39            request: std::marker::PhantomData,
40            return_type: std::marker::PhantomData,
41            error_type: std::marker::PhantomData,
42        }
43    }
44
45    pub const fn name(&self) -> &'static str {
46        self.method
47    }
48
49    pub fn create_request(&self, params: I, json_rpc_id: String) -> JsonRpcRequest<I> {
50        JsonRpcRequest::<I> {
51            jsonrpc: String::from("2.0"),
52            id: json_rpc_id,
53            method: self.method.into(),
54            params,
55        }
56    }
57}
58
59impl<O, E> JsonRpcMethod<NoParams, O, E>
60where
61    E: MapErrorCode,
62{
63    pub fn create_request_no_params(&self, json_rpc_id: String) -> JsonRpcRequest<NoParams> {
64        self.create_request(NoParams::default(), json_rpc_id)
65    }
66}
67
68impl<I, O, E> std::convert::From<&JsonRpcMethod<I, O, E>> for String 
69where
70    E: MapErrorCode
71		{
72    fn from(value: &JsonRpcMethod<I, O, E>) -> Self {
73        value.method.into()
74    }
75}
76
77impl<'de, I, O, E> JsonRpcMethod<I, O, E>
78where
79    O: Deserialize<'de>,
80    E: Deserialize<'de> + MapErrorCode,
81{
82    pub fn parse_json_response_str(
83        &self,
84        json_str: &'de str,
85    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error> {
86        serde_json::from_str(json_str)
87    }
88}
89
90impl<I, O, E> JsonRpcMethod<I, O, E>
91where
92    O: DeserializeOwned,
93    E: DeserializeOwned + MapErrorCode,
94{
95    pub fn parse_json_response_value(
96        &self,
97        json_value: serde_json::Value,
98    ) -> Result<JsonRpcResponse<O, E>, serde_json::Error> {
99        serde_json::from_value(json_value)
100    }
101}
102
103// We only intend to implement to implement an LSP-client and only intend on sending requests
104// Therefore, we only implement the serialization of requests
105//
106// D is the data-type of the request-data
107// R is the data-type of the result if the query is successful
108#[derive(Serialize, Deserialize, Debug)]
109pub struct JsonRpcRequest<I> {
110    pub jsonrpc: String,
111    pub id: String,
112    pub method: String,
113    pub params: I,
114}
115
116// LSPS0 specifies that the RPC-request must use a parameter-by-name structure.
117//
118// A JSONRpcRequest<(),()> will be serialized to a json where "params" : null
119// A JsonRpcRequest<NoParams, ()> will be serialized to "params" : {} which is compliant
120#[derive(Debug, Default, Clone, Deserialize, PartialEq)]
121pub struct NoParams {}
122
123// Serde serializes NoParams to null by default
124// LSPS0 requires an empty dictionary in this situation
125impl Serialize for NoParams {
126    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
127    where
128        S: serde::Serializer,
129    {
130        serializer.serialize_map(Some(0))?.end()
131    }
132}
133
134impl<I> JsonRpcRequest<I> {
135    pub fn new<O, E>(method: JsonRpcMethod<I, O, E>, params: I) -> Self
136    where
137        E: MapErrorCode,
138    {
139        return Self {
140            jsonrpc: String::from("2.0"),
141            id: generate_random_rpc_id(),
142            method: method.method.into(),
143            params,
144        }
145    }
146}
147
148impl JsonRpcRequest<NoParams> {
149    pub fn new_no_params<O, E>(method: JsonRpcMethod<NoParams, O, E>) -> Self
150    where
151        E: MapErrorCode,
152    {
153        return Self {
154            jsonrpc: String::from("2.0"),
155            id: generate_random_rpc_id(),
156            method: method.method.into(),
157            params: NoParams::default(),
158        }
159    }
160}
161
162#[derive(Debug, Serialize, Deserialize)]
163pub struct JsonRpcResponseSuccess<O> {
164    pub id: String,
165    pub result: O,
166    pub jsonrpc: String,
167}
168
169#[derive(Debug, Serialize, Deserialize)]
170pub struct JsonRpcResponseFailure<E> {
171    pub id: String,
172    pub error: ErrorData<E>,
173    pub jsonrpc: String,
174}
175
176#[derive(Debug, Serialize, Deserialize)]
177#[serde(untagged)]
178pub enum JsonRpcResponse<O, E> {
179    Error(JsonRpcResponseFailure<E>),
180    Ok(JsonRpcResponseSuccess<O>),
181}
182
183#[derive(Debug, Serialize, Deserialize)]
184pub struct ErrorData<E> {
185    pub code: i64,
186    pub message: String,
187    pub data: Option<E>,
188}
189
190impl<E> ErrorData<E>
191where
192    E: MapErrorCode,
193{
194    pub fn code_str(&self) -> &str {
195        return E::get_code_str(self.code);
196    }
197}
198
199#[derive(Debug, Serialize, Deserialize)]
200pub struct DefaultError;
201
202pub trait MapErrorCode {
203    fn get_code_str(code: i64) -> &'static str;
204}
205
206impl MapErrorCode for DefaultError {
207    fn get_code_str(code: i64) -> &'static str {
208        map_json_rpc_error_code_to_str(code)
209    }
210}
211
212#[cfg(test)]
213mod test {
214
215    use super::*;
216
217    #[test]
218    fn serialize_no_params() {
219        let no_params = NoParams::default();
220        let json_str = serde_json::to_string(&no_params).unwrap();
221
222        assert_eq!(json_str, "{}")
223    }
224
225    #[test]
226    fn deserialize_no_params() {
227        let _: NoParams = serde_json::from_str("{}").unwrap();
228    }
229
230    #[test]
231    fn serialize_json_rpc_request() {
232        let rpc_request = JsonRpcRequest {
233            id: "abcefg".into(),
234            jsonrpc: "2.0".into(),
235            params: NoParams::default(),
236            method: "test.method".into(),
237        };
238
239        let json_str = serde_json::to_string(&rpc_request).unwrap();
240
241        let value: serde_json::Value = serde_json::from_str(&json_str).unwrap();
242        assert_eq!(value.get("jsonrpc").unwrap(), "2.0");
243        assert_eq!(value.get("id").unwrap(), &rpc_request.id);
244        assert_eq!(value.get("method").unwrap(), "test.method");
245        assert!(value.get("params").unwrap().as_object().unwrap().is_empty())
246    }
247
248    #[test]
249    fn serialize_json_rpc_response_success() {
250        let rpc_response_ok: JsonRpcResponseSuccess<String> = JsonRpcResponseSuccess {
251            id: String::from("abc"),
252            result: String::from("result_data"),
253            jsonrpc: String::from("2.0"),
254        };
255
256        let rpc_response: JsonRpcResponse<String, ()> = JsonRpcResponse::Ok(rpc_response_ok);
257
258        let json_str: String = serde_json::to_string(&rpc_response).unwrap();
259
260        let value: serde_json::Value = serde_json::from_str(&json_str).unwrap();
261        assert_eq!(value.get("jsonrpc").unwrap(), "2.0");
262        assert_eq!(value.get("id").unwrap(), "abc");
263        assert_eq!(value.get("result").unwrap(), "result_data")
264    }
265
266    #[test]
267    fn serialize_json_rpc_response_error() {
268        let rpc_response: JsonRpcResponse<String, ()> =
269            JsonRpcResponse::Error(JsonRpcResponseFailure {
270                jsonrpc: String::from("2.0"),
271                id: String::from("abc"),
272                error: ErrorData {
273                    code: -32700,
274                    message: String::from("Failed to parse data"),
275                    data: None,
276                },
277            });
278
279        let json_str: String = serde_json::to_string(&rpc_response).unwrap();
280
281        let value: serde_json::Value = serde_json::from_str(&json_str).unwrap();
282        assert_eq!(value.get("jsonrpc").unwrap(), "2.0");
283        assert_eq!(value.get("id").unwrap(), "abc");
284        assert_eq!(value.get("error").unwrap().get("code").unwrap(), -32700);
285        assert_eq!(
286            value.get("error").unwrap().get("message").unwrap(),
287            "Failed to parse data"
288        );
289    }
290
291    #[test]
292    fn create_rpc_request_from_call() {
293        let rpc_method = JsonRpcMethod::<NoParams, (), DefaultError>::new("test.method");
294        let json_rpc_id = generate_random_rpc_id();
295        let rpc_request = rpc_method.create_request_no_params(json_rpc_id);
296
297        assert_eq!(rpc_request.method, "test.method");
298        assert_eq!(rpc_request.jsonrpc, "2.0");
299        assert_eq!(rpc_request.params, NoParams::default());
300    }
301
302    #[test]
303    fn parse_rpc_response_success_from_call() {
304        let rpc_method = JsonRpcMethod::<NoParams, String, DefaultError>::new("test.return_string");
305
306        let json_value = serde_json::json!({
307            "jsonrpc" : "2.0",
308            "result" : "result_data",
309            "id" : "request_id"
310        });
311
312        let json_str = serde_json::to_string(&json_value).unwrap();
313
314        let result = rpc_method.parse_json_response_str(&json_str).unwrap();
315
316        match result {
317            JsonRpcResponse::Error(_) => panic!("Deserialized a good response but got panic"),
318            JsonRpcResponse::Ok(ok) => {
319                assert_eq!(ok.jsonrpc, "2.0");
320                assert_eq!(ok.id, "request_id");
321                assert_eq!(ok.result, "result_data")
322            }
323        }
324    }
325
326    #[test]
327    fn parse_rpc_response_failure_from_call() {
328        let rpc_method = JsonRpcMethod::<NoParams, String, DefaultError>::new("test.return_string");
329
330        let json_value = serde_json::json!({
331            "jsonrpc" : "2.0",
332            "error" : { "code" : -32700, "message" : "Failed to parse response"},
333            "id" : "request_id"
334        });
335
336        let json_str = serde_json::to_string(&json_value).unwrap();
337
338        let result = rpc_method.parse_json_response_str(&json_str).unwrap();
339
340        match result {
341            JsonRpcResponse::Error(err) => {
342                assert_eq!(err.jsonrpc, "2.0");
343
344                assert_eq!(err.error.code, -32700);
345                assert_eq!(err.error.code_str(), "parsing_error");
346
347                assert_eq!(err.error.message, "Failed to parse response");
348                assert_eq!(err.id, "request_id");
349            }
350            JsonRpcResponse::Ok(_ok) => {
351                panic!("Failure deserialized as Ok")
352            }
353        }
354    }
355}