use async_trait::async_trait;
use eyre::Result;
use serde_json::Value;
use crate::libs::{
error_code::ErrorCode,
toolbox::{ArcToolbox, RequestContext, Toolbox},
ws::{WsRequest, request_error_to_resp},
};
#[allow(type_alias_bounds)]
pub type Response<T: WsRequest> = Result<T::Response>;
#[async_trait(?Send)]
pub trait RequestHandler: Send + Sync {
type Request: WsRequest + 'static;
async fn handle(&self, ctx: RequestContext, req: Self::Request) -> Response<Self::Request>;
}
#[doc(hidden)]
#[async_trait(?Send)]
pub trait RequestHandlerErased: Send + Sync {
async fn handle(&self, toolbox: &ArcToolbox, ctx: RequestContext, req: Value);
}
#[async_trait(?Send)]
impl<T: RequestHandler> RequestHandlerErased for T {
async fn handle(&self, toolbox: &ArcToolbox, ctx: RequestContext, req: Value) {
let buf = serde_json::to_string(&req).unwrap();
let data: T::Request = match serde_json::from_value(req) {
Ok(data) => data,
Err(err) => {
let jd = &mut serde_json::Deserializer::from_str(&buf);
let data: Result<T::Request, _> = serde_path_to_error::deserialize(jd);
let path = data.err().map(|err| err.path().to_string());
toolbox.send(
ctx.connection_id,
request_error_to_resp(
&ctx,
ErrorCode::BAD_REQUEST,
if let Some(path) = path {
format!("{path}: {err}")
} else {
format!("{err}")
},
),
);
return;
}
};
let fut = RequestHandler::handle(self, ctx.clone(), data);
let resp = fut.await;
if let Some(resp) = Toolbox::encode_ws_response(ctx.clone(), resp) {
toolbox.send(ctx.connection_id, resp);
}
}
}