All checks were successful
Test / test-frontend (pull_request) Successful in 23s
Test / lint-frontend (pull_request) Successful in 25s
Test / frontend-build (pull_request) Successful in 29s
Test / test (pull_request) Successful in 46s
Verify / verify-generated-code (pull_request) Successful in 59s
Verify / verify-openapi-spec (pull_request) Successful in 1m1s
Verify / verify-frontend-api-client (pull_request) Successful in 20s
Test / lint (pull_request) Successful in 1m3s
134 lines
4.4 KiB
Rust
134 lines
4.4 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().unwrap(),
|
|
port: 8080,
|
|
serve_openapi: false,
|
|
cors: CORSSettings {
|
|
allowed_origins: vec![],
|
|
},
|
|
cookies: CookiesSettings { secure: true },
|
|
}
|
|
}
|
|
}
|