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