bfile/filed/src/env.rs

171 lines
6.2 KiB
Rust
Raw Normal View History

2023-09-29 12:15:07 +02:00
/*
env.rs - The environment loader. It loads all the .env config to a convenient `Env` struct.
This file provides the `loadenv` function that will do just that.
*/
2023-10-23 12:54:15 +02:00
use std::{env::var, net::{SocketAddr, ToSocketAddrs, IpAddr}, path::Path, fs};
2023-09-29 12:15:07 +02:00
2023-10-20 17:31:08 +02:00
pub const DEFAULT_CONFIG: &'static str = include_str!("../config/filed.toml.example");
2023-10-01 02:14:35 +02:00
#[derive(Debug, Clone)]
pub struct Redis {
pub pass: String,
pub host: String,
pub port: u16,
pub prefix: String
}
2023-10-29 10:11:38 +01:00
#[derive(Debug, Clone)]
pub struct VersionData {
2023-10-29 10:14:58 +01:00
pub commit: String,
2023-10-29 10:44:31 +01:00
pub short_commit: String,
2023-10-29 10:14:58 +01:00
pub branch: String
2023-10-29 10:11:38 +01:00
}
2023-10-29 10:14:58 +01:00
2023-10-29 10:11:38 +01:00
impl Default for VersionData {
fn default() -> Self {
VersionData {
2023-10-29 10:14:58 +01:00
commit: env!("COMMIT_HASH").to_string(),
2023-10-29 10:44:31 +01:00
short_commit: env!("COMMIT_HASH").to_string().chars().take(6).collect(),
2023-10-29 10:14:58 +01:00
branch: env!("COMMIT_BRANCH").to_string()
2023-10-29 10:11:38 +01:00
}
}
}
2023-10-01 02:14:35 +02:00
#[derive(Debug, Clone)]
2023-09-29 12:15:07 +02:00
pub struct Env {
2023-09-29 12:57:53 +02:00
pub logging: bool,
2023-10-01 02:14:35 +02:00
pub listen: SocketAddr,
2023-10-23 12:54:15 +02:00
pub proxy_addr: IpAddr,
2023-10-01 02:14:35 +02:00
pub redis: Redis,
pub filedir: String,
2023-10-07 11:29:11 +02:00
pub instanceurl: String,
2023-10-20 17:12:16 +02:00
pub uploadspath: String,
2023-10-29 10:11:38 +01:00
pub confpath: String,
pub version: VersionData
2023-09-29 12:15:07 +02:00
}
fn get_var<T: Into<String>, O: From<String>>(name: T) -> Result<O, String> {
let name: String = name.into();
let v = var(name.clone());
if v.is_err() {
return Err(format!("Variable {name} does not exist!"));
}
return Ok(v.unwrap().into())
}
pub fn loadenv() -> Result<Env, Box<dyn std::error::Error>> {
Ok(
Env {
logging: get_var::<&str, String>("APP_LOGGING")?.to_lowercase() == "true",
2023-10-01 02:14:35 +02:00
listen: get_var::<&str, String>("APP_HOST")?.parse::<SocketAddr>().unwrap(),
2023-10-23 12:54:15 +02:00
proxy_addr: {
let env_var = get_var::<&str, String>("PROXY_IP")?;
let ip = env_var.parse::<IpAddr>();
2023-10-26 10:30:21 +02:00
let ret =
2023-10-23 12:54:15 +02:00
if let Ok(ip) = ip {
if ip == IpAddr::from([127, 0, 0, 1]) {
log::warn!("Proxy address is 127.0.0.1. No proxy will be trusted")
}
if ip == IpAddr::from([0, 0, 0, 0]) {
log::warn!("Proxy address is 0.0.0.0. All proxies will be trusted.");
#[cfg(not(debug_assertions))]
log::warn!("The warning above will not work well with production mode! Please consider setting the proxy address to a proper IP.")
}
ip
} else {
2023-10-26 10:30:21 +02:00
let mut env_var = env_var;
// add port if not added
if env_var.split(":").collect::<Vec<&str>>().len() == 1 {
env_var.push_str(":80");
}
2023-10-23 12:54:15 +02:00
let sock = env_var.to_socket_addrs();
if let Err(err) = sock {
return Err(format!("Can't resolve {env_var}: {:?}", err).into());
}
let mut addrs = sock.unwrap();
if addrs.len() == 0 {
return Err(format!("{env_var} resolved to nothing").into());
}
2023-10-26 10:30:21 +02:00
let addr = addrs.next().unwrap().ip();
addr
};
#[cfg(debug_assertions)] {
if ret != IpAddr::from([ 127, 0, 0, 1 ]) {
log::debug!("Proxy ip is {}", ret)
}
2023-10-23 12:54:15 +02:00
}
2023-10-26 10:30:21 +02:00
ret
2023-10-23 12:54:15 +02:00
},
2023-10-01 02:14:35 +02:00
redis: Redis {
pass: get_var("REDIS_PASS")?,
host: get_var("REDIS_HOST")?,
port: get_var::<&str, String>("REDIS_PORT")?.parse().unwrap(),
prefix: get_var("REDIS_PREFIX")?
2023-10-01 06:17:58 +02:00
},
filedir: {
let spath: String = get_var("USERCONTENT_DIR")?;
let path = Path::new(&spath);
if ! path.exists() {
fs::create_dir_all(path).map_err(|err| format!("Could not create usercontent directory: {err}"))?;
}
if ! path.is_dir() {
return Err(format!("USERCONTENT_DIR is set to \"{}\", which exists but is not a directory!", &spath).into())
2023-10-01 06:17:58 +02:00
}
spath
},
2023-10-07 11:29:11 +02:00
instanceurl: get_var("INSTANCE_URL")?,
2023-10-20 17:12:16 +02:00
uploadspath: get_var("UPLOADS_PATH")?,
confpath: {
2023-10-20 17:12:52 +02:00
let spath: String = get_var("CONF_FILE").unwrap_or("/etc/filed/filed.toml".into());
2023-10-20 17:12:16 +02:00
let path = Path::new(&spath);
let mut dirpath = path.components();
2023-10-20 17:31:08 +02:00
dirpath.next_back();
let dirpath = dirpath.as_path();
2023-10-20 17:12:16 +02:00
if ! path.is_file() {
2023-10-20 17:35:13 +02:00
log::error!("Config file is not a file");
log::info!("Trying to recover from error");
if ! dirpath.is_dir() {
log::info!("The config file directory does not exist. Trying to create it");
let created = fs::create_dir_all(dirpath);
if created.is_err() {
log::warn!("Could not create the config directory: {:?}", created.unwrap_err());
} else {
log::info!("Created the config directory");
}
}
2023-10-20 17:31:08 +02:00
if dirpath.is_dir() {
log::info!("Config file does not exist, trying to write the example");
2023-10-20 17:31:08 +02:00
let wrote = fs::write(path, DEFAULT_CONFIG);
2023-10-20 17:31:08 +02:00
if wrote.is_err() {
log::warn!("Could not write example because of the following error: {:?}", wrote.unwrap_err());
2023-10-20 17:31:08 +02:00
} else {
log::info!("Wrote example to {}", spath);
}
}
2023-10-20 17:35:13 +02:00
log::info!("Giving up");
2023-10-20 17:12:16 +02:00
return Err(format!("CONF_FILE is {}, which is not a file!", spath).into())
}
spath
2023-10-29 10:11:38 +01:00
},
version: VersionData::default()
2023-09-29 12:15:07 +02:00
}
)
2023-10-01 06:17:58 +02:00
}
impl Env {
pub fn usercontent_dir(self: &Self) -> Box<&Path> {
Box::new(Path::new(&self.filedir))
}
2023-09-29 12:15:07 +02:00
}