alux_jsonrpc_direct/
dispatch.rs1use crate::error::RpcError;
2use crate::table::MethodTable;
3use serde::Serialize;
4use serde_json::Value;
5use std::sync::Arc;
6
7#[derive(Debug, Serialize)]
9struct Response {
10 jsonrpc: &'static str,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 result: Option<Value>,
13 #[serde(skip_serializing_if = "Option::is_none")]
14 error: Option<RpcError>,
15 id: Value,
16}
17
18impl Response {
19 fn of(id: Value, outcome: Result<Value, RpcError>) -> Self {
21 match outcome {
22 Ok(result) => Self { jsonrpc: "2.0", result: Some(result), error: None, id },
23 Err(error) => Self { jsonrpc: "2.0", result: None, error: Some(error), id },
24 }
25 }
26}
27
28#[derive(Debug, Serialize)]
30#[serde(untagged)]
31enum Answered {
32 One(Response),
33 Many(Vec<Response>),
34}
35
36fn members(call: Value) -> Result<serde_json::Map<String, Value>, RpcError> {
38 match call {
39 Value::Object(members) => Ok(members),
40 _ => Err(RpcError::invalid_request()),
41 }
42}
43
44fn is_identifier(id: &Value) -> bool {
47 matches!(id, Value::String(_) | Value::Number(_) | Value::Null)
48}
49
50impl MethodTable {
51 pub async fn dispatch(&self, request: &str) -> Option<String> {
55 let answered = match serde_json::from_str::<Value>(request) {
56 Ok(document) => self.answer(document).await?,
57 Err(_) => Answered::One(Response::of(Value::Null, Err(RpcError::parse_error()))),
58 };
59
60 Some(render(&answered))
61 }
62
63 async fn answer(&self, document: Value) -> Option<Answered> {
65 let Value::Array(calls) = document else {
66 return self.call(document).await.map(Answered::One);
67 };
68 if calls.is_empty() {
69 return Some(Answered::One(Response::of(Value::Null, Err(RpcError::invalid_request()))));
70 }
71 let mut answers = Vec::new();
72 for call in calls {
73 if let Some(answer) = self.call(call).await {
74 answers.push(answer);
75 }
76 }
77
78 (!answers.is_empty()).then_some(Answered::Many(answers))
79 }
80
81 async fn call(&self, call: Value) -> Option<Response> {
83 let (id, outcome) = self.outcome(call).await;
84
85 id.map(|id| Response::of(id, outcome))
86 }
87
88 async fn outcome(&self, call: Value) -> (Option<Value>, Result<Value, RpcError>) {
93 let mut members = match members(call) {
94 Ok(members) => members,
95 Err(error) => return (Some(Value::Null), Err(error)),
96 };
97 let respond_to = members.remove("id");
100 if respond_to.as_ref().is_some_and(|id| !is_identifier(id)) {
101 return (Some(Value::Null), Err(RpcError::invalid_request()));
102 }
103 if members.get("jsonrpc").and_then(Value::as_str) != Some("2.0") {
104 return (respond_to, Err(RpcError::invalid_request()));
105 }
106 let Some(Value::String(method)) = members.remove("method") else {
107 return (respond_to, Err(RpcError::invalid_request()));
108 };
109 let params = members.remove("params");
110 if params.as_ref().is_some_and(|params| !(params.is_array() || params.is_object() || params.is_null())) {
111 return (respond_to, Err(RpcError::invalid_request()));
112 }
113 let Some(method) = self.get(method.as_str()).map(Arc::clone) else {
114 return (respond_to, Err(RpcError::method_not_found(&method)));
115 };
116
117 (respond_to, method(params).await)
118 }
119}
120
121fn render(answered: &Answered) -> String {
123 serde_json::to_string(answered).unwrap_or_else(|_| {
124 r#"{"jsonrpc":"2.0","error":{"code":-32603,"message":"the answer cannot be serialized"},"id":null}"#.to_owned()
125 })
126}