refactor(server): lay groundwork for unix socket configuration
parent
7abce21aee
commit
dca4d2d1ec
|
@ -1,3 +1,6 @@
|
|||
data_dir = "./data"
|
||||
domain = "127.0.0.1"
|
||||
port = 8080
|
||||
|
||||
[net]
|
||||
type = "tcp"
|
||||
|
|
|
@ -4,7 +4,7 @@ mod serve;
|
|||
|
||||
use std::path::PathBuf;
|
||||
|
||||
use clap::{Args, Parser, Subcommand};
|
||||
use clap::{Args, Parser, Subcommand, ValueEnum};
|
||||
use figment::{
|
||||
providers::{Env, Format, Serialized, Toml},
|
||||
Figment,
|
||||
|
@ -24,7 +24,7 @@ pub struct Cli {
|
|||
pub cmd: Command,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Args, Clone)]
|
||||
#[derive(Serialize, Args, Clone, Debug)]
|
||||
pub struct ClapConfig {
|
||||
#[arg(
|
||||
short,
|
||||
|
@ -35,21 +35,37 @@ pub struct ClapConfig {
|
|||
)]
|
||||
config_file: Option<PathBuf>,
|
||||
|
||||
#[command(flatten)]
|
||||
net: NetConfig,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[arg(long = "data", value_name = "DATA_DIR", global = true)]
|
||||
data_dir: Option<PathBuf>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[arg(short, long, value_name = "DOMAIN", global = true)]
|
||||
#[arg(short, long = "log", value_name = "LOG_LEVEL", global = true)]
|
||||
log_level: Option<LogLevel>,
|
||||
}
|
||||
|
||||
#[derive(ValueEnum, Serialize, Clone, Debug)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum NetConfigType {
|
||||
Tcp,
|
||||
}
|
||||
|
||||
#[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<NetConfigType>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[arg(long, value_name = "DOMAIN", global = true)]
|
||||
domain: Option<String>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[arg(short, long, value_name = "PORT", global = true)]
|
||||
#[arg(long, value_name = "PORT", global = true)]
|
||||
port: Option<u16>,
|
||||
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
#[arg(short, long = "log", value_name = "LOG_LEVEL", global = true)]
|
||||
log_level: Option<LogLevel>,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
|
@ -65,17 +81,18 @@ pub enum Command {
|
|||
|
||||
impl Cli {
|
||||
pub fn run(&self) -> u8 {
|
||||
let mut figment = Figment::new();
|
||||
let mut figment =
|
||||
Figment::new().merge(Serialized::defaults(crate::config::Config::default()));
|
||||
|
||||
if let Some(config_path) = &self.config.config_file {
|
||||
figment = figment.merge(Toml::file(config_path));
|
||||
}
|
||||
|
||||
let config: crate::config::Config = match figment
|
||||
let config = figment
|
||||
.merge(Env::prefixed("OTTER_"))
|
||||
.merge(Serialized::defaults(self.config.clone()))
|
||||
.extract()
|
||||
{
|
||||
.merge(Serialized::defaults(self.config.clone()));
|
||||
|
||||
let config = match config.extract::<crate::config::Config>() {
|
||||
Ok(config) => config,
|
||||
Err(err) => {
|
||||
eprintln!("{}", err);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::{sync::Arc, time::Duration};
|
||||
|
||||
use crate::server;
|
||||
use crate::{config::NetConfig, server};
|
||||
|
||||
pub fn serve(config: &crate::config::Config) -> u8 {
|
||||
tracing_subscriber::fmt()
|
||||
|
@ -27,36 +27,45 @@ pub fn serve(config: &crate::config::Config) -> u8 {
|
|||
.build()
|
||||
.unwrap();
|
||||
|
||||
let address = format!("{}:{}", config.domain, config.port);
|
||||
tracing::info!("Starting server on {address}");
|
||||
|
||||
// Spawn the session cleanup background task
|
||||
let session_removal_duration = Duration::from_secs(config.session_cleanup_interval);
|
||||
|
||||
rt.block_on(async {
|
||||
tokio::task::spawn(async move {
|
||||
let mut interval = tokio::time::interval(session_removal_duration);
|
||||
tracing::info!("Starting session cleanup background task");
|
||||
|
||||
loop {
|
||||
interval.tick().await;
|
||||
rt.spawn(async move {
|
||||
let mut interval = tokio::time::interval(session_removal_duration);
|
||||
|
||||
tracing::info!("Performing session cleanup");
|
||||
loop {
|
||||
interval.tick().await;
|
||||
|
||||
match ctx.store.remove_old_sessions() {
|
||||
Ok(n) => {
|
||||
tracing::info!("Removed {} old sessions", n);
|
||||
}
|
||||
Err(err) => {
|
||||
tracing::error!("Error occured during session cleanup: {}", err);
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
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()
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::path::PathBuf;
|
|||
use clap::ValueEnum;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, ValueEnum, Copy)]
|
||||
#[derive(Deserialize, Serialize, Clone, ValueEnum, Copy, Debug)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
pub enum LogLevel {
|
||||
Debug,
|
||||
|
@ -23,37 +23,32 @@ impl From<LogLevel> for tracing::Level {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[serde(rename_all = "lowercase")]
|
||||
#[serde(tag = "type")]
|
||||
pub enum NetConfig {
|
||||
Tcp { domain: String, port: u16 },
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
#[serde(default = "default_data_dir")]
|
||||
pub net: NetConfig,
|
||||
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,
|
||||
}
|
||||
|
||||
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
|
||||
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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue