1#[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#[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
35pub const RFID_VERSION: &str = "1.0.0";
37
38#[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 pub struct RfidService {
49 pub capturing: Arc<AtomicBool>,
51 pub digits: Arc<Mutex<Vec<char>>>,
53 pub last_activity: Arc<Mutex<Instant>>,
55 pub handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
57 pub input_handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
59 }
60
61 impl RfidService {
62 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 pub async fn stop(&self) {
76 if !self.capturing.load(Ordering::Relaxed) {
77 info!("RFID service is already stopped.");
78 return;
79 }
80
81 if let Some(handle) = self.handle.lock().await.take() {
83 handle.abort();
84 info!("RFID processing task aborted.");
85 }
86
87 if let Some(input_handle) = self.input_handle.lock().await.take() {
89 input_handle.abort();
90 info!("RFID input task aborted.");
91 }
92
93 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 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 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 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 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#[cfg(not(target_os = "windows"))]
294mod stub_rfid {
295 use super::*;
296
297 pub struct RfidService;
299
300 impl RfidService {
301 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#[cfg(target_os = "windows")]
331pub use windows_rfid::RfidService;
332
333#[cfg(not(target_os = "windows"))]
334pub use stub_rfid::RfidService;