diff --git a/otter.toml b/otter.toml index 168a1f4..1f93f85 100644 --- a/otter.toml +++ b/otter.toml @@ -1,6 +1,3 @@ data_dir = "./data" domain = "127.0.0.1" port = 8080 - -[net] -type = "tcp" diff --git a/server/src/cli/mod.rs b/server/src/cli/mod.rs index 5df94a2..fbd3dac 100644 --- a/server/src/cli/mod.rs +++ b/server/src/cli/mod.rs @@ -4,7 +4,7 @@ mod serve; use std::path::PathBuf; -use clap::{Args, Parser, Subcommand, ValueEnum}; +use clap::{Args, Parser, Subcommand}; use figment::{ providers::{Env, Format, Serialized, Toml}, Figment, @@ -24,7 +24,7 @@ pub struct Cli { pub cmd: Command, } -#[derive(Serialize, Args, Clone, Debug)] +#[derive(Serialize, Args, Clone)] pub struct ClapConfig { #[arg( short, @@ -35,43 +35,21 @@ pub struct ClapConfig { )] config_file: Option, - #[command(flatten)] - net: NetConfig, - #[serde(skip_serializing_if = "Option::is_none")] #[arg(long = "data", value_name = "DATA_DIR", global = true)] data_dir: Option, #[serde(skip_serializing_if = "Option::is_none")] - #[arg(short, long = "log", value_name = "LOG_LEVEL", global = true)] - log_level: Option, -} - -#[derive(ValueEnum, Serialize, Clone, Debug)] -#[serde(rename_all = "lowercase")] -pub enum NetConfigType { - Tcp, - Unix, -} - -#[derive(Serialize, Clone, Args, Debug)] -pub struct NetConfig { - #[serde(skip_serializing_if = "Option::is_none")] - #[arg(long = "net", value_name = "NET", global = true)] - r#type: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - #[arg(long, value_name = "DOMAIN", global = true)] + #[arg(short, long, value_name = "DOMAIN", global = true)] domain: Option, #[serde(skip_serializing_if = "Option::is_none")] - #[arg(long, value_name = "PORT", global = true)] + #[arg(short, long, value_name = "PORT", global = true)] port: Option, #[serde(skip_serializing_if = "Option::is_none")] - #[serde(rename = "path")] - #[arg(long, value_name = "SOCKET", global = true)] - socket: Option, + #[arg(short, long = "log", value_name = "LOG_LEVEL", global = true)] + log_level: Option, } #[derive(Subcommand)] @@ -87,18 +65,17 @@ pub enum Command { impl Cli { pub fn run(&self) -> u8 { - let mut figment = - Figment::new().merge(Serialized::defaults(crate::config::Config::default())); + let mut figment = Figment::new(); if let Some(config_path) = &self.config.config_file { figment = figment.merge(Toml::file(config_path)); } - let config = figment + let config: crate::config::Config = match figment .merge(Env::prefixed("OTTER_")) - .merge(Serialized::defaults(self.config.clone())); - - let config = match config.extract::() { + .merge(Serialized::defaults(self.config.clone())) + .extract() + { Ok(config) => config, Err(err) => { eprintln!("{}", err); diff --git a/server/src/cli/serve.rs b/server/src/cli/serve.rs index 639bafa..b9c0e27 100644 --- a/server/src/cli/serve.rs +++ b/server/src/cli/serve.rs @@ -1,6 +1,6 @@ use std::{sync::Arc, time::Duration}; -use crate::{config::NetConfig, server}; +use crate::server; pub fn serve(config: &crate::config::Config) -> u8 { tracing_subscriber::fmt() @@ -27,63 +27,36 @@ pub fn serve(config: &crate::config::Config) -> u8 { .build() .unwrap(); - // Spawn the session cleanup background task + let address = format!("{}:{}", config.domain, config.port); + tracing::info!("Starting server on {address}"); + let session_removal_duration = Duration::from_secs(config.session_cleanup_interval); - tracing::info!("Starting session cleanup background task"); + rt.block_on(async { + tokio::task::spawn(async move { + let mut interval = tokio::time::interval(session_removal_duration); - rt.spawn(async move { - let mut interval = tokio::time::interval(session_removal_duration); + loop { + interval.tick().await; - loop { - interval.tick().await; + tracing::info!("Performing session cleanup"); - tracing::info!("Performing session cleanup"); - - match ctx.store.remove_old_sessions() { - Ok(n) => { - tracing::info!("Removed {} old sessions", n); - } - Err(err) => { - tracing::error!("Error occured during session cleanup: {}", err); + match ctx.store.remove_old_sessions() { + Ok(n) => { + tracing::info!("Removed {} old sessions", n); + } + Err(err) => { + tracing::error!("Error occured during session cleanup: {}", err); + } } } - } + }); + + let listener = tokio::net::TcpListener::bind(address).await.unwrap(); + axum::serve(listener, app.into_make_service()) + .await + .unwrap() }); - tracing::info!("Initializing server"); - - match &config.net { - NetConfig::Tcp { domain, port } => { - let address = format!("{}:{}", domain, port); - tracing::info!("Listening on TCP address {address}"); - - rt.block_on(async { - let listener = tokio::net::TcpListener::bind(address).await.unwrap(); - axum::serve(listener, app.into_make_service()) - .await - .unwrap() - }); - } - NetConfig::Unix { path } => { - // Try to remove the socket file first if it exists - let _ = std::fs::remove_file(&path); - - if let Some(parent) = path.parent() { - std::fs::create_dir_all(parent).unwrap(); - } - - tracing::info!("Listening on Unix socket {:?}", path); - - rt.block_on(async { - let listener = tokio::net::UnixListener::bind(path).unwrap(); - - axum::serve(listener, app.into_make_service()) - .await - .unwrap() - }); - } - } - 0 } diff --git a/server/src/config.rs b/server/src/config.rs index 25b4195..c015933 100644 --- a/server/src/config.rs +++ b/server/src/config.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use clap::ValueEnum; use serde::{Deserialize, Serialize}; -#[derive(Deserialize, Serialize, Clone, ValueEnum, Copy, Debug)] +#[derive(Deserialize, Serialize, Clone, ValueEnum, Copy)] #[serde(rename_all = "lowercase")] pub enum LogLevel { Debug, @@ -23,33 +23,37 @@ impl From for tracing::Level { } } -#[derive(Serialize, Deserialize)] -#[serde(rename_all = "lowercase")] -#[serde(tag = "type")] -pub enum NetConfig { - Tcp { domain: String, port: u16 }, - Unix { path: PathBuf }, -} - -#[derive(Serialize, Deserialize)] +#[derive(Deserialize)] pub struct Config { - pub net: NetConfig, + #[serde(default = "default_data_dir")] pub data_dir: PathBuf, + #[serde(default = "default_domain")] + pub domain: String, + #[serde(default = "default_port")] + pub port: u16, + #[serde(default = "default_session_cleanup_interval")] pub session_cleanup_interval: u64, + #[serde(default = "default_log_level")] pub log_level: LogLevel, } -impl Default for Config { - fn default() -> Self { - Self { - net: NetConfig::Tcp { - domain: "127.0.0.1".to_string(), - port: 8080, - }, - data_dir: "./data".into(), - // Once per day - session_cleanup_interval: 60 * 60 * 24, - log_level: LogLevel::Warn, - } - } +fn default_data_dir() -> PathBuf { + PathBuf::from("./data") +} + +fn default_domain() -> String { + "127.0.0.1".to_string() +} + +fn default_port() -> u16 { + 8080 +} + +fn default_session_cleanup_interval() -> u64 { + // Default is once a day + 60 * 60 * 24 +} + +fn default_log_level() -> LogLevel { + LogLevel::Warn }