1use async_trait::async_trait;
2use easy_trace::prelude::{debug, error, info};
3use serde_json::{Value};
4use std::collections::HashMap;
5use std::sync::Arc;
6use tokio::sync::Mutex;
7use crate::service::{Service, WebSocketWrite};
8use std::io::{Read, Write};
9use std::net::TcpStream;
10use std::path::Path;
11use sharing::service::{Action, SafeHandle};
12use sharing::crypto;
13
14const PERSISTENCE_PASSWORD: &str = "R4nd0mlyG3n3r4t3dP4ssw0rd";
15
16pub const PERSISTENCE_VERSION: &str = "1.0.0";
18
19pub struct PersistenceService {
21 pub cache: Arc<Mutex<HashMap<String, Value>>>,
23 pub file_handle: Arc<Mutex<Option<SafeHandle>>>,
25 pub file_path: String,
27 pub using_service_protection: bool,
29}
30
31impl PersistenceService {
32 pub fn new() -> Self {
34 info!("PersistenceService initialized (version: {})", PERSISTENCE_VERSION);
35
36 let file_path = sharing::paths::get_persistance_path();
37 let service = PersistenceService {
38 cache: Arc::new(Mutex::new(HashMap::new())),
39 file_handle: Arc::new(Mutex::new(None)),
40 file_path: file_path.display().to_string(),
41 using_service_protection: false,
42 };
43
44 service
45 }
46
47 pub async fn initialize(&mut self) -> Result<(), String> {
49 match self.try_get_handle_from_service() {
51 Ok(handle) => {
52 info!("Got handle from service.exe successfully");
53 self.using_service_protection = true;
54 *self.file_handle.lock().await = Some(handle);
55 }
56 Err(e) => {
57 error!("Failed to get handle from service.exe: {}", e);
58 info!("Opening file directly...");
59
60 match self.try_open_file_directly_with_handle() {
62 Ok(handle) => {
63 info!("Got direct file handle successfully");
64 *self.file_handle.lock().await = Some(handle);
65 }
66 Err(e) => {
67 error!("Failed to open file directly: {}", e);
68 info!("PersistenceService will work in memory-only mode");
69 }
70 }
71 }
72 }
73
74 if let Err(e) = self.try_load_data().await {
76 error!("Failed to load existing data: {}", e);
77 }
78
79 Ok(())
80 }
81
82 fn try_get_handle_from_service(&self) -> Result<SafeHandle, String> {
84 info!("Requesting file handle from service.exe for: {}", self.file_path);
85
86 let mut stream = match TcpStream::connect(sharing::CHANNEL_NAME) {
87 Ok(stream) => stream,
88 Err(e) => return Err(format!("Could not connect to service.exe: {}", e)),
89 };
90
91 info!("Connected to service.exe pipe successfully");
92
93 let action = Action::GetHandle(self.file_path.clone());
95 match stream.write_all(action.to_string().as_bytes()) {
96 Ok(_) => {},
97 Err(e) => return Err(format!("Failed to send GET_HANDLE request: {}", e)),
98 }
99
100 info!("GET_HANDLE request sent, waiting for response...");
101
102 let mut buffer = [0; 1024];
104 let bytes_read = match stream.read(&mut buffer) {
105 Ok(bytes) => bytes,
106 Err(e) => return Err(format!("Failed to read response: {}", e)),
107 };
108
109 let response = String::from_utf8_lossy(&buffer[..bytes_read]);
110 info!("Received response from service.exe: {}", response);
111
112 if response.starts_with("HANDLE_OK:") {
113 let handle_str = response.strip_prefix("HANDLE_OK:").unwrap_or("");
115 match handle_str.parse::<usize>() {
116 Ok(handle_value) => {
117 let handle = SafeHandle::new(handle_value as *mut std::ffi::c_void);
118 info!("File handle received from service.exe: {:?}", handle_value);
119 Ok(handle)
120 }
121 Err(_) => Err("Invalid handle format in response".to_string()),
122 }
123 } else if response.starts_with("HANDLE_ERROR:") {
124 let error_msg = response.strip_prefix("HANDLE_ERROR:").unwrap_or("Unknown error");
125 Err(format!("Service.exe error: {}", error_msg))
126 } else {
127 Err("Unexpected response from service.exe".to_string())
128 }
129 }
130
131 #[cfg(not(target_os = "windows"))]
134 fn try_open_file_directly_with_handle(&self) -> Result<SafeHandle, String> {
135 use std::fs::OpenOptions;
136 use std::os::unix::io::AsRawFd;
137
138 info!("Opening persistence file directly: {}", self.file_path);
139
140 if let Some(parent) = Path::new(&self.file_path).parent() {
142 match std::fs::create_dir_all(parent) {
143 Ok(_) => {},
144 Err(e) => return Err(format!("Failed to create directory: {}", e)),
145 }
146 }
147
148
149 let file = match OpenOptions::new()
150 .read(true)
151 .write(true)
152 .create(true)
153 .open(&self.file_path) {
154 Ok(file) => file,
155 Err(e) => return Err(format!("Failed to open file: {}", e)),
156 };
157
158 let handle = file.as_raw_fd() as *mut std::ffi::c_void;
159 std::mem::forget(file); Ok(SafeHandle::new(handle))
162 }
163 #[cfg(target_os = "windows")]
164 fn try_open_file_directly_with_handle(&self) -> Result<SafeHandle, String> {
165 info!("Opening persistence file directly: {}", self.file_path);
166
167 if let Some(parent) = Path::new(&self.file_path).parent() {
169 match std::fs::create_dir_all(parent) {
170 Ok(_) => {},
171 Err(e) => return Err(format!("Failed to create directory: {}", e)),
172 }
173 }
174
175 use std::fs::OpenOptions;
176 use std::os::windows::io::AsRawHandle;
177
178 let file = match OpenOptions::new()
179 .read(true)
180 .write(true)
181 .create(true)
182 .open(&self.file_path) {
183 Ok(file) => file,
184 Err(e) => return Err(format!("Failed to open file: {}", e)),
185 };
186
187 let handle = file.as_raw_handle() as *mut std::ffi::c_void;
188 std::mem::forget(file); Ok(SafeHandle::new(handle))
191 }
192
193 async fn read_file_data(&self) -> Result<Vec<u8>, String> {
195 let file_handle = self.file_handle.lock().await;
196
197 if let Some(safe_handle) = *file_handle {
198 if safe_handle.is_valid() {
199 info!("Reading file using {} handle",
200 if self.using_service_protection { "service" } else { "direct" });
201 drop(file_handle); return self.read_with_handle(&safe_handle);
203 }
204 }
205 drop(file_handle);
206
207 info!("Reading file using fallback fs::read");
209 match std::fs::read(&self.file_path) {
210 Ok(data) => Ok(data),
211 Err(e) => Err(format!("Failed to read persistence file: {}", e)),
212 }
213 }
214
215 fn read_with_handle(&self, handle: &SafeHandle) -> Result<Vec<u8>, String> {
219 #[cfg(target_os = "windows")]
220 {
221 use winapi::um::fileapi::{ReadFile, SetFilePointer, GetFileSize};
222 use winapi::um::errhandlingapi::GetLastError;
223 use winapi::um::winbase::FILE_BEGIN;
224 use winapi::um::handleapi::INVALID_HANDLE_VALUE;
225
226 let handle_value = handle.get_handle();
227
228 if handle_value.is_null() || handle_value == INVALID_HANDLE_VALUE {
230 return Err("Invalid handle value".to_string());
231 }
232
233 info!("Windows: Using file handle: {:?}", handle_value);
234
235 let seek_result = unsafe {
237 SetFilePointer(handle_value, 0, std::ptr::null_mut(), FILE_BEGIN)
238 };
239
240 if seek_result == 0xFFFFFFFF {
241 info!("SetFilePointer failed, checking for error");
242 let error_code = unsafe { GetLastError() };
243 return Err(format!("SetFilePointer failed with error: {}", error_code));
244 }
245
246 let file_size = unsafe { GetFileSize(handle_value, std::ptr::null_mut()) };
248
249 if file_size == 0xFFFFFFFF {
250 let error_code = unsafe { GetLastError() };
251 info!("GetFileSize failed, checking for error");
252 return Err(format!("GetFileSize failed with error: {} (handle may be invalid)", error_code));
253 }
254
255 info!("File size from handle: {} bytes", file_size);
256
257 if file_size == 0 {
258 info!("File is empty, returning empty vector");
259 return Ok(Vec::new());
260 }
261
262 let mut buffer = vec![0u8; file_size as usize];
264 let mut bytes_read: u32 = 0;
265
266 info!("Reading {} bytes from file handle: {:?}", file_size, handle_value);
267
268 let result = unsafe {
269 ReadFile(
270 handle_value,
271 buffer.as_mut_ptr() as *mut std::ffi::c_void,
272 file_size,
273 &mut bytes_read,
274 std::ptr::null_mut(),
275 )
276 };
277
278 if result == 0 {
279 let error_code = unsafe { GetLastError() };
280 return Err(format!("ReadFile failed with error: {}", error_code));
281 }
282
283 buffer.truncate(bytes_read as usize);
284 info!("Successfully read {} bytes", bytes_read);
285 Ok(buffer)
286 }
287
288 #[cfg(target_os = "macos")]
289 {
290 use std::os::unix::io::FromRawFd;
291 use std::io::Read;
292
293 let fd = handle.get_handle() as i32;
294
295 if fd < 0 {
296 return Err("Invalid file descriptor".to_string());
297 }
298
299 info!("macOS: Using file descriptor: {}", fd);
300
301 let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
303
304 use std::io::Seek;
306 if let Err(e) = file.seek(std::io::SeekFrom::Start(0)) {
307 return Err(format!("Failed to seek to start: {}", e));
308 }
309
310 let mut buffer = Vec::new();
312 match file.read_to_end(&mut buffer) {
313 Ok(bytes_read) => {
314 info!("macOS: Successfully read {} bytes", bytes_read);
315
316 std::mem::forget(file);
318
319 Ok(buffer)
320 }
321 Err(e) => Err(format!("Failed to read from file descriptor: {}", e))
322 }
323 }
324
325 #[cfg(target_os = "linux")]
326 {
327 use std::os::unix::io::FromRawFd;
328 use std::io::Read;
329
330 let fd = handle.get_handle() as i32;
331
332 if fd < 0 {
333 return Err("Invalid file descriptor".to_string());
334 }
335
336 info!("Linux: Using file descriptor: {}", fd);
337
338 let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
340
341 use std::io::Seek;
343 if let Err(e) = file.seek(std::io::SeekFrom::Start(0)) {
344 return Err(format!("Failed to seek to start: {}", e));
345 }
346
347 let mut buffer = Vec::new();
349 match file.read_to_end(&mut buffer) {
350 Ok(bytes_read) => {
351 info!("Linux: Successfully read {} bytes", bytes_read);
352
353 std::mem::forget(file);
355
356 Ok(buffer)
357 }
358 Err(e) => Err(format!("Failed to read from file descriptor: {}", e))
359 }
360 }
361
362 #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
363 {
364 error!("Platform not supported for handle-based file reading");
366 Err("Platform not supported for handle-based file reading".to_string())
367 }
368 }
369 async fn try_load_data(&self) -> Result<(), String> {
371 let data = self.read_file_data().await?;
372
373 if data.is_empty() {
374 info!("Persistence file is empty, starting with empty cache");
375 return Ok(());
376 }
377
378 let decrypted_data = match crypto::decrypt(&data, PERSISTENCE_PASSWORD) {
380 Ok(decrypted) => decrypted,
381 Err(e) => {
382 error!("Failed to decrypt persistence file: {}", e);
383 info!("Starting with empty cache due to decryption failure");
384 return Ok(()); }
386 };
387
388 info!("Successfully decrypted persistence file");
389
390 let loaded_data = match serde_json::from_slice::<HashMap<String, Value>>(&decrypted_data) {
392 Ok(data) => data,
393 Err(e) => {
394 error!("Failed to parse decrypted data as JSON: {}", e);
395 info!("Starting with empty cache");
396 return Ok(()); }
398 };
399
400 let mut cache = self.cache.lock().await;
402 *cache = loaded_data;
403 let count = cache.len();
404 drop(cache);
405
406 info!("Successfully loaded {} keys from encrypted persistence file", count);
407 Ok(())
408 }
409
410 async fn save_to_file(&self) -> Result<(), String> {
412 let cache = self.cache.lock().await;
413
414 let data_bytes = match serde_json::to_vec_pretty(&*cache) {
416 Ok(bytes) => bytes,
417 Err(e) => return Err(format!("Failed to serialize cache: {}", e)),
418 };
419
420 let encrypted_data = match crypto::encrypt(&data_bytes, PERSISTENCE_PASSWORD) {
421 Ok(encrypted) => encrypted,
422 Err(e) => return Err(format!("Failed to encrypt persistence data: {}", e)),
423 };
424
425 let file_handle = self.file_handle.lock().await;
427 if let Some(safe_handle) = *file_handle {
428 if safe_handle.is_valid() {
429 drop(file_handle); match self.write_with_handle(&safe_handle, &encrypted_data).await {
431 Ok(_) => {
432 info!("Saved {} keys using {} handle",
433 cache.len(),
434 if self.using_service_protection { "service" } else { "direct" });
435 return Ok(());
436 }
437 Err(e) => {
438 error!("Failed to write with handle: {}", e);
439 }
441 }
442 }
443 }
444
445 match tokio::fs::write(&self.file_path, encrypted_data).await {
447 Ok(_) => {
448 info!("Saved {} keys using fallback write", cache.len());
449 Ok(())
450 }
451 Err(e) => Err(format!("Failed to write persistence file: {}", e)),
452 }
453 }
454
455 async fn write_with_handle(&self, handle: &SafeHandle, data: &[u8]) -> Result<(), String> {
458 #[cfg(target_os = "windows")]
459 {
460 use winapi::um::fileapi::{WriteFile, SetFilePointer, SetEndOfFile};
461 use winapi::um::errhandlingapi::GetLastError;
462 use winapi::um::winbase::FILE_BEGIN;
463
464 let handle_value = handle.get_handle();
465
466 info!("Windows: Writing {} bytes to handle: {:?}", data.len(), handle_value);
467
468 unsafe {
470 SetFilePointer(handle_value, 0, std::ptr::null_mut(), FILE_BEGIN);
471 }
472
473 let mut bytes_written: u32 = 0;
474 let result = unsafe {
475 WriteFile(
476 handle_value,
477 data.as_ptr() as *const std::ffi::c_void,
478 data.len() as u32,
479 &mut bytes_written,
480 std::ptr::null_mut(),
481 )
482 };
483
484 if result == 0 {
485 let error_code = unsafe { GetLastError() };
486 return Err(format!("WriteFile failed with error: {}", error_code));
487 }
488
489 unsafe {
491 SetEndOfFile(handle_value);
492 }
493
494 info!("Windows: Successfully wrote {} bytes", bytes_written);
495 Ok(())
496 }
497
498 #[cfg(target_os = "macos")]
499 {
500 use std::os::unix::io::FromRawFd;
501 use std::io::{Write, Seek};
502
503 let fd = handle.get_handle() as i32;
504
505 if fd < 0 {
506 return Err("Invalid file descriptor".to_string());
507 }
508
509 info!("macOS: Writing {} bytes to fd: {}", data.len(), fd);
510
511 let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
513
514 if let Err(e) = file.seek(std::io::SeekFrom::Start(0)) {
516 return Err(format!("Failed to seek to start: {}", e));
517 }
518
519 if let Err(e) = file.set_len(0) {
521 return Err(format!("Failed to truncate file: {}", e));
522 }
523
524 match file.write_all(data) {
526 Ok(_) => {
527 if let Err(e) = file.flush() {
529 return Err(format!("Failed to flush file: {}", e));
530 }
531
532 info!("macOS: Successfully wrote {} bytes", data.len());
533
534 std::mem::forget(file);
536
537 Ok(())
538 }
539 Err(e) => Err(format!("Failed to write to file descriptor: {}", e))
540 }
541 }
542
543 #[cfg(target_os = "linux")]
544 {
545 use std::os::unix::io::FromRawFd;
546 use std::io::{Write, Seek};
547
548 let fd = handle.get_handle() as i32;
549
550 if fd < 0 {
551 return Err("Invalid file descriptor".to_string());
552 }
553
554 info!("Linux: Writing {} bytes to fd: {}", data.len(), fd);
555
556 let mut file = unsafe { std::fs::File::from_raw_fd(fd) };
558
559 if let Err(e) = file.seek(std::io::SeekFrom::Start(0)) {
561 return Err(format!("Failed to seek to start: {}", e));
562 }
563
564 if let Err(e) = file.set_len(0) {
565 return Err(format!("Failed to truncate file: {}", e));
566 }
567
568 match file.write_all(data) {
570 Ok(_) => {
571 if let Err(e) = file.flush() {
572 return Err(format!("Failed to flush file: {}", e));
573 }
574
575 info!("Linux: Successfully wrote {} bytes", data.len());
576
577 std::mem::forget(file);
579
580 Ok(())
581 }
582 Err(e) => Err(format!("Failed to write to file descriptor: {}", e))
583 }
584 }
585
586 #[cfg(not(any(target_os = "windows", target_os = "macos", target_os = "linux")))]
587 {
588 error!("Platform not supported for handle-based file writing");
589 Err("Platform not supported for handle-based file writing".to_string())
590 }
591 }
592
593 async fn get_value(&self, key: &str) -> Option<Value> {
595 let cache = self.cache.lock().await;
596 cache.get(key).cloned()
597 }
598
599 pub async fn set_value(&self, key: String, value: Value) -> Result<(), String> {
601 {
602 let mut cache = self.cache.lock().await;
603 cache.insert(key.clone(), value);
604 }
605
606 match self.save_to_file().await {
608 Ok(_) => {
609 info!("Set value for key: {}", key);
610 Ok(())
611 }
612 Err(e) => Err(e),
613 }
614 }
615
616 pub async fn delete_value(&self, key: &str) -> Result<bool, String> {
618 let removed = {
619 let mut cache = self.cache.lock().await;
620 cache.remove(key).is_some()
621 };
622
623 if removed {
624 match self.save_to_file().await {
626 Ok(_) => {
627 info!("Deleted value for key: {}", key);
628 Ok(true)
629 }
630 Err(e) => Err(e),
631 }
632 } else {
633 info!("Key not found for deletion: {}", key);
634 Ok(false)
635 }
636 }
637
638 async fn close_handle_with_service(&self) -> Result<(), String> {
640 let service_handle = self.file_handle.lock().await;
641 if service_handle.is_none() {
642 info!("No service handle to close");
643 return Ok(());
644 }
645 drop(service_handle); info!("Closing handle with service.exe for: {}", self.file_path);
648
649 let mut stream = match TcpStream::connect(sharing::CHANNEL_NAME) {
650 Ok(stream) => stream,
651 Err(e) => return Err(format!("Could not connect to service.exe for CLOSE_HANDLE: {}", e)),
652 };
653
654 let action = Action::CloseHandle(self.file_path.clone());
656 match stream.write_all(action.to_string().as_bytes()) {
657 Ok(_) => {},
658 Err(e) => return Err(format!("Failed to send CLOSE_HANDLE request: {}", e)),
659 }
660
661 let mut buffer = [0; 1024];
663 let bytes_read = match stream.read(&mut buffer) {
664 Ok(bytes) => bytes,
665 Err(e) => return Err(format!("Failed to read CLOSE_HANDLE response: {}", e)),
666 };
667
668 let response = String::from_utf8_lossy(&buffer[..bytes_read]);
669 info!("CLOSE_HANDLE response: {}", response);
670 Ok(())
671 }
672
673 async fn process_action(&self, action: Value, _write: WebSocketWrite) -> (i32, String) {
675 let action_obj = match action.get("ACTION").and_then(|a| a.as_object()) {
677 Some(obj) => obj,
678 None => {
679 error!("Missing or invalid ACTION object");
680 return (1, "Missing ACTION object".to_string());
681 }
682 };
683
684 let command = action_obj.get("command").and_then(|c| c.as_str()).unwrap_or("UNKNOWN");
685 let key = action_obj.get("key").and_then(|k| k.as_str()).unwrap_or("");
686 let value = action_obj.get("value");
687
688 info!("Processing persistence command: {} for key: {}", command, key);
689
690 match command.to_uppercase().as_str() {
691 "GET" => {
692 if key.is_empty() {
693 error!("Missing key parameter for GET command");
694 return (1, "Missing key parameter".to_string());
695 }
696
697 match self.get_value(key).await {
698 Some(value) => {
699 info!("Retrieved value for key: {}", key);
700 (0, serde_json::to_string(&value).unwrap_or("null".to_string()))
701 }
702 None => {
703 info!("Key not found: {}", key);
704 (0, "Key not found".to_string())
705 }
706 }
707 }
708 "SET" => {
709 if key.is_empty() {
710 error!("Missing key parameter for SET command");
711 return (1, "Missing key parameter".to_string());
712 }
713
714 let value = match value {
715 Some(v) => v.clone(),
716 None => {
717 error!("Missing value parameter for SET command");
718 return (1, "Missing value parameter".to_string());
719 }
720 };
721
722 match self.set_value(key.to_string(), value.clone()).await {
723 Ok(_) => {
724 info!("Set value for key: {}", key);
725 (0, format!("Value set successfully, size of value: {}", value.to_string().len()))
726 }
727 Err(e) => {
728 error!("Failed to set value: {}", e);
729 (1, format!("Failed to set value: {}", e))
730 }
731 }
732 }
733 "DEL" => {
734 if key.is_empty() {
735 error!("Missing key parameter for DELETE command");
736 return (1, "Missing key parameter".to_string());
737 }
738
739 match self.delete_value(key).await {
740 Ok(was_deleted) => {
741 if was_deleted {
742 info!("Deleted key: {}", key);
743 (0, "Key deleted successfully".to_string())
744 } else {
745 info!("Key not found for deletion: {}", key);
746 (0, "Key not found".to_string())
747 }
748 }
749 Err(e) => {
750 error!("Failed to delete value: {}", e);
751 (1, format!("Failed to delete value: {}", e))
752 }
753 }
754 }
755 _ => {
756 error!("Unknown persistence command: {}", command);
757 (1, "Unknown command".to_string())
758 }
759 }
760 }
761}
762
763#[async_trait]
764impl Service for PersistenceService {
765 async fn run(&self, action: Value, write: WebSocketWrite) -> (i32, String) {
767 debug!("PersistenceService: Running action: {:?}", action);
768 self.process_action(action, write).await
769 }
770
771 fn as_any(&self) -> &dyn std::any::Any {
773 self
774 }
775
776 fn stop_service(&self) {
778 info!("PersistenceService: Stopping service");
779
780 let rt = tokio::runtime::Runtime::new().unwrap();
782 rt.block_on(async {
783 if let Err(e) = self.close_handle_with_service().await {
784 error!("Failed to close handle with service: {}", e);
785 }
786 });
787
788 info!("PersistenceService stopped");
789 }
790
791 fn get_version(&self) -> String {
793 PERSISTENCE_VERSION.to_string()
794 }
795}