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