use std::env;
use std::fmt;
use std::path::PathBuf;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
enum XdgDirectory {
Config,
Data,
State,
}
impl XdgDirectory {
fn env_var(self) -> &'static str {
match self {
Self::Config => "XDG_CONFIG_HOME",
Self::Data => "XDG_DATA_HOME",
Self::State => "XDG_STATE_HOME",
}
}
fn fallback_suffix(self) -> &'static str {
match self {
Self::Config => ".config",
Self::Data => ".local/share",
Self::State => ".local/state",
}
}
fn label(self) -> &'static str {
match self {
Self::Config => "config",
Self::Data => "data",
Self::State => "state",
}
}
}
#[derive(Debug)]
pub struct XdgPathError {
directory: XdgDirectory,
}
impl fmt::Display for XdgPathError {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"unable to resolve the XDG {} base directory: set {} or HOME",
self.directory.label(),
self.directory.env_var()
)
}
}
impl std::error::Error for XdgPathError {}
pub fn default_config_path() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::Config)?.join("config.toml"))
}
pub fn default_client_identity_material_dir() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::Data)?
.join("client")
.join("identity"))
}
pub fn default_client_server_ca_path() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::Data)?
.join("client")
.join("server-ca.crt"))
}
pub fn default_server_cert_material_dir() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::Data)?
.join("server")
.join("cert"))
}
pub fn default_server_acme_state_dir() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::State)?
.join("server")
.join("acme"))
}
pub fn default_client_public_cert_material_dir() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::Data)?
.join("client")
.join("public-cert"))
}
pub fn default_client_acme_state_dir() -> Result<PathBuf, XdgPathError> {
Ok(runewarp_dir(XdgDirectory::State)?
.join("client")
.join("acme"))
}
fn runewarp_dir(directory: XdgDirectory) -> Result<PathBuf, XdgPathError> {
Ok(xdg_base_dir(directory)?.join("runewarp"))
}
fn xdg_base_dir(directory: XdgDirectory) -> Result<PathBuf, XdgPathError> {
if let Some(path) = env::var_os(directory.env_var()).filter(|value| !value.is_empty()) {
return Ok(PathBuf::from(path));
}
let Some(home) = env::var_os("HOME").filter(|value| !value.is_empty()) else {
return Err(XdgPathError { directory });
};
Ok(PathBuf::from(home).join(directory.fallback_suffix()))
}