1use anyhow::Result;
2use std::io::Write;
3use std::path::{Path, PathBuf};
4
5use crate::config::SafirConfig;
6
7use colored::*;
8use sysinfo::{Pid, System, SystemExt};
9use tokio::fs;
10
11pub async fn init() -> Result<SafirConfig> {
12 let store_dir = create_safir_directory().await?;
13 let cfg = load_safir_config(&store_dir).await?;
14 Ok(cfg)
15}
16
17pub fn check_rubin_installed() -> bool {
18 if which::which("rubin").is_ok() {
19 return true;
20 }
21
22 false
23}
24
25pub fn check_process_running(pid: u32) -> bool {
26 let mut system = System::new_all();
27 system.refresh_all();
28 if system.process(Pid::from(pid as usize)).is_some() {
29 return true;
30 }
31
32 false
33}
34
35pub fn is_safir_running(pid: Option<u32>) -> bool {
36 match pid {
37 Some(pid) => check_process_running(pid),
38 None => false,
39 }
40}
41
42pub async fn path_exists(path: impl AsRef<Path>) -> bool {
43 path.as_ref().exists()
44}
45
46pub async fn create_safir_directory() -> Result<PathBuf> {
47 let home_dir = dirs::home_dir().unwrap();
48 let store_path = home_dir.join(".safirstore");
49 fs::create_dir_all(&store_path).await?;
50
51 Ok(store_path)
52}
53
54#[cfg(target_family = "unix")]
55pub async fn kill_process(pid: u32) -> Result<()> {
56 if let Ok(process) = psutil::process::Process::new(pid) {
57 if let Err(err) = process.kill() {
58 eprintln!("failed to kill process: {}", err);
59 }
60 } else {
61 eprintln!("failed to get process information");
62 }
63
64 Ok(())
65}
66
67#[cfg(target_os = "windows")]
68pub async fn kill_process(pid: u32) {
69 println!("*** Windows -- This is experimental and may not work as intended! ***");
70 let output = Command::new("taskkill")
71 .arg("/F")
72 .arg("/PID")
73 .arg(pid.to_string())
74 .output()
75 .expect("failed to call taskkill");
76
77 if !output.status.success() {
78 eprintln!("failed to terminate process");
79 }
80}
81
82pub fn print_output(msg: &str) {
84 println!("{}\n", msg);
85}
86
87pub fn print_header() {
89 println!("{}", "--=Safirstore=--\n".bold());
90}
91
92pub fn print_headless(prefix: &str, key: &str, value: &str) {
93 if value == "" {
94 return;
95 }
96
97 let has_whitespace = value.contains(char::is_whitespace);
98
99 let output = if has_whitespace {
100 format!("{}=\"{}\"", key, value)
101 } else {
102 format!("{}={}", key, value)
103 };
104
105 if !prefix.is_empty() {
106 println!("{} {}", prefix, output);
107 } else {
108 println!("{}", output);
109 }
110}
111
112pub fn confirm_entry(msg: &str) -> bool {
114 let mut answer = String::new();
115 print!("{} (y/n) ", msg);
116 std::io::stdout().flush().expect("failed to flush buffer");
117
118 let _ = std::io::stdin()
119 .read_line(&mut answer)
120 .expect("unable to get input from user");
121
122 let answer = answer.trim().to_lowercase();
123 if answer == "y" || answer == "yes" {
124 return true;
125 }
126
127 false
128}
129
130pub async fn load_safir_config(store_dir: impl AsRef<Path>) -> Result<SafirConfig> {
131 let cfg_path = &store_dir.as_ref().join("safir.cfg");
132 let mut cfg = if path_exists(&cfg_path).await {
133 SafirConfig::load(&cfg_path).await?
134 } else {
135 SafirConfig::new()
136 };
137
138 cfg.root_path = store_dir.as_ref().to_owned();
139 cfg.config_path = cfg_path.to_owned();
140
141 if let Some(pid) = cfg.memcache_pid {
143 if !check_process_running(pid) {
144 cfg = SafirConfig::new();
145 cfg.write().await?;
146 }
147 }
148
149 Ok(cfg)
150}