rush_sync_server/server/
manager.rs1use crate::core::prelude::*;
6use crate::server::{ServerInfo, ServerInstance, ServerMode, ServerStatus};
7use std::collections::HashMap;
8use std::sync::{Arc, Mutex};
9use tokio::sync::RwLock;
10
11pub struct ServerManager {
13 pub(crate) servers: Arc<RwLock<HashMap<String, ServerInstance>>>,
14 pub(crate) config_file: std::path::PathBuf,
15}
16
17impl ServerManager {
18 pub fn new() -> Self {
20 let config_file = std::path::PathBuf::from("config/servers.json");
21
22 Self {
23 servers: Arc::new(RwLock::new(HashMap::new())),
24 config_file,
25 }
26 }
27
28 pub async fn load_servers(&self) -> Result<()> {
30 if !self.config_file.exists() {
31 log::info!("📁 No existing server config, starting fresh");
32 return Ok(());
33 }
34
35 let content = tokio::fs::read_to_string(&self.config_file)
36 .await
37 .map_err(AppError::Io)?;
38
39 let server_infos: Vec<ServerInfo> = serde_json::from_str(&content)
40 .map_err(|e| AppError::Validation(format!("Invalid server config: {}", e)))?;
41
42 let mut servers = self.servers.write().await;
43 for info in server_infos {
44 let server = ServerInstance::from_info(info);
45 servers.insert(server.get_server_id(), server);
46 }
47
48 log::info!("📊 Loaded {} servers from config", servers.len());
49 Ok(())
50 }
51
52 pub async fn save_servers(&self) -> Result<()> {
54 if let Some(parent) = self.config_file.parent() {
56 tokio::fs::create_dir_all(parent)
57 .await
58 .map_err(AppError::Io)?;
59 }
60
61 let servers = self.servers.read().await;
62 let server_infos: Vec<ServerInfo> = servers
63 .values()
64 .map(|server| {
65 let info = server.info.lock().unwrap_or_else(|poisoned| {
66 log::warn!("Recovered from poisoned mutex");
67 poisoned.into_inner()
68 });
69 info.clone()
70 })
71 .collect();
72
73 let content = serde_json::to_string_pretty(&server_infos)
74 .map_err(|e| AppError::Validation(format!("Failed to serialize servers: {}", e)))?;
75
76 tokio::fs::write(&self.config_file, content)
77 .await
78 .map_err(AppError::Io)?;
79
80 log::debug!("💾 Saved {} servers to config", server_infos.len());
81 Ok(())
82 }
83
84 pub async fn create_server(&self, port: u16, mode: ServerMode) -> Result<String> {
86 let servers = self.servers.read().await;
88 for server in servers.values() {
89 let info = server.info.lock().unwrap_or_else(|poisoned| {
90 log::warn!("Recovered from poisoned mutex");
91 poisoned.into_inner()
92 });
93 if info.port == port {
94 return Err(AppError::Validation(format!(
95 "Port {} already in use",
96 port
97 )));
98 }
99 }
100 drop(servers);
101
102 let server = ServerInstance::new(port, mode);
104 let server_id = server.get_server_id();
105
106 let mut servers = self.servers.write().await;
108 servers.insert(server_id.clone(), server);
109 drop(servers);
110
111 self.save_servers().await?;
113
114 log::info!(
115 "✅ Created server {} on port {} ({})",
116 server_id,
117 port,
118 mode
119 );
120 Ok(server_id)
121 }
122
123 pub async fn start_server(&self, server_id: &str) -> Result<()> {
126 let mut servers = self.servers.write().await;
128
129 let server = servers
131 .get_mut(server_id)
132 .ok_or_else(|| AppError::Validation(format!("Server {} not found", server_id)))?;
133
134 match server.get_status() {
136 ServerStatus::Running => {
137 return Err(AppError::Validation(format!(
138 "Server {} already running",
139 server_id
140 )));
141 }
142 ServerStatus::Starting => {
143 return Err(AppError::Validation(format!(
144 "Server {} already starting",
145 server_id
146 )));
147 }
148 _ => {}
149 }
150
151 server.start().await?;
153
154 drop(servers);
156
157 self.save_servers().await?;
159
160 Ok(())
161 }
162
163 pub async fn stop_server(&self, server_id: &str) -> Result<()> {
165 let mut servers = self.servers.write().await;
167
168 let server = servers
169 .get_mut(server_id)
170 .ok_or_else(|| AppError::Validation(format!("Server {} not found", server_id)))?;
171
172 match server.get_status() {
173 ServerStatus::Stopped => {
174 return Err(AppError::Validation(format!(
175 "Server {} already stopped",
176 server_id
177 )));
178 }
179 ServerStatus::Stopping => {
180 return Err(AppError::Validation(format!(
181 "Server {} already stopping",
182 server_id
183 )));
184 }
185 _ => {}
186 }
187
188 server.stop().await?;
190
191 drop(servers);
192 self.save_servers().await?;
193
194 Ok(())
195 }
196
197 pub async fn delete_server(&self, server_id: &str) -> Result<()> {
199 let mut servers = self.servers.write().await;
200
201 let server = servers
202 .get(server_id)
203 .ok_or_else(|| AppError::Validation(format!("Server {} not found", server_id)))?;
204
205 match server.get_status() {
207 ServerStatus::Running | ServerStatus::Starting => {
208 return Err(AppError::Validation(format!(
209 "Server {} must be stopped before deletion",
210 server_id
211 )));
212 }
213 _ => {}
214 }
215
216 let working_dir = {
218 let info = server.info.lock().unwrap_or_else(|poisoned| {
219 log::warn!("Recovered from poisoned mutex");
220 poisoned.into_inner()
221 });
222 info.working_dir.clone()
223 };
224
225 if working_dir.exists() {
226 tokio::fs::remove_dir_all(&working_dir)
227 .await
228 .map_err(AppError::Io)?;
229 log::debug!("🗑️ Deleted working directory: {}", working_dir.display());
230 }
231
232 servers.remove(server_id);
234 drop(servers);
235
236 self.save_servers().await?;
237
238 log::info!("🗑️ Deleted server {}", server_id);
239 Ok(())
240 }
241
242 pub async fn list_servers(&self) -> Vec<String> {
244 let servers = self.servers.read().await;
245 servers.values().map(|server| server.debug_info()).collect()
246 }
247
248 pub async fn get_server_status(&self, server_id: &str) -> Result<String> {
250 let servers = self.servers.read().await;
251
252 let server = servers
253 .get(server_id)
254 .ok_or_else(|| AppError::Validation(format!("Server {} not found", server_id)))?;
255
256 Ok(server.debug_info())
257 }
258
259 pub async fn stop_all_servers(&self) -> Result<()> {
261 let servers = self.servers.read().await;
262 let server_ids: Vec<String> = servers.keys().cloned().collect();
263 drop(servers);
264
265 for server_id in server_ids {
266 if let Err(e) = self.stop_server(&server_id).await {
267 log::warn!("Failed to stop server {}: {}", server_id, e);
268 }
269 }
270
271 Ok(())
272 }
273
274 pub async fn find_free_port(&self, start_port: u16) -> u16 {
276 let servers = self.servers.read().await;
277 let used_ports: std::collections::HashSet<u16> = servers
278 .values()
279 .map(|server| {
280 let info = server.info.lock().unwrap_or_else(|poisoned| {
281 log::warn!("Recovered from poisoned mutex");
282 poisoned.into_inner()
283 });
284 info.port
285 })
286 .collect();
287
288 for port in start_port..=65535 {
289 if !used_ports.contains(&port) && self.is_port_available(port).await {
290 return port;
291 }
292 }
293
294 8080 }
296
297 async fn is_port_available(&self, port: u16) -> bool {
299 use std::net::TcpListener;
300
301 TcpListener::bind(format!("127.0.0.1:{}", port)).is_ok()
302 }
303
304 pub async fn get_stats(&self) -> HashMap<String, usize> {
306 let servers = self.servers.read().await;
307 let mut stats = HashMap::new();
308
309 stats.insert("total".to_string(), servers.len());
310
311 let mut running = 0;
312 let mut stopped = 0;
313
314 for server in servers.values() {
315 match server.get_status() {
316 ServerStatus::Running => running += 1,
317 ServerStatus::Stopped => stopped += 1,
318 _ => {}
319 }
320 }
321
322 stats.insert("running".to_string(), running);
323 stats.insert("stopped".to_string(), stopped);
324
325 stats
326 }
327}
328
329impl Default for ServerManager {
330 fn default() -> Self {
331 Self::new()
332 }
333}
334
335impl ServerInstance {
336 pub fn from_info(info: ServerInfo) -> Self {
338 let config = crate::server::config::ServerConfig::for_mode(info.mode, info.port);
339
340 Self {
341 info: Arc::new(Mutex::new(info)),
342 config,
343 shutdown_tx: None,
344 server_handle: None,
345 file_watcher: None,
346 }
347 }
348}