rush_sync_server/commands/server/
mod.rs

1// =====================================================
2// FILE: src/commands/server/mod.rs - SERVER CLI COMMANDS
3// =====================================================
4
5use crate::commands::command::Command;
6use crate::core::prelude::*;
7use crate::server::{ServerManager, ServerMode};
8use std::future::Future;
9use std::pin::Pin;
10use std::sync::{Arc, Mutex};
11
12// Global Server Manager (Singleton)
13lazy_static::lazy_static! {
14    static ref SERVER_MANAGER: Arc<Mutex<Option<ServerManager>>> = Arc::new(Mutex::new(None));
15}
16
17/// Holt oder erstellt Server Manager
18fn get_server_manager() -> ServerManager {
19    let mut manager_guard = SERVER_MANAGER.lock().unwrap_or_else(|poisoned| {
20        log::warn!("Recovered from poisoned mutex");
21        poisoned.into_inner()
22    });
23
24    if manager_guard.is_none() {
25        *manager_guard = Some(ServerManager::new());
26    }
27
28    manager_guard.as_ref().unwrap().clone()
29}
30
31/// Server-Management Command
32#[derive(Debug)]
33pub struct ServerCommand;
34
35impl Command for ServerCommand {
36    fn name(&self) -> &'static str {
37        "server"
38    }
39
40    fn description(&self) -> &'static str {
41        "Manage Actix-Web server instances (create, start, stop, status)"
42    }
43
44    fn matches(&self, command: &str) -> bool {
45        command.trim().to_lowercase().starts_with("server")
46    }
47
48    fn execute_sync(&self, args: &[&str]) -> Result<String> {
49        // Für Server-Management brauchen wir async, also nutzen wir eine einfache Synchronisation
50        let rt = tokio::runtime::Runtime::new()
51            .map_err(|e| AppError::Terminal(format!("Failed to create async runtime: {}", e)))?;
52
53        rt.block_on(self.execute_async_internal(args))
54    }
55
56    fn execute_async<'a>(
57        &'a self,
58        args: &'a [&'a str],
59    ) -> Pin<Box<dyn Future<Output = Result<String>> + Send + 'a>> {
60        Box::pin(self.execute_async_internal(args))
61    }
62
63    fn supports_async(&self) -> bool {
64        true
65    }
66
67    fn priority(&self) -> u8 {
68        90 // Hohe Priorität für Server-Management
69    }
70}
71
72impl ServerCommand {
73    async fn execute_async_internal(&self, args: &[&str]) -> Result<String> {
74        if args.is_empty() {
75            return Ok(self.show_help());
76        }
77
78        let manager = get_server_manager();
79
80        match args[0].to_lowercase().as_str() {
81            "create" => self.handle_create(&manager, &args[1..]).await,
82            "start" => self.handle_start(&manager, &args[1..]).await,
83            "stop" => self.handle_stop(&manager, &args[1..]).await,
84            "delete" | "remove" => self.handle_delete(&manager, &args[1..]).await,
85            "status" => self.handle_status(&manager, &args[1..]).await,
86            "list" => self.handle_list(&manager).await,
87            "logs" => self.handle_logs(&args[1..]).await,
88            "--help" | "-h" => Ok(self.show_help()),
89            _ => Ok(format!(
90                "❌ Unknown server command: {}\n\n{}",
91                args[0],
92                self.show_help()
93            )),
94        }
95    }
96
97    /// Server erstellen
98    async fn handle_create(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
99        let mut port = 8080;
100        let mut mode = ServerMode::Dev;
101
102        // Argumente parsen
103        let mut i = 0;
104        while i < args.len() {
105            match args[i] {
106                "--port" | "-p" => {
107                    if i + 1 < args.len() {
108                        port = args[i + 1]
109                            .parse()
110                            .map_err(|_| AppError::Validation("Invalid port number".to_string()))?;
111                        i += 2;
112                    } else {
113                        return Err(AppError::Validation("--port requires a value".to_string()));
114                    }
115                }
116                "--mode" | "-m" => {
117                    if i + 1 < args.len() {
118                        mode = match args[i + 1].to_lowercase().as_str() {
119                            "dev" | "development" => ServerMode::Dev,
120                            "prod" | "production" => ServerMode::Prod,
121                            _ => {
122                                return Err(AppError::Validation(
123                                    "Mode must be 'dev' or 'prod'".to_string(),
124                                ))
125                            }
126                        };
127                        i += 2;
128                    } else {
129                        return Err(AppError::Validation("--mode requires a value".to_string()));
130                    }
131                }
132                "--help" | "-h" => {
133                    return Ok(self.show_create_help());
134                }
135                _ => {
136                    return Err(AppError::Validation(format!(
137                        "Unknown create option: {}",
138                        args[i]
139                    )));
140                }
141            }
142        }
143
144        // Port verfügbar?
145        if port < 1024 {
146            return Err(AppError::Validation(
147                "Ports < 1024 require root privileges".to_string(),
148            ));
149        }
150
151        // Auto-Port-Finding wenn gewünscht
152        if port == 0 {
153            port = manager.find_free_port(8080).await;
154        }
155
156        // Server erstellen
157        let server_id = manager.create_server(port, mode).await?;
158
159        Ok(format!(
160            "✅ Server created successfully!\n\n\
161            📊 Server Details:\n\
162            • ID: {}\n\
163            • Port: {}\n\
164            • Mode: {}\n\
165            • Status: Stopped\n\n\
166            🚀 Next steps:\n\
167            • Start server: server start {}\n\
168            • Check status: server status {}\n\
169            • Open in browser: http://localhost:{}",
170            server_id, port, mode, server_id, server_id, port
171        ))
172    }
173
174    /// Server starten
175    async fn handle_start(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
176        if args.is_empty() {
177            return Err(AppError::Validation(
178                "Usage: server start <server-id>".to_string(),
179            ));
180        }
181
182        let server_id = args[0];
183        manager.start_server(server_id).await?;
184
185        Ok(format!("🚀 Server {} started successfully!", server_id))
186    }
187
188    /// Server stoppen
189    async fn handle_stop(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
190        if args.is_empty() {
191            return Err(AppError::Validation(
192                "Usage: server stop <server-id>".to_string(),
193            ));
194        }
195
196        let server_id = args[0];
197        manager.stop_server(server_id).await?;
198
199        Ok(format!("🛑 Server {} stopped successfully!", server_id))
200    }
201
202    /// Server löschen
203    async fn handle_delete(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
204        if args.is_empty() {
205            return Err(AppError::Validation(
206                "Usage: server delete <server-id>".to_string(),
207            ));
208        }
209
210        let server_id = args[0];
211        manager.delete_server(server_id).await?;
212
213        Ok(format!("🗑️ Server {} deleted successfully!", server_id))
214    }
215
216    /// Server-Status anzeigen
217    async fn handle_status(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
218        if args.is_empty() || args[0] == "--all" || args[0] == "-a" {
219            // Alle Server anzeigen
220            let servers = manager.list_servers().await;
221            if servers.is_empty() {
222                return Ok(
223                    "📭 No servers found.\n\n💡 Create one with: server create --port 8080"
224                        .to_string(),
225                );
226            }
227
228            let stats = manager.get_stats().await;
229            let mut result = format!(
230                "📊 Server Overview ({} total, {} running, {} stopped)\n\n",
231                stats.get("total").unwrap_or(&0),
232                stats.get("running").unwrap_or(&0),
233                stats.get("stopped").unwrap_or(&0)
234            );
235
236            for server_info in servers {
237                result.push_str(&server_info);
238                result.push_str("\n\n");
239            }
240
241            Ok(result)
242        } else {
243            // Spezifischen Server anzeigen
244            let server_id = args[0];
245            let status = manager.get_server_status(server_id).await?;
246            Ok(status)
247        }
248    }
249
250    /// Server auflisten
251    async fn handle_list(&self, manager: &ServerManager) -> Result<String> {
252        self.handle_status(manager, &["--all"]).await
253    }
254
255    /// Server-Logs anzeigen
256    async fn handle_logs(&self, args: &[&str]) -> Result<String> {
257        if args.is_empty() {
258            return Err(AppError::Validation(
259                "Usage: server logs <server-id>".to_string(),
260            ));
261        }
262
263        let _server_id = args[0];
264
265        // TODO: Implementiere Log-Anzeige
266        Ok("📋 Server Logs (TODO: Implement)\n\n\
267    • Real-time logs will be shown here\n\
268    • Use Ctrl+C to exit log view\n\
269    • Add --follow flag for live updates"
270            .to_string())
271    }
272
273    /// Zeigt Hilfe für create Befehl
274    fn show_create_help(&self) -> String {
275        "🏗️  Server Create Command\n\n\
276    Usage: server create [OPTIONS]\n\n\
277    Options:\n\
278    • --port, -p <PORT>     Specify port (default: auto-find)\n\
279    • --mode, -m <MODE>     Set mode: dev|prod (default: dev)\n\
280    • --help, -h            Show this help\n\n\
281    Examples:\n\
282    • server create                    # Auto-port, dev mode\n\
283    • server create --port 8080        # Specific port\n\
284    • server create --mode prod        # Production mode\n\
285    • server create -p 3000 -m dev     # Port + mode\n\n\
286    Modes:\n\
287    • dev:  Hot-reloading, CORS, debug logs\n\
288    • prod: Optimized, TLS support, minimal logs"
289            .to_string()
290    }
291
292    /// Zeigt allgemeine Hilfe
293    fn show_help(&self) -> String {
294        "🖥️  Server Management Commands\n\n\
295    Usage: server <command> [OPTIONS]\n\n\
296    Commands:\n\
297    • create                Create new server instance\n\
298    • start <id>            Start server\n\
299    • stop <id>             Stop server\n\
300    • delete <id>           Delete server (must be stopped)\n\
301    • status [id|--all]     Show server status\n\
302    • list                  List all servers\n\
303    • logs <id>             Show server logs\n\n\
304    Examples:\n\
305    • server create --port 8080 --mode dev\n\
306    • server start ABC12345\n\
307    • server status --all\n\
308    • server stop ABC12345\n\n\
309    💡 Server IDs are shown in status output (first 8 characters)"
310            .to_string()
311    }
312}
313
314impl Default for ServerCommand {
315    fn default() -> Self {
316        Self
317    }
318}
319
320// TODO: Implement Clone for ServerManager
321impl Clone for ServerManager {
322    fn clone(&self) -> Self {
323        // Für jetzt einfache Implementierung
324        // In echter Anwendung würden wir shared state verwenden
325        Self {
326            servers: Arc::clone(&self.servers),
327            config_file: self.config_file.clone(),
328        }
329    }
330}