pub fn is_installed() -> bool {
is_in_install_dir() || is_service_registered()
}
fn is_in_install_dir() -> bool {
let current_exe = match std::env::current_exe() {
Ok(p) => p,
Err(_) => return false,
};
let install_dir = match get_install_dir() {
Some(d) => d,
None => return false,
};
let exe_dir = match current_exe.parent() {
Some(d) => d,
None => return false,
};
paths_equivalent(exe_dir, &install_dir)
}
fn is_service_registered() -> bool {
let has_registry = winreg::RegKey::predef(winreg::enums::HKEY_CURRENT_USER)
.open_subkey(r"Software\Microsoft\Windows\CurrentVersion\Run")
.ok()
.and_then(|k| k.get_value::<String, _>("Freenet").ok())
.is_some();
if has_registry {
return true;
}
std::process::Command::new("schtasks")
.args(["/query", "/tn", "Freenet"])
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()
.map(|s| s.success())
.unwrap_or(false)
}
pub fn get_install_dir() -> Option<std::path::PathBuf> {
dirs::data_local_dir().map(|d| d.join("Freenet").join("bin"))
}
fn paths_equivalent(a: &std::path::Path, b: &std::path::Path) -> bool {
let a_canon = a.canonicalize().unwrap_or_else(|_| a.to_path_buf());
let b_canon = b.canonicalize().unwrap_or_else(|_| b.to_path_buf());
let a_str = a_canon.to_string_lossy().to_lowercase();
let b_str = b_canon.to_string_lossy().to_lowercase();
let a_trimmed = a_str.trim_end_matches(['/', '\\']);
let b_trimmed = b_str.trim_end_matches(['/', '\\']);
a_trimmed == b_trimmed
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_paths_equivalent_same_path() {
let a = std::path::Path::new("/tmp/test");
assert!(paths_equivalent(a, a));
}
#[test]
fn test_paths_equivalent_trailing_separator() {
let a = std::path::Path::new("/tmp/test");
let b = std::path::Path::new("/tmp/test/");
assert!(paths_equivalent(a, b));
}
#[test]
fn test_paths_not_equivalent() {
let a = std::path::Path::new("/tmp/test");
let b = std::path::Path::new("/tmp/other");
assert!(!paths_equivalent(a, b));
}
#[test]
fn test_get_install_dir_returns_something() {
let dir = get_install_dir();
assert!(dir.is_some());
let dir = dir.unwrap();
assert!(dir.to_string_lossy().contains("Freenet"));
}
}