1use std::{collections::HashMap, path::PathBuf};
2
3use serde::Deserialize;
4
5pub mod cors;
6pub mod env;
7pub mod loader;
8pub mod metrics;
9pub mod rate_limiting;
10#[cfg(test)]
11mod tests;
12pub mod tracing;
13pub mod validation;
14
15pub use cors::CorsConfig;
17pub use metrics::{LatencyTargets, MetricsConfig, SloConfig};
18pub use rate_limiting::{BackpressureConfig, RateLimitRule, RateLimitingConfig};
19pub use tracing::TracingConfig;
20
21#[derive(Debug, Clone, Deserialize)]
23pub struct RuntimeConfig {
24 pub server: ServerConfig,
25 pub database: DatabaseConfig,
26
27 #[serde(default)]
28 pub webhooks: HashMap<String, WebhookConfig>,
29
30 #[serde(default)]
31 pub files: HashMap<String, FileConfig>,
32
33 #[serde(default)]
34 pub auth: Option<AuthConfig>,
35
36 #[serde(default)]
37 pub notifications: Option<NotificationsConfig>,
38
39 #[serde(default)]
40 pub observers: HashMap<String, ObserverConfig>,
41
42 #[serde(default)]
43 pub interceptors: HashMap<String, Vec<String>>,
44
45 #[serde(default)]
46 pub rate_limiting: Option<RateLimitingConfig>,
47
48 #[serde(default)]
49 pub cors: Option<CorsConfig>,
50
51 #[serde(default)]
52 pub metrics: Option<MetricsConfig>,
53
54 #[serde(default)]
55 pub tracing: Option<TracingConfig>,
56
57 #[serde(default)]
58 pub logging: Option<LoggingConfig>,
59
60 #[serde(default)]
61 pub storage: HashMap<String, StorageConfig>,
62
63 #[serde(default)]
64 pub search: Option<SearchConfig>,
65
66 #[serde(default)]
67 pub cache: Option<CacheConfig>,
68
69 #[serde(default)]
70 pub queues: Option<QueueConfig>,
71
72 #[serde(default)]
73 pub realtime: Option<RealtimeConfig>,
74
75 #[serde(default)]
76 pub custom_endpoints: Option<CustomEndpointsConfig>,
77
78 #[serde(default)]
79 pub lifecycle: Option<LifecycleConfig>,
80}
81
82#[derive(Debug, Clone, Deserialize)]
83pub struct ServerConfig {
84 #[serde(default = "default_port")]
85 pub port: u16,
86
87 #[serde(default = "default_host")]
88 pub host: String,
89
90 #[serde(default)]
91 pub workers: Option<usize>,
92
93 #[serde(default)]
94 pub tls: Option<TlsConfig>,
95
96 #[serde(default)]
97 pub limits: Option<ServerLimitsConfig>,
98}
99
100fn default_port() -> u16 {
101 4000
102}
103fn default_host() -> String {
104 "127.0.0.1".to_string()
105}
106
107#[derive(Debug, Clone, Deserialize)]
108pub struct TlsConfig {
109 pub cert_file: PathBuf,
110 pub key_file: PathBuf,
111}
112
113#[derive(Debug, Clone, Deserialize)]
114pub struct ServerLimitsConfig {
115 #[serde(default = "default_max_request_size")]
116 pub max_request_size: String,
117
118 #[serde(default = "default_request_timeout")]
119 pub request_timeout: String,
120
121 #[serde(default = "default_max_concurrent")]
122 pub max_concurrent_requests: usize,
123
124 #[serde(default = "default_max_queue_depth")]
125 pub max_queue_depth: usize,
126}
127
128fn default_max_request_size() -> String {
129 "10MB".to_string()
130}
131fn default_request_timeout() -> String {
132 "30s".to_string()
133}
134fn default_max_concurrent() -> usize {
135 1000
136}
137fn default_max_queue_depth() -> usize {
138 5000
139}
140
141#[derive(Debug, Clone, Deserialize)]
142pub struct DatabaseConfig {
143 pub url_env: String,
144
145 #[serde(default = "default_pool_size")]
146 pub pool_size: u32,
147
148 #[serde(default)]
149 pub pool_timeout: Option<String>,
150
151 #[serde(default)]
152 pub statement_timeout: Option<String>,
153
154 #[serde(default)]
155 pub replicas: Vec<ReplicaConfig>,
156
157 #[serde(default)]
158 pub health_check_interval: Option<String>,
159}
160
161fn default_pool_size() -> u32 {
162 10
163}
164
165#[derive(Debug, Clone, Deserialize)]
166pub struct ReplicaConfig {
167 pub url_env: String,
168
169 #[serde(default = "default_weight")]
170 pub weight: u32,
171}
172
173fn default_weight() -> u32 {
174 1
175}
176
177#[derive(Debug, Clone, Deserialize)]
179pub struct LifecycleConfig {
180 #[serde(default = "default_shutdown_timeout")]
182 pub shutdown_timeout: String,
183
184 #[serde(default = "default_shutdown_delay")]
186 pub shutdown_delay: String,
187
188 #[serde(default = "default_health_path")]
190 pub health_path: String,
191
192 #[serde(default = "default_ready_path")]
194 pub ready_path: String,
195}
196
197impl Default for LifecycleConfig {
198 fn default() -> Self {
199 Self {
200 shutdown_timeout: default_shutdown_timeout(),
201 shutdown_delay: default_shutdown_delay(),
202 health_path: default_health_path(),
203 ready_path: default_ready_path(),
204 }
205 }
206}
207
208fn default_shutdown_timeout() -> String {
209 "30s".to_string()
210}
211fn default_shutdown_delay() -> String {
212 "5s".to_string()
213}
214fn default_health_path() -> String {
215 "/health".to_string()
216}
217fn default_ready_path() -> String {
218 "/ready".to_string()
219}
220
221#[derive(Debug, Clone, Deserialize)]
224pub struct WebhookConfig {
225 pub secret_env: String,
226 pub provider: String,
227 #[serde(default)]
228 pub path: Option<String>,
229}
230
231#[derive(Debug, Clone, Deserialize)]
232pub struct FileConfig {
233 pub storage: String,
234 pub max_size: String,
235 #[serde(default)]
236 pub path: Option<String>,
237}
238
239#[derive(Debug, Clone, Deserialize)]
240pub struct AuthConfig {
241 pub jwt: JwtConfig,
242 #[serde(default)]
243 pub providers: HashMap<String, OAuthProviderConfig>,
244 #[serde(default)]
245 pub callback_base_url: Option<String>,
246}
247
248#[derive(Debug, Clone, Deserialize)]
249pub struct JwtConfig {
250 pub secret_env: String,
251}
252
253#[derive(Debug, Clone, Deserialize)]
254pub struct OAuthProviderConfig {
255 pub provider_type: String,
256 pub client_id_env: String,
257 pub client_secret_env: String,
258 #[serde(default)]
259 pub issuer_url: Option<String>,
260}
261
262#[derive(Debug, Clone, Deserialize)]
263pub struct NotificationsConfig {
264 }
266
267#[derive(Debug, Clone, Deserialize)]
268pub struct ObserverConfig {
269 pub entity: String,
270 pub events: Vec<String>,
271 pub actions: Vec<ActionConfig>,
272}
273
274#[derive(Debug, Clone, Deserialize)]
275pub struct ActionConfig {
276 #[serde(rename = "type")]
277 pub action_type: String,
278 #[serde(default)]
279 pub template: Option<String>,
280}
281
282#[derive(Debug, Clone, Deserialize)]
285pub struct LoggingConfig {
286 }
288
289#[derive(Debug, Clone, Deserialize)]
290pub struct StorageConfig {
291 pub backend: String,
292 #[serde(default)]
293 pub bucket: Option<String>,
294 #[serde(default)]
295 pub path: Option<String>,
296}
297
298#[derive(Debug, Clone, Deserialize)]
299pub struct SearchConfig {
300 }
302
303#[derive(Debug, Clone, Deserialize)]
304pub struct CacheConfig {
305 }
307
308#[derive(Debug, Clone, Deserialize)]
309pub struct QueueConfig {
310 }
312
313#[derive(Debug, Clone, Deserialize)]
314pub struct RealtimeConfig {
315 }
317
318#[derive(Debug, Clone, Deserialize)]
319pub struct CustomEndpointsConfig {
320 }