rush_sync_server/server/
shared.rs1use crate::core::config::Config;
3use crate::server::persistence::ServerRegistry;
4use crate::server::types::{ServerContext, ServerStatus};
5use crate::server::utils::port::is_port_available;
6use std::sync::OnceLock;
7
8static SHARED_CONTEXT: OnceLock<ServerContext> = OnceLock::new();
9static PERSISTENT_REGISTRY: OnceLock<ServerRegistry> = OnceLock::new();
10
11pub fn get_shared_context() -> &'static ServerContext {
12 SHARED_CONTEXT.get_or_init(ServerContext::default)
13}
14
15pub fn get_persistent_registry() -> &'static ServerRegistry {
16 PERSISTENT_REGISTRY
17 .get_or_init(|| ServerRegistry::new().expect("Failed to initialize server registry"))
18}
19
20pub async fn initialize_server_system() -> crate::core::error::Result<()> {
22 let config = Config::load().await?;
23 let registry = get_persistent_registry();
24 let context = get_shared_context();
25
26 let mut persistent_servers = registry.load_servers().await?;
27 let mut corrected_servers = 0;
28
29 for (_server_id, persistent_info) in persistent_servers.iter_mut() {
30 if persistent_info.status == ServerStatus::Running {
31 if !is_port_available(persistent_info.port) {
32 log::warn!(
33 "Server {} claims to be running on port {}, but port is occupied",
34 persistent_info.name,
35 persistent_info.port
36 );
37 persistent_info.status = ServerStatus::Failed;
38 corrected_servers += 1;
39 } else {
40 log::info!(
41 "Server {} was running but is no longer active, correcting status",
42 persistent_info.name
43 );
44 persistent_info.status = ServerStatus::Stopped;
45 corrected_servers += 1;
46 }
47 }
48 }
49
50 if corrected_servers > 0 {
51 registry.save_servers(&persistent_servers).await?;
52 log::info!(
53 "Corrected {} server statuses after program restart",
54 corrected_servers
55 );
56 }
57
58 {
59 let mut servers = context.servers.write().unwrap();
60 servers.clear();
61 for (id, persistent_info) in persistent_servers.iter() {
62 let server_info = crate::server::types::ServerInfo::from(persistent_info.clone());
63 servers.insert(id.clone(), server_info);
64 }
65 }
66
67 log::info!(
69 "Server system initialized with {} persistent servers",
70 persistent_servers.len()
71 );
72 log::info!(
73 "Server Config: Port Range {}-{}, Max Concurrent: {}, Workers: {}",
74 config.server.port_range_start,
75 config.server.port_range_end,
76 config.server.max_concurrent,
77 config.server.workers
78 );
79 log::info!(
80 "Logging Config: Max Size {}MB, Archives: {}, Compression: {}, Request Logging: {}",
81 config.logging.max_file_size_mb,
82 config.logging.max_archive_files,
83 config.logging.compress_archives,
84 config.logging.log_requests
85 );
86
87 let auto_start_servers = registry.get_auto_start_servers(&persistent_servers);
88 if !auto_start_servers.is_empty() {
89 log::info!(
90 "Found {} servers marked for auto-start",
91 auto_start_servers.len()
92 );
93
94 if auto_start_servers.len() > config.server.max_concurrent {
96 log::warn!(
97 "Auto-start servers ({}) exceed max_concurrent ({}), some will be skipped",
98 auto_start_servers.len(),
99 config.server.max_concurrent
100 );
101 }
102 }
103
104 Ok(())
105}
106
107pub async fn persist_server_update(server_id: &str, status: crate::server::types::ServerStatus) {
108 let registry = get_persistent_registry();
109 if let Ok(servers) = registry.load_servers().await {
110 if let Err(e) = registry
111 .update_server_status(servers, server_id, status)
112 .await
113 {
114 log::error!("Failed to persist server status update: {}", e);
115 }
116 }
117}
118
119pub async fn shutdown_all_servers_on_exit() -> crate::core::error::Result<()> {
121 let config = Config::load().await.unwrap_or_default();
122 let registry = get_persistent_registry();
123 let context = get_shared_context();
124
125 let server_handles: Vec<_> = {
126 let mut handles = context.handles.write().unwrap();
127 handles.drain().collect()
128 };
129
130 log::info!("Shutting down {} active servers...", server_handles.len());
131
132 let shutdown_timeout = std::time::Duration::from_secs(config.server.shutdown_timeout);
134
135 for (server_id, handle) in server_handles {
136 log::info!("Stopping server {}", server_id);
137
138 if let Err(_) = tokio::time::timeout(shutdown_timeout, handle.stop(true)).await {
140 log::warn!("Server {} shutdown timeout, forcing stop", server_id);
141 handle.stop(false).await;
142 }
143
144 if let Ok(servers) = registry.load_servers().await {
145 let _ = registry
146 .update_server_status(servers, &server_id, ServerStatus::Stopped)
147 .await;
148 }
149 }
150
151 if let Ok(mut servers) = registry.load_servers().await {
152 let mut updated = false;
153 for server in servers.values_mut() {
154 if server.status == ServerStatus::Running {
155 server.status = ServerStatus::Stopped;
156 updated = true;
157 }
158 }
159
160 if updated {
161 let _ = registry.save_servers(&servers).await;
162 log::info!("Updated all running servers to stopped status");
163 }
164 }
165
166 log::info!("Server system shutdown complete");
167 Ok(())
168}
169
170pub async fn validate_server_creation(
172 name: &str,
173 port: Option<u16>,
174) -> crate::core::error::Result<()> {
175 let config = Config::load().await?;
176 let context = get_shared_context();
177 let servers = context.servers.read().unwrap();
178
179 if servers.len() >= config.server.max_concurrent {
181 return Err(crate::core::error::AppError::Validation(format!(
182 "Server limit reached: {}/{}. Use 'cleanup' command to remove stopped servers.",
183 servers.len(),
184 config.server.max_concurrent
185 )));
186 }
187
188 if let Some(port) = port {
190 if port < config.server.port_range_start || port > config.server.port_range_end {
191 return Err(crate::core::error::AppError::Validation(format!(
192 "Port {} outside configured range {}-{}",
193 port, config.server.port_range_start, config.server.port_range_end
194 )));
195 }
196 }
197
198 if servers.values().any(|s| s.name == name) {
200 return Err(crate::core::error::AppError::Validation(format!(
201 "Server name '{}' already exists",
202 name
203 )));
204 }
205
206 Ok(())
207}
208
209pub async fn get_server_system_stats() -> serde_json::Value {
211 let config = Config::load().await.unwrap_or_default();
212 let context = get_shared_context();
213 let servers = context.servers.read().unwrap();
214
215 let running_count = servers
216 .values()
217 .filter(|s| s.status == ServerStatus::Running)
218 .count();
219 let stopped_count = servers
220 .values()
221 .filter(|s| s.status == ServerStatus::Stopped)
222 .count();
223 let failed_count = servers
224 .values()
225 .filter(|s| s.status == ServerStatus::Failed)
226 .count();
227
228 serde_json::json!({
229 "total_servers": servers.len(),
230 "running": running_count,
231 "stopped": stopped_count,
232 "failed": failed_count,
233 "max_concurrent": config.server.max_concurrent,
234 "utilization_percent": (servers.len() as f64 / config.server.max_concurrent as f64 * 100.0),
235 "port_range": format!("{}-{}", config.server.port_range_start, config.server.port_range_end),
236 "available_ports": config.server.port_range_end - config.server.port_range_start + 1,
237 "config": {
238 "workers_per_server": config.server.workers,
239 "shutdown_timeout_sec": config.server.shutdown_timeout,
240 "startup_delay_ms": config.server.startup_delay_ms,
241 "logging": {
242 "max_file_size_mb": config.logging.max_file_size_mb,
243 "max_archives": config.logging.max_archive_files,
244 "compression": config.logging.compress_archives,
245 "request_logging": config.logging.log_requests,
246 "security_alerts": config.logging.log_security_alerts,
247 "performance_monitoring": config.logging.log_performance
248 }
249 }
250 })
251}
252
253pub async fn auto_start_servers() -> crate::core::error::Result<Vec<String>> {
255 let config = Config::load().await?;
256 let registry = get_persistent_registry();
257 let auto_start_servers = {
258 let servers = registry.load_servers().await?;
259 registry.get_auto_start_servers(&servers)
260 };
261
262 if auto_start_servers.is_empty() {
263 return Ok(vec![]);
264 }
265
266 let max_to_start = config.server.max_concurrent.min(auto_start_servers.len());
267 let mut started_servers = Vec::new();
268
269 for server in auto_start_servers.iter().take(max_to_start) {
270 log::info!(
272 "Auto-starting server: {} on port {}",
273 server.name,
274 server.port
275 );
276 started_servers.push(format!("{}:{}", server.name, server.port));
277 }
278
279 if auto_start_servers.len() > max_to_start {
280 log::warn!(
281 "Skipped {} auto-start servers due to max_concurrent limit of {}",
282 auto_start_servers.len() - max_to_start,
283 config.server.max_concurrent
284 );
285 }
286
287 Ok(started_servers)
288}