Files
YANPM/apps/api/src/configs/server.rs
GW_MC 6f5596dc69
All checks were successful
Test / test-frontend (pull_request) Successful in 26s
Test / lint-frontend (pull_request) Successful in 28s
Test / frontend-build (pull_request) Successful in 32s
Verify / verify-generated-database-code (pull_request) Successful in 1m7s
Verify / verify-generated-agent-code (pull_request) Successful in 1m10s
Verify / verify-openapi-spec (pull_request) Successful in 1m9s
Verify / verify-frontend-api-client (pull_request) Successful in 7s
Test / test-crates (pull_request) Successful in 54s
Test / lint-crates (pull_request) Successful in 1m10s
Enforce deny unwrap_used
2025-12-28 19:07:17 +08:00

134 lines
4.5 KiB
Rust

use std::net::IpAddr;
use config::{Config, ConfigError};
use tracing::warn;
use crate::configs::key::{
SERVER_COOKIES_SECURE_KEY, SERVER_CORS_ALLOWED_ORIGINS_KEY, SERVER_SERVE_OPENAPI_KEY,
};
use super::{
FromConfig,
key::{SERVER_ADDRESS_KEY, SERVER_PORT_KEY},
};
#[derive(Debug, Clone)]
pub struct ServerSettings {
pub address: IpAddr,
pub port: u16,
pub serve_openapi: bool,
pub cors: CORSSettings,
pub cookies: CookiesSettings,
}
#[derive(Debug, Clone)]
pub struct CORSSettings {
pub allowed_origins: Vec<String>,
}
#[derive(Debug, Clone)]
pub struct CookiesSettings {
pub secure: bool,
}
impl FromConfig for ServerSettings {
fn from_config(_config: &Config) -> Result<Self, String> {
Ok(ServerSettings {
address: _config
.get_string(SERVER_ADDRESS_KEY)
.unwrap_or_else(|err| {
const DEFAULT_ADDRESS: &str = "0.0.0.0";
match err {
ConfigError::NotFound(_) => {}
_ => {
warn!(
"Failed to read {} from configuration, defaulting to {}. Error: {}",
SERVER_ADDRESS_KEY, DEFAULT_ADDRESS, err
);
}
};
DEFAULT_ADDRESS.to_string()
})
.parse()
.map_err(|e| format!("Invalid {} in configuration: {}", SERVER_ADDRESS_KEY, e))?,
port: _config.get_int(SERVER_PORT_KEY).unwrap_or_else(|err| {
const DEFAULT_PORT: i64 = 8080;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
SERVER_PORT_KEY, DEFAULT_PORT, err
);
DEFAULT_PORT
}) as u16,
serve_openapi: _config
.get_bool(SERVER_SERVE_OPENAPI_KEY)
.unwrap_or_else(|err| {
const DEFAULT_SERVE_OPENAPI: bool = false;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
SERVER_SERVE_OPENAPI_KEY, DEFAULT_SERVE_OPENAPI, err
);
DEFAULT_SERVE_OPENAPI
}),
cors: CORSSettings {
allowed_origins: _config
.get_array(SERVER_CORS_ALLOWED_ORIGINS_KEY)
.unwrap_or_else(|_| vec![])
.into_iter()
.filter_map(|val| match val.into_string() {
Ok(s) => Some(s),
Err(e) => {
warn!(
"Invalid origin in {} configuration: {}",
SERVER_CORS_ALLOWED_ORIGINS_KEY, e
);
None
}
})
.collect(),
},
cookies: CookiesSettings {
secure: _config
.get_bool(SERVER_COOKIES_SECURE_KEY)
.inspect(|is_secure| {
if !*is_secure {
warn!("Cookie 'secure' flag is disabled; this is not recommended in production environments.");
}
})
.unwrap_or_else(|err| {
const DEFAULT_COOKIES_SECURE: bool = true;
warn!(
"{} not set or invalid in configuration, defaulting to {}. Error: {}",
SERVER_COOKIES_SECURE_KEY, DEFAULT_COOKIES_SECURE, err
);
DEFAULT_COOKIES_SECURE
}),
},
})
}
fn validate(&self) -> Result<(), String> {
#[allow(clippy::absurd_extreme_comparisons, unused_comparisons)]
if self.port == 0 || self.port > 65535 {
return Err("Server port must be between 1 and 65535".into());
}
Ok(())
}
#[cfg(test)]
fn mock() -> Self {
ServerSettings {
address: "0.0.0.0".parse().expect("Failed to parse mock IP address"),
port: 8080,
serve_openapi: false,
cors: CORSSettings {
allowed_origins: vec![],
},
cookies: CookiesSettings { secure: true },
}
}
}