use anyhow::Result;
use lifeline::impl_storage_clone;
use serde::Deserialize;
use serde::Serialize;
use std::{env, fs::File, io::BufReader, path::PathBuf};
use sysinfo::{ProcessExt, RefreshKind, SystemExt};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DaemonConfig {
pub pid: i32,
pub port: u16,
pub executable: Option<String>,
pub tab_version: Option<String>,
pub auth_token: String,
}
impl_storage_clone!(DaemonConfig);
pub fn mkdir() -> Result<()> {
let data_path = data_path()?;
std::fs::create_dir_all(data_path)?;
Ok(())
}
pub fn data_path() -> Result<PathBuf> {
if let Ok(var) = env::var("TAB_RUNTIME_DIR") {
return Ok(PathBuf::from(var));
}
let mut dir = dirs::data_dir().ok_or_else(|| anyhow::Error::msg("tab data dir not found"))?;
dir.push("tab");
Ok(dir)
}
pub fn daemon_file() -> Result<PathBuf> {
let mut dir = data_path()?;
dir.push("daemon-pid.yml");
Ok(dir)
}
pub fn is_running(config: &DaemonConfig) -> bool {
let mut system = sysinfo::System::new_with_specifics(RefreshKind::new());
system.refresh_process(config.pid);
match system.get_process(config.pid) {
Some(proc) => {
let command = proc.cmd();
command.contains(&"--_launch".to_string()) && command.contains(&"daemon".to_string())
}
None => false,
}
}
pub fn daemon_log() -> Result<PathBuf> {
let mut dir = data_path()?;
dir.push("daemon.log");
Ok(dir)
}
pub fn pty_log() -> Result<PathBuf> {
let mut dir = data_path()?;
dir.push("pty.log");
Ok(dir)
}
pub fn history_path(shell: &str, name: &str) -> Result<PathBuf> {
let mut path = data_path()?;
path.push("history");
let name = name.replace("/", "_");
let filename = format!("history-{}-{}.txt", shell, name);
path.push(filename);
Ok(path)
}
pub fn load_daemon_file() -> anyhow::Result<Option<DaemonConfig>> {
let path = daemon_file()?;
if !path.is_file() {
log::trace!("File {:?} does not exist", path.as_path());
return Ok(None);
}
let file = File::open(path)?;
let reader = BufReader::new(file);
let config = serde_yaml::from_reader(reader)?;
Ok(Some(config))
}
pub fn global_config_file() -> Option<PathBuf> {
if let Ok(path) = env::var("TAB_CONFIG") {
return Some(PathBuf::from(path));
}
if let Some(mut home_path) = dirs::home_dir() {
home_path.push(".config");
home_path.push("tab.yml");
if home_path.exists() {
return Some(home_path);
}
}
if let Some(mut config_path) = dirs::config_dir() {
config_path.push("tab.yml");
if config_path.exists() {
return Some(config_path);
}
}
None
}
#[cfg(test)]
mod tests {
use super::{daemon_file, data_path};
#[test]
fn data_path_matches() {
let mut expected = dirs::data_dir().expect("home dir required");
expected.push("tab");
let path = data_path();
assert!(path.is_ok());
assert_eq!(expected, path.unwrap());
}
#[test]
fn daemonfile_path_matches() {
let mut expected = dirs::data_dir().expect("home dir required");
expected.push("tab");
expected.push("daemon-pid.yml");
let path = daemon_file();
assert!(path.is_ok());
assert_eq!(expected, path.unwrap());
}
}