truffle_core/synced_store/
mod.rs1pub mod backend;
22pub mod sync;
23pub mod types;
24
25#[cfg(test)]
26mod tests;
27
28pub use backend::{MemoryBackend, StoreBackend};
29pub use types::{Slice, StoreEvent, SyncMessage};
30
31use std::collections::HashMap;
32use std::sync::atomic::{AtomicU64, Ordering};
33use std::sync::Arc;
34use std::time::{SystemTime, UNIX_EPOCH};
35
36use serde::de::DeserializeOwned;
37use serde::Serialize;
38use tokio::sync::{broadcast, mpsc, RwLock};
39use tokio::task::JoinHandle;
40
41use crate::network::NetworkProvider;
42use crate::node::Node;
43
44pub(crate) struct StoreInner<T> {
51 pub(crate) store_id: String,
53 pub(crate) device_id: String,
55 pub(crate) local: RwLock<Option<Slice<T>>>,
57 pub(crate) remotes: RwLock<HashMap<String, Slice<T>>>,
59 pub(crate) version: AtomicU64,
61 pub(crate) event_tx: broadcast::Sender<StoreEvent<T>>,
63}
64
65pub struct SyncedStore<T> {
77 pub(crate) inner: Arc<StoreInner<T>>,
78 broadcast_tx: mpsc::UnboundedSender<SyncMessage>,
80 task_handle: tokio::sync::Mutex<Option<JoinHandle<()>>>,
82}
83
84impl<T: Serialize + DeserializeOwned + Clone + Send + Sync + 'static> SyncedStore<T> {
85 pub fn new<N: NetworkProvider + 'static>(
91 node: Arc<Node<N>>,
92 store_id: &str,
93 ) -> Arc<Self> {
94 let device_id = node.local_info().id;
95 let (event_tx, _) = broadcast::channel(256);
96 let (broadcast_tx, broadcast_rx) = mpsc::unbounded_channel();
97
98 let inner = Arc::new(StoreInner {
99 store_id: store_id.to_string(),
100 device_id,
101 local: RwLock::new(None),
102 remotes: RwLock::new(HashMap::new()),
103 version: AtomicU64::new(0),
104 event_tx,
105 });
106
107 let task_handle = sync::spawn_sync_task(node, inner.clone(), broadcast_rx);
108
109 Arc::new(Self {
110 inner,
111 broadcast_tx,
112 task_handle: tokio::sync::Mutex::new(Some(task_handle)),
113 })
114 }
115
116 pub async fn set(&self, data: T) {
120 let version = self.inner.version.fetch_add(1, Ordering::SeqCst) + 1;
121 let now = SystemTime::now()
122 .duration_since(UNIX_EPOCH)
123 .unwrap_or_default()
124 .as_millis() as u64;
125
126 let slice = Slice {
127 device_id: self.inner.device_id.clone(),
128 data: data.clone(),
129 version,
130 updated_at: now,
131 };
132
133 {
134 let mut local = self.inner.local.write().await;
135 *local = Some(slice);
136 }
137
138 if let Ok(serialized) = serde_json::to_value(&data) {
140 let msg = SyncMessage::Update {
141 device_id: self.inner.device_id.clone(),
142 data: serialized,
143 version,
144 updated_at: now,
145 };
146 let _ = self.broadcast_tx.send(msg);
147 }
148
149 let _ = self.inner.event_tx.send(StoreEvent::LocalChanged(data));
150 }
151
152 pub async fn local(&self) -> Option<T> {
156 let local = self.inner.local.read().await;
157 local.as_ref().map(|s| s.data.clone())
158 }
159
160 pub async fn get(&self, device_id: &str) -> Option<Slice<T>> {
162 let remotes = self.inner.remotes.read().await;
163 remotes.get(device_id).cloned()
164 }
165
166 pub async fn all(&self) -> HashMap<String, Slice<T>> {
168 let mut result = HashMap::new();
169
170 {
171 let local = self.inner.local.read().await;
172 if let Some(slice) = local.as_ref() {
173 result.insert(slice.device_id.clone(), slice.clone());
174 }
175 }
176
177 {
178 let remotes = self.inner.remotes.read().await;
179 for (id, slice) in remotes.iter() {
180 result.insert(id.clone(), slice.clone());
181 }
182 }
183
184 result
185 }
186
187 pub async fn device_ids(&self) -> Vec<String> {
189 let mut ids = Vec::new();
190
191 {
192 let local = self.inner.local.read().await;
193 if let Some(slice) = local.as_ref() {
194 ids.push(slice.device_id.clone());
195 }
196 }
197
198 {
199 let remotes = self.inner.remotes.read().await;
200 ids.extend(remotes.keys().cloned());
201 }
202
203 ids
204 }
205
206 pub fn subscribe(&self) -> broadcast::Receiver<StoreEvent<T>> {
208 self.inner.event_tx.subscribe()
209 }
210
211 pub fn store_id(&self) -> &str {
213 &self.inner.store_id
214 }
215
216 pub fn device_id(&self) -> &str {
218 &self.inner.device_id
219 }
220
221 pub fn version(&self) -> u64 {
223 self.inner.version.load(Ordering::SeqCst)
224 }
225
226 pub async fn stop(&self) {
230 let mut handle = self.task_handle.lock().await;
231 if let Some(h) = handle.take() {
232 h.abort();
233 tracing::info!(store = self.inner.store_id.as_str(), "synced_store: stopped");
234 }
235 }
236}
237
238impl<T> Drop for SyncedStore<T> {
239 fn drop(&mut self) {
240 if let Ok(mut handle) = self.task_handle.try_lock() {
242 if let Some(h) = handle.take() {
243 h.abort();
244 }
245 }
246 }
247}