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