rush_sync_server/commands/
handler.rs1use super::registry::CommandRegistry;
6use crate::core::prelude::*;
7use crate::i18n;
8use std::sync::Arc;
9
10#[derive(Debug, Clone)]
11pub struct CommandResult {
12 pub message: String,
13 pub success: bool,
14 pub should_exit: bool,
15}
16
17pub struct CommandHandler {
19 registry: Arc<CommandRegistry>,
20}
21
22impl CommandHandler {
23 pub fn new() -> Self {
24 Self {
25 registry: Arc::new(crate::create_default_registry()),
26 }
27 }
28
29 pub fn with_registry(registry: CommandRegistry) -> Self {
30 Self {
31 registry: Arc::new(registry),
32 }
33 }
34
35 pub fn with_shared_registry(registry: Arc<CommandRegistry>) -> Self {
37 Self { registry }
38 }
39
40 pub fn handle_input(&self, input: &str) -> CommandResult {
42 self.process_input(input, false)
43 }
44
45 pub async fn handle_input_async(&self, input: &str) -> CommandResult {
46 self.process_input_async(input).await
47 }
48
49 pub fn add_command<T: crate::commands::command::Command>(&mut self, command: T) -> Result<()> {
50 if let Some(registry) = Arc::get_mut(&mut self.registry) {
51 registry.register(command);
52 Ok(())
53 } else {
54 log::warn!("Registry is shared, creating new instance with added command");
56
57 let mut new_registry = CommandRegistry::new();
58
59 let existing_commands = self.registry.list_commands();
61 for (name, _) in existing_commands {
62 log::warn!("Cannot copy existing command: {}", name);
64 }
65
66 new_registry.register(command);
68 self.registry = Arc::new(new_registry);
69
70 Err(AppError::Validation(
71 "Registry was shared, created new instance".to_string(),
72 ))
73 }
74 }
75
76 pub fn list_commands(&self) -> Vec<(&str, &str)> {
77 self.registry.list_commands()
78 }
79
80 pub fn debug_info(&self) -> String {
81 self.registry.debug_info()
82 }
83}
84
85impl CommandHandler {
87 fn process_input(&self, input: &str, is_async: bool) -> CommandResult {
89 let input = input.trim();
91 if input.is_empty() {
92 return CommandResult::empty();
93 }
94
95 if input.len() > 1000 {
97 log::warn!("Command input too long: {} chars", input.len());
98 return CommandResult::error("Command input too long (max 1000 characters)");
99 }
100
101 let parts = InputParser::parse(input);
103
104 if is_async {
105 log::debug!("Processing async command: '{}'", parts.command);
106 } else {
107 log::debug!("Processing sync command: '{}'", parts.command);
108 }
109
110 match self.registry.execute_sync(parts.command, &parts.args) {
112 Some(result) => self.process_command_result(result),
113 None => self.create_unknown_command_result(input),
114 }
115 }
116
117 async fn process_input_async(&self, input: &str) -> CommandResult {
119 let input = input.trim();
120 if input.is_empty() {
121 return CommandResult::empty();
122 }
123
124 if input.len() > 1000 {
125 log::warn!("Async command input too long: {} chars", input.len());
126 return CommandResult::error("Command input too long (max 1000 characters)");
127 }
128
129 let parts = InputParser::parse(input);
130 log::debug!("Processing async command: '{}'", parts.command);
131
132 match self
133 .registry
134 .execute_async(parts.command, &parts.args)
135 .await
136 {
137 Some(result) => self.process_command_result(result),
138 None => self.create_unknown_command_result(input),
139 }
140 }
141
142 fn process_command_result(&self, result: Result<String>) -> CommandResult {
144 match result {
145 Ok(msg) => {
146 if log::log_enabled!(log::Level::Debug) {
148 self.log_command_success(&msg);
149 }
150
151 CommandResult {
152 message: msg.clone(),
153 success: true,
154 should_exit: ExitChecker::should_exit(&msg),
155 }
156 }
157 Err(e) => {
158 log::error!("Command execution failed: {}", e);
159 CommandResult::error(&e.to_string())
160 }
161 }
162 }
163
164 fn create_unknown_command_result(&self, input: &str) -> CommandResult {
166 log::warn!("Unknown command: '{}'", input);
167 CommandResult::error(&UnknownCommandCache::get_message(input))
168 }
169
170 fn log_command_success(&self, msg: &str) {
172 let char_count = msg.chars().count();
173
174 let preview = if char_count <= 100 {
175 msg
176 } else {
177 &format!("{}...", msg.chars().take(97).collect::<String>())
179 };
180
181 log::debug!("Command returned {} chars: '{}'", char_count, preview);
182 }
183}
184
185struct InputParser;
187
188impl InputParser {
189 fn parse(input: &str) -> ParsedInput<'_> {
190 let parts: Vec<&str> = input.split_whitespace().collect();
192
193 if parts.is_empty() {
194 ParsedInput {
195 command: "",
196 args: Vec::new(),
197 }
198 } else {
199 ParsedInput {
200 command: parts[0],
201 args: parts[1..].to_vec(),
202 }
203 }
204 }
205}
206
207struct ParsedInput<'a> {
208 command: &'a str,
209 args: Vec<&'a str>,
210}
211
212struct ExitChecker;
214
215impl ExitChecker {
216 const EXIT_PREFIXES: &'static [&'static str] = &[
217 "__EXIT__",
218 "__CONFIRM_EXIT__",
219 "__RESTART__",
220 "__CONFIRM_RESTART__",
221 ];
222
223 fn should_exit(message: &str) -> bool {
224 Self::EXIT_PREFIXES
225 .iter()
226 .any(|&prefix| message.starts_with(prefix))
227 }
228}
229
230use std::sync::OnceLock;
232
233struct UnknownCommandCache;
234
235impl UnknownCommandCache {
236 fn get_message(input: &str) -> String {
237 static TEMPLATE: OnceLock<String> = OnceLock::new();
238
239 let template = TEMPLATE
240 .get_or_init(|| i18n::get_command_translation("system.commands.unknown", &["%INPUT%"]));
241
242 template.replace("%INPUT%", input)
243 }
244}
245
246impl CommandResult {
248 pub fn empty() -> Self {
249 Self {
250 message: String::new(),
251 success: false,
252 should_exit: false,
253 }
254 }
255
256 pub fn success(message: String) -> Self {
257 Self {
258 message,
259 success: true,
260 should_exit: false,
261 }
262 }
263
264 pub fn error(message: &str) -> Self {
265 Self {
266 message: message.to_string(),
267 success: false,
268 should_exit: false,
269 }
270 }
271
272 pub fn exit(message: String) -> Self {
273 Self {
274 message,
275 success: true,
276 should_exit: true,
277 }
278 }
279
280 pub fn is_success(&self) -> bool {
282 self.success
283 }
284
285 pub fn is_error(&self) -> bool {
286 !self.success
287 }
288
289 pub fn has_message(&self) -> bool {
290 !self.message.is_empty()
291 }
292}
293
294impl Clone for CommandHandler {
296 fn clone(&self) -> Self {
297 Self {
298 registry: Arc::clone(&self.registry),
299 }
300 }
301}
302
303impl Default for CommandHandler {
304 fn default() -> Self {
305 Self::new()
306 }
307}
308
309impl CommandHandler {
311 pub fn create_shared() -> Arc<Self> {
312 Arc::new(Self::new())
313 }
314
315 pub fn with_shared_handler(handler: Arc<Self>) -> Self {
316 Self {
317 registry: Arc::clone(&handler.registry),
318 }
319 }
320}