forge_core/config/
gateway.rs1use std::time::Duration;
4
5use serde::{Deserialize, Serialize};
6
7use super::default_true;
8use super::types::{DurationStr, SizeStr};
9
10#[derive(Debug, Clone, Serialize, Deserialize)]
12#[non_exhaustive]
13pub struct GatewayConfig {
14 #[serde(default = "default_http_port")]
16 pub port: u16,
17
18 #[serde(default = "default_grpc_port")]
24 pub grpc_port: u16,
25
26 #[serde(default = "default_max_connections")]
28 pub max_connections: usize,
29
30 #[serde(default = "default_request_timeout")]
32 pub request_timeout: DurationStr,
33
34 #[serde(default = "default_cors_enabled")]
36 pub cors_enabled: bool,
37
38 #[serde(default = "default_cors_origins")]
40 pub cors_origins: Vec<String>,
41
42 #[serde(default = "default_quiet_paths")]
45 pub quiet_paths: Vec<String>,
46
47 #[serde(default = "default_max_body_size")]
49 pub max_body_size: SizeStr,
50
51 #[serde(default = "default_max_json_body_size")]
53 pub max_json_body_size: SizeStr,
54
55 #[serde(default = "default_max_file_size")]
60 pub max_file_size: SizeStr,
61
62 #[serde(default)]
64 pub tls: TlsConfig,
65
66 #[serde(default = "default_max_multipart_fields")]
68 pub max_multipart_fields: usize,
69
70 #[serde(default = "default_true")]
73 pub security_headers: bool,
74
75 #[serde(default)]
78 pub hsts: bool,
79
80 #[serde(default)]
85 pub trusted_proxies: Vec<String>,
86
87 #[serde(default = "default_max_jobs_per_request")]
91 pub max_jobs_per_request: usize,
92
93 #[serde(default = "default_max_result_size_bytes")]
96 pub max_result_size_bytes: usize,
97
98 #[serde(default = "default_max_json_depth")]
102 pub max_json_depth: usize,
103 }
105
106impl Default for GatewayConfig {
107 fn default() -> Self {
108 Self {
109 port: default_http_port(),
110 grpc_port: default_grpc_port(),
111 max_connections: default_max_connections(),
112 request_timeout: default_request_timeout(),
113 cors_enabled: default_cors_enabled(),
114 cors_origins: default_cors_origins(),
115 quiet_paths: default_quiet_paths(),
116 max_body_size: default_max_body_size(),
117 max_json_body_size: default_max_json_body_size(),
118 max_file_size: default_max_file_size(),
119 tls: TlsConfig::default(),
120 max_multipart_fields: default_max_multipart_fields(),
121 security_headers: true,
122 hsts: false,
123 trusted_proxies: Vec::new(),
124 max_jobs_per_request: default_max_jobs_per_request(),
125 max_result_size_bytes: default_max_result_size_bytes(),
126 max_json_depth: default_max_json_depth(),
127 }
128 }
129}
130
131#[derive(Debug, Clone, Default, Serialize, Deserialize)]
140pub struct TlsConfig {
141 #[serde(default, deserialize_with = "deserialize_optional_nonempty")]
143 pub cert_path: Option<String>,
144
145 #[serde(default, deserialize_with = "deserialize_optional_nonempty")]
147 pub key_path: Option<String>,
148}
149
150fn deserialize_optional_nonempty<'de, D>(
154 deserializer: D,
155) -> std::result::Result<Option<String>, D::Error>
156where
157 D: serde::Deserializer<'de>,
158{
159 let opt: Option<String> = Option::deserialize(deserializer)?;
160 Ok(opt.filter(|s| !s.trim().is_empty()))
161}
162
163impl TlsConfig {
164 pub fn is_enabled(&self) -> bool {
166 self.cert_path.is_some() && self.key_path.is_some()
167 }
168
169 pub fn validate(&self) -> crate::Result<()> {
171 match (self.cert_path.as_deref(), self.key_path.as_deref()) {
172 (Some(_), Some(_)) | (None, None) => Ok(()),
173 (Some(_), None) => Err(crate::ForgeError::config(
174 "gateway.tls.cert_path is set but gateway.tls.key_path is missing. \
175 Set both to enable TLS, or neither to serve plain HTTP.",
176 )),
177 (None, Some(_)) => Err(crate::ForgeError::config(
178 "gateway.tls.key_path is set but gateway.tls.cert_path is missing. \
179 Set both to enable TLS, or neither to serve plain HTTP.",
180 )),
181 }
182 }
183}
184
185fn default_http_port() -> u16 {
186 9081
187}
188
189fn default_grpc_port() -> u16 {
190 9000
191}
192
193fn default_max_connections() -> usize {
194 4096
195}
196
197fn default_request_timeout() -> DurationStr {
198 DurationStr::new(Duration::from_secs(30))
199}
200
201fn default_cors_enabled() -> bool {
202 false
203}
204
205fn default_cors_origins() -> Vec<String> {
206 Vec::new()
207}
208
209fn default_quiet_paths() -> Vec<String> {
210 vec![
211 "/_api/health".to_string(),
212 "/_api/ready".to_string(),
213 "/_api/signal".to_string(),
214 ]
215}
216
217fn default_max_body_size() -> SizeStr {
218 SizeStr::new(20 * 1024 * 1024)
219}
220
221fn default_max_file_size() -> SizeStr {
222 SizeStr::new(10 * 1024 * 1024)
223}
224
225fn default_max_multipart_fields() -> usize {
226 20
227}
228
229fn default_max_jobs_per_request() -> usize {
230 10
231}
232
233fn default_max_result_size_bytes() -> usize {
234 10 * 1024 * 1024
235}
236
237fn default_max_json_body_size() -> SizeStr {
238 SizeStr::new(1024 * 1024)
239}
240
241fn default_max_json_depth() -> usize {
242 64
243}