opencode_cloud_core/platform/
mod.rs1use std::path::PathBuf;
7
8use anyhow::Result;
9
10#[cfg(any(
11 target_os = "linux",
12 not(any(target_os = "linux", target_os = "macos"))
13))]
14use anyhow::anyhow;
15
16#[cfg(target_os = "linux")]
17mod systemd;
18
19#[cfg(target_os = "macos")]
20mod launchd;
21
22#[cfg(target_os = "linux")]
23pub use systemd::{SystemdManager, systemd_available};
24
25#[cfg(target_os = "macos")]
26pub use launchd::LaunchdManager;
27
28#[derive(Debug, Clone)]
30pub struct ServiceConfig {
31 pub executable_path: PathBuf,
33
34 pub restart_retries: u32,
36
37 pub restart_delay: u32,
39
40 pub boot_mode: String,
42}
43
44#[derive(Debug, Clone)]
46pub struct InstallResult {
47 pub service_file_path: PathBuf,
49
50 pub service_name: String,
52
53 pub started: bool,
55
56 pub requires_root: bool,
58}
59
60pub trait ServiceManager: Send + Sync {
65 fn install(&self, config: &ServiceConfig) -> Result<InstallResult>;
70
71 fn uninstall(&self) -> Result<()>;
75
76 fn is_installed(&self) -> Result<bool>;
78
79 fn service_file_path(&self) -> PathBuf;
81
82 fn service_name(&self) -> &str;
84}
85
86pub fn get_service_manager(boot_mode: &str) -> Result<Box<dyn ServiceManager>> {
94 #[cfg(target_os = "linux")]
95 {
96 if !systemd::systemd_available() {
97 return Err(anyhow!(
98 "systemd not available on this system. \
99 Service registration requires systemd as the init system."
100 ));
101 }
102 Ok(Box::new(systemd::SystemdManager::new(boot_mode)))
103 }
104 #[cfg(target_os = "macos")]
105 {
106 Ok(Box::new(launchd::LaunchdManager::new(boot_mode)))
107 }
108 #[cfg(not(any(target_os = "linux", target_os = "macos")))]
109 {
110 Err(anyhow!("Unsupported platform for service registration"))
111 }
112}
113
114pub fn is_service_registration_supported() -> bool {
118 cfg!(any(target_os = "linux", target_os = "macos"))
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_service_config_creation() {
127 let config = ServiceConfig {
128 executable_path: PathBuf::from("/usr/local/bin/occ"),
129 restart_retries: 3,
130 restart_delay: 5,
131 boot_mode: "user".to_string(),
132 };
133
134 assert_eq!(config.executable_path, PathBuf::from("/usr/local/bin/occ"));
135 assert_eq!(config.restart_retries, 3);
136 assert_eq!(config.restart_delay, 5);
137 assert_eq!(config.boot_mode, "user");
138 }
139
140 #[test]
141 fn test_install_result_creation() {
142 let result = InstallResult {
143 service_file_path: PathBuf::from("/etc/systemd/user/opencode-cloud.service"),
144 service_name: "opencode-cloud".to_string(),
145 started: true,
146 requires_root: false,
147 };
148
149 assert_eq!(
150 result.service_file_path,
151 PathBuf::from("/etc/systemd/user/opencode-cloud.service")
152 );
153 assert_eq!(result.service_name, "opencode-cloud");
154 assert!(result.started);
155 assert!(!result.requires_root);
156 }
157
158 #[test]
159 fn test_is_service_registration_supported() {
160 #[cfg(any(target_os = "linux", target_os = "macos"))]
162 assert!(is_service_registration_supported());
163
164 #[cfg(not(any(target_os = "linux", target_os = "macos")))]
165 assert!(!is_service_registration_supported());
166 }
167
168 #[test]
169 fn test_get_service_manager_behavior() {
170 let result = get_service_manager("user");
171
172 #[cfg(target_os = "linux")]
177 {
178 let _ = result;
181 }
182 #[cfg(target_os = "macos")]
183 {
184 assert!(result.is_ok());
186 let manager = result.unwrap();
187 assert_eq!(manager.service_name(), "com.opencode-cloud.service");
188 }
189 #[cfg(not(any(target_os = "linux", target_os = "macos")))]
190 {
191 assert!(result.is_err());
192 }
193 }
194
195 #[test]
196 fn test_get_service_manager_respects_boot_mode() {
197 let user_result = get_service_manager("user");
199 let system_result = get_service_manager("system");
200
201 let _ = user_result;
204 let _ = system_result;
205 }
206}