endpoint_libs/libs/
handler.rs

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