rush_sync_server/server/
shared.rs

1// Updated src/server/shared.rs
2use 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
20// Updated to use Config
21pub 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    // Enhanced logging with config info
68    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        // Check if auto-start would exceed max_concurrent
95        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
119// Enhanced shutdown with config awareness
120pub 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    // Use configurable shutdown timeout
133    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        // Use configured timeout
139        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
170// NEW: Validation functions using config
171pub 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    // Check server limit
180    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    // Check port range if specified
189    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    // Check name uniqueness
199    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
209// NEW: Get server statistics with config context
210pub 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
253// NEW: Auto-start servers with config limits
254pub 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        // Use the start command logic here or call it directly
271        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}