Spawn an axum server

Concurrently spawn an axum server, which is not doing much yet, in
order to prepare for the creation, etc. of reminders.
This commit is contained in:
finga 2023-01-30 17:01:25 +01:00
parent 0434505b2d
commit 6b6f5aa48a
5 changed files with 519 additions and 84 deletions

View file

@ -1,21 +1,25 @@
use anyhow::{bail, Result};
use anyhow::{bail, Error, Result};
use serde::Deserialize;
use std::{env, fs, path::PathBuf};
use tracing::{error, info, trace};
use std::{
env, fs,
net::{IpAddr, Ipv6Addr},
path::PathBuf,
};
use tracing::{error, info, trace, warn};
fn default_host() -> String {
fn default_database_host() -> String {
"localhost".to_string()
}
const fn default_port() -> u16 {
const fn default_database_port() -> u16 {
5432
}
fn default_name() -> String {
fn default_database_name() -> String {
"whakarite".to_string()
}
fn default_user() -> String {
fn default_database_user() -> String {
"whakarite".to_string()
}
@ -23,68 +27,105 @@ fn default_user() -> String {
#[serde(deny_unknown_fields)]
pub struct Database {
/// Host of the database
#[serde(default = "default_host")]
#[serde(default = "default_database_host")]
pub host: String,
/// Port of the database
#[serde(default = "default_port")]
#[serde(default = "default_database_port")]
pub port: u16,
/// Name of the database
#[serde(default = "default_name")]
#[serde(default = "default_database_name")]
pub name: String,
/// Name of the user to connect to the database
#[serde(default = "default_user")]
#[serde(default = "default_database_user")]
pub user: String,
/// Password of the user to connect to the database
pub pass: String,
}
const fn default_server_address() -> IpAddr {
IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1))
}
const fn default_server_port() -> u16 {
8080
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Server {
/// Listening address of the server
#[serde(default = "default_server_address")]
pub address: IpAddr,
/// Port of the database
#[serde(default = "default_server_port")]
pub port: u16,
}
impl Default for Server {
fn default() -> Self {
Self {
address: default_server_address(),
port: default_server_port(),
}
}
}
#[derive(Debug, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
/// Database configuration
pub database: Database,
/// server configuration
#[serde(default)]
pub server: Server,
}
impl Config {
fn try_paths() -> Result<(PathBuf, String)> {
let file = "config.toml";
fn load_file(file: &PathBuf) -> Result<Self> {
info!(?file, "loading configuration");
if let Ok(config) = fs::read_to_string(&file) {
return Ok((file.into(), config));
let config = toml::from_str(&fs::read_to_string(file)?)?;
trace!(?file, ?config, "loaded configuration");
Ok(config)
}
#[allow(clippy::cognitive_complexity)]
fn try_paths() -> Result<Self> {
let file = "config.toml";
match Self::load_file(&file.into()) {
Ok(config) => return Ok(config),
Err(error) => warn!(?file, "cannot load configuration: {:#}", Error::msg(error)),
}
let user_file =
let user_config =
xdg::BaseDirectories::with_prefix(env!("CARGO_BIN_NAME"))?.get_config_file(file);
info!(file = ?user_file, "loading configuration");
if let Ok(config) = fs::read_to_string(&user_file) {
return Ok((user_file, config));
match Self::load_file(&user_config) {
Ok(config) => return Ok(config),
Err(error) => warn!(file = ?user_config, "cannot load configuration: {:#}", Error::msg(error)),
}
let global_file = format!("/etc/{}/{}", env!("CARGO_BIN_NAME"), file);
info!(file = ?global_file, "loading configuration");
if let Ok(config) = fs::read_to_string(&global_file) {
return Ok((global_file.into(), config));
let global_config = format!("/etc/{}/{}", env!("CARGO_BIN_NAME"), file);
match Self::load_file(&global_config.clone().into()) {
Ok(config) => return Ok(config),
Err(error) => {
warn!(file = ?global_config, "cannot load configuration: {:#}", Error::msg(error));
}
}
error!("no configuration file found");
bail!("no configuration file found");
error!("no valid configuration file found");
bail!("no valid configuration file found");
}
pub fn load_config(file: Option<PathBuf>) -> Result<Self> {
if let Some(file) = file {
info!(?file, "loading configuration");
let config: Config = toml::from_str(&fs::read_to_string(&file)?)?;
trace!(?file, ?config, "loaded configuration");
Ok(config)
Ok(Self::load_file(&file)?)
} else {
let (file, config) = Self::try_paths()?;
let config = toml::from_str(&config)?;
trace!(?file, ?config, "loaded configuration");
Ok(config)
Ok(Self::try_paths()?)
}
}
}