1pub use axum::extract::*;
2
3use crate::error::{Result, WebError};
4use crate::AppState;
5use anyhow::Context;
6use axum::http::request::Parts;
7use spring::config::{ConfigRegistry, Configurable};
8use spring::plugin::ComponentRegistry;
9use std::ops::{Deref, DerefMut};
10use std::result::Result as StdResult;
11
12pub trait RequestPartsExt {
14 fn get_app_state(&self) -> &AppState;
16
17 fn get_component<T: Clone + Send + Sync + 'static>(&self) -> Result<T>;
19
20 fn get_config<T: serde::de::DeserializeOwned + Configurable>(&self) -> Result<T>;
22}
23
24impl RequestPartsExt for Parts {
25 fn get_app_state(&self) -> &AppState {
26 self.extensions
27 .get::<AppState>()
28 .expect("extract app state from extension failed")
29 }
30
31 fn get_component<T: Clone + Send + Sync + 'static>(&self) -> Result<T> {
32 Ok(self
33 .get_app_state()
34 .app
35 .try_get_component()
36 .context("get_component failed")?)
37 }
38
39 fn get_config<T: serde::de::DeserializeOwned + Configurable>(&self) -> Result<T> {
40 self.get_app_state()
41 .app
42 .get_config::<T>()
43 .map_err(|e| WebError::ConfigDeserializeErr(std::any::type_name::<T>(), Box::new(e)))
44 }
45}
46
47pub struct Component<T: Clone>(pub T);
49
50impl<T, S> FromRequestParts<S> for Component<T>
51where
52 T: Clone + Send + Sync + 'static,
53 S: Sync,
54{
55 type Rejection = WebError;
56
57 async fn from_request_parts(parts: &mut Parts, _s: &S) -> StdResult<Self, Self::Rejection> {
58 parts.get_component::<T>().map(|c| Component(c))
59 }
60}
61
62#[cfg(feature = "openapi")]
63impl<T: Clone> aide::OperationInput for Component<T> {}
64
65impl<T: Clone> Deref for Component<T> {
66 type Target = T;
67
68 fn deref(&self) -> &Self::Target {
69 &self.0
70 }
71}
72
73impl<T: Clone> DerefMut for Component<T> {
74 fn deref_mut(&mut self) -> &mut Self::Target {
75 &mut self.0
76 }
77}
78
79pub struct Config<T>(pub T)
80where
81 T: serde::de::DeserializeOwned + Configurable;
82
83impl<T, S> FromRequestParts<S> for Config<T>
84where
85 T: serde::de::DeserializeOwned + Configurable,
86 S: Sync,
87{
88 type Rejection = WebError;
89
90 async fn from_request_parts(parts: &mut Parts, _s: &S) -> StdResult<Self, Self::Rejection> {
91 parts.get_config().map(|c| Config(c))
92 }
93}
94
95#[cfg(feature = "openapi")]
96impl<T> aide::OperationInput for Config<T> where T: serde::de::DeserializeOwned + Configurable {}
97
98impl<T> Deref for Config<T>
99where
100 T: serde::de::DeserializeOwned + Configurable,
101{
102 type Target = T;
103
104 fn deref(&self) -> &Self::Target {
105 &self.0
106 }
107}
108
109impl<T> DerefMut for Config<T>
110where
111 T: serde::de::DeserializeOwned + Configurable,
112{
113 fn deref_mut(&mut self) -> &mut Self::Target {
114 &mut self.0
115 }
116}