1use std::collections::HashMap;
21
22use rand::{rngs::OsRng, Rng};
23use tinyjson::JsonValue;
24
25use crate::{
26 error::RpcError,
27 system::{Publisher, PublisherPtr},
28 Result,
29};
30
31#[derive(Copy, Clone, Debug)]
34pub enum ErrorCode {
35 ParseError,
38 InvalidRequest,
40 MethodNotFound,
42 InvalidParams,
44 InternalError,
46 IdMismatch,
48 InvalidReply,
50 ServerError(i32),
52}
53
54impl ErrorCode {
55 pub fn code(&self) -> i32 {
56 match *self {
57 Self::ParseError => -32700,
58 Self::InvalidRequest => -32600,
59 Self::MethodNotFound => -32601,
60 Self::InvalidParams => -32602,
61 Self::InternalError => -32603,
62 Self::IdMismatch => -32360,
63 Self::InvalidReply => -32361,
64 Self::ServerError(c) => c,
65 }
66 }
67
68 pub fn message(&self) -> String {
69 match *self {
70 Self::ParseError => "parse error".to_string(),
71 Self::InvalidRequest => "invalid request".to_string(),
72 Self::MethodNotFound => "method not found".to_string(),
73 Self::InvalidParams => "invalid params".to_string(),
74 Self::InternalError => "internal error".to_string(),
75 Self::IdMismatch => "id mismatch".to_string(),
76 Self::InvalidReply => "invalid reply".to_string(),
77 Self::ServerError(_) => "server error".to_string(),
78 }
79 }
80
81 pub fn desc(&self) -> JsonValue {
82 JsonValue::String(self.message())
83 }
84}
85
86#[derive(Clone, Debug)]
89pub enum JsonResult {
90 Response(JsonResponse),
91 Error(JsonError),
92 Notification(JsonNotification),
93 Subscriber(JsonSubscriber),
95 SubscriberWithReply(JsonSubscriber, JsonResponse),
96 Request(JsonRequest),
97}
98
99impl JsonResult {
100 pub fn try_from_value(value: &JsonValue) -> Result<Self> {
101 if let Ok(response) = JsonResponse::try_from(value) {
102 return Ok(Self::Response(response))
103 }
104
105 if let Ok(error) = JsonError::try_from(value) {
106 return Ok(Self::Error(error))
107 }
108
109 if let Ok(notification) = JsonNotification::try_from(value) {
110 return Ok(Self::Notification(notification))
111 }
112
113 Err(RpcError::InvalidJson("Invalid JSON Result".to_string()).into())
114 }
115}
116
117impl From<JsonResponse> for JsonResult {
118 fn from(resp: JsonResponse) -> Self {
119 Self::Response(resp)
120 }
121}
122
123impl From<JsonError> for JsonResult {
124 fn from(err: JsonError) -> Self {
125 Self::Error(err)
126 }
127}
128
129impl From<JsonNotification> for JsonResult {
130 fn from(notif: JsonNotification) -> Self {
131 Self::Notification(notif)
132 }
133}
134
135impl From<JsonSubscriber> for JsonResult {
136 fn from(sub: JsonSubscriber) -> Self {
137 Self::Subscriber(sub)
138 }
139}
140
141impl From<(JsonSubscriber, JsonResponse)> for JsonResult {
142 fn from(tuple: (JsonSubscriber, JsonResponse)) -> Self {
143 Self::SubscriberWithReply(tuple.0, tuple.1)
144 }
145}
146
147#[derive(Clone, Debug)]
150pub struct JsonRequest {
151 pub jsonrpc: &'static str,
153 pub id: u16,
155 pub method: String,
157 pub params: JsonValue,
159}
160impl JsonRequest {
163 pub fn new(method: &str, params: JsonValue) -> Self {
166 assert!(params.is_object() || params.is_array());
167 Self { jsonrpc: "2.0", id: OsRng::gen(&mut OsRng), method: method.to_string(), params }
168 }
169
170 pub fn stringify(&self) -> Result<String> {
172 let v: JsonValue = self.into();
173 Ok(v.stringify()?)
174 }
175}
176
177impl From<&JsonRequest> for JsonValue {
178 fn from(req: &JsonRequest) -> JsonValue {
179 JsonValue::Object(HashMap::from([
180 ("jsonrpc".to_string(), JsonValue::String(req.jsonrpc.to_string())),
181 ("id".to_string(), JsonValue::Number(req.id.into())),
182 ("method".to_string(), JsonValue::String(req.method.clone())),
183 ("params".to_string(), req.params.clone()),
184 ]))
185 }
186}
187
188impl TryFrom<&JsonValue> for JsonRequest {
189 type Error = RpcError;
190
191 fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
192 if !value.is_object() {
193 return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
194 }
195
196 let mut value = value.clone();
199 let map: &mut HashMap<String, JsonValue> = value.get_mut().unwrap();
200
201 if !map.contains_key("jsonrpc") ||
202 !map["jsonrpc"].is_string() ||
203 map["jsonrpc"] != JsonValue::String("2.0".to_string())
204 {
205 return Err(RpcError::InvalidJson(
206 "Request does not contain valid \"jsonrpc\" field".to_string(),
207 ))
208 }
209
210 if !map.contains_key("id")
211 {
213 return Err(RpcError::InvalidJson(
214 "Request does not contain valid \"id\" field".to_string(),
215 ))
216 }
217
218 if !map.contains_key("method") || !map["method"].is_string() {
219 return Err(RpcError::InvalidJson(
220 "Request does not contain valid \"method\" field".to_string(),
221 ))
222 }
223
224 if !map.contains_key("params") {
225 map.insert("params".to_string(), JsonValue::from(vec![]));
228 }
229
230 if !map["params"].is_object() && !map["params"].is_array() {
231 return Err(RpcError::InvalidJson(
232 "Request does not contain valid \"params\" field".to_string(),
233 ))
234 }
235
236 let id = if map["id"].is_number() {
240 *map["id"].get::<f64>().unwrap() as u16
241 } else if map["id"].is_string() {
242 match map["id"].get::<String>().unwrap().parse::<f64>() {
243 Ok(v) => v as u16,
244 Err(_) => {
245 return Err(RpcError::InvalidJson(
246 "Request does not contain valid \"id\" field".to_string(),
247 ))
248 }
249 }
250 } else {
251 return Err(RpcError::InvalidJson(
252 "Request does not contain valid \"id\" field".to_string(),
253 ))
254 };
255
256 Ok(Self {
257 jsonrpc: "2.0",
258 id,
259 method: map["method"].get::<String>().unwrap().clone(),
260 params: map["params"].clone(),
261 })
262 }
263}
264
265#[derive(Clone, Debug)]
267pub struct JsonNotification {
268 pub jsonrpc: &'static str,
270 pub method: String,
272 pub params: JsonValue,
274}
275
276impl JsonNotification {
277 pub fn new(method: &str, params: JsonValue) -> Self {
279 assert!(params.is_object() || params.is_array());
280 Self { jsonrpc: "2.0", method: method.to_string(), params }
281 }
282
283 pub fn stringify(&self) -> Result<String> {
285 let v: JsonValue = self.into();
286 Ok(v.stringify()?)
287 }
288}
289
290impl From<&JsonNotification> for JsonValue {
291 fn from(notif: &JsonNotification) -> JsonValue {
292 JsonValue::Object(HashMap::from([
293 ("jsonrpc".to_string(), JsonValue::String(notif.jsonrpc.to_string())),
294 ("method".to_string(), JsonValue::String(notif.method.clone())),
295 ("params".to_string(), notif.params.clone()),
296 ]))
297 }
298}
299
300impl TryFrom<&JsonValue> for JsonNotification {
301 type Error = RpcError;
302
303 fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
304 if !value.is_object() {
305 return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
306 }
307
308 let map: &HashMap<String, JsonValue> = value.get().unwrap();
309
310 if !map.contains_key("jsonrpc") ||
311 !map["jsonrpc"].is_string() ||
312 map["jsonrpc"] != JsonValue::String("2.0".to_string())
313 {
314 return Err(RpcError::InvalidJson(
315 "Notification does not contain valid \"jsonrpc\" field".to_string(),
316 ))
317 }
318
319 if !map.contains_key("method") || !map["method"].is_string() {
320 return Err(RpcError::InvalidJson(
321 "Notification does not contain valid \"method\" field".to_string(),
322 ))
323 }
324
325 if !map.contains_key("params") {
326 return Err(RpcError::InvalidJson(
327 "Notification does not contain valid \"params\" field".to_string(),
328 ))
329 }
330
331 if !map["params"].is_object() && !map["params"].is_array() {
332 return Err(RpcError::InvalidJson(
333 "Request does not contain valid \"params\" field".to_string(),
334 ))
335 }
336
337 Ok(Self {
338 jsonrpc: "2.0",
339 method: map["method"].get::<String>().unwrap().clone(),
340 params: map["params"].clone(),
341 })
342 }
343}
344
345#[derive(Clone, Debug)]
347pub struct JsonResponse {
348 pub jsonrpc: &'static str,
350 pub id: u16,
352 pub result: JsonValue,
354}
355
356impl JsonResponse {
357 pub fn new(result: JsonValue, id: u16) -> Self {
360 Self { jsonrpc: "2.0", id, result }
361 }
362
363 pub fn stringify(&self) -> Result<String> {
365 let v: JsonValue = self.into();
366 Ok(v.stringify()?)
367 }
368}
369
370impl From<&JsonResponse> for JsonValue {
371 fn from(rep: &JsonResponse) -> JsonValue {
372 JsonValue::Object(HashMap::from([
373 ("jsonrpc".to_string(), JsonValue::String(rep.jsonrpc.to_string())),
374 ("id".to_string(), JsonValue::Number(rep.id.into())),
375 ("result".to_string(), rep.result.clone()),
376 ]))
377 }
378}
379
380impl TryFrom<&JsonValue> for JsonResponse {
381 type Error = RpcError;
382
383 fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
384 if !value.is_object() {
385 return Err(RpcError::InvalidJson("Json is not an Object".to_string()))
386 }
387
388 let map: &HashMap<String, JsonValue> = value.get().unwrap();
389
390 if !map.contains_key("jsonrpc") ||
391 !map["jsonrpc"].is_string() ||
392 map["jsonrpc"] != JsonValue::String("2.0".to_string())
393 {
394 return Err(RpcError::InvalidJson(
395 "Response does not contain valid \"jsonrpc\" field".to_string(),
396 ))
397 }
398
399 if !map.contains_key("id") || !map["id"].is_number() {
400 return Err(RpcError::InvalidJson(
401 "Response does not contain valid \"id\" field".to_string(),
402 ))
403 }
404
405 if !map.contains_key("result") {
406 return Err(RpcError::InvalidJson(
407 "Response does not contain valid \"result\" field".to_string(),
408 ))
409 }
410
411 Ok(Self {
412 jsonrpc: "2.0",
413 id: *map["id"].get::<f64>().unwrap() as u16,
414 result: map["result"].clone(),
415 })
416 }
417}
418
419impl TryFrom<JsonResult> for JsonResponse {
420 type Error = RpcError;
421
422 fn try_from(result: JsonResult) -> std::result::Result<Self, Self::Error> {
425 match result {
426 JsonResult::Response(response) => Ok(response),
427 _ => Err(RpcError::InvalidJson("Not a JsonResult::Response".to_string())),
428 }
429 }
430}
431
432#[derive(Clone, Debug)]
434pub struct JsonError {
435 pub jsonrpc: &'static str,
437 pub id: u16,
439 pub error: JsonErrorVal,
441}
442
443#[derive(Clone, Debug)]
445pub struct JsonErrorVal {
446 pub code: i32,
448 pub message: String,
450}
451
452impl JsonError {
453 pub fn new(c: ErrorCode, message: Option<String>, id: u16) -> Self {
457 let error = JsonErrorVal { code: c.code(), message: message.unwrap_or(c.message()) };
458 Self { jsonrpc: "2.0", id, error }
459 }
460
461 pub fn stringify(&self) -> Result<String> {
463 let v: JsonValue = self.into();
464 Ok(v.stringify()?)
465 }
466}
467
468impl From<&JsonError> for JsonValue {
469 fn from(err: &JsonError) -> JsonValue {
470 let errmap = JsonValue::Object(HashMap::from([
471 ("code".to_string(), JsonValue::Number(err.error.code.into())),
472 ("message".to_string(), JsonValue::String(err.error.message.clone())),
473 ]));
474
475 JsonValue::Object(HashMap::from([
476 ("jsonrpc".to_string(), JsonValue::String(err.jsonrpc.to_string())),
477 ("id".to_string(), JsonValue::Number(err.id.into())),
478 ("error".to_string(), errmap),
479 ]))
480 }
481}
482
483impl TryFrom<JsonResult> for JsonError {
484 type Error = RpcError;
485
486 fn try_from(result: JsonResult) -> std::result::Result<Self, Self::Error> {
489 match result {
490 JsonResult::Error(error) => Ok(error),
491 _ => Err(RpcError::InvalidJson("Not a JsonResult::Error".to_string())),
492 }
493 }
494}
495
496impl TryFrom<&JsonValue> for JsonError {
497 type Error = RpcError;
498
499 fn try_from(value: &JsonValue) -> std::result::Result<Self, Self::Error> {
500 if !value.is_object() {
501 return Err(RpcError::InvalidJson("JSON is not an Object".to_string()))
502 }
503
504 let map: &HashMap<String, JsonValue> = value.get().unwrap();
505
506 if !map.contains_key("jsonrpc") ||
507 !map["jsonrpc"].is_string() ||
508 map["jsonrpc"] != JsonValue::String("2.0".to_string())
509 {
510 return Err(RpcError::InvalidJson(
511 "Error does not contain valid \"jsonrpc\" field".to_string(),
512 ))
513 }
514
515 if !map.contains_key("id") || !map["id"].is_number() {
516 return Err(RpcError::InvalidJson(
517 "Error does not contain valid \"id\" field".to_string(),
518 ))
519 }
520
521 if !map.contains_key("error") || !map["error"].is_object() {
522 return Err(RpcError::InvalidJson(
523 "Error does not contain valid \"error\" field".to_string(),
524 ))
525 }
526
527 if !map["error"]["code"].is_number() {
528 return Err(RpcError::InvalidJson(
529 "Error does not contain valid \"error.code\" field".to_string(),
530 ))
531 }
532
533 if !map["error"]["message"].is_string() {
534 return Err(RpcError::InvalidJson(
535 "Error does not contain valid \"error.message\" field".to_string(),
536 ))
537 }
538
539 Ok(Self {
540 jsonrpc: "2.0",
541 id: *map["id"].get::<f64>().unwrap() as u16,
542 error: JsonErrorVal {
543 code: *map["error"]["code"].get::<f64>().unwrap() as i32,
544 message: map["error"]["message"].get::<String>().unwrap().to_string(),
545 },
546 })
547 }
548}
549
550#[derive(Clone, Debug)]
552pub struct JsonSubscriber {
553 pub method: &'static str,
555 pub publisher: PublisherPtr<JsonNotification>,
557}
558
559impl JsonSubscriber {
560 pub fn new(method: &'static str) -> Self {
561 let publisher = Publisher::new();
562 Self { method, publisher }
563 }
564
565 pub async fn notify(&self, params: JsonValue) {
567 let notification = JsonNotification::new(self.method, params);
568 self.publisher.notify(notification).await;
569 }
570}
571
572pub fn parse_json_string(name: &str, value: &JsonValue) -> std::result::Result<String, RpcError> {
575 value
576 .get::<String>()
577 .cloned()
578 .ok_or_else(|| RpcError::InvalidJson(format!("Parameter '{name}' is not a valid string")))
579}
580
581pub fn parse_json_number(name: &str, value: &JsonValue) -> std::result::Result<f64, RpcError> {
584 value.get::<f64>().cloned().ok_or_else(|| {
585 RpcError::InvalidJson(format!("Parameter '{name}' is not a supported number type"))
586 })
587}
588
589pub fn parse_json_array_string(
593 name: &str,
594 index: usize,
595 array_value: &JsonValue,
596) -> std::result::Result<String, RpcError> {
597 match array_value {
598 JsonValue::Array(values) => values
599 .get(index)
600 .ok_or_else(|| {
601 RpcError::InvalidJson(format!("Parameter '{name}' at index {index} is missing"))
602 })
603 .and_then(|param| parse_json_string(name, param)),
604 _ => Err(RpcError::InvalidJson(format!("Parameter '{name}' is not an array"))),
605 }
606}
607
608pub fn parse_json_array_number(
612 name: &str,
613 index: usize,
614 array_value: &JsonValue,
615) -> std::result::Result<f64, RpcError> {
616 match array_value {
617 JsonValue::Array(values) => values
618 .get(index)
619 .ok_or_else(|| {
620 RpcError::InvalidJson(format!("Parameter '{name}' at index {index} is missing"))
621 })
622 .and_then(|param| parse_json_number(name, param)),
623 _ => Err(RpcError::InvalidJson(format!("Parameter '{name}' is not an array"))),
624 }
625}
626
627pub fn parse_json_response_string(
631 json_result: JsonResult,
632) -> std::result::Result<String, RpcError> {
633 let json_response: JsonResponse = json_result.try_into().map_err(|_| {
635 RpcError::InvalidJson("Failed to convert JsonResult into JsonResponse".to_string())
636 })?;
637
638 json_response.result.get::<String>().map(|value| value.to_string()).ok_or_else(|| {
640 RpcError::InvalidJson("Failed to parse string from JsonResponse result".to_string())
641 })
642}
643
644pub fn to_json_array(params: &JsonValue) -> std::result::Result<&Vec<JsonValue>, RpcError> {
648 if let JsonValue::Array(array) = params {
649 Ok(array)
650 } else {
651 Err(RpcError::InvalidJson(
652 "Expected an array of values, but received a different JSON type.".to_string(),
653 ))
654 }
655}
656
657pub fn validate_empty_params(params: &JsonValue) -> std::result::Result<(), RpcError> {
659 match to_json_array(params) {
660 Ok(array) if array.is_empty() => Ok(()),
661 Ok(_) => Err(RpcError::InvalidJson(format!(
662 "Parameters not permited, received: {:?}",
663 params.stringify().unwrap_or("Error converting JSON to string".to_string())
664 ))),
665 Err(err) => Err(RpcError::InvalidJson(err.to_string())),
666 }
667}