witchcraft_server_config/install/
mod.rsuse crate::ConfigError;
use serde::de::Error;
use serde::{Deserialize, Deserializer};
use staged_builder::{staged_builder, Validate};
use std::env;
use std::path::{Path, PathBuf};
use std::time::Duration;
mod de;
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
#[builder(validate)]
pub struct InstallConfig {
#[builder(into)]
product_name: String,
#[builder(into)]
product_version: String,
port: u16,
#[builder(default, into)]
management_port: Option<u16>,
#[builder(default)]
keystore: KeystoreConfig,
#[builder(default, into)]
client_auth_truststore: Option<ClientAuthTruststoreConfig>,
#[builder(into, default = "/".to_string())]
context_path: String,
#[builder(default = env::var_os("CONTAINER").is_some())]
use_console_log: bool,
#[builder(default)]
server: ServerConfig,
}
impl Validate for InstallConfig {
type Error = ConfigError;
fn validate(&self) -> Result<(), Self::Error> {
if !(self.context_path == "/"
|| (self.context_path.starts_with('/') && !self.context_path.ends_with('/')))
{
return Err(ConfigError(
"context-path must either be `/` or start but not end with a `/`".to_string(),
));
}
Ok(())
}
}
impl<'de> Deserialize<'de> for InstallConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::InstallConfig::deserialize(deserializer)?;
let mut builder = InstallConfig::builder()
.product_name(raw.product_name)
.product_version(raw.product_version)
.port(raw.port);
if let Some(management_port) = raw.management_port {
builder = builder.management_port(management_port);
}
if let Some(keystore) = raw.keystore {
builder = builder.keystore(keystore);
}
if let Some(client_auth_truststore) = raw.client_auth_truststore {
builder = builder.client_auth_truststore(client_auth_truststore);
}
if let Some(context_path) = raw.context_path {
builder = builder.context_path(context_path);
}
if let Some(use_console_log) = raw.use_console_log {
builder = builder.use_console_log(use_console_log);
}
if let Some(server) = raw.server {
builder = builder.server(server);
}
builder.build().map_err(Error::custom)
}
}
impl AsRef<InstallConfig> for InstallConfig {
#[inline]
fn as_ref(&self) -> &InstallConfig {
self
}
}
impl InstallConfig {
#[inline]
pub fn product_name(&self) -> &str {
&self.product_name
}
#[inline]
pub fn product_version(&self) -> &str {
&self.product_version
}
#[inline]
pub fn port(&self) -> u16 {
self.port
}
pub fn management_port(&self) -> Option<u16> {
self.management_port
}
#[inline]
pub fn keystore(&self) -> &KeystoreConfig {
&self.keystore
}
#[inline]
pub fn client_auth_truststore(&self) -> Option<&ClientAuthTruststoreConfig> {
self.client_auth_truststore.as_ref()
}
#[inline]
pub fn context_path(&self) -> &str {
&self.context_path
}
#[inline]
pub fn use_console_log(&self) -> bool {
self.use_console_log
}
#[inline]
pub fn server(&self) -> &ServerConfig {
&self.server
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct KeystoreConfig {
#[builder(into, default = PathBuf::from("var/security/key.pem"))]
key_path: PathBuf,
#[builder(into, default = PathBuf::from("var/security/cert.cer"))]
cert_path: PathBuf,
}
impl Default for KeystoreConfig {
#[inline]
fn default() -> Self {
KeystoreConfig::builder().build()
}
}
impl<'de> Deserialize<'de> for KeystoreConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::KeystoreConfig::deserialize(deserializer)?;
let mut builder = KeystoreConfig::builder();
if let Some(key_path) = raw.key_path {
builder = builder.key_path(key_path);
}
if let Some(cert_path) = raw.cert_path {
builder = builder.cert_path(cert_path);
}
Ok(builder.build())
}
}
impl KeystoreConfig {
#[inline]
pub fn key_path(&self) -> &Path {
&self.key_path
}
#[inline]
pub fn cert_path(&self) -> &Path {
&self.cert_path
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct ClientAuthTruststoreConfig {
#[builder(into, default = PathBuf::from("var/security/ca.cer"))]
path: PathBuf,
}
impl Default for ClientAuthTruststoreConfig {
#[inline]
fn default() -> Self {
ClientAuthTruststoreConfig::builder().build()
}
}
impl<'de> Deserialize<'de> for ClientAuthTruststoreConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::ClientAuthTruststoreConfig::deserialize(deserializer)?;
let mut builder = ClientAuthTruststoreConfig::builder();
if let Some(path) = raw.path {
builder = builder.path(path);
}
Ok(builder.build())
}
}
impl ClientAuthTruststoreConfig {
#[inline]
pub fn path(&self) -> &Path {
&self.path
}
}
#[derive(Clone, PartialEq, Debug)]
#[staged_builder]
pub struct ServerConfig {
#[builder(default = num_cpus::get())]
processors: usize,
#[builder(default, custom(type = usize, convert = Some))]
min_threads: Option<usize>,
#[builder(default, custom(type = usize, convert = Some))]
max_threads: Option<usize>,
#[builder(default, custom(type = usize, convert = Some))]
max_connections: Option<usize>,
#[builder(default, custom(type = usize, convert = Some))]
io_threads: Option<usize>,
#[builder(default = Duration::from_secs(5 * 60))]
idle_thread_timeout: Duration,
#[builder(default = Duration::from_secs(15))]
shutdown_timeout: Duration,
#[builder(default = true)]
gzip: bool,
#[builder(default = false)]
http2: bool,
#[builder(default, into)]
idle_connection_timeout: Option<Duration>,
}
impl Default for ServerConfig {
#[inline]
fn default() -> Self {
ServerConfig::builder().build()
}
}
impl<'de> Deserialize<'de> for ServerConfig {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let raw = de::ServerConfig::deserialize(deserializer)?;
let mut builder = ServerConfig::builder();
if let Some(processors) = raw.processors {
builder = builder.processors(processors);
}
if let Some(min_threads) = raw.min_threads {
builder = builder.min_threads(min_threads);
}
if let Some(max_threads) = raw.max_threads {
builder = builder.max_threads(max_threads);
}
if let Some(max_connections) = raw.max_connections {
builder = builder.max_connections(max_connections);
}
if let Some(io_threads) = raw.io_threads {
builder = builder.io_threads(io_threads);
}
if let Some(idle_thread_timeout) = raw.idle_thread_timeout {
builder = builder.idle_thread_timeout(idle_thread_timeout);
}
if let Some(shutdown_timeout) = raw.shutdown_timeout {
builder = builder.shutdown_timeout(shutdown_timeout);
}
if let Some(gzip) = raw.gzip {
builder = builder.gzip(gzip);
}
if let Some(http2) = raw.http2 {
builder = builder.http2(http2);
}
if let Some(idle_connection_timeout) = raw.idle_connection_timeout {
builder = builder.idle_connection_timeout(idle_connection_timeout);
}
Ok(builder.build())
}
}
impl ServerConfig {
#[inline]
pub fn processors(&self) -> usize {
self.processors
}
#[inline]
pub fn min_threads(&self) -> usize {
self.min_threads.unwrap_or(self.processors * 8)
}
#[inline]
pub fn max_threads(&self) -> usize {
self.max_threads
.unwrap_or_else(|| usize::max(self.processors * 32, 256))
}
#[inline]
pub fn max_connections(&self) -> usize {
self.max_connections
.unwrap_or_else(|| self.max_threads() * 10)
}
#[inline]
pub fn io_threads(&self) -> usize {
self.io_threads
.unwrap_or_else(|| usize::max(1, self.processors / 2))
}
#[inline]
pub fn idle_thread_timeout(&self) -> Duration {
self.idle_thread_timeout
}
#[inline]
pub fn shutdown_timeout(&self) -> Duration {
self.shutdown_timeout
}
#[inline]
pub fn gzip(&self) -> bool {
self.gzip
}
#[inline]
pub fn http2(&self) -> bool {
self.http2
}
#[inline]
pub fn idle_connection_timeout(&self) -> Option<Duration> {
self.idle_connection_timeout
}
}