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}