use crate::{env_xdg_config, env_xdg_data, tokio::fs::File, RatmanError, Result};
use directories::ProjectDirs;
use std::{os::fd::AsRawFd, path::PathBuf};
pub enum Os {
Android,
Unix,
Unknown,
Ios,
Windows,
}
pub struct StateDirectoryLock(#[allow(unused)] File);
impl Os {
pub fn match_os() -> Os {
match std::env::consts::OS.as_ref() {
"linux" | "macos" | "freebsd" | "dragonfly" | "netbsd" | "openbsd" | "solaris" => {
Self::Unix
}
"android" => Self::Android,
"ios" => Self::Ios,
"windows" => Self::Windows,
_ => Self::Unknown, }
}
pub async fn lock_state_directory(path: Option<PathBuf>) -> Result<Option<StateDirectoryLock>> {
#[cfg(target_family = "unix")]
{
let path: PathBuf = path.unwrap_or_else(|| Self::match_os().data_path());
let f = File::open(&path).await?;
match nix::fcntl::flock(f.as_raw_fd(), nix::fcntl::FlockArg::LockExclusiveNonblock)
.map(|_| Some(StateDirectoryLock(f)))
{
Ok(lock) => Ok(lock),
Err(_) => Err(RatmanError::StateDirectoryAlreadyLocked),
}
}
#[cfg(target_family = "windows")]
{
warn!(
"Directory locks are not implemented on Windows! \
please make sure only one ratmand instance runs at a time"
);
Ok(None)
}
}
pub fn data_path(&self) -> PathBuf {
match self {
Self::Android => Self::android_data_path(),
Self::Unix | Self::Windows => Self::xdg_data_path(),
_ => Self::xdg_data_path(), }
}
pub fn xdg_config_path() -> PathBuf {
let dirs = ProjectDirs::from("org", "irdest", "ratmand")
.expect("Failed to initialise project directories");
let config_dir = env_xdg_config()
.map(|path| PathBuf::new().join(path))
.unwrap_or_else(|| dirs.config_dir().to_path_buf());
trace!("Ensure data directory exists: {:?}", config_dir);
let _ = std::fs::create_dir_all(&config_dir);
config_dir
}
pub fn xdg_data_path() -> PathBuf {
let dirs = ProjectDirs::from("org", "irdest", "ratmand")
.expect("Failed to initialise project directories");
let data_dir = env_xdg_data()
.map(|path| PathBuf::new().join(path))
.unwrap_or_else(|| dirs.data_dir().to_path_buf());
trace!("Ensure data directory exists: {:?}", data_dir);
let _ = std::fs::create_dir_all(&data_dir);
data_dir
}
pub fn android_data_path() -> PathBuf {
PathBuf::new().join("/data/user/0/org.irdest.IrdestVPN/files/")
}
}