Skip to main content

lb_rs/
blocking.rs

1use std::{future::Future, path::PathBuf};
2
3use tokio::sync::broadcast::Receiver;
4use uuid::Uuid;
5
6use crate::model::account::{Account, Username};
7use crate::model::api::{
8    AccountFilter, AccountIdentifier, AccountInfo, AdminFileInfoResponse, AdminSetUserTierInfo,
9    AdminValidateAccount, AdminValidateServer, ServerIndex, StripeAccountTier, SubscriptionInfo,
10};
11use crate::model::core_config::Config;
12use crate::model::crypto::DecryptedDocument;
13use crate::model::errors::{LbResult, Warning};
14use crate::model::file::{File, ShareMode};
15use crate::model::file_metadata::{DocumentHmac, FileType};
16use crate::model::path_ops::Filter;
17use crate::service::activity::RankingWeights;
18
19use crate::service::events::Event;
20use crate::service::import_export::{ExportFileInfo, ImportStatus};
21use crate::service::usage::UsageMetrics;
22use crate::subscribers::status::Status;
23
24#[cfg(not(target_family = "wasm"))]
25use {std::sync::Arc, tokio::runtime::Runtime};
26
27#[cfg(not(target_family = "wasm"))]
28use crate::service::debug::DebugInfo;
29
30#[derive(Clone)]
31pub struct Lb {
32    lb: crate::Lb,
33    #[cfg(not(target_family = "wasm"))]
34    rt: Arc<Runtime>,
35}
36
37impl Lb {
38    #[cfg(target_family = "wasm")]
39    pub fn init(config: Config) -> LbResult<Self> {
40        let lb = crate::Lb::init_dummy(config)?;
41        Ok(Self { lb })
42    }
43
44    #[cfg(target_family = "wasm")]
45    fn block_on<F>(&self, future: F) -> F::Output
46    where
47        F: Future,
48    {
49        futures::executor::block_on(future)
50    }
51
52    #[cfg(not(target_family = "wasm"))]
53    fn block_on<F>(&self, future: F) -> F::Output
54    where
55        F: Future,
56    {
57        self.rt.block_on(future)
58    }
59
60    #[cfg(not(target_family = "wasm"))]
61    pub fn init(config: Config) -> LbResult<Self> {
62        let rt = Arc::new(Runtime::new().unwrap());
63        let lb = rt.block_on(crate::Lb::init(config))?;
64        Ok(Self { rt, lb })
65    }
66
67    /// The underlying async [`crate::Lb`], for callers that run their own
68    /// runtime (the blocking methods `block_on` this wrapper's runtime, which
69    /// panics when called from inside another).
70    pub fn async_lb(&self) -> &crate::Lb {
71        &self.lb
72    }
73
74    /// Apply other processes' commits before reading from a core without background work.
75    pub fn refresh(&self) {
76        self.block_on(async { self.lb.begin_tx().await.end() });
77    }
78
79    pub fn create_account(
80        &self, username: &str, api_url: &str, welcome_doc: bool,
81    ) -> LbResult<Account> {
82        self.block_on(self.lb.create_account(username, api_url, welcome_doc))
83    }
84
85    pub fn import_account(&self, key: &str, api_url: Option<&str>) -> LbResult<Account> {
86        self.block_on(self.lb.import_account(key, api_url))
87    }
88
89    pub fn export_account_private_key(&self) -> LbResult<String> {
90        self.lb.export_account_private_key()
91    }
92
93    pub fn export_account_phrase(&self) -> LbResult<String> {
94        self.lb.export_account_phrase()
95    }
96
97    pub fn export_account_qr(&self) -> LbResult<Vec<u8>> {
98        self.lb.export_account_qr()
99    }
100
101    pub fn get_account(&self) -> LbResult<&Account> {
102        self.lb.get_account()
103    }
104
105    pub fn get_config(&self) -> Config {
106        self.lb.config.clone()
107    }
108
109    pub fn create_file(&self, name: &str, parent: &Uuid, file_type: FileType) -> LbResult<File> {
110        self.block_on(self.lb.create_file(name, parent, file_type))
111    }
112
113    pub fn safe_write(
114        &self, id: Uuid, old_hmac: Option<DocumentHmac>, content: Vec<u8>, origin: Option<Uuid>,
115    ) -> LbResult<DocumentHmac> {
116        self.block_on(self.lb.safe_write(id, old_hmac, content, origin))
117    }
118
119    pub fn document_hmac(&self, id: Uuid) -> LbResult<Option<DocumentHmac>> {
120        use crate::model::{file_like::FileLike, tree_like::TreeLike};
121        self.block_on(async {
122            let tx = self.lb.ro_tx().await;
123            let db = tx.db();
124            let tree = db.base_metadata.stage(&db.local_metadata);
125            Ok(tree.find(&id)?.document_hmac().copied())
126        })
127    }
128
129    pub fn write_document(&self, id: Uuid, content: &[u8]) -> LbResult<()> {
130        self.block_on(self.lb.write_document(id, content))
131    }
132
133    pub fn get_root(&self) -> LbResult<File> {
134        self.block_on(self.lb.root())
135    }
136
137    pub fn get_children(&self, id: &Uuid) -> LbResult<Vec<File>> {
138        self.block_on(self.lb.get_children(id))
139    }
140
141    pub fn get_and_get_children_recursively(&self, id: &Uuid) -> LbResult<Vec<File>> {
142        self.block_on(self.lb.get_and_get_children_recursively(id))
143    }
144
145    pub fn get_file_by_id(&self, id: Uuid) -> LbResult<File> {
146        self.block_on(self.lb.get_file_by_id(id))
147    }
148
149    pub fn delete_file(&self, id: &Uuid) -> LbResult<()> {
150        self.block_on(self.lb.delete(id))
151    }
152
153    pub fn duplicate_file(&self, id: &Uuid) -> LbResult<File> {
154        self.block_on(self.lb.duplicate_file(id))
155    }
156
157    pub fn read_document(&self, id: Uuid, user_activity: bool) -> LbResult<DecryptedDocument> {
158        self.block_on(self.lb.read_document(id, user_activity))
159    }
160
161    pub fn read_document_with_hmac(
162        &self, id: Uuid, user_activity: bool,
163    ) -> LbResult<(Option<DocumentHmac>, DecryptedDocument)> {
164        self.block_on(self.lb.read_document_with_hmac(id, user_activity))
165    }
166
167    pub fn list_metadatas(&self) -> LbResult<Vec<File>> {
168        self.block_on(self.lb.list_metadatas())
169    }
170
171    pub fn rename_file(&self, id: &Uuid, new_name: &str) -> LbResult<()> {
172        self.block_on(self.lb.rename_file(id, new_name))
173    }
174
175    pub fn move_file(&self, id: &Uuid, new_parent: &Uuid) -> LbResult<()> {
176        self.block_on(self.lb.move_file(id, new_parent))
177    }
178
179    pub fn share_file(&self, id: Uuid, username: &str, mode: ShareMode) -> LbResult<()> {
180        self.block_on(self.lb.share_file(id, username, mode))
181    }
182
183    pub fn get_pending_shares(&self) -> LbResult<Vec<File>> {
184        self.block_on(self.lb.get_pending_shares())
185    }
186
187    pub fn get_pending_share_files(&self) -> LbResult<Vec<File>> {
188        self.block_on(self.lb.get_pending_share_files())
189    }
190
191    pub fn delete_pending_share(&self, id: &Uuid) -> LbResult<()> {
192        self.block_on(async { self.lb.reject_share(id).await })
193    }
194
195    /// Usernames we've seen (pub key lookup cache) — suggestions + offline hits.
196    pub fn known_usernames(&self) -> LbResult<Vec<String>> {
197        self.block_on(self.lb.known_usernames())
198    }
199
200    pub fn get_sharing_contacts(&self) -> LbResult<Vec<crate::service::share::SharingContact>> {
201        self.block_on(self.lb.get_sharing_contacts())
202    }
203
204    /// Whether `username` exists (cache + server). May hit the network.
205    pub fn username_exists(&self, username: &str) -> LbResult<bool> {
206        self.block_on(self.lb.username_exists(username))
207    }
208
209    pub fn create_link_at_path(&self, path_and_name: &str, target_id: Uuid) -> LbResult<File> {
210        self.block_on(self.lb.create_link_at_path(path_and_name, target_id))
211    }
212
213    pub fn create_at_path(&self, path_and_name: &str) -> LbResult<File> {
214        self.block_on(self.lb.create_at_path(path_and_name))
215    }
216
217    pub fn get_by_path(&self, path: &str) -> LbResult<File> {
218        self.block_on(self.lb.get_by_path(path))
219    }
220
221    pub fn get_path_by_id(&self, id: Uuid) -> LbResult<String> {
222        self.block_on(self.lb.get_path_by_id(id))
223    }
224
225    pub fn list_paths(&self, filter: Option<Filter>) -> LbResult<Vec<String>> {
226        self.block_on(self.lb.list_paths(filter))
227    }
228
229    pub fn list_paths_with_ids(&self, filter: Option<Filter>) -> LbResult<Vec<(Uuid, String)>> {
230        self.block_on(self.lb.list_paths_with_ids(filter))
231    }
232
233    pub fn get_local_changes(&self) -> LbResult<Vec<Uuid>> {
234        Ok(self.block_on(self.lb.local_changes()))
235    }
236
237    pub fn sync(&self) -> LbResult<()> {
238        self.block_on(self.lb.sync())
239    }
240
241    pub fn get_last_synced(&self) -> LbResult<i64> {
242        self.block_on(self.lb.get_last_synced())
243    }
244
245    pub fn get_last_synced_human_string(&self) -> LbResult<String> {
246        self.block_on(self.lb.get_last_synced_human())
247    }
248
249    pub fn get_timestamp_human_string(&self, timestamp: i64) -> String {
250        self.lb.get_timestamp_human_string(timestamp)
251    }
252
253    pub fn suggested_docs(&self, settings: RankingWeights) -> LbResult<Vec<Uuid>> {
254        self.block_on(self.lb.suggested_docs(settings))
255    }
256
257    pub fn clear_suggested(&self) -> LbResult<()> {
258        self.block_on(self.lb.clear_suggested())
259    }
260
261    pub fn clear_suggested_id(&self, target_id: Uuid) -> LbResult<()> {
262        self.block_on(self.lb.clear_suggested_id(target_id))
263    }
264
265    pub fn pin_file(&self, id: Uuid) -> LbResult<()> {
266        self.block_on(self.lb.pin_file(id))
267    }
268
269    pub fn unpin_file(&self, id: Uuid) -> LbResult<()> {
270        self.block_on(self.lb.unpin_file(id))
271    }
272
273    pub fn list_pinned(&self) -> LbResult<Vec<Uuid>> {
274        self.block_on(self.lb.list_pinned())
275    }
276
277    // TODO: examine why the old get_usage does a bunch of things
278    pub fn get_usage(&self) -> LbResult<UsageMetrics> {
279        self.block_on(self.lb.get_usage())
280    }
281
282    pub fn import_files<F: Fn(ImportStatus)>(
283        &self, sources: &[PathBuf], dest: Uuid, update_status: &F,
284    ) -> LbResult<()> {
285        self.block_on(self.lb.import_files(sources, dest, update_status))
286    }
287
288    pub fn export_files(
289        &self, id: Uuid, dest: PathBuf, edit: bool,
290        export_progress: &Option<Box<dyn Fn(ExportFileInfo)>>,
291    ) -> LbResult<()> {
292        self.block_on(self.lb.export_file(id, dest, edit, export_progress))
293    }
294
295    pub fn get_file_link_url(&self, id: Uuid) -> LbResult<String> {
296        self.block_on(self.lb.get_file_link_url(id))
297    }
298
299    pub fn path_searcher(&self) -> crate::search::PathSearcher {
300        self.block_on(self.lb.path_searcher())
301    }
302
303    pub fn content_searcher(&self) -> crate::search::ContentSearcher {
304        crate::search::ContentSearcher::new(self)
305    }
306
307    pub fn validate(&self) -> LbResult<Vec<Warning>> {
308        self.block_on(self.lb.test_repo_integrity(true))
309    }
310
311    pub fn upgrade_account_stripe(&self, account_tier: StripeAccountTier) -> LbResult<()> {
312        self.block_on(self.lb.upgrade_account_stripe(account_tier))
313    }
314
315    pub fn upgrade_account_google_play(
316        &self, purchase_token: &str, account_id: &str,
317    ) -> LbResult<()> {
318        self.block_on(
319            self.lb
320                .upgrade_account_google_play(purchase_token, account_id),
321        )
322    }
323
324    pub fn upgrade_account_app_store(
325        &self, original_transaction_id: String, app_account_token: String,
326    ) -> LbResult<()> {
327        self.block_on(
328            self.lb
329                .upgrade_account_app_store(original_transaction_id, app_account_token),
330        )
331    }
332
333    pub fn cancel_subscription(&self) -> LbResult<()> {
334        self.block_on(self.lb.cancel_subscription())
335    }
336
337    pub fn get_subscription_info(&self) -> LbResult<Option<SubscriptionInfo>> {
338        self.block_on(self.lb.get_subscription_info())
339    }
340
341    pub fn delete_account(&self) -> LbResult<()> {
342        self.block_on(self.lb.delete_account())
343    }
344
345    pub fn admin_disappear_account(&self, username: &str) -> LbResult<()> {
346        self.block_on(self.lb.disappear_account(username))
347    }
348
349    pub fn admin_disappear_file(&self, id: Uuid) -> LbResult<()> {
350        self.block_on(self.lb.disappear_file(id))
351    }
352
353    pub fn admin_list_users(&self, filter: Option<AccountFilter>) -> LbResult<Vec<Username>> {
354        self.block_on(self.lb.list_users(filter))
355    }
356
357    pub fn admin_get_account_info(&self, identifier: AccountIdentifier) -> LbResult<AccountInfo> {
358        self.block_on(self.lb.get_account_info(identifier))
359    }
360
361    pub fn admin_validate_account(&self, username: &str) -> LbResult<AdminValidateAccount> {
362        self.block_on(self.lb.validate_account(username))
363    }
364
365    pub fn admin_validate_server(&self) -> LbResult<AdminValidateServer> {
366        self.block_on(self.lb.validate_server())
367    }
368
369    pub fn admin_file_info(&self, id: Uuid) -> LbResult<AdminFileInfoResponse> {
370        self.block_on(self.lb.file_info(id))
371    }
372
373    pub fn admin_rebuild_index(&self, index: ServerIndex) -> LbResult<()> {
374        self.block_on(self.lb.rebuild_index(index))
375    }
376
377    pub fn admin_set_user_tier(&self, username: &str, info: AdminSetUserTierInfo) -> LbResult<()> {
378        self.block_on(self.lb.set_user_tier(username, info))
379    }
380
381    pub fn subscribe(&self) -> Receiver<Event> {
382        self.lb.subscribe()
383    }
384
385    pub fn status(&self) -> Status {
386        self.block_on(self.lb.status())
387    }
388
389    pub fn app_foregrounded(&self) {
390        #[cfg(not(target_family = "wasm"))]
391        {
392            let _rt = self.rt.enter();
393            self.lb.app_foregrounded();
394        }
395    }
396
397    pub fn user_active(&self) -> bool {
398        self.block_on(self.lb.user_active())
399    }
400
401    #[cfg(not(target_family = "wasm"))]
402    pub fn debug_info(&self, os_info: String) -> LbResult<DebugInfo> {
403        self.rt.block_on(self.lb.debug_info(os_info, true))
404    }
405
406    pub fn recent_panic(&self) -> LbResult<Option<chrono::DateTime<chrono::Local>>> {
407        #[cfg(not(target_family = "wasm"))]
408        return self.block_on(self.lb.recent_panic());
409        #[cfg(target_family = "wasm")]
410        Ok(None)
411    }
412
413    #[cfg(not(target_family = "wasm"))]
414    pub fn write_panic_to_file(&self, error_header: String, bt: String) -> LbResult<String> {
415        self.block_on(self.lb.write_panic_to_file(error_header, bt))
416    }
417}