use std::time::Duration;
use serde::{Deserialize, Serialize};
use super::default_true;
use super::types::{DurationStr, SizeStr};
#[derive(Debug, Clone, Serialize, Deserialize)]
#[non_exhaustive]
pub struct GatewayConfig {
#[serde(default = "default_http_port")]
pub port: u16,
#[serde(default = "default_grpc_port")]
pub grpc_port: u16,
#[serde(default = "default_max_connections")]
pub max_connections: usize,
#[serde(default = "default_request_timeout")]
pub request_timeout: DurationStr,
#[serde(default = "default_cors_enabled")]
pub cors_enabled: bool,
#[serde(default = "default_cors_origins")]
pub cors_origins: Vec<String>,
#[serde(default = "default_quiet_paths")]
pub quiet_paths: Vec<String>,
#[serde(default = "default_max_body_size")]
pub max_body_size: SizeStr,
#[serde(default = "default_max_json_body_size")]
pub max_json_body_size: SizeStr,
#[serde(default = "default_max_file_size")]
pub max_file_size: SizeStr,
#[serde(default)]
pub tls: TlsConfig,
#[serde(default = "default_max_multipart_fields")]
pub max_multipart_fields: usize,
#[serde(default = "default_true")]
pub security_headers: bool,
#[serde(default)]
pub hsts: bool,
#[serde(default)]
pub trusted_proxies: Vec<String>,
#[serde(default = "default_max_jobs_per_request")]
pub max_jobs_per_request: usize,
#[serde(default = "default_max_result_size_bytes")]
pub max_result_size_bytes: usize,
#[serde(default = "default_max_json_depth")]
pub max_json_depth: usize,
}
impl Default for GatewayConfig {
fn default() -> Self {
Self {
port: default_http_port(),
grpc_port: default_grpc_port(),
max_connections: default_max_connections(),
request_timeout: default_request_timeout(),
cors_enabled: default_cors_enabled(),
cors_origins: default_cors_origins(),
quiet_paths: default_quiet_paths(),
max_body_size: default_max_body_size(),
max_json_body_size: default_max_json_body_size(),
max_file_size: default_max_file_size(),
tls: TlsConfig::default(),
max_multipart_fields: default_max_multipart_fields(),
security_headers: true,
hsts: false,
trusted_proxies: Vec::new(),
max_jobs_per_request: default_max_jobs_per_request(),
max_result_size_bytes: default_max_result_size_bytes(),
max_json_depth: default_max_json_depth(),
}
}
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct TlsConfig {
#[serde(default, deserialize_with = "deserialize_optional_nonempty")]
pub cert_path: Option<String>,
#[serde(default, deserialize_with = "deserialize_optional_nonempty")]
pub key_path: Option<String>,
}
fn deserialize_optional_nonempty<'de, D>(
deserializer: D,
) -> std::result::Result<Option<String>, D::Error>
where
D: serde::Deserializer<'de>,
{
let opt: Option<String> = Option::deserialize(deserializer)?;
Ok(opt.filter(|s| !s.trim().is_empty()))
}
impl TlsConfig {
pub fn is_enabled(&self) -> bool {
self.cert_path.is_some() && self.key_path.is_some()
}
pub fn validate(&self) -> crate::Result<()> {
match (self.cert_path.as_deref(), self.key_path.as_deref()) {
(Some(_), Some(_)) | (None, None) => Ok(()),
(Some(_), None) => Err(crate::ForgeError::config(
"gateway.tls.cert_path is set but gateway.tls.key_path is missing. \
Set both to enable TLS, or neither to serve plain HTTP.",
)),
(None, Some(_)) => Err(crate::ForgeError::config(
"gateway.tls.key_path is set but gateway.tls.cert_path is missing. \
Set both to enable TLS, or neither to serve plain HTTP.",
)),
}
}
}
fn default_http_port() -> u16 {
9081
}
fn default_grpc_port() -> u16 {
9000
}
fn default_max_connections() -> usize {
4096
}
fn default_request_timeout() -> DurationStr {
DurationStr::new(Duration::from_secs(30))
}
fn default_cors_enabled() -> bool {
false
}
fn default_cors_origins() -> Vec<String> {
Vec::new()
}
fn default_quiet_paths() -> Vec<String> {
vec![
"/_api/health".to_string(),
"/_api/ready".to_string(),
"/_api/signal".to_string(),
]
}
fn default_max_body_size() -> SizeStr {
SizeStr::new(20 * 1024 * 1024)
}
fn default_max_file_size() -> SizeStr {
SizeStr::new(10 * 1024 * 1024)
}
fn default_max_multipart_fields() -> usize {
20
}
fn default_max_jobs_per_request() -> usize {
10
}
fn default_max_result_size_bytes() -> usize {
10 * 1024 * 1024
}
fn default_max_json_body_size() -> SizeStr {
SizeStr::new(1024 * 1024)
}
fn default_max_json_depth() -> usize {
64
}