sync15/engine/
bridged_engine.rs1use crate::error::debug;
6use crate::{ServerTimestamp, telemetry};
7use anyhow::Result;
8
9use crate::Guid;
10use crate::bso::IncomingBso;
11
12use super::{CollSyncIds, EngineSyncAssociation, SyncEngine};
13
14pub struct BridgedEngineWrapper {
28 inner: Box<dyn SyncEngine + Send + Sync>,
29}
30
31impl BridgedEngineWrapper {
32 pub fn new(inner: Box<dyn SyncEngine + Send + Sync>) -> Self {
33 Self { inner }
34 }
35
36 pub fn last_sync(&self) -> Result<i64> {
41 Ok(self.inner.last_sync()?.unwrap_or_default().as_millis())
42 }
43
44 pub fn reset_last_sync(&self) -> Result<()> {
47 self.inner.reset_last_sync()
48 }
49
50 pub fn sync_id(&self) -> Result<Option<String>> {
54 Ok(match self.inner.get_sync_assoc()? {
55 EngineSyncAssociation::Disconnected => None,
56 EngineSyncAssociation::Connected(c) => Some(c.coll.into()),
57 })
58 }
59
60 pub fn reset_sync_id(&self) -> Result<String> {
63 let global = Guid::empty();
64 let coll = Guid::random();
65 self.inner
66 .reset(&EngineSyncAssociation::Connected(CollSyncIds {
67 global,
68 coll: coll.clone(),
69 }))?;
70 Ok(coll.to_string())
71 }
72
73 pub fn ensure_current_sync_id(&self, sync_id: &str) -> Result<String> {
76 let assoc = self.inner.get_sync_assoc()?;
77 if matches!(assoc, EngineSyncAssociation::Connected(c) if c.coll == sync_id) {
78 debug!("ensure_current_sync_id is current");
79 } else {
80 let new_coll_ids = CollSyncIds {
81 global: Guid::empty(),
82 coll: sync_id.into(),
83 };
84 self.inner
85 .reset(&EngineSyncAssociation::Connected(new_coll_ids))?;
86 }
87 Ok(sync_id.to_string())
88 }
89
90 pub fn set_clients(&self, client_data: &str) -> Result<()> {
91 self.inner
94 .set_clients(&|| serde_json::from_str::<crate::ClientData>(client_data).unwrap())
95 }
96
97 pub fn sync_started(&self) -> Result<()> {
98 self.inner.sync_started()
99 }
100
101 pub fn store_incoming(&self, incoming: Vec<String>) -> Result<()> {
104 let mut bsos = Vec::with_capacity(incoming.len());
105 for inc in incoming {
106 bsos.push(serde_json::from_str::<IncomingBso>(&inc)?);
107 }
108 let mut telem = telemetry::Engine::new(self.inner.collection_name());
109 self.inner.stage_incoming(bsos, &mut telem)
110 }
111
112 pub fn apply(&self, server_modified_millis: i64) -> Result<Vec<String>> {
121 let mut telem = telemetry::Engine::new(self.inner.collection_name());
122 let records = self.inner.apply(
123 ServerTimestamp::from_millis(server_modified_millis),
124 &mut telem,
125 )?;
126 let mut outgoing = Vec::with_capacity(records.len());
127 for e in records {
128 outgoing.push(serde_json::to_string(&e)?);
129 }
130 Ok(outgoing)
131 }
132
133 pub fn set_uploaded(&self, server_modified_millis: i64, ids: Vec<String>) -> Result<()> {
136 let guids: Vec<Guid> = ids.into_iter().map(Guid::from).collect();
137 self.inner
138 .set_uploaded(ServerTimestamp::from_millis(server_modified_millis), guids)
139 }
140
141 pub fn sync_finished(&self) -> Result<()> {
142 self.inner.sync_finished()
143 }
144
145 pub fn reset(&self) -> Result<()> {
146 self.inner.reset(&EngineSyncAssociation::Disconnected)
147 }
148
149 pub fn wipe(&self) -> Result<()> {
150 self.inner.wipe()
151 }
152}
153
154#[macro_export]
173macro_rules! uniffi_bridged_engine {
174 ($name:ident) => {
175 pub struct $name($crate::engine::BridgedEngineWrapper);
178
179 impl $name {
180 pub fn new(
181 inner: ::std::boxed::Box<dyn $crate::engine::SyncEngine + Send + Sync>,
182 ) -> Self {
183 Self($crate::engine::BridgedEngineWrapper::new(inner))
184 }
185
186 pub fn last_sync(&self) -> ::anyhow::Result<i64> {
187 self.0.last_sync()
188 }
189
190 pub fn reset_last_sync(&self) -> ::anyhow::Result<()> {
191 self.0.reset_last_sync()
192 }
193
194 pub fn sync_id(&self) -> ::anyhow::Result<Option<String>> {
195 self.0.sync_id()
196 }
197
198 pub fn reset_sync_id(&self) -> ::anyhow::Result<String> {
199 self.0.reset_sync_id()
200 }
201
202 pub fn ensure_current_sync_id(&self, sync_id: &str) -> ::anyhow::Result<String> {
203 self.0.ensure_current_sync_id(sync_id)
204 }
205
206 pub fn set_clients(&self, client_data: &str) -> ::anyhow::Result<()> {
207 self.0.set_clients(client_data)
208 }
209
210 pub fn sync_started(&self) -> ::anyhow::Result<()> {
211 self.0.sync_started()
212 }
213
214 pub fn store_incoming(&self, incoming: Vec<String>) -> ::anyhow::Result<()> {
215 self.0.store_incoming(incoming)
216 }
217
218 pub fn apply(&self, server_modified_millis: i64) -> ::anyhow::Result<Vec<String>> {
219 self.0.apply(server_modified_millis)
220 }
221
222 pub fn set_uploaded(
223 &self,
224 server_modified_millis: i64,
225 ids: Vec<String>,
226 ) -> ::anyhow::Result<()> {
227 self.0.set_uploaded(server_modified_millis, ids)
228 }
229
230 pub fn sync_finished(&self) -> ::anyhow::Result<()> {
231 self.0.sync_finished()
232 }
233
234 pub fn reset(&self) -> ::anyhow::Result<()> {
235 self.0.reset()
236 }
237
238 pub fn wipe(&self) -> ::anyhow::Result<()> {
239 self.0.wipe()
240 }
241 }
242 };
243}
244
245#[cfg(test)]
246mod wrapper_tests {
247 use super::*;
248 use crate::CollectionName;
249 use crate::bso::OutgoingBso;
250 use crate::engine::CollectionRequest;
251 use std::sync::Mutex;
252
253 #[derive(Default)]
257 struct RecordingEngine {
258 uploaded: Mutex<Vec<Guid>>,
259 }
260
261 impl SyncEngine for RecordingEngine {
262 fn collection_name(&self) -> CollectionName {
263 "test".into()
264 }
265 fn stage_incoming(
266 &self,
267 _inbound: Vec<IncomingBso>,
268 _telem: &mut telemetry::Engine,
269 ) -> Result<()> {
270 Ok(())
271 }
272 fn apply(
273 &self,
274 _timestamp: ServerTimestamp,
275 _telem: &mut telemetry::Engine,
276 ) -> Result<Vec<OutgoingBso>> {
277 Ok(vec![])
278 }
279 fn set_uploaded(&self, _new_timestamp: ServerTimestamp, ids: Vec<Guid>) -> Result<()> {
280 self.uploaded.lock().unwrap().extend(ids);
281 Ok(())
282 }
283 fn get_collection_request(
284 &self,
285 _server_timestamp: ServerTimestamp,
286 ) -> Result<Option<CollectionRequest>> {
287 Ok(None)
288 }
289 fn get_sync_assoc(&self) -> Result<EngineSyncAssociation> {
290 Ok(EngineSyncAssociation::Disconnected)
291 }
292 fn reset(&self, _assoc: &EngineSyncAssociation) -> Result<()> {
293 Ok(())
294 }
295 fn wipe(&self) -> Result<()> {
296 Ok(())
297 }
298 }
299
300 #[test]
301 fn set_uploaded_converts_string_ids() {
302 let wrapper = BridgedEngineWrapper::new(Box::new(RecordingEngine::default()));
303 wrapper
305 .set_uploaded(1, vec!["aaaa".to_string(), "bbbb".to_string()])
306 .unwrap();
307 }
308}