endpoint_libs/libs/
handler.rs

1use async_trait::async_trait;
2use eyre::Result;
3use serde_json::Value;
4
5use super::{
6    error_code::ErrorCode,
7    toolbox::{ArcToolbox, RequestContext, Toolbox},
8    ws::{request_error_to_resp, WsRequest},
9};
10
11#[allow(type_alias_bounds)]
12pub type Response<T: WsRequest> = Result<T::Response>;
13#[async_trait(?Send)]
14pub trait RequestHandler: Send + Sync {
15    type Request: WsRequest + 'static;
16
17    async fn handle(&self, ctx: RequestContext, req: Self::Request) -> Response<Self::Request>;
18}
19
20#[doc(hidden)]
21#[async_trait(?Send)]
22pub trait RequestHandlerErased: Send + Sync {
23    async fn handle(&self, toolbox: &ArcToolbox, ctx: RequestContext, req: Value);
24}
25
26#[async_trait(?Send)]
27impl<T: RequestHandler> RequestHandlerErased for T {
28    async fn handle(&self, toolbox: &ArcToolbox, ctx: RequestContext, req: Value) {
29        // TODO: find a better way to avoid double parsing or serialization
30        let buf = serde_json::to_string(&req).unwrap();
31        let data: T::Request = match serde_json::from_value(req) {
32            Ok(data) => data,
33            Err(err) => {
34                let jd = &mut serde_json::Deserializer::from_str(&buf);
35                let data: Result<T::Request, _> = serde_path_to_error::deserialize(jd);
36                let path = data.err().map(|err| err.path().to_string());
37                toolbox.send(
38                    ctx.connection_id,
39                    request_error_to_resp(
40                        &ctx,
41                        ErrorCode::new(100400), // Bad Request
42                        if let Some(path) = path {
43                            format!("{path}: {err}")
44                        } else {
45                            format!("{err}")
46                        },
47                    ),
48                );
49                return;
50            }
51        };
52
53        let fut = RequestHandler::handle(self, ctx, data);
54
55        let resp = fut.await;
56        if let Some(resp) = Toolbox::encode_ws_response(ctx, resp) {
57            toolbox.send(ctx.connection_id, resp);
58        }
59    }
60}