rush_sync_server/commands/server/
mod.rs1use 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
12lazy_static::lazy_static! {
14 static ref SERVER_MANAGER: Arc<Mutex<Option<ServerManager>>> = Arc::new(Mutex::new(None));
15}
16
17fn 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#[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 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 }
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 async fn handle_create(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
99 let mut port = 8080;
100 let mut mode = ServerMode::Dev;
101
102 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 if port < 1024 {
146 return Err(AppError::Validation(
147 "Ports < 1024 require root privileges".to_string(),
148 ));
149 }
150
151 if port == 0 {
153 port = manager.find_free_port(8080).await;
154 }
155
156 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 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 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 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 async fn handle_status(&self, manager: &ServerManager, args: &[&str]) -> Result<String> {
218 if args.is_empty() || args[0] == "--all" || args[0] == "-a" {
219 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 let server_id = args[0];
245 let status = manager.get_server_status(server_id).await?;
246 Ok(status)
247 }
248 }
249
250 async fn handle_list(&self, manager: &ServerManager) -> Result<String> {
252 self.handle_status(manager, &["--all"]).await
253 }
254
255 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 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 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 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
320impl Clone for ServerManager {
322 fn clone(&self) -> Self {
323 Self {
326 servers: Arc::clone(&self.servers),
327 config_file: self.config_file.clone(),
328 }
329 }
330}