rush_sync_server/server/
shared.rs

1use crate::core::config::Config;
2use crate::proxy::ProxyManager;
3use crate::server::persistence::ServerRegistry;
4use crate::server::types::{ServerContext, ServerStatus};
5use crate::server::utils::port::is_port_available;
6use std::sync::{Arc, OnceLock};
7
8static SHARED_CONTEXT: OnceLock<ServerContext> = OnceLock::new();
9static PERSISTENT_REGISTRY: OnceLock<ServerRegistry> = OnceLock::new();
10static PROXY_MANAGER: OnceLock<Arc<ProxyManager>> = OnceLock::new();
11
12pub fn get_shared_context() -> &'static ServerContext {
13    SHARED_CONTEXT.get_or_init(ServerContext::default)
14}
15
16pub fn get_persistent_registry() -> &'static ServerRegistry {
17    PERSISTENT_REGISTRY
18        .get_or_init(|| ServerRegistry::new().expect("Failed to initialize server registry"))
19}
20
21pub fn get_proxy_manager() -> &'static Arc<ProxyManager> {
22    PROXY_MANAGER.get_or_init(|| {
23        // Config laden und Proxy Manager erstellen
24        let config = tokio::task::block_in_place(|| {
25            tokio::runtime::Handle::current().block_on(async {
26                crate::core::config::Config::load()
27                    .await
28                    .unwrap_or_default()
29            })
30        });
31
32        Arc::new(ProxyManager::new(config.proxy))
33    })
34}
35
36// NEU: Proxy System starten
37async fn start_proxy_system(config: &Config) -> crate::core::error::Result<()> {
38    if !config.proxy.enabled {
39        log::info!("Proxy system disabled in config");
40        return Ok(());
41    }
42
43    let proxy_manager = get_proxy_manager();
44
45    // Proxy Server starten (HTTP auf 8000 + HTTPS auf 8443)
46    Arc::clone(proxy_manager).start_proxy_server().await?;
47
48    log::info!("Proxy system started:");
49    log::info!("  HTTP:  http://{{name}}.localhost:{}", config.proxy.port);
50
51    let https_port = config.proxy.port + config.proxy.https_port_offset;
52    log::info!("HTTPS: https://{{name}}.localhost:{}", https_port);
53
54    Ok(())
55}
56
57// NEU: HTTP Redirect Server starten
58// async fn start_http_redirect(config: &Config) -> crate::core::error::Result<()> {
59//     if !config.proxy.enabled {
60//         return Ok(());
61//     }
62
63//     // Port 80 nur wenn verfügbar
64//     if !is_port_available(80) {
65//         log::warn!("Port 80 already in use - HTTP redirect disabled");
66//         log::info!("Tip: Use 'sudo lsof -i :80' to check what's using it");
67//         return Ok(());
68//     }
69
70//     // Import aus server::redirect
71//     use crate::server::redirect::HttpRedirectServer;
72
73//     let redirect = HttpRedirectServer::new(80, 8443); // Redirect zu HTTPS Proxy
74
75//     std::thread::spawn(move || {
76//         // Single-thread Tokio-Runtime (keine Send-Anforderung für Futures)
77//         let rt = tokio::runtime::Builder::new_current_thread()
78//             .enable_all()
79//             .build()
80//             .expect("failed to build single-thread runtime");
81
82//         rt.block_on(async move {
83//             if let Err(e) = redirect.run().await {
84//                 log::error!("HTTP redirect server failed: {}", e);
85//             }
86//         });
87//     });
88
89//     log::info!("HTTP→HTTPS redirect active on port 80");
90//     Ok(())
91// }
92
93pub async fn initialize_server_system() -> crate::core::error::Result<()> {
94    let config = Config::load().await?;
95
96    crate::server::handlers::web::set_global_config(config.clone());
97
98    let registry = get_persistent_registry();
99    let context = get_shared_context();
100
101    let mut persistent_servers = registry.load_servers().await?;
102    let mut corrected_servers = 0;
103
104    for (_server_id, persistent_info) in persistent_servers.iter_mut() {
105        if persistent_info.status == ServerStatus::Running {
106            if !is_port_available(persistent_info.port) {
107                log::warn!(
108                    "Server {} claims to be running on port {}, but port is occupied",
109                    persistent_info.name,
110                    persistent_info.port
111                );
112                persistent_info.status = ServerStatus::Failed;
113                corrected_servers += 1;
114            } else {
115                log::info!(
116                    "Server {} was running but is no longer active, correcting status",
117                    persistent_info.name
118                );
119                persistent_info.status = ServerStatus::Stopped;
120                corrected_servers += 1;
121            }
122        }
123    }
124
125    if corrected_servers > 0 {
126        registry.save_servers(&persistent_servers).await?;
127        log::info!(
128            "Corrected {} server statuses after program restart",
129            corrected_servers
130        );
131    }
132
133    {
134        let mut servers = context.servers.write().unwrap();
135        servers.clear();
136        for (id, persistent_info) in persistent_servers.iter() {
137            let server_info = crate::server::types::ServerInfo::from(persistent_info.clone());
138            servers.insert(id.clone(), server_info);
139        }
140    }
141
142    log::info!(
143        "Server system initialized with {} persistent servers",
144        persistent_servers.len()
145    );
146    log::info!(
147        "Server Config: Port Range {}-{}, Max Concurrent: {}, Workers: {}",
148        config.server.port_range_start,
149        config.server.port_range_end,
150        config.server.max_concurrent,
151        config.server.workers
152    );
153    log::info!(
154        "Logging Config: Max Size {}MB, Archives: {}, Compression: {}, Request Logging: {}",
155        config.logging.max_file_size_mb,
156        config.logging.max_archive_files,
157        config.logging.compress_archives,
158        config.logging.log_requests
159    );
160
161    let auto_start_servers = registry.get_auto_start_servers(&persistent_servers);
162    if !auto_start_servers.is_empty() {
163        log::info!(
164            "Found {} servers marked for auto-start",
165            auto_start_servers.len()
166        );
167
168        if auto_start_servers.len() > config.server.max_concurrent {
169            log::warn!(
170                "Auto-start servers ({}) exceed max_concurrent ({}), some will be skipped",
171                auto_start_servers.len(),
172                config.server.max_concurrent
173            );
174        }
175    }
176
177    // ÜBERARBEITET: Proxy Manager mit verbesserter Struktur
178    if config.proxy.enabled {
179        // 1. Proxy System starten (HTTP + HTTPS)
180        if let Err(e) = start_proxy_system(&config).await {
181            log::error!("Failed to start proxy system: {}", e);
182            // Proxy ist optional - wir laufen trotzdem weiter
183        } else {
184            // 2. HTTP Redirect starten (optional, braucht sudo für Port 80)
185            if let Err(e) = start_http_redirect_server(&config).await {
186                log::warn!("Failed to start HTTP redirect: {}", e);
187                // Nicht fatal - läuft auch ohne
188            }
189
190            // 3. Bereits laufende Server beim Proxy registrieren
191            let proxy_manager = get_proxy_manager();
192            for (_id, persistent_info) in persistent_servers.iter() {
193                if persistent_info.status == ServerStatus::Running {
194                    if let Err(e) = proxy_manager
195                        .add_route(
196                            &persistent_info.name,
197                            &persistent_info.id,
198                            persistent_info.port,
199                        )
200                        .await
201                    {
202                        log::error!(
203                            "Failed to register server {} with proxy: {}",
204                            persistent_info.name,
205                            e
206                        );
207                    } else {
208                        log::info!(
209                            "Registered existing server {} with proxy",
210                            persistent_info.name
211                        );
212                    }
213                }
214            }
215        }
216
217        if is_port_available(80) {
218            log::info!("  With sudo: http://{{name}}.localhost → redirects to HTTPS");
219        }
220        log::info!("  Add to /etc/hosts: 127.0.0.1 {{name}}.localhost");
221    } else {
222        log::info!("Reverse Proxy disabled in configuration");
223    }
224
225    Ok(())
226}
227
228pub async fn persist_server_update(server_id: &str, status: crate::server::types::ServerStatus) {
229    let registry = get_persistent_registry();
230    if let Err(e) = registry.update_server_status(server_id, status).await {
231        log::error!("Failed to persist server status update: {}", e);
232    }
233}
234
235pub async fn shutdown_all_servers_on_exit() -> crate::core::error::Result<()> {
236    let config = Config::load().await.unwrap_or_default();
237    let registry = get_persistent_registry();
238    let context = get_shared_context();
239
240    let server_handles: Vec<_> = {
241        let mut handles = context.handles.write().unwrap();
242        handles.drain().collect()
243    };
244
245    log::info!("Shutting down {} active servers...", server_handles.len());
246
247    let shutdown_timeout = std::time::Duration::from_secs(config.server.shutdown_timeout);
248
249    for (server_id, handle) in server_handles {
250        log::info!("Stopping server {}", server_id);
251
252        if tokio::time::timeout(shutdown_timeout, handle.stop(true))
253            .await
254            .is_err()
255        {
256            log::warn!("Server {} shutdown timeout, forcing stop", server_id);
257            handle.stop(false).await;
258        }
259
260        // Korrigierte API-Aufrufe
261        let _ = registry
262            .update_server_status(&server_id, ServerStatus::Stopped)
263            .await;
264    }
265
266    log::info!("Server system shutdown complete");
267    Ok(())
268}
269
270pub async fn validate_server_creation(
271    name: &str,
272    port: Option<u16>,
273) -> crate::core::error::Result<()> {
274    let config = Config::load().await?;
275    let context = get_shared_context();
276    let servers = context.servers.read().unwrap();
277
278    if servers.len() >= config.server.max_concurrent {
279        return Err(crate::core::error::AppError::Validation(format!(
280            "Server limit reached: {}/{}. Use 'cleanup' command to remove stopped servers.",
281            servers.len(),
282            config.server.max_concurrent
283        )));
284    }
285
286    if let Some(port) = port {
287        if port < config.server.port_range_start || port > config.server.port_range_end {
288            return Err(crate::core::error::AppError::Validation(format!(
289                "Port {} outside configured range {}-{}",
290                port, config.server.port_range_start, config.server.port_range_end
291            )));
292        }
293    }
294
295    if servers.values().any(|s| s.name == name) {
296        return Err(crate::core::error::AppError::Validation(format!(
297            "Server name '{}' already exists",
298            name
299        )));
300    }
301
302    Ok(())
303}
304
305pub async fn get_server_system_stats() -> serde_json::Value {
306    let config = Config::load().await.unwrap_or_default();
307    let context = get_shared_context();
308    let servers = context.servers.read().unwrap();
309
310    let running_count = servers
311        .values()
312        .filter(|s| s.status == ServerStatus::Running)
313        .count();
314    let stopped_count = servers
315        .values()
316        .filter(|s| s.status == ServerStatus::Stopped)
317        .count();
318    let failed_count = servers
319        .values()
320        .filter(|s| s.status == ServerStatus::Failed)
321        .count();
322
323    serde_json::json!({
324        "total_servers": servers.len(),
325        "running": running_count,
326        "stopped": stopped_count,
327        "failed": failed_count,
328        "max_concurrent": config.server.max_concurrent,
329        "utilization_percent": (servers.len() as f64 / config.server.max_concurrent as f64 * 100.0),
330        "port_range": format!("{}-{}", config.server.port_range_start, config.server.port_range_end),
331        "available_ports": config.server.port_range_end - config.server.port_range_start + 1,
332        "proxy": {
333            "enabled": config.proxy.enabled,
334            "http_port": config.proxy.port,
335            "https_port": 8443,
336            "redirect_port": if is_port_available(80) { None } else { Some(80) }
337        },
338        "config": {
339            "workers_per_server": config.server.workers,
340            "shutdown_timeout_sec": config.server.shutdown_timeout,
341            "startup_delay_ms": config.server.startup_delay_ms,
342            "logging": {
343                "max_file_size_mb": config.logging.max_file_size_mb,
344                "max_archives": config.logging.max_archive_files,
345                "compression": config.logging.compress_archives,
346                "request_logging": config.logging.log_requests,
347                "security_alerts": config.logging.log_security_alerts,
348                "performance_monitoring": config.logging.log_performance
349            }
350        }
351    })
352}
353
354pub async fn auto_start_servers() -> crate::core::error::Result<Vec<String>> {
355    let config = Config::load().await?;
356    let registry = get_persistent_registry();
357    let auto_start_servers = {
358        let servers = registry.load_servers().await?;
359        registry.get_auto_start_servers(&servers)
360    };
361
362    if auto_start_servers.is_empty() {
363        return Ok(vec![]);
364    }
365
366    let max_to_start = config.server.max_concurrent.min(auto_start_servers.len());
367    let mut started_servers = Vec::new();
368
369    for server in auto_start_servers.iter().take(max_to_start) {
370        log::info!(
371            "Auto-starting server: {} on port {}",
372            server.name,
373            server.port
374        );
375        started_servers.push(format!("{}:{}", server.name, server.port));
376    }
377
378    if auto_start_servers.len() > max_to_start {
379        log::warn!(
380            "Skipped {} auto-start servers due to max_concurrent limit of {}",
381            auto_start_servers.len() - max_to_start,
382            config.server.max_concurrent
383        );
384    }
385
386    Ok(started_servers)
387}
388
389// Füge das ganz am Ende der Datei ein, nach der letzten Funktion
390// Ersetze die start_http_redirect_server Funktion in src/server/shared.rs
391
392async fn start_http_redirect_server(_config: &Config) -> crate::core::error::Result<()> {
393    let redirect_port = 80;
394    let target_https_port = 8443;
395
396    if !crate::server::utils::port::is_port_available(redirect_port) {
397        log::warn!(
398            "Port {} already in use - HTTP redirect disabled",
399            redirect_port
400        );
401        return Ok(());
402    }
403
404    log::info!(
405        "Starting HTTP→HTTPS redirect server on port {}",
406        redirect_port
407    );
408
409    // LÖSUNG: std::thread::spawn statt tokio::spawn verwenden
410    std::thread::spawn(move || {
411        // Single-thread Tokio-Runtime (keine Send-Anforderung für Futures)
412        let rt = tokio::runtime::Builder::new_current_thread()
413            .enable_all()
414            .build()
415            .expect("Failed to build single-thread runtime for redirect server");
416
417        rt.block_on(async move {
418            let redirect_server =
419                crate::server::redirect::HttpRedirectServer::new(redirect_port, target_https_port);
420
421            if let Err(e) = redirect_server.run().await {
422                log::error!("HTTP redirect server error: {}", e);
423            }
424        });
425    });
426
427    // Kurz warten für Startup
428    tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
429    log::info!(
430        "HTTP redirect active: Port {} → HTTPS Port {}",
431        redirect_port,
432        target_https_port
433    );
434
435    Ok(())
436}