json_rpc2/futures.rs
1//! Non-blocking implementation, requires the `async` feature.
2
3use crate::{Error, Request, Response, Result};
4use async_trait::async_trait;
5
6#[async_trait]
7/// Trait for async services that maybe handle a request.
8///
9/// Only available with the `async` feature.
10pub trait Service: Send + Sync {
11 /// Type of the user data for this service.
12 type Data: Send + Sync;
13
14 /// See [Service](crate::Service) for more information.
15 async fn handle(
16 &self,
17 request: &Request,
18 ctx: &Self::Data,
19 ) -> Result<Option<Response>>;
20}
21
22/// Serve requests.
23///
24/// Requests are passed to each service in turn and the first service
25/// that returns a response wins.
26///
27/// Only available with the `async` feature.
28pub struct Server<'a, T: Send + Sync> {
29 /// Services that the server should invoke for every request.
30 services: Vec<&'a Box<dyn Service<Data = T>>>,
31}
32
33impl<'a, T: Send + Sync> Server<'a, T> {
34 /// Create a new server.
35 pub fn new(services: Vec<&'a Box<dyn Service<Data = T>>>) -> Self {
36 Self { services }
37 }
38
39 /// Call services in order and return the first response message.
40 ///
41 /// If no services match the incoming request this will
42 /// return `Error::MethodNotFound`.
43 pub(crate) async fn handle(
44 &self,
45 request: &Request,
46 ctx: &T,
47 ) -> Result<Response> {
48 for service in self.services.iter() {
49 if let Some(result) = service.handle(request, ctx).await? {
50 return Ok(result);
51 }
52 }
53
54 let err = Error::MethodNotFound {
55 name: request.method().to_string(),
56 id: request.id.clone(),
57 };
58
59 Ok((request, err).into())
60 }
61
62 /// Infallible service handler, errors are automatically converted to responses.
63 ///
64 /// If a request was a notification (no id field) this will yield `None`.
65 pub async fn serve(&self, request: &Request, ctx: &T) -> Option<Response> {
66 match self.handle(request, ctx).await {
67 Ok(response) => {
68 if response.error().is_some() || response.id().is_some() {
69 Some(response)
70 } else {
71 None
72 }
73 }
74 Err(e) => Some((request, e).into()),
75 }
76 }
77}