use std::path::PathBuf;
use crate::connector::{ServiceConnector, ServiceInfo, ServiceStatus};
use super::helpers::{binary_on_path, fetch_health_version, read_addr_file, tcp_probe};
pub struct ReviewConnector {
home_dir: Option<PathBuf>,
}
impl ReviewConnector {
pub fn new() -> Self {
Self { home_dir: None }
}
#[cfg(test)]
pub fn with_home(home_dir: PathBuf) -> Self {
Self {
home_dir: Some(home_dir),
}
}
fn addr_file_path(&self) -> PathBuf {
let home = self
.home_dir
.clone()
.or_else(dirs::home_dir)
.unwrap_or_else(|| PathBuf::from("/tmp"));
home.join(".trusty-review").join("http_addr")
}
pub(crate) fn default_addr() -> &'static str {
"127.0.0.1:7880"
}
}
impl Default for ReviewConnector {
fn default() -> Self {
Self::new()
}
}
impl ServiceConnector for ReviewConnector {
fn id(&self) -> &'static str {
"trusty-review"
}
fn display_name(&self) -> &'static str {
"Trusty Review"
}
fn detect(&self) -> ServiceInfo {
if !binary_on_path("trusty-review") {
return ServiceInfo {
id: self.id().to_string(),
display_name: self.display_name().to_string(),
status: ServiceStatus::Absent,
version: None,
url: None,
hint: None,
};
}
if let Some(addr) = read_addr_file(&self.addr_file_path())
&& tcp_probe(&addr)
{
let base_url = format!("http://{addr}");
let version = fetch_health_version(&addr);
return ServiceInfo {
id: self.id().to_string(),
display_name: self.display_name().to_string(),
status: ServiceStatus::Running,
version,
url: Some(base_url),
hint: None,
};
}
let default_addr = Self::default_addr();
if tcp_probe(default_addr) {
let base_url = format!("http://{default_addr}");
let version = fetch_health_version(default_addr);
return ServiceInfo {
id: self.id().to_string(),
display_name: self.display_name().to_string(),
status: ServiceStatus::Running,
version,
url: Some(base_url),
hint: None,
};
}
ServiceInfo {
id: self.id().to_string(),
display_name: self.display_name().to_string(),
status: ServiceStatus::Available,
version: None,
url: None,
hint: None,
}
}
}
#[cfg(test)]
mod tests {
use super::super::helpers::tcp_probe;
use super::*;
use std::fs;
use tempfile::TempDir;
fn make_home_with_addr(rel_path: &str, content: &str) -> TempDir {
let tmp = TempDir::new().expect("tempdir");
let path = tmp.path().join(rel_path);
fs::create_dir_all(path.parent().expect("parent")).expect("mkdir");
fs::write(&path, content).expect("write addr file");
tmp
}
#[test]
fn test_review_connector_with_stale_addr_file() {
let tmp = make_home_with_addr(".trusty-review/http_addr", "127.0.0.1:14997");
let connector = ReviewConnector::with_home(tmp.path().to_path_buf());
let info = connector.detect();
let binary_present = which::which("trusty-review").is_ok();
let default_running = tcp_probe(ReviewConnector::default_addr());
if !binary_present {
assert_eq!(info.status, ServiceStatus::Absent, "binary absent → Absent");
} else if default_running {
assert_eq!(
info.status,
ServiceStatus::Running,
"binary present, default port running → Running"
);
} else {
assert_eq!(
info.status,
ServiceStatus::Available,
"binary present, no running daemon → Available"
);
}
assert_eq!(info.id, "trusty-review");
assert_eq!(info.display_name, "Trusty Review");
}
#[test]
fn test_review_connector_no_addr_file() {
let tmp = TempDir::new().expect("tempdir");
let connector = ReviewConnector::with_home(tmp.path().to_path_buf());
let info = connector.detect();
let binary_present = which::which("trusty-review").is_ok();
let default_running = tcp_probe(ReviewConnector::default_addr());
if !binary_present {
assert_eq!(info.status, ServiceStatus::Absent, "binary absent → Absent");
} else if default_running {
assert_eq!(
info.status,
ServiceStatus::Running,
"binary present, default port running → Running"
);
} else {
assert_eq!(
info.status,
ServiceStatus::Available,
"binary present, no running daemon → Available"
);
}
assert!(info.url.is_none() || info.status == ServiceStatus::Running);
}
}