redfish_axum/
metric_definition_collection.rs1pub 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 MetricDefinitionCollection<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    members_router: axum::routing::MethodRouter<S>,
26    metric_definition: Option<axum::Router<S>>,
27}
28
29impl<S> Default for MetricDefinitionCollection<S, DefaultPrivileges>
30where
31    S: Clone,
32{
33    fn default() -> Self {
34        Self {
35            router: Default::default(),
36            privilege_marker: Default::default(),
37            allowed_methods: Vec::new(),
38            members_router: Default::default(),
39            metric_definition: Default::default(),
40        }
41    }
42}
43
44impl<S, P> MetricDefinitionCollection<S, P>
45where
46    S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
47    P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
48    <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
49    <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
50{
51    pub fn get<H, T>(mut self, handler: H) -> Self
52    where
53        H: axum::handler::Handler<T, S, axum::body::Body>,
54        T: 'static,
55    {
56        let operation = axum::routing::get(
57            |auth: redfish_core::extract::RedfishAuth<P::Get>,
58             axum::extract::State(state): axum::extract::State<S>,
59             mut request: axum::http::Request<axum::body::Body>| async {
60                request.extensions_mut().insert(auth.user);
61                handler.call(request, state).await
62            },
63        );
64        self.router = self.router.get(operation);
65        self.allowed_methods.push(axum::http::method::Method::GET);
66        self
67    }
68
69    pub fn post<H, T>(mut self, handler: H) -> Self
70    where
71        H: axum::handler::Handler<T, S, axum::body::Body>,
72        T: 'static,
73    {
74        let operation = axum::routing::post(
75            |auth: redfish_core::extract::RedfishAuth<P::Post>,
76             axum::extract::State(state): axum::extract::State<S>,
77             mut request: axum::http::Request<axum::body::Body>| async {
78                request.extensions_mut().insert(auth.user);
79                handler.call(request, state).await
80            },
81        );
82        self.members_router = self.members_router.post(operation.clone());
83        self.router = self.router.post(operation);
84        self.allowed_methods.push(axum::http::method::Method::POST);
85        self
86    }
87
88    pub fn metric_definition(mut self, metric_definition: axum::Router<S>) -> Self {
90        self.metric_definition = Some(metric_definition);
91        self
92    }
93
94    pub fn into_router(self) -> axum::Router<S> {
95        let Self {
96            router,
97            mut allowed_methods,
98            members_router,
99            metric_definition,
100            ..
101        } = self;
102        let result = axum::Router::default();
103        let result = match metric_definition {
104            Some(router) => result.nest("/:metric_definition_id", router),
105            None => result,
106        };
107        let result = result.route(
108            "/Members",
109            members_router.fallback(|| async {
110                (
111                    axum::http::StatusCode::METHOD_NOT_ALLOWED,
112                    axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
113                )
114            })
115        );
116        allowed_methods.dedup();
117        let allow_header = allowed_methods
118            .into_iter()
119            .map(|method| method.to_string())
120            .reduce(|one, two| one + "," + &two)
121            .unwrap();
122        result.route(
123            "/",
124            router.fallback(|| async {
125                (
126                    axum::http::StatusCode::METHOD_NOT_ALLOWED,
127                    axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
128                )
129            })
130            .route_layer(axum::middleware::from_fn_with_state(
131                allow_header,
132                |axum::extract::State(allow_header): axum::extract::State<String>,
133                 request: axum::http::Request<axum::body::Body>,
134                 next: axum::middleware::Next<axum::body::Body>| async move {
135                    let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
136                    let mut response = next.run(request).await;
137                    if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
138                        response.headers_mut().insert(
139                            axum::http::header::ALLOW,
140                            axum::http::HeaderValue::from_str(&allow_header).unwrap(),
141                        );
142                    }
143                    response
144                },
145            )),
146        )
147    }
148}