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
8pub fn generate_random_rpc_id() -> String {
13 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#[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#[derive(Debug, Default, Clone, Deserialize, PartialEq)]
121pub struct NoParams {}
122
123impl 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}