use serde::{Deserialize, Serialize};
use std::path::{Path, PathBuf};
use tokio::fs;
use url::Url;
use crate::{Error, Result};
#[derive(Default, Serialize, Deserialize)]
#[serde(default)]
pub struct ServerConfig {
pub session: SessionConfig,
pub tls: Option<TlsConfig>,
pub cors: CorsConfig,
}
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub struct TlsConfig {
pub cert: PathBuf,
pub key: PathBuf,
}
#[derive(Debug, Serialize, Deserialize)]
#[serde(rename_all = "kebab-case")]
pub struct SessionConfig {
pub timeout: u64,
pub interval: u64,
}
impl Default for SessionConfig {
fn default() -> Self {
Self {
timeout: 300,
interval: 900,
}
}
}
impl ServerConfig {
pub async fn load<P: AsRef<Path>>(path: P) -> Result<Self> {
if !fs::try_exists(path.as_ref()).await? {
return Err(Error::NotFile(path.as_ref().to_path_buf()));
}
let contents = fs::read_to_string(path.as_ref()).await?;
let mut config: ServerConfig = toml::from_str(&contents)?;
if config.session.interval <= config.session.timeout {
return Err(Error::SessionTimeoutConfig);
}
let dir = Self::directory(path.as_ref())?;
if let Some(tls) = config.tls.as_mut() {
if tls.cert.is_relative() {
tls.cert = dir.join(&tls.cert).canonicalize()?;
}
if tls.key.is_relative() {
tls.key = dir.join(&tls.key).canonicalize()?;
}
}
Ok(config)
}
fn directory(file: impl AsRef<Path>) -> Result<PathBuf> {
file.as_ref()
.parent()
.map(|p| p.to_path_buf())
.ok_or_else(|| Error::NoParentDir)
}
}
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct CorsConfig {
pub origins: Vec<Url>,
}