whatsapp_rust/store/
persistence_manager.rs1use super::error::StoreError;
2use crate::store::Device;
3use crate::store::traits::Backend;
4use log::{debug, error};
5use std::sync::Arc;
6use tokio::sync::{Mutex, Notify, RwLock};
7use tokio::time::{Duration, sleep};
8
9pub struct PersistenceManager {
10 device: Arc<RwLock<Device>>,
11 backend: Arc<dyn Backend>,
12 dirty: Arc<Mutex<bool>>,
13 save_notify: Arc<Notify>,
14 device_id: Option<i32>, }
16
17impl PersistenceManager {
18 pub async fn new(backend: Arc<dyn Backend>) -> Result<Self, StoreError> {
20 debug!("PersistenceManager: Ensuring device row exists (single-device mode).");
21 let exists = backend
23 .device_exists(1)
24 .await
25 .map_err(|e| StoreError::Database(e.to_string()))?;
26 if !exists {
27 debug!("PersistenceManager: No device row found. Creating new device row.");
28 let id = backend
29 .create_new_device()
30 .await
31 .map_err(|e| StoreError::Database(e.to_string()))?;
32 debug!("PersistenceManager: Created device row with id={id}.");
33 }
34
35 debug!("PersistenceManager: Attempting to load device data via Backend.");
36 let device_data_opt = backend
37 .load_device_data()
38 .await
39 .map_err(|e| StoreError::Database(e.to_string()))?;
40
41 let device = if let Some(serializable_device) = device_data_opt {
42 debug!(
43 "PersistenceManager: Loaded existing device data (PushName: '{}'). Initializing Device.",
44 serializable_device.push_name
45 );
46 let mut dev = Device::new(backend.clone());
47 dev.load_from_serializable(serializable_device);
48 dev
49 } else {
50 debug!("PersistenceManager: No data yet; initializing default Device in memory.");
51 Device::new(backend.clone())
52 };
53
54 Ok(Self {
55 device: Arc::new(RwLock::new(device)),
56 backend,
57 dirty: Arc::new(Mutex::new(false)),
58 save_notify: Arc::new(Notify::new()),
59 device_id: None, })
61 }
62
63 pub async fn new_for_device(
65 device_id: i32,
66 backend: Arc<dyn Backend>,
67 ) -> Result<Self, StoreError> {
68 debug!(
69 "PersistenceManager: Loading device data for device ID {}",
70 device_id
71 );
72
73 let device_data_opt = backend
75 .load_device_data_for_device(device_id)
76 .await
77 .map_err(|e| StoreError::Database(e.to_string()))?;
78
79 let device = if let Some(serializable_device) = device_data_opt {
80 debug!(
81 "PersistenceManager: Loaded existing device data for device {} (PushName: '{}'). Initializing Device.",
82 device_id, serializable_device.push_name
83 );
84 let mut dev = Device::new(backend.clone());
85 dev.load_from_serializable(serializable_device);
86 dev
87 } else {
88 return Err(StoreError::DeviceNotFound(device_id));
90 };
91
92 Ok(Self {
93 device: Arc::new(RwLock::new(device)),
94 backend,
95 dirty: Arc::new(Mutex::new(false)),
96 save_notify: Arc::new(Notify::new()),
97 device_id: Some(device_id),
98 })
99 }
100
101 pub fn device_id(&self) -> i32 {
103 self.device_id.unwrap_or(1) }
105
106 pub fn is_multi_account(&self) -> bool {
108 self.device_id.is_some()
109 }
110
111 pub async fn get_device_arc(&self) -> Arc<RwLock<Device>> {
112 self.device.clone()
113 }
114
115 pub async fn get_device_snapshot(&self) -> Device {
116 self.device.read().await.clone()
117 }
118
119 pub fn backend(&self) -> Arc<dyn Backend> {
120 self.backend.clone()
121 }
122
123 pub async fn modify_device<F, R>(&self, modifier: F) -> R
124 where
125 F: FnOnce(&mut Device) -> R,
126 {
127 let mut device_guard = self.device.write().await;
128 let result = modifier(&mut device_guard);
129
130 let mut dirty_guard = self.dirty.lock().await;
131 *dirty_guard = true;
132 self.save_notify.notify_one();
133
134 result
135 }
136
137 async fn save_to_disk(&self) -> Result<(), StoreError> {
138 let mut dirty_guard = self.dirty.lock().await;
139 if *dirty_guard {
140 debug!("Device state is dirty, saving to disk.");
141 let device_guard = self.device.read().await;
142 let serializable_device = device_guard.to_serializable();
143 drop(device_guard);
144
145 if let Some(device_id) = self.device_id {
148 self.backend
149 .save_device_data_for_device(device_id, &serializable_device)
150 .await
151 .map_err(|e| StoreError::Database(e.to_string()))?;
152 } else {
153 self.backend
154 .save_device_data(&serializable_device)
155 .await
156 .map_err(|e| StoreError::Database(e.to_string()))?;
157 }
158 *dirty_guard = false;
159 debug!("Device state saved successfully.");
160 }
161 Ok(())
162 }
163
164 pub fn run_background_saver(self: Arc<Self>, interval: Duration) {
165 tokio::spawn(async move {
166 loop {
167 tokio::select! {
168 _ = self.save_notify.notified() => {
169 debug!("Save notification received.");
170 }
171 _ = sleep(interval) => {}
172 }
173
174 if let Err(e) = self.save_to_disk().await {
175 error!("Error saving device state in background: {e}");
176 }
177 }
178 });
179 debug!("Background saver task started with interval {interval:?}");
180 }
181}
182
183use super::commands::{DeviceCommand, apply_command_to_device};
184
185impl PersistenceManager {
186 pub async fn process_command(&self, command: DeviceCommand) {
187 self.modify_device(|device| {
188 apply_command_to_device(device, command);
189 })
190 .await;
191 }
192}