diff --git a/src/core/bootstrap.rs b/src/core/bootstrap.rs index df90160..2e58233 100644 --- a/src/core/bootstrap.rs +++ b/src/core/bootstrap.rs @@ -12,7 +12,7 @@ use crate::{ DEFAULT_CONFIG_PATH, DEFAULT_SOCKET_PATH, UnixUser, executable_is_suid_or_sgid, }, server::{ - config::{MysqlConfig, read_config_from_path}, + config::{MysqlConfig, ServerConfig}, session_handler, }, }; @@ -244,7 +244,8 @@ fn run_forked_server( server_socket: StdUnixStream, unix_user: UnixUser, ) -> anyhow::Result<()> { - let config = read_config_from_path(Some(config_path))?; + let config = ServerConfig::read_config_from_path(&config_path) + .context("Failed to read server config in forked process")?; let result: anyhow::Result<()> = tokio::runtime::Builder::new_current_thread() .enable_all() diff --git a/src/server/command.rs b/src/server/command.rs index 2b832d9..ea37c45 100644 --- a/src/server/command.rs +++ b/src/server/command.rs @@ -5,23 +5,13 @@ use clap::Parser; use clap_verbosity_flag::Verbosity; use systemd_journal_logger::JournalLog; -use crate::server::{ - config::{ServerConfigArgs, read_config_from_path_with_arg_overrides}, - supervisor::Supervisor, - // server_loop::{ - // listen_for_incoming_connections_with_socket_path, - // listen_for_incoming_connections_with_systemd_socket, - // }, -}; +use crate::{core::common::DEFAULT_CONFIG_PATH, server::supervisor::Supervisor}; #[derive(Parser, Debug, Clone)] pub struct ServerArgs { #[command(subcommand)] subcmd: ServerCommand, - #[command(flatten)] - config_overrides: ServerConfigArgs, - #[arg(long)] systemd: bool, } @@ -85,10 +75,15 @@ pub async fn handle_command( log::info!("Running in standalone mode"); } - let config = read_config_from_path_with_arg_overrides(config_path, args.config_overrides)?; + let config_path = config_path.unwrap_or_else(|| PathBuf::from(DEFAULT_CONFIG_PATH)); match args.subcmd { - ServerCommand::Listen => Supervisor::new(config, systemd_mode).await?.run().await, + ServerCommand::Listen => { + Supervisor::new(config_path, systemd_mode) + .await? + .run() + .await + } ServerCommand::SocketActivate => { if !args.systemd { anyhow::bail!(concat!( @@ -97,7 +92,10 @@ pub async fn handle_command( )); } - Supervisor::new(config, systemd_mode).await?.run().await + Supervisor::new(config_path, systemd_mode) + .await? + .run() + .await } } } diff --git a/src/server/config.rs b/src/server/config.rs index a91eb5f..82cb9de 100644 --- a/src/server/config.rs +++ b/src/server/config.rs @@ -1,12 +1,12 @@ -use std::{fs, path::PathBuf}; +use std::{ + fs, + path::{Path, PathBuf}, +}; use anyhow::Context; -use clap::Parser; use serde::{Deserialize, Serialize}; use sqlx::{ConnectOptions, mysql::MySqlConnectOptions}; -use crate::core::common::DEFAULT_CONFIG_PATH; - pub const DEFAULT_PORT: u16 = 3306; fn default_mysql_port() -> u16 { DEFAULT_PORT @@ -17,12 +17,6 @@ fn default_mysql_timeout() -> u64 { DEFAULT_TIMEOUT } -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ServerConfig { - pub socket_path: Option, - pub mysql: MysqlConfig, -} - #[derive(Debug, Clone, Deserialize, Serialize)] #[serde(rename = "mysql")] pub struct MysqlConfig { @@ -76,94 +70,20 @@ impl MysqlConfig { } } -#[derive(Parser, Debug, Clone)] -pub struct ServerConfigArgs { - /// Path where the server socket should be created. - #[arg(long, value_name = "PATH", global = true)] - socket_path: Option, - - /// Path to the socket of the MySQL server. - #[arg(long, value_name = "PATH", global = true)] - mysql_socket_path: Option, - - /// Hostname of the MySQL server. - #[arg( - long, - value_name = "HOST", - global = true, - conflicts_with = "socket_path" - )] - mysql_host: Option, - - /// Port of the MySQL server. - #[arg( - long, - value_name = "PORT", - global = true, - conflicts_with = "socket_path" - )] - mysql_port: Option, - - /// Username to use for the MySQL connection. - #[arg(long, value_name = "USER", global = true)] - mysql_user: Option, - - /// Path to a file containing the MySQL password. - #[arg(long, value_name = "PATH", global = true)] - mysql_password_file: Option, - - /// Seconds to wait for the MySQL connection to be established. - #[arg(long, value_name = "SECONDS", global = true)] - mysql_connect_timeout: Option, +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct ServerConfig { + pub socket_path: Option, + pub mysql: MysqlConfig, } -/// Use the arguments and whichever configuration file which might or might not -/// be found and default values to determine the configuration for the program. -pub fn read_config_from_path_with_arg_overrides( - config_path: Option, - args: ServerConfigArgs, -) -> anyhow::Result { - let config = read_config_from_path(config_path)?; +impl ServerConfig { + /// Reads the server configuration from the specified path, or the default path if none is provided. + pub fn read_config_from_path(config_path: &Path) -> anyhow::Result { + log::debug!("Reading config file at {:?}", config_path); - let mysql = config.mysql; - - let password = if let Some(path) = &args.mysql_password_file { - Some( - fs::read_to_string(path) - .context("Failed to read MySQL password file") - .map(|s| s.trim().to_owned())?, - ) - } else if let Some(path) = &mysql.password_file { - Some( - fs::read_to_string(path) - .context("Failed to read MySQL password file") - .map(|s| s.trim().to_owned())?, - ) - } else { - mysql.password.to_owned() - }; - - Ok(ServerConfig { - socket_path: args.socket_path.or(config.socket_path), - mysql: MysqlConfig { - socket_path: args.mysql_socket_path.or(mysql.socket_path), - host: args.mysql_host.or(mysql.host), - port: args.mysql_port.unwrap_or(mysql.port), - username: args.mysql_user.or(mysql.username.to_owned()), - password, - password_file: args.mysql_password_file.or(mysql.password_file), - timeout: args.mysql_connect_timeout.unwrap_or(mysql.timeout), - }, - }) -} - -pub fn read_config_from_path(config_path: Option) -> anyhow::Result { - let config_path = config_path.unwrap_or_else(|| PathBuf::from(DEFAULT_CONFIG_PATH)); - - log::debug!("Reading config file at {:?}", &config_path); - - fs::read_to_string(&config_path) - .context(format!("Failed to read config file at {:?}", &config_path)) - .and_then(|c| toml::from_str(&c).context("Failed to parse config file")) - .context(format!("Failed to parse config file at {:?}", &config_path)) + fs::read_to_string(config_path) + .context(format!("Failed to read config file at {:?}", config_path)) + .and_then(|c| toml::from_str(&c).context("Failed to parse config file")) + .context(format!("Failed to parse config file at {:?}", config_path)) + } } diff --git a/src/server/supervisor.rs b/src/server/supervisor.rs index 8d5e934..50124cb 100644 --- a/src/server/supervisor.rs +++ b/src/server/supervisor.rs @@ -44,6 +44,7 @@ use crate::server::{ #[allow(dead_code)] pub struct Supervisor { + config_path: PathBuf, config: ServerConfig, systemd_mode: bool, @@ -63,13 +64,16 @@ pub struct Supervisor { } impl Supervisor { - pub async fn new(config: ServerConfig, systemd_mode: bool) -> anyhow::Result { + pub async fn new(config_path: PathBuf, systemd_mode: bool) -> anyhow::Result { log::debug!("Starting server supervisor"); log::debug!( "Running in tokio with {} worker threads", tokio::runtime::Handle::current().metrics().num_workers() ); + let config = ServerConfig::read_config_from_path(&config_path) + .context("Failed to read server configuration")?; + let mut watchdog_duration = None; let mut watchdog_micro_seconds = 0; let watchdog_task = @@ -113,6 +117,7 @@ impl Supervisor { // let sigterm_cancel_token = CancellationToken::new(); Ok(Self { + config_path, config, systemd_mode, // sighup_cancel_token,