rush_sync_server/server/
shared.rs

1use 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}