1pub struct DefaultPrivileges;
5impl redfish_core::privilege::OperationPrivilegeMapping for DefaultPrivileges {
6 type Get = redfish_core::privilege::Login;
7 type Head = redfish_core::privilege::Login;
8 type Post = redfish_core::privilege::ConfigureManager;
9 type Put = redfish_core::privilege::ConfigureManager;
10 type Patch = redfish_core::privilege::ConfigureManager;
11 type Delete = redfish_core::privilege::ConfigureManager;
12}
13
14pub struct Battery<S, P>
19where
20 S: Clone,
21{
22 router: axum::routing::MethodRouter<S>,
23 privilege_marker: std::marker::PhantomData<fn() -> P>,
24 allowed_methods: Vec<axum::http::method::Method>,
25 assembly: Option<axum::Router<S>>,
26 metrics: Option<axum::Router<S>>,
27 calibrate: Option<axum::routing::MethodRouter<S>>,
28 reset: Option<axum::routing::MethodRouter<S>>,
29 self_test: Option<axum::routing::MethodRouter<S>>,
30}
31
32impl<S> Default for Battery<S, DefaultPrivileges>
33where
34 S: Clone,
35{
36 fn default() -> Self {
37 Self {
38 router: Default::default(),
39 privilege_marker: Default::default(),
40 allowed_methods: Vec::new(),
41 assembly: Default::default(),
42 metrics: Default::default(),
43 calibrate: Default::default(),
44 reset: Default::default(),
45 self_test: Default::default(),
46 }
47 }
48}
49
50impl<S, P> Battery<S, P>
51where
52 S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
53 P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
54 <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
55 <P as redfish_core::privilege::OperationPrivilegeMapping>::Put: Send,
56 <P as redfish_core::privilege::OperationPrivilegeMapping>::Patch: Send,
57 <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
58{
59 pub fn get<H, T>(mut self, handler: H) -> Self
60 where
61 H: axum::handler::Handler<T, S, axum::body::Body>,
62 T: 'static,
63 {
64 let operation = axum::routing::get(
65 |auth: redfish_core::extract::RedfishAuth<P::Get>,
66 axum::extract::State(state): axum::extract::State<S>,
67 mut request: axum::http::Request<axum::body::Body>| async {
68 request.extensions_mut().insert(auth.user);
69 handler.call(request, state).await
70 },
71 );
72 self.router = self.router.get(operation);
73 self.allowed_methods.push(axum::http::method::Method::GET);
74 self
75 }
76
77 pub fn put<H, T>(mut self, handler: H) -> Self
78 where
79 H: axum::handler::Handler<T, S, axum::body::Body>,
80 T: 'static,
81 {
82 let operation = axum::routing::put(
83 |auth: redfish_core::extract::RedfishAuth<P::Put>,
84 axum::extract::State(state): axum::extract::State<S>,
85 mut request: axum::http::Request<axum::body::Body>| async {
86 request.extensions_mut().insert(auth.user);
87 handler.call(request, state).await
88 },
89 );
90 self.router = self.router.put(operation);
91 self.allowed_methods.push(axum::http::method::Method::PUT);
92 self
93 }
94
95 pub fn patch<H, T>(mut self, handler: H) -> Self
96 where
97 H: axum::handler::Handler<T, S, axum::body::Body>,
98 T: 'static,
99 {
100 let operation = axum::routing::patch(
101 |auth: redfish_core::extract::RedfishAuth<P::Patch>,
102 axum::extract::State(state): axum::extract::State<S>,
103 mut request: axum::http::Request<axum::body::Body>| async {
104 request.extensions_mut().insert(auth.user);
105 handler.call(request, state).await
106 },
107 );
108 self.router = self.router.patch(operation);
109 self.allowed_methods.push(axum::http::method::Method::PATCH);
110 self
111 }
112
113 pub fn assembly(mut self, assembly: axum::Router<S>) -> Self {
115 self.assembly = Some(assembly);
116 self
117 }
118
119 pub fn metrics(mut self, metrics: axum::Router<S>) -> Self {
121 self.metrics = Some(metrics);
122 self
123 }
124
125 pub fn calibrate<H, T>(mut self, handler: H) -> Self
127 where
128 H: axum::handler::Handler<T, S, axum::body::Body>,
129 T: 'static,
130 {
131 self.calibrate = Some(axum::routing::post(
132 |auth: redfish_core::extract::RedfishAuth<P::Post>,
133 axum::extract::State(state): axum::extract::State<S>,
134 mut request: axum::http::Request<axum::body::Body>| async {
135 request.extensions_mut().insert(auth.user);
136 handler.call(request, state).await
137 },
138 ));
139 self
140 }
141
142 pub fn reset<H, T>(mut self, handler: H) -> Self
144 where
145 H: axum::handler::Handler<T, S, axum::body::Body>,
146 T: 'static,
147 {
148 self.reset = Some(axum::routing::post(
149 |auth: redfish_core::extract::RedfishAuth<P::Post>,
150 axum::extract::State(state): axum::extract::State<S>,
151 mut request: axum::http::Request<axum::body::Body>| async {
152 request.extensions_mut().insert(auth.user);
153 handler.call(request, state).await
154 },
155 ));
156 self
157 }
158
159 pub fn self_test<H, T>(mut self, handler: H) -> Self
161 where
162 H: axum::handler::Handler<T, S, axum::body::Body>,
163 T: 'static,
164 {
165 self.self_test = Some(axum::routing::post(
166 |auth: redfish_core::extract::RedfishAuth<P::Post>,
167 axum::extract::State(state): axum::extract::State<S>,
168 mut request: axum::http::Request<axum::body::Body>| async {
169 request.extensions_mut().insert(auth.user);
170 handler.call(request, state).await
171 },
172 ));
173 self
174 }
175
176 pub fn into_router(self) -> axum::Router<S> {
177 let Self {
178 router,
179 mut allowed_methods,
180 assembly,
181 metrics,
182 calibrate,
183 reset,
184 self_test,
185 ..
186 } = self;
187 let result = axum::Router::default();
188 let result = match assembly {
189 Some(router) => result.nest("/Assembly", router),
190 None => result,
191 };
192 let result = match metrics {
193 Some(router) => result.nest("/Metrics", router),
194 None => result,
195 };
196 let result = match calibrate {
197 Some(router) => result.route("/Actions/Battery.Calibrate", router),
198 None => result,
199 };
200 let result = match reset {
201 Some(router) => result.route("/Actions/Battery.Reset", router),
202 None => result,
203 };
204 let result = match self_test {
205 Some(router) => result.route("/Actions/Battery.SelfTest", router),
206 None => result,
207 };
208 allowed_methods.dedup();
209 let allow_header = allowed_methods
210 .into_iter()
211 .map(|method| method.to_string())
212 .reduce(|one, two| one + "," + &two)
213 .unwrap();
214 result.route(
215 "/",
216 router.fallback(|| async {
217 (
218 axum::http::StatusCode::METHOD_NOT_ALLOWED,
219 axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
220 )
221 })
222 .route_layer(axum::middleware::from_fn_with_state(
223 allow_header,
224 |axum::extract::State(allow_header): axum::extract::State<String>,
225 request: axum::http::Request<axum::body::Body>,
226 next: axum::middleware::Next<axum::body::Body>| async move {
227 let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
228 let mut response = next.run(request).await;
229 if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
230 response.headers_mut().insert(
231 axum::http::header::ALLOW,
232 axum::http::HeaderValue::from_str(&allow_header).unwrap(),
233 );
234 }
235 response
236 },
237 )),
238 )
239 }
240}