1#![cfg_attr(docsrs, feature(doc_cfg))]
2
3use std::collections::HashMap;
8use std::sync::Arc;
9
10use http::header::{CONTENT_LENGTH, CONTENT_TYPE};
11use http::{HeaderMap, HeaderValue, StatusCode};
12
13use dxr::{Error, Fault, FaultResponse, MethodCall, MethodResponse, Value};
14
15#[cfg(feature = "multicall")]
16use dxr::multicall;
17
18mod handler;
19pub use handler::*;
20
21#[cfg(feature = "axum")]
22mod axum_support;
23#[cfg(feature = "axum")]
24pub use self::axum_support::*;
25
26#[cfg(feature = "axum")]
28pub use axum;
29
30pub use async_trait::async_trait;
32
33pub const DEFAULT_SERVER_ROUTE: &str = "/";
35
36pub type HandlerMap = Arc<HashMap<&'static str, Box<dyn Handler>>>;
38
39pub async fn server(handlers: HandlerMap, body: &str, headers: HeaderMap) -> (StatusCode, HeaderMap, String) {
45 if headers.get(CONTENT_LENGTH).is_none() {
46 return fault_to_response(411, "Content-Length header missing.");
47 }
48
49 let call: MethodCall = match MethodCall::from_xml(body) {
50 Ok(call) => call,
51 Err(error) => {
52 let e = Error::invalid_data(error.to_string());
53 let f = Fault::from(e);
54 return fault_to_response(f.code(), f.string());
55 },
56 };
57
58 #[cfg(feature = "multicall")]
59 if call.name == "system.multicall" {
60 let calls = match multicall::from_multicall_params(call.params) {
61 Ok(calls) => calls,
62 Err(error) => {
63 let f = Fault::from(error);
64 return fault_to_response(f.code(), f.string());
65 },
66 };
67
68 let mut results = Vec::new();
69
70 for multi in calls {
71 match multi {
72 Ok((name, params)) => {
73 let Some(handler) = handlers.get(name.as_str()) else {
74 log_no_handler(&name);
75 results.push(Err(Fault::new(404, String::from("Unknown method."))));
76 continue;
77 };
78
79 let result = handler.handle(¶ms, headers.clone()).await;
80 results.push(result);
81 },
82 Err(error) => {
83 results.push(Err(Fault::from(error)));
84 },
85 }
86 }
87
88 let value = multicall::into_multicall_response(results);
89
90 return success_to_response(value);
91 }
92
93 let Some(handler) = handlers.get(call.name.as_ref()) else {
94 log_no_handler(&call.name);
95 return fault_to_response(404, "Unknown method.");
96 };
97
98 match handler.handle(&call.params, headers).await {
99 Ok(value) => success_to_response(value),
100 Err(fault) => fault_to_response(fault.code(), fault.string()),
101 }
102}
103
104fn response_headers() -> HeaderMap {
105 let mut headers = HeaderMap::new();
106 headers.insert(CONTENT_TYPE, HeaderValue::from_static("text/xml"));
107 headers
108}
109
110fn success_to_response(value: Value) -> (StatusCode, HeaderMap, String) {
111 let response = MethodResponse { value };
112
113 match response.to_xml() {
114 Ok(success) => (StatusCode::OK, response_headers(), success),
115 Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, response_headers(), error.to_string()),
116 }
117}
118
119fn fault_to_response(code: i32, string: &str) -> (StatusCode, HeaderMap, String) {
120 let fault = Fault::new(code, string.to_owned());
121 let response: FaultResponse = FaultResponse { fault };
122
123 match response.to_xml() {
124 Ok(fault) => (StatusCode::OK, response_headers(), fault),
125 Err(error) => (StatusCode::INTERNAL_SERVER_ERROR, response_headers(), error.to_string()),
126 }
127}
128
129fn log_no_handler(method: &str) {
131 log::debug!("No handler registered for method: {method}");
132}