pispas_modules/
rfid.rs

1// ===== RFID SERVICE - SOLO WINDOWS =====
2
3// Importaciones solo para Windows
4#[cfg(target_os = "windows")]
5use {
6    async_trait::async_trait,
7    futures_util::SinkExt,
8    serde_json::json,
9    serde_json::Value,
10    std::sync::{
11        atomic::{AtomicBool, Ordering},
12        Arc,
13    },
14    tokio::sync::{Mutex, mpsc},
15    tokio::time::{sleep, Duration, Instant},
16    tokio::task,
17    inputbot::KeybdKey::*,
18    inputbot::*,
19    tokio_tungstenite::tungstenite::protocol::Message,
20    crate::service::{Service, WebSocketWrite},
21    lazy_static::lazy_static,
22    log::debug,
23    easy_trace::prelude::{info, error},
24};
25
26// Importaciones básicas para otras plataformas
27#[cfg(not(target_os = "windows"))]
28use {
29    async_trait::async_trait,
30    serde_json::Value,
31    crate::service::{Service, WebSocketWrite},
32    easy_trace::prelude::{info, error},
33};
34
35/// Defines the version of the RFID service.
36pub const RFID_VERSION: &str = "1.0.0";
37
38// ===== IMPLEMENTACIÓN WINDOWS =====
39#[cfg(target_os = "windows")]
40mod windows_rfid {
41    use super::*;
42
43    lazy_static! {
44        static ref STOP_SIGNAL: AtomicBool = AtomicBool::new(false);
45    }
46
47    /// RFID Service implementation for reading RFID data using keyboard input.
48    pub struct RfidService {
49        /// Tracks whether the service is actively capturing RFID data.
50        pub capturing: Arc<AtomicBool>,
51        /// Holds the collected digits for the current RFID sequence.
52        pub digits: Arc<Mutex<Vec<char>>>,
53        /// Tracks the last activity time to clear digits on inactivity.
54        pub last_activity: Arc<Mutex<Instant>>,
55        /// Handle for the main processing task.
56        pub handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
57        /// Handle for the input event loop task.
58        pub input_handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
59    }
60
61    impl RfidService {
62        /// Creates a new instance of the RFID Service.
63        pub fn new() -> Self {
64            info!("Creating RFID Service for Windows");
65            RfidService {
66                capturing: Arc::new(AtomicBool::new(false)),
67                digits: Arc::new(Mutex::new(Vec::new())),
68                last_activity: Arc::new(Mutex::new(Instant::now())),
69                handle: Arc::new(Mutex::new(None)),
70                input_handle: Arc::new(Mutex::new(None)),
71            }
72        }
73
74        /// Stops the RFID service, including its background tasks and key bindings.
75        pub async fn stop(&self) {
76            if !self.capturing.load(Ordering::Relaxed) {
77                info!("RFID service is already stopped.");
78                return;
79            }
80
81            // Abort the main processing task
82            if let Some(handle) = self.handle.lock().await.take() {
83                handle.abort();
84                info!("RFID processing task aborted.");
85            }
86
87            // Abort the keyboard event loop task
88            if let Some(input_handle) = self.input_handle.lock().await.take() {
89                input_handle.abort();
90                info!("RFID input task aborted.");
91            }
92
93            // Remove all keyboard bindings
94            for key in [
95                Numrow0Key, Numrow1Key, Numrow2Key, Numrow3Key, Numrow4Key,
96                Numrow5Key, Numrow6Key, Numrow7Key, Numrow8Key, Numrow9Key,
97            ] {
98                key.unbind();
99                info!("Key binding removed for {:?}", key);
100            }
101
102            self.capturing.store(false, Ordering::Relaxed);
103            STOP_SIGNAL.store(true, Ordering::Relaxed);
104            info!("RFID service stopped.");
105        }
106
107        /// Starts a cleanup task to clear digits on inactivity.
108        pub fn start_cleanup_task(&self) {
109            let capturing = self.capturing.clone();
110            let digits = self.digits.clone();
111            let last_activity = self.last_activity.clone();
112
113            tokio::spawn(async move {
114                while capturing.load(Ordering::Relaxed) {
115                    let now = Instant::now();
116                    let last = *last_activity.lock().await;
117
118                    if now.duration_since(last) > Duration::from_secs(2) {
119                        let mut digits = digits.lock().await;
120                        if !digits.is_empty() {
121                            info!("Clearing digits due to inactivity: {:?}", digits);
122                            digits.clear();
123                        }
124                    }
125
126                    sleep(Duration::from_millis(100)).await;
127                }
128                info!("Cleanup task stopped.");
129            });
130        }
131
132        /// Starts capturing RFID input from the keyboard and processes it asynchronously.
133        pub async fn read_rfid(&self, write: WebSocketWrite, uuid: String) {
134            if self.capturing.load(Ordering::Relaxed) {
135                info!("RFID service is already running.");
136                return;
137            }
138
139            self.capturing.store(true, Ordering::Relaxed);
140            STOP_SIGNAL.store(false, Ordering::Relaxed);
141
142            let capturing = self.capturing.clone();
143            let digits = self.digits.clone();
144            let last_activity = self.last_activity.clone();
145
146            let (tx, mut rx) = mpsc::unbounded_channel::<char>();
147
148            let process_task = tokio::spawn(async move {
149                info!("RFID processing task started.");
150                while capturing.load(Ordering::Relaxed) {
151                    if let Some(key_char) = rx.recv().await {
152                        info!("Key received: {}", key_char);
153                        if key_char.is_digit(10) {
154                            let mut digits = digits.lock().await;
155                            digits.push(key_char);
156                            *last_activity.lock().await = Instant::now();
157
158                            if digits.len() == 10 {
159                                let rfid: String = digits.iter().collect();
160                                info!("RFID completed: {}", rfid);
161                                digits.clear();
162
163                                let message_data = json!({
164                                    "SERVICE_NAME": "RFID",
165                                    "SERVICE_VERS": RFID_VERSION,
166                                    "MESSAGE_TYPE": "RESPONSE",
167                                    "MESSAGE_EXEC": "SUCCESS",
168                                    "MESSAGE_UUID": uuid,
169                                    "MESSAGE_DATA": rfid,
170                                })
171                                    .to_string();
172
173                                info!("Sending RFID data via WebSocket: {}", message_data);
174
175                                if let Some(ws_lock) = &write {
176                                    let mut ws = ws_lock.write().await;
177                                    match ws.send(Message::Text(message_data.clone())).await {
178                                        Ok(_) => {
179                                            info!("RFID data sent successfully: {}", message_data);
180                                        }
181                                        Err(e) => {
182                                            error!("Failed to send RFID data: {:?}", e);
183                                        }
184                                    }
185                                } else {
186                                    error!("WebSocket write lock is None, cannot send RFID data.");
187                                }
188                            }
189                        } else {
190                            error!("Received non-numeric key: {}", key_char);
191                        }
192                    }
193                }
194                info!("RFID processing task stopped.");
195            });
196
197            // Bind key events to send their respective numeric values to the processing task.
198            for (key, num) in [
199                (Numrow0Key, '0'),
200                (Numrow1Key, '1'),
201                (Numrow2Key, '2'),
202                (Numrow3Key, '3'),
203                (Numrow4Key, '4'),
204                (Numrow5Key, '5'),
205                (Numrow6Key, '6'),
206                (Numrow7Key, '7'),
207                (Numrow8Key, '8'),
208                (Numrow9Key, '9'),
209            ] {
210                let tx = tx.clone();
211                key.bind(move || {
212                    debug!("Key pressed: {}", num);
213                    if let Err(e) = tx.send(num) {
214                        error!("Failed to send key event: {:?}", e);
215                    }
216                });
217            }
218
219            // Start the input event loop in a blocking task.
220            let input_task = task::spawn_blocking(move || {
221                info!("Starting input event loop.");
222                handle_input_events();
223                info!("Input event loop stopped.");
224            });
225
226            *self.handle.lock().await = Some(process_task);
227            *self.input_handle.lock().await = Some(input_task);
228        }
229    }
230
231    #[async_trait]
232    impl Service for RfidService {
233        async fn run(&self, action: Value, write: WebSocketWrite) -> (i32, String) {
234            info!("Windows RFID service action received: {:?}", action);
235            let action_object = action.get("ACTION").and_then(|a| a.as_object());
236            if let Some(action) = action_object {
237                let command = action.get("command").and_then(|c| c.as_str()).unwrap_or("UNKNOWN");
238                let device = action.get("device").and_then(|d| d.as_str()).unwrap_or("UNKNOWN");
239                let port = action.get("port").and_then(|p| p.as_str()).unwrap_or("UNKNOWN");
240                let uuid = action
241                    .get("UUIDV4")
242                    .and_then(|u| u.as_str())
243                    .unwrap_or("unknown-uuid")
244                    .to_string();
245
246                info!("RFID action received: command={}, device={}, port={}", command, device, port);
247
248                match command {
249                    "START" => {
250                        self.start_cleanup_task();
251                        self.read_rfid(write, uuid.clone()).await;
252                        (0, "Started reading RFID".to_string())
253                    }
254                    "STOP" => {
255                        self.stop().await;
256                        (0, "Stopped RFID reader".to_string())
257                    }
258                    _ => (1, "Unknown command".to_string()),
259                }
260            } else {
261                error!("Invalid ACTION format in message.");
262                (1, "Invalid ACTION format".to_string())
263            }
264        }
265
266        fn as_any(&self) -> &dyn std::any::Any {
267            self
268        }
269
270        fn stop_service(&self) {
271            let capturing = self.capturing.clone();
272            let handle = self.handle.clone();
273
274            tokio::spawn(async move {
275                if let Some(handle) = handle.lock().await.take() {
276                    handle.abort();
277                    info!("RFID service task aborted.");
278                }
279
280                capturing.store(false, Ordering::Relaxed);
281                STOP_SIGNAL.store(true, Ordering::Relaxed);
282                info!("RFID service stopped.");
283            });
284        }
285
286        fn get_version(&self) -> String {
287            format!("{}-windows", RFID_VERSION)
288        }
289    }
290}
291
292// ===== IMPLEMENTACIÓN NO-WINDOWS (STUB) =====
293#[cfg(not(target_os = "windows"))]
294mod stub_rfid {
295    use super::*;
296
297    /// RFID Service stub for non-Windows platforms.
298    pub struct RfidService;
299
300    impl RfidService {
301        /// Creates a new instance of the RFID Service stub.
302        pub fn new() -> Self {
303            info!("Creating RFID Service stub (non-Windows platform)");
304            RfidService
305        }
306    }
307
308    #[async_trait]
309    impl Service for RfidService {
310        async fn run(&self, _action: Value, _write: WebSocketWrite) -> (i32, String) {
311            error!("RFID service is not supported on this platform (Windows only)");
312            (1, "RFID service not supported on this platform".to_string())
313        }
314
315        fn as_any(&self) -> &dyn std::any::Any {
316            self
317        }
318
319        fn stop_service(&self) {
320            info!("RFID service stub: nothing to stop on non-Windows platform");
321        }
322
323        fn get_version(&self) -> String {
324            format!("{}-unsupported", RFID_VERSION)
325        }
326    }
327}
328
329// ===== RE-EXPORTS =====
330#[cfg(target_os = "windows")]
331pub use windows_rfid::RfidService;
332
333#[cfg(not(target_os = "windows"))]
334pub use stub_rfid::RfidService;