Init
This commit is contained in:
+134
@@ -0,0 +1,134 @@
|
||||
use config::{Config, ConfigError, File, FileFormat};
|
||||
use serde::Deserialize;
|
||||
use std::error::Error;
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
use std::path::Path;
|
||||
use std::{fmt, fs};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum AppConfigError {
|
||||
Io(std::io::Error),
|
||||
Config(ConfigError),
|
||||
}
|
||||
|
||||
impl fmt::Display for AppConfigError {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(err) => write!(f, "failed to access config file: {err}"),
|
||||
Self::Config(err) => write!(f, "failed to load config: {err}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for AppConfigError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
Self::Io(err) => Some(err),
|
||||
Self::Config(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<std::io::Error> for AppConfigError {
|
||||
fn from(err: std::io::Error) -> Self {
|
||||
Self::Io(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConfigError> for AppConfigError {
|
||||
fn from(err: ConfigError) -> Self {
|
||||
Self::Config(err)
|
||||
}
|
||||
}
|
||||
|
||||
pub const DEFAULT_CONFIG_TOML: &str = r#"[network]
|
||||
# IP address to bind to
|
||||
host = "0.0.0.0"
|
||||
# hostv6 = "::"
|
||||
# TCP and UDP port can be the same
|
||||
# HTTP port
|
||||
tcp_port = 8080
|
||||
# Voice/Video port
|
||||
udp_port = 8080
|
||||
|
||||
[database]
|
||||
# DSN for database
|
||||
# SQLite
|
||||
url = "sqlite://oxspeak.db"
|
||||
# PostgreSQL
|
||||
# url = "postgresql://user:passwd@localhost:5432/db_name"
|
||||
# MySQL
|
||||
# url = "mysql://user:passwd@localhost:3306/db_name"
|
||||
|
||||
[jwt]
|
||||
secret = "changeme"
|
||||
# Duration in seconds
|
||||
duration = 86400 # 1 day
|
||||
refresh_duration = 1296000 # 15 days
|
||||
"#;
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct AppConfig {
|
||||
pub network: NetworkConfig,
|
||||
pub database: DatabaseConfig,
|
||||
pub jwt: JwtConfig,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct NetworkConfig {
|
||||
pub host: Ipv4Addr,
|
||||
pub hostv6: Option<Ipv6Addr>,
|
||||
pub tcp_port: u16,
|
||||
pub udp_port: u16,
|
||||
}
|
||||
|
||||
#[derive(Clone, Deserialize)]
|
||||
pub struct DatabaseConfig {
|
||||
pub url: String,
|
||||
}
|
||||
|
||||
impl fmt::Debug for DatabaseConfig {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("DatabaseConfig")
|
||||
.field("url", &"<hidden>")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct JwtConfig {
|
||||
pub secret: String,
|
||||
pub duration: u64,
|
||||
pub refresh_duration: u64,
|
||||
}
|
||||
|
||||
impl AppConfig {
|
||||
pub fn file_exists() -> bool {
|
||||
Path::new("config.toml").exists()
|
||||
}
|
||||
|
||||
pub fn load() -> Result<Self, AppConfigError> {
|
||||
let settings = Config::builder()
|
||||
.add_source(File::new("config.toml", FileFormat::Toml))
|
||||
.build()?;
|
||||
|
||||
Ok(settings.try_deserialize()?)
|
||||
}
|
||||
|
||||
pub fn gen_config() -> Result<(), AppConfigError> {
|
||||
if !Self::file_exists() {
|
||||
fs::write("config.toml", DEFAULT_CONFIG_TOML)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn load_or_generate() -> Result<Self, AppConfigError> {
|
||||
if !Self::file_exists() {
|
||||
Self::gen_config()?;
|
||||
tracing::info!(config_path = "config.toml", "Generated");
|
||||
}
|
||||
|
||||
Self::load()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user