1#[cfg(feature = "openapi")]
2use aide::openapi::Info;
3use schemars::JsonSchema;
4use serde::Deserialize;
5use spring::config::Configurable;
6use std::net::{IpAddr, Ipv4Addr};
7use tracing::Level;
8
9spring::submit_config_schema!("web", WebConfig);
10
11#[derive(Debug, Configurable, JsonSchema, Deserialize)]
13#[config_prefix = "web"]
14pub struct WebConfig {
15 #[serde(flatten)]
16 pub(crate) server: ServerConfig,
17 #[cfg(feature = "openapi")]
18 pub(crate) openapi: OpenApiConfig,
19 pub(crate) middlewares: Option<Middlewares>,
20}
21
22#[derive(Debug, Clone, JsonSchema, Deserialize)]
23pub struct ServerConfig {
24 #[serde(default = "default_binding")]
25 pub(crate) binding: IpAddr,
26 #[serde(default = "default_port")]
27 pub(crate) port: u16,
28 #[serde(default)]
29 pub(crate) connect_info: bool,
30 #[serde(default)]
31 pub(crate) graceful: bool,
32}
33
34#[cfg(feature = "openapi")]
35#[derive(Debug, Clone, JsonSchema, Deserialize)]
36pub struct OpenApiConfig {
37 #[serde(default = "default_doc_prefix")]
38 pub(crate) doc_prefix: String,
39 #[serde(default)]
40 pub(crate) info: aide::openapi::Info,
41}
42
43fn default_binding() -> IpAddr {
44 IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0))
45}
46
47fn default_port() -> u16 {
48 8080
49}
50
51#[cfg(feature = "openapi")]
52fn default_doc_prefix() -> String {
53 "/docs".into()
54}
55
56#[derive(Debug, Clone, JsonSchema, Deserialize)]
58pub struct Middlewares {
59 pub compression: Option<EnableMiddleware>,
61 pub limit_payload: Option<LimitPayloadMiddleware>,
63 pub logger: Option<TraceLoggerMiddleware>,
66 pub catch_panic: Option<EnableMiddleware>,
68 pub timeout_request: Option<TimeoutRequestMiddleware>,
70 pub cors: Option<CorsMiddleware>,
72 #[serde(rename = "static")]
74 pub static_assets: Option<StaticAssetsMiddleware>,
75}
76
77#[derive(Debug, Clone, JsonSchema, Deserialize)]
79pub struct StaticAssetsMiddleware {
80 pub enable: bool,
82 #[serde(default = "bool::default")]
84 pub must_exist: bool,
85 #[serde(default = "default_fallback")]
88 pub fallback: String,
89 #[serde(default = "bool::default")]
91 pub precompressed: bool,
92 #[serde(default = "default_assets_uri")]
94 pub uri: String,
95 #[serde(default = "default_assets_path")]
97 pub path: String,
98}
99
100#[derive(Debug, Clone, JsonSchema, Deserialize)]
102pub struct TraceLoggerMiddleware {
103 pub enable: bool,
105 pub level: LogLevel,
106}
107
108#[derive(Debug, Default, Clone, JsonSchema, Deserialize)]
109pub enum LogLevel {
110 #[serde(rename = "trace")]
112 Trace,
113 #[serde(rename = "debug")]
115 Debug,
116 #[serde(rename = "info")]
118 #[default]
119 Info,
120 #[serde(rename = "warn")]
122 Warn,
123 #[serde(rename = "error")]
125 Error,
126}
127
128#[allow(clippy::from_over_into)]
129impl Into<Level> for LogLevel {
130 fn into(self) -> Level {
131 match self {
132 Self::Trace => Level::TRACE,
133 Self::Debug => Level::DEBUG,
134 Self::Info => Level::INFO,
135 Self::Warn => Level::WARN,
136 Self::Error => Level::ERROR,
137 }
138 }
139}
140
141#[derive(Debug, Clone, JsonSchema, Deserialize)]
143pub struct CorsMiddleware {
144 pub enable: bool,
146 pub allow_origins: Option<Vec<String>>,
148 pub allow_headers: Option<Vec<String>>,
150 pub allow_methods: Option<Vec<String>>,
152 pub max_age: Option<u64>,
154}
155
156#[derive(Debug, Clone, JsonSchema, Deserialize)]
158pub struct TimeoutRequestMiddleware {
159 pub enable: bool,
161 pub timeout: u64,
163}
164
165#[derive(Debug, Clone, JsonSchema, Deserialize)]
167pub struct LimitPayloadMiddleware {
168 pub enable: bool,
170 pub body_limit: String,
172}
173
174#[derive(Debug, PartialEq, Clone, JsonSchema, Deserialize)]
177pub struct EnableMiddleware {
178 pub enable: bool,
180}
181
182fn default_assets_path() -> String {
183 "static".to_string()
184}
185
186fn default_assets_uri() -> String {
187 "/static".to_string()
188}
189
190fn default_fallback() -> String {
191 "index.html".to_string()
192}