redfish_axum/
registered_client_collection.rs1pub struct RegisteredClientCollection<S, P>
8where
9    S: Clone,
10{
11    router: axum::routing::MethodRouter<S>,
12    privilege_marker: std::marker::PhantomData<fn() -> P>,
13    allowed_methods: Vec<axum::http::method::Method>,
14    members_router: axum::routing::MethodRouter<S>,
15    registered_client: Option<axum::Router<S>>,
16}
17
18
19impl<S, P> RegisteredClientCollection<S, P>
20where
21    S: AsRef<dyn redfish_core::auth::AuthenticateRequest> + Clone + Send + Sync + 'static,
22    P: redfish_core::privilege::OperationPrivilegeMapping + 'static,
23    <P as redfish_core::privilege::OperationPrivilegeMapping>::Get: Send,
24    <P as redfish_core::privilege::OperationPrivilegeMapping>::Post: Send,
25{
26    pub fn get<H, T>(mut self, handler: H) -> Self
27    where
28        H: axum::handler::Handler<T, S, axum::body::Body>,
29        T: 'static,
30    {
31        let operation = axum::routing::get(
32            |auth: redfish_core::extract::RedfishAuth<P::Get>,
33             axum::extract::State(state): axum::extract::State<S>,
34             mut request: axum::http::Request<axum::body::Body>| async {
35                request.extensions_mut().insert(auth.user);
36                handler.call(request, state).await
37            },
38        );
39        self.router = self.router.get(operation);
40        self.allowed_methods.push(axum::http::method::Method::GET);
41        self
42    }
43
44    pub fn post<H, T>(mut self, handler: H) -> Self
45    where
46        H: axum::handler::Handler<T, S, axum::body::Body>,
47        T: 'static,
48    {
49        let operation = axum::routing::post(
50            |auth: redfish_core::extract::RedfishAuth<P::Post>,
51             axum::extract::State(state): axum::extract::State<S>,
52             mut request: axum::http::Request<axum::body::Body>| async {
53                request.extensions_mut().insert(auth.user);
54                handler.call(request, state).await
55            },
56        );
57        self.members_router = self.members_router.post(operation.clone());
58        self.router = self.router.post(operation);
59        self.allowed_methods.push(axum::http::method::Method::POST);
60        self
61    }
62
63    pub fn registered_client(mut self, registered_client: axum::Router<S>) -> Self {
65        self.registered_client = Some(registered_client);
66        self
67    }
68
69    pub fn into_router(self) -> axum::Router<S> {
70        let Self {
71            router,
72            mut allowed_methods,
73            members_router,
74            registered_client,
75            ..
76        } = self;
77        let result = axum::Router::default();
78        let result = match registered_client {
79            Some(router) => result.nest("/:registered_client_id", router),
80            None => result,
81        };
82        let result = result.route(
83            "/Members",
84            members_router.fallback(|| async {
85                (
86                    axum::http::StatusCode::METHOD_NOT_ALLOWED,
87                    axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
88                )
89            })
90        );
91        allowed_methods.dedup();
92        let allow_header = allowed_methods
93            .into_iter()
94            .map(|method| method.to_string())
95            .reduce(|one, two| one + "," + &two)
96            .unwrap();
97        result.route(
98            "/",
99            router.fallback(|| async {
100                (
101                    axum::http::StatusCode::METHOD_NOT_ALLOWED,
102                    axum::Json(redfish_core::error::one_message(redfish_codegen::registries::base::v1_16_0::Base::OperationNotAllowed.into())),
103                )
104            })
105            .route_layer(axum::middleware::from_fn_with_state(
106                allow_header,
107                |axum::extract::State(allow_header): axum::extract::State<String>,
108                 request: axum::http::Request<axum::body::Body>,
109                 next: axum::middleware::Next<axum::body::Body>| async move {
110                    let apply_allow = matches!(*request.method(), axum::http::Method::GET | axum::http::Method::HEAD);
111                    let mut response = next.run(request).await;
112                    if apply_allow && !response.headers().contains_key(axum::http::header::ALLOW) {
113                        response.headers_mut().insert(
114                            axum::http::header::ALLOW,
115                            axum::http::HeaderValue::from_str(&allow_header).unwrap(),
116                        );
117                    }
118                    response
119                },
120            )),
121        )
122    }
123}