use std::path::PathBuf;
use anyhow::Result;
#[cfg(any(
target_os = "linux",
not(any(target_os = "linux", target_os = "macos"))
))]
use anyhow::anyhow;
#[cfg(target_os = "linux")]
mod systemd;
#[cfg(target_os = "macos")]
mod launchd;
#[cfg(target_os = "linux")]
pub use systemd::{SystemdManager, systemd_available};
#[cfg(target_os = "macos")]
pub use launchd::LaunchdManager;
#[derive(Debug, Clone)]
pub struct ServiceConfig {
pub executable_path: PathBuf,
pub restart_retries: u32,
pub restart_delay: u32,
pub boot_mode: String,
}
#[derive(Debug, Clone)]
pub struct InstallResult {
pub service_file_path: PathBuf,
pub service_name: String,
pub started: bool,
pub requires_root: bool,
}
pub trait ServiceManager: Send + Sync {
fn install(&self, config: &ServiceConfig) -> Result<InstallResult>;
fn uninstall(&self) -> Result<()>;
fn is_installed(&self) -> Result<bool>;
fn service_file_path(&self) -> PathBuf;
fn service_name(&self) -> &str;
}
pub fn get_service_manager(boot_mode: &str) -> Result<Box<dyn ServiceManager>> {
#[cfg(target_os = "linux")]
{
if !systemd::systemd_available() {
return Err(anyhow!(
"systemd not available on this system. \
Service registration requires systemd as the init system."
));
}
Ok(Box::new(systemd::SystemdManager::new(boot_mode)))
}
#[cfg(target_os = "macos")]
{
Ok(Box::new(launchd::LaunchdManager::new(boot_mode)))
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
Err(anyhow!("Unsupported platform for service registration"))
}
}
pub fn is_service_registration_supported() -> bool {
cfg!(any(target_os = "linux", target_os = "macos"))
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_service_config_creation() {
let config = ServiceConfig {
executable_path: PathBuf::from("/usr/local/bin/occ"),
restart_retries: 3,
restart_delay: 5,
boot_mode: "user".to_string(),
};
assert_eq!(config.executable_path, PathBuf::from("/usr/local/bin/occ"));
assert_eq!(config.restart_retries, 3);
assert_eq!(config.restart_delay, 5);
assert_eq!(config.boot_mode, "user");
}
#[test]
fn test_install_result_creation() {
let result = InstallResult {
service_file_path: PathBuf::from("/etc/systemd/user/opencode-cloud.service"),
service_name: "opencode-cloud".to_string(),
started: true,
requires_root: false,
};
assert_eq!(
result.service_file_path,
PathBuf::from("/etc/systemd/user/opencode-cloud.service")
);
assert_eq!(result.service_name, "opencode-cloud");
assert!(result.started);
assert!(!result.requires_root);
}
#[test]
fn test_is_service_registration_supported() {
#[cfg(any(target_os = "linux", target_os = "macos"))]
assert!(is_service_registration_supported());
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
assert!(!is_service_registration_supported());
}
#[test]
fn test_get_service_manager_behavior() {
let result = get_service_manager("user");
#[cfg(target_os = "linux")]
{
let _ = result;
}
#[cfg(target_os = "macos")]
{
assert!(result.is_ok());
let manager = result.unwrap();
assert_eq!(manager.service_name(), "com.opencode-cloud.service");
}
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
{
assert!(result.is_err());
}
}
#[test]
fn test_get_service_manager_respects_boot_mode() {
let user_result = get_service_manager("user");
let system_result = get_service_manager("system");
let _ = user_result;
let _ = system_result;
}
}