2023-02-26 02:31:39 +00:00
|
|
|
use serde::Deserialize;
|
2023-04-21 23:39:52 +00:00
|
|
|
use std::fmt::{Display, Formatter};
|
2023-02-26 02:31:39 +00:00
|
|
|
use std::net::IpAddr;
|
2023-07-07 19:22:30 +00:00
|
|
|
use thiserror::Error;
|
2023-02-26 02:31:39 +00:00
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct MagnetarNetworking {
|
|
|
|
pub host: String,
|
|
|
|
pub port: u16,
|
|
|
|
pub bind_addr: IpAddr,
|
2023-04-21 23:39:52 +00:00
|
|
|
pub protocol: MagnetarNetworkingProtocol,
|
2023-11-05 14:23:48 +00:00
|
|
|
pub media_proxy: Option<String>,
|
|
|
|
pub proxy_remote_files: bool,
|
2023-04-21 23:39:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
2023-04-22 00:17:24 +00:00
|
|
|
#[serde(rename_all = "snake_case")]
|
2023-04-21 23:39:52 +00:00
|
|
|
pub enum MagnetarNetworkingProtocol {
|
|
|
|
Http,
|
|
|
|
Https,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AsRef<str> for MagnetarNetworkingProtocol {
|
|
|
|
fn as_ref(&self) -> &str {
|
|
|
|
match *self {
|
|
|
|
MagnetarNetworkingProtocol::Http => "http",
|
|
|
|
MagnetarNetworkingProtocol::Https => "https",
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for MagnetarNetworkingProtocol {
|
|
|
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
|
|
write!(f, "{}", self.as_ref())
|
|
|
|
}
|
2023-02-26 02:31:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn env_host() -> String {
|
|
|
|
std::env::var("MAG_C_HOST")
|
2023-04-21 23:39:52 +00:00
|
|
|
.expect("MAG_C_HOST or \"networking.host\" in the default configuration must be set")
|
2023-02-26 02:31:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn env_bind_addr() -> IpAddr {
|
|
|
|
std::env::var("MAG_C_BIND_ADDR")
|
|
|
|
.unwrap_or_else(|_| "::".to_owned())
|
|
|
|
.parse()
|
|
|
|
.map_err(|e| format!("Failed to parse \"MAG_C_BIND_ADDR\": {e}"))
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_port() -> u16 {
|
|
|
|
std::env::var("MAG_C_PORT")
|
|
|
|
.unwrap_or_else(|_| "4939".to_owned())
|
|
|
|
.parse()
|
|
|
|
.expect("MAG_C_PORT must be a valid port number")
|
|
|
|
}
|
|
|
|
|
2023-04-21 23:39:52 +00:00
|
|
|
fn env_protocol() -> MagnetarNetworkingProtocol {
|
|
|
|
match std::env::var("MAG_C_PROTOCOL")
|
|
|
|
.unwrap_or_else(|_| "https".to_owned())
|
|
|
|
.to_lowercase()
|
|
|
|
.as_str()
|
|
|
|
{
|
|
|
|
"http" => MagnetarNetworkingProtocol::Http,
|
|
|
|
"https" => MagnetarNetworkingProtocol::Https,
|
|
|
|
_ => panic!("MAG_C_PROTOCOL must be a valid protocol"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-11-05 14:23:48 +00:00
|
|
|
fn env_media_proxy() -> Option<String> {
|
|
|
|
std::env::var("MAG_C_MEDIA_PROXY")
|
|
|
|
.ok()
|
|
|
|
.filter(String::is_empty)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_proxy_remote_files() -> bool {
|
|
|
|
std::env::var("MAG_C_PROXY_REMOTE_FILES")
|
|
|
|
.unwrap_or_else(|_| "false".to_string())
|
|
|
|
.parse()
|
|
|
|
.expect("MAG_C_PROXY_REMOTE_FILES must be a boolean")
|
|
|
|
}
|
|
|
|
|
2023-02-26 02:31:39 +00:00
|
|
|
impl Default for MagnetarNetworking {
|
|
|
|
fn default() -> Self {
|
|
|
|
MagnetarNetworking {
|
|
|
|
host: env_host(),
|
|
|
|
bind_addr: env_bind_addr(),
|
|
|
|
port: env_port(),
|
2023-04-21 23:39:52 +00:00
|
|
|
protocol: env_protocol(),
|
2023-11-05 14:23:48 +00:00
|
|
|
media_proxy: env_media_proxy(),
|
|
|
|
proxy_remote_files: env_proxy_remote_files(),
|
2023-04-21 23:39:52 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-07 19:22:30 +00:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct MagnetarCalckeyFrontendConfig {
|
|
|
|
pub bind_addr: IpAddr,
|
|
|
|
pub port: u16,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_fe_bind_addr() -> IpAddr {
|
|
|
|
std::env::var("MAG_C_CK_FE_BIND_ADDR")
|
|
|
|
.unwrap_or_else(|_| "::".to_owned())
|
|
|
|
.parse()
|
|
|
|
.map_err(|e| format!("Failed to parse \"MAG_C_CK_FE_BIND_ADDR\": {e}"))
|
|
|
|
.unwrap()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_fe_port() -> u16 {
|
|
|
|
std::env::var("MAG_C_CK_FE_PORT")
|
|
|
|
.unwrap_or_else(|_| "4938".to_owned())
|
|
|
|
.parse()
|
|
|
|
.expect("MAG_C_CK_FE_PORT must be a valid port number")
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for MagnetarCalckeyFrontendConfig {
|
|
|
|
fn default() -> Self {
|
|
|
|
MagnetarCalckeyFrontendConfig {
|
|
|
|
bind_addr: env_fe_bind_addr(),
|
|
|
|
port: env_fe_port(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-21 23:39:52 +00:00
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct MagnetarBranding {
|
|
|
|
pub name: String,
|
|
|
|
pub version: String,
|
|
|
|
pub homepage: String,
|
|
|
|
pub repository: String,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_brand_name() -> String {
|
|
|
|
std::env::var("MAG_C_BR_NAME").unwrap_or_else(|_| "magnetar".to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_brand_version() -> String {
|
|
|
|
std::env::var("MAG_C_BR_VERSION").unwrap_or_else(|_| env!("CARGO_PKG_VERSION").to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_brand_homepage() -> String {
|
|
|
|
std::env::var("MAG_C_BR_HOMEPAGE")
|
|
|
|
.unwrap_or_else(|_| "https://git.astolfo.cool/natty/magnetar".to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env_brand_repository() -> String {
|
|
|
|
std::env::var("MAG_C_BR_REPOSITORY")
|
|
|
|
.unwrap_or_else(|_| "https://git.astolfo.cool/natty/magnetar".to_owned())
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Default for MagnetarBranding {
|
|
|
|
fn default() -> Self {
|
|
|
|
MagnetarBranding {
|
|
|
|
name: env_brand_name(),
|
|
|
|
version: env_brand_version(),
|
|
|
|
homepage: env_brand_homepage(),
|
|
|
|
repository: env_brand_repository(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct MagnetarData {
|
|
|
|
pub database_url: String,
|
2023-08-02 01:10:53 +00:00
|
|
|
pub redis_url: String,
|
2023-04-21 23:39:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn env_database_url() -> String {
|
|
|
|
std::env::var("MAG_C_DATABASE_URL")
|
|
|
|
.or_else(|_| std::env::var("DATABASE_URL"))
|
2023-05-18 23:51:58 +00:00
|
|
|
.expect("MAG_C_DATABASE_URL, DATABASE_URL or \"data.database_url\" in the default configuration must be set")
|
2023-04-21 23:39:52 +00:00
|
|
|
}
|
|
|
|
|
2023-08-02 01:10:53 +00:00
|
|
|
fn env_redis_url() -> String {
|
|
|
|
std::env::var("MAG_C_REDIS_URL")
|
|
|
|
.expect("MAG_C_REDIS_URL or \"data.redis_url\" in the default configuration must be set")
|
|
|
|
}
|
|
|
|
|
2023-04-21 23:39:52 +00:00
|
|
|
impl Default for MagnetarData {
|
|
|
|
fn default() -> Self {
|
|
|
|
MagnetarData {
|
|
|
|
database_url: env_database_url(),
|
2023-08-02 01:10:53 +00:00
|
|
|
redis_url: env_redis_url(),
|
2023-02-26 02:31:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Deserialize, Debug, Default)]
|
|
|
|
#[non_exhaustive]
|
|
|
|
pub struct MagnetarConfig {
|
|
|
|
#[serde(default)]
|
|
|
|
pub networking: MagnetarNetworking,
|
2023-04-21 23:39:52 +00:00
|
|
|
#[serde(default)]
|
|
|
|
pub branding: MagnetarBranding,
|
|
|
|
#[serde(default)]
|
2023-07-07 19:22:30 +00:00
|
|
|
pub calckey_frontend: MagnetarCalckeyFrontendConfig,
|
|
|
|
#[serde(default)]
|
2023-04-21 23:39:52 +00:00
|
|
|
pub data: MagnetarData,
|
2023-02-26 02:31:39 +00:00
|
|
|
}
|
|
|
|
|
2023-07-07 19:22:30 +00:00
|
|
|
#[derive(Debug, Error)]
|
|
|
|
pub enum MagnetarConfigError {
|
|
|
|
#[error("Failed to load configuration: {0}")]
|
|
|
|
IoError(#[from] std::io::Error),
|
|
|
|
#[error("Failed to parse configuration: {0}")]
|
|
|
|
DeserializeError(#[from] toml::de::Error),
|
2023-11-05 14:23:48 +00:00
|
|
|
#[error("Configuration error: Not a valid hostname")]
|
|
|
|
ConfigHostnameError(#[from] idna::Errors),
|
2023-07-07 19:22:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_config() -> Result<MagnetarConfig, MagnetarConfigError> {
|
2023-02-26 02:31:39 +00:00
|
|
|
let path =
|
|
|
|
std::env::var("MAG_CONFIG_PATH").unwrap_or_else(|_| "config/default.toml".to_owned());
|
|
|
|
|
2023-07-07 19:22:30 +00:00
|
|
|
let str_cfg = std::fs::read_to_string(path)?;
|
2023-02-26 02:31:39 +00:00
|
|
|
|
2023-11-05 14:23:48 +00:00
|
|
|
let mut config: MagnetarConfig = toml::from_str(&str_cfg)?;
|
|
|
|
|
|
|
|
// Validate the host
|
|
|
|
idna::domain_to_unicode(&config.networking.host).1?;
|
|
|
|
|
|
|
|
if config
|
|
|
|
.networking
|
|
|
|
.media_proxy
|
|
|
|
.as_deref()
|
|
|
|
.is_some_and(str::is_empty)
|
|
|
|
{
|
|
|
|
config.networking.media_proxy = None;
|
|
|
|
}
|
2023-02-26 02:31:39 +00:00
|
|
|
|
|
|
|
Ok(config)
|
|
|
|
}
|