1#![deny(missing_docs)]
2#![allow(clippy::borrowed_box)]
3#[cfg(any(test, feature = "async"))]
62pub mod futures;
63
64use rand::Rng;
65use serde::{de::DeserializeOwned, Deserialize, Serialize};
66use serde_json::{Number, Value};
67
68const VERSION: &str = "2.0";
69const INVALID_REQUEST: isize = -32600;
70const METHOD_NOT_FOUND: isize = -32601;
71const INVALID_PARAMS: isize = -32602;
72const INTERNAL_ERROR: isize = -32603;
73const PARSE_ERROR: isize = -32700;
74
75pub type Result<T> = std::result::Result<T, Error>;
77
78#[derive(Debug, thiserror::Error)]
80pub enum Error {
81 #[error("Parsing failed, invalid JSON data")]
83 Parse {
84 data: String,
86 },
87 #[error("Invalid JSON-RPC request")]
90 InvalidRequest {
91 data: String,
93 },
94
95 #[error("Service method not found: {name}")]
98 MethodNotFound {
99 id: Option<Value>,
101 name: String,
103 },
104
105 #[error("Message parameters are invalid")]
108 InvalidParams {
109 id: Option<Value>,
111 data: String,
113 },
114
115 #[error(transparent)]
117 Boxed(#[from] Box<dyn std::error::Error + Send + Sync>),
118}
119
120impl<'a> From<&'a Error> for (isize, Option<String>) {
121 fn from(error: &'a Error) -> Self {
122 match error {
123 Error::MethodNotFound { .. } => (METHOD_NOT_FOUND, None),
124 Error::InvalidParams { data, .. } => {
125 (INVALID_PARAMS, Some(data.to_string()))
126 }
127 Error::Parse { data } => (PARSE_ERROR, Some(data.to_string())),
128 Error::InvalidRequest { data } => {
129 (INVALID_REQUEST, Some(data.to_string()))
130 }
131 _ => (INTERNAL_ERROR, None),
132 }
133 }
134}
135
136impl<'a> From<(&'a mut Request, &'a str)> for Error {
137 fn from(value: (&'a mut Request, &'a str)) -> Error {
138 Error::from((value.0, value.1.to_string()))
139 }
140}
141
142impl<'a> From<(&'a mut Request, String)> for Error {
143 fn from(value: (&'a mut Request, String)) -> Error {
144 Error::InvalidParams {
145 id: value.0.id().clone(),
146 data: value.1,
147 }
148 }
149}
150
151#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
153pub struct RpcError {
154 pub code: isize,
156 pub message: String,
158 #[serde(skip_serializing_if = "Option::is_none")]
161 pub data: Option<String>,
162}
163
164impl RpcError {
165 pub fn new(message: String, data: Option<String>) -> Self {
167 Self {
168 code: INTERNAL_ERROR,
169 message,
170 data,
171 }
172 }
173}
174
175pub trait Service: Send + Sync {
177 type Data;
179
180 fn handle(
187 &self,
188 request: &Request,
189 ctx: &Self::Data,
190 ) -> Result<Option<Response>>;
191}
192
193pub struct Server<'a, T> {
198 services: Vec<&'a Box<dyn Service<Data = T>>>,
200}
201
202impl<'a, T> Server<'a, T> {
203 pub fn new(services: Vec<&'a Box<dyn Service<Data = T>>>) -> Self {
205 Self { services }
206 }
207
208 pub(crate) fn handle(
213 &self,
214 request: &Request,
215 ctx: &T,
216 ) -> Result<Response> {
217 for service in self.services.iter() {
218 if let Some(result) = service.handle(request, ctx)? {
219 return Ok(result);
220 }
221 }
222
223 let err = Error::MethodNotFound {
224 name: request.method().to_string(),
225 id: request.id.clone(),
226 };
227
228 Ok((request, err).into())
229 }
230
231 pub fn serve(&self, request: &Request, ctx: &T) -> Option<Response> {
233 match self.handle(request, ctx) {
234 Ok(response) => {
235 if response.error().is_some() || response.id().is_some() {
236 Some(response)
237 } else {
238 None
239 }
240 }
241 Err(e) => Some((request, e).into()),
242 }
243 }
244}
245
246pub fn from_str(payload: &str) -> Result<Request> {
248 serde_json::from_str::<Request>(payload).map_err(map_json_error)
249}
250
251pub fn from_value(payload: Value) -> Result<Request> {
253 serde_json::from_value::<Request>(payload).map_err(map_json_error)
254}
255
256pub fn from_slice(payload: &[u8]) -> Result<Request> {
258 serde_json::from_slice::<Request>(payload).map_err(map_json_error)
259}
260
261pub fn from_reader<R: std::io::Read>(payload: R) -> Result<Request> {
263 serde_json::from_reader::<R, Request>(payload).map_err(map_json_error)
264}
265
266#[derive(Serialize, Deserialize, Debug, Clone)]
268pub struct Request {
269 jsonrpc: String,
270 method: String,
271 #[serde(skip_serializing_if = "Option::is_none")]
272 id: Option<Value>,
273 #[serde(skip_serializing_if = "Option::is_none")]
274 params: Option<Value>,
275}
276
277impl Request {
278 pub fn new(
280 id: Option<Value>,
281 method: String,
282 params: Option<Value>,
283 ) -> Self {
284 Self {
285 jsonrpc: VERSION.to_string(),
286 id,
287 method,
288 params,
289 }
290 }
291
292 pub fn new_reply(method: &str, params: Option<Value>) -> Self {
296 Self {
297 jsonrpc: VERSION.to_string(),
298 method: method.to_string(),
299 params,
300 id: Some(Value::Number(Number::from(
301 rand::thread_rng().gen_range(1..std::u32::MAX),
302 ))),
303 }
304 }
305
306 pub fn new_notification(method: &str, params: Option<Value>) -> Self {
310 Self {
311 jsonrpc: VERSION.to_string(),
312 method: method.to_string(),
313 params,
314 id: None,
315 }
316 }
317
318 pub fn id(&self) -> &Option<Value> {
320 &self.id
321 }
322
323 pub fn id_mut(&mut self) -> &mut Option<Value> {
326 &mut self.id
327 }
328
329 pub fn method(&self) -> &str {
331 &self.method
332 }
333
334 pub fn params(&self) -> &Option<Value> {
336 &self.params
337 }
338
339 #[deprecated(note = "Use match expression on method() instead")]
340 pub fn matches(&self, name: &str) -> bool {
342 *name == self.method
343 }
344
345 pub fn deserialize<T: DeserializeOwned>(&self) -> Result<T> {
351 if let Some(params) = &self.params {
352 Ok(serde_json::from_value::<T>(params.clone()).map_err(|e| {
353 Error::InvalidParams {
354 id: self.id.clone(),
355 data: e.to_string(),
356 }
357 })?)
358 } else {
359 Err(Error::InvalidParams {
360 id: self.id.clone(),
361 data: "No parameters given".to_string(),
362 })
363 }
364 }
365}
366
367fn map_json_error(e: serde_json::Error) -> Error {
368 if e.is_data() {
369 Error::InvalidRequest {
370 data: e.to_string(),
371 }
372 } else {
373 Error::Parse {
374 data: e.to_string(),
375 }
376 }
377}
378
379#[derive(Deserialize, Serialize, Debug, Eq, PartialEq)]
381pub struct Response {
382 jsonrpc: String,
383 #[serde(skip_serializing_if = "Option::is_none")]
384 id: Option<Value>,
385 #[serde(skip_serializing_if = "Option::is_none")]
386 result: Option<Value>,
387 #[serde(skip_serializing_if = "Option::is_none")]
388 error: Option<RpcError>,
389}
390
391impl Response {
392 pub fn id(&self) -> &Option<Value> {
394 &self.id
395 }
396
397 pub fn result(&self) -> &Option<Value> {
399 &self.result
400 }
401
402 pub fn error(&self) -> &Option<RpcError> {
404 &self.error
405 }
406}
407
408impl From<Response> for (Option<Value>, Option<RpcError>, Option<Value>) {
409 fn from(response: Response) -> Self {
410 (response.id, response.error, response.result)
411 }
412}
413
414impl From<Response> for Option<Value> {
415 fn from(response: Response) -> Self {
416 response.result
417 }
418}
419
420impl From<Response> for Option<RpcError> {
421 fn from(response: Response) -> Self {
422 response.error
423 }
424}
425
426impl From<Error> for Response {
427 fn from(error: Error) -> Self {
428 let (code, data): (isize, Option<String>) = (&error).into();
429 Response {
430 jsonrpc: VERSION.to_string(),
431 id: Some(Value::Null),
432 result: None,
433 error: Some(RpcError {
434 code,
435 message: error.to_string(),
436 data,
437 }),
438 }
439 }
440}
441
442impl<'a> From<(&'a Request, Error)> for Response {
443 fn from(result: (&'a Request, Error)) -> Self {
444 let (code, data): (isize, Option<String>) = (&result.1).into();
445 Response {
446 jsonrpc: VERSION.to_string(),
447 id: result.0.id.clone(),
448 result: None,
449 error: Some(RpcError {
450 code,
451 message: result.1.to_string(),
452 data,
453 }),
454 }
455 }
456}
457
458impl<'a> From<(&'a Request, RpcError)> for Response {
459 fn from(result: (&'a Request, RpcError)) -> Self {
460 Response {
461 jsonrpc: VERSION.to_string(),
462 id: result.0.id.clone(),
463 result: None,
464 error: Some(result.1),
465 }
466 }
467}
468
469impl<'a> From<(&'a Request, Value)> for Response {
470 fn from(req: (&'a Request, Value)) -> Self {
471 Self {
472 jsonrpc: VERSION.to_string(),
473 id: req.0.id.clone(),
474 result: Some(req.1),
475 error: None,
476 }
477 }
478}
479
480impl<'a> From<&'a Request> for Response {
481 fn from(req: &'a Request) -> Self {
482 Self {
483 jsonrpc: VERSION.to_string(),
484 result: None,
485 error: None,
486 id: req.id.clone(),
487 }
488 }
489}
490
491impl From<Value> for Response {
492 fn from(result: Value) -> Self {
493 Self {
494 jsonrpc: VERSION.to_string(),
495 result: Some(result),
496 error: None,
497 id: Some(Value::from(Number::from(0))),
498 }
499 }
500}
501
502mod test {
503 use super::*;
504
505 #[derive(Debug, thiserror::Error)]
506 enum MockError {
507 #[error("{0}")]
508 Internal(String),
509 }
510
511 struct HelloServiceHandler;
512 impl Service for HelloServiceHandler {
513 type Data = ();
514 fn handle(
515 &self,
516 request: &Request,
517 _context: &Self::Data,
518 ) -> Result<Option<Response>> {
519 let response = match request.method() {
520 "hello" => {
521 let params: String = request.deserialize()?;
522 let message = format!("Hello, {}!", params);
523 Some((request, Value::String(message)).into())
524 }
525 _ => None,
526 };
527 Ok(response)
528 }
529 }
530
531 struct InternalErrorService;
532 impl Service for InternalErrorService {
533 type Data = ();
534 fn handle(
535 &self,
536 _request: &Request,
537 _context: &Self::Data,
538 ) -> Result<Option<Response>> {
539 Err(Error::from(Box::from(MockError::Internal(
541 "Mock error".to_string(),
542 ))))
543 }
544 }
545
546 struct InternalRpcErrorService;
547 impl Service for InternalRpcErrorService {
548 type Data = ();
549 fn handle(
550 &self,
551 request: &Request,
552 _context: &Self::Data,
553 ) -> Result<Option<Response>> {
554 let err = RpcError::new("Mock RPC error".to_string(), Some("close-connection".to_string()));
555 let res = Some((request, err).into());
556 Ok(res)
557 }
558 }
559
560 #[test]
561 fn jsonrpc_service_ok() -> Result<()> {
562 let service: Box<dyn Service<Data = ()>> =
563 Box::new(HelloServiceHandler {});
564 let mut request = Request::new_reply(
565 "hello",
566 Some(Value::String("world".to_string())),
567 );
568 let server = Server::new(vec![&service]);
569 let response = server.serve(&mut request, &());
570 assert_eq!(
571 Some(Value::String("Hello, world!".to_string())),
572 response.unwrap().into()
573 );
574 Ok(())
575 }
576
577 #[test]
578 fn jsonrpc_service_notification() -> Result<()> {
579 let service: Box<dyn Service<Data = ()>> =
580 Box::new(HelloServiceHandler {});
581 let mut request = Request::new_notification(
582 "hello",
583 Some(Value::String("world".to_string())),
584 );
585 let server = Server::new(vec![&service]);
586 let response = server.serve(&mut request, &());
587 assert_eq!(None, response);
588 Ok(())
589 }
590
591 #[test]
592 fn jsonrpc_invalid_request_error() -> Result<()> {
593 let bad_json = "{}";
594 let response: Response = match from_str(bad_json) {
595 Ok(request) => (&request).into(),
596 Err(e) => e.into(),
597 };
598 assert_eq!(
599 Some(RpcError {
600 code: -32600,
601 message: "Invalid JSON-RPC request".to_string(),
602 data: Some(
603 "missing field `jsonrpc` at line 1 column 2".to_string()
604 )
605 }),
606 response.into()
607 );
608 Ok(())
609 }
610
611 #[test]
612 fn jsonrpc_service_method_not_found() -> Result<()> {
613 let service: Box<dyn Service<Data = ()>> =
614 Box::new(HelloServiceHandler {});
615 let mut request = Request::new_reply("non-existent", None);
616 let server = Server::new(vec![&service]);
617 let response = server.serve(&mut request, &());
618 assert_eq!(
619 Some(RpcError {
620 code: -32601,
621 message: "Service method not found: non-existent".to_string(),
622 data: None
623 }),
624 response.unwrap().into()
625 );
626 Ok(())
627 }
628
629 #[test]
630 fn jsonrpc_invalid_params() -> Result<()> {
631 let service: Box<dyn Service<Data = ()>> =
632 Box::new(HelloServiceHandler {});
633 let mut request = Request::new_reply("hello", Some(Value::Bool(true)));
634 let server = Server::new(vec![&service]);
635 let response = server.serve(&mut request, &());
636 assert_eq!(
637 Some(RpcError {
638 code: -32602,
639 message: "Message parameters are invalid".to_string(),
640 data: Some(
641 "invalid type: boolean `true`, expected a string"
642 .to_string()
643 )
644 }),
645 response.unwrap().into()
646 );
647 Ok(())
648 }
649
650 #[test]
651 fn jsonrpc_internal_error() -> Result<()> {
652 let service: Box<dyn Service<Data = ()>> =
653 Box::new(InternalErrorService {});
654 let request = Request::new_reply("foo", None);
655 let server = Server::new(vec![&service]);
656 let response = server.serve(&request, &());
657 assert_eq!(
658 Some(RpcError {
659 code: -32603,
660 message: "Mock error".to_string(),
661 data: None
662 }),
663 response.unwrap().into()
664 );
665 Ok(())
666 }
667
668 #[test]
669 fn jsonrpc_parse_error() -> Result<()> {
670 let bad_json = r#"{"jsonrpc": "oops}"#;
671 let response: Response = match from_str(bad_json) {
672 Ok(request) => (&request).into(),
673 Err(e) => e.into(),
674 };
675 assert_eq!(
676 Some(RpcError {
677 code: -32700,
678 message: "Parsing failed, invalid JSON data".to_string(),
679 data: Some(
680 "EOF while parsing a string at line 1 column 18"
681 .to_string()
682 )
683 }),
684 response.into()
685 );
686 Ok(())
687 }
688
689 #[test]
690 fn jsonrpc_internal_rpc_error() -> Result<()> {
691
692 let service: Box<dyn Service<Data = ()>> =
693 Box::new(InternalRpcErrorService {});
694 let request = Request::new_reply("foo", None);
695 let server = Server::new(vec![&service]);
696 let response = server.serve(&request, &());
697 assert_eq!(
698 Some(RpcError {
699 code: -32603,
700 message: "Mock RPC error".to_string(),
701 data: Some("close-connection".to_string())
702 }),
703 response.unwrap().into()
704 );
705 Ok(())
706 }
707}