1use std::{collections::HashMap, path::PathBuf, sync::Arc};
2
3use tokio::{runtime::Runtime, sync::broadcast::Receiver};
4use uuid::Uuid;
5
6use crate::{
7 model::{
8 account::{Account, Username},
9 api::{
10 AccountFilter, AccountIdentifier, AccountInfo, AdminFileInfoResponse,
11 AdminSetUserTierInfo, AdminValidateAccount, AdminValidateServer, ServerIndex,
12 StripeAccountTier, SubscriptionInfo,
13 },
14 core_config::Config,
15 crypto::DecryptedDocument,
16 errors::{LbResult, Warning},
17 file::{File, ShareMode},
18 file_metadata::{DocumentHmac, FileType},
19 path_ops::Filter,
20 },
21 service::{
22 activity::RankingWeights,
23 events::Event,
24 import_export::{ExportFileInfo, ImportStatus},
25 sync::{SyncProgress, SyncStatus},
26 usage::{UsageItemMetric, UsageMetrics},
27 },
28 subscribers::{
29 search::{SearchConfig, SearchResult},
30 status::Status,
31 },
32};
33
34#[derive(Clone)]
35pub struct Lb {
36 lb: crate::Lb,
37 rt: Arc<Runtime>,
38}
39
40impl Lb {
41 pub fn init(config: Config) -> LbResult<Self> {
42 let rt = Arc::new(Runtime::new().unwrap());
43 let lb = rt.block_on(crate::Lb::init(config))?;
44 Ok(Self { rt, lb })
45 }
46
47 pub fn create_account(
48 &self, username: &str, api_url: &str, welcome_doc: bool,
49 ) -> LbResult<Account> {
50 self.rt
51 .block_on(self.lb.create_account(username, api_url, welcome_doc))
52 }
53
54 pub fn import_account(&self, key: &str, api_url: Option<&str>) -> LbResult<Account> {
55 self.rt.block_on(self.lb.import_account(key, api_url))
56 }
57
58 pub fn export_account_private_key(&self) -> LbResult<String> {
59 self.lb.export_account_private_key_v1()
60 }
61
62 pub fn export_account_phrase(&self) -> LbResult<String> {
63 self.lb.export_account_phrase()
64 }
65
66 pub fn export_account_qr(&self) -> LbResult<Vec<u8>> {
67 self.lb.export_account_qr()
68 }
69
70 pub fn get_account(&self) -> LbResult<&Account> {
71 self.lb.get_account()
72 }
73
74 pub fn get_config(&self) -> Config {
75 self.lb.config.clone()
76 }
77
78 pub fn create_file(&self, name: &str, parent: &Uuid, file_type: FileType) -> LbResult<File> {
79 self.rt
80 .block_on(self.lb.create_file(name, parent, file_type))
81 }
82
83 pub fn safe_write(
84 &self, id: Uuid, old_hmac: Option<DocumentHmac>, content: Vec<u8>,
85 ) -> LbResult<DocumentHmac> {
86 self.rt.block_on(self.lb.safe_write(id, old_hmac, content))
87 }
88
89 pub fn write_document(&self, id: Uuid, content: &[u8]) -> LbResult<()> {
90 self.rt.block_on(self.lb.write_document(id, content))
91 }
92
93 pub fn get_root(&self) -> LbResult<File> {
94 self.rt.block_on(self.lb.root())
95 }
96
97 pub fn get_children(&self, id: &Uuid) -> LbResult<Vec<File>> {
98 self.rt.block_on(self.lb.get_children(id))
99 }
100
101 pub fn get_and_get_children_recursively(&self, id: &Uuid) -> LbResult<Vec<File>> {
102 self.rt
103 .block_on(self.lb.get_and_get_children_recursively(id))
104 }
105
106 pub fn get_file_by_id(&self, id: Uuid) -> LbResult<File> {
107 self.rt.block_on(self.lb.get_file_by_id(id))
108 }
109
110 pub fn delete_file(&self, id: &Uuid) -> LbResult<()> {
111 self.rt.block_on(self.lb.delete(id))
112 }
113
114 pub fn read_document(&self, id: Uuid, user_activity: bool) -> LbResult<DecryptedDocument> {
115 self.rt.block_on(self.lb.read_document(id, user_activity))
116 }
117
118 pub fn read_document_with_hmac(
119 &self, id: Uuid, user_activity: bool,
120 ) -> LbResult<(Option<DocumentHmac>, DecryptedDocument)> {
121 self.rt
122 .block_on(self.lb.read_document_with_hmac(id, user_activity))
123 }
124
125 pub fn list_metadatas(&self) -> LbResult<Vec<File>> {
126 self.rt.block_on(self.lb.list_metadatas())
127 }
128
129 pub fn rename_file(&self, id: &Uuid, new_name: &str) -> LbResult<()> {
130 self.rt.block_on(self.lb.rename_file(id, new_name))
131 }
132
133 pub fn move_file(&self, id: &Uuid, new_parent: &Uuid) -> LbResult<()> {
134 self.rt.block_on(self.lb.move_file(id, new_parent))
135 }
136
137 pub fn share_file(&self, id: Uuid, username: &str, mode: ShareMode) -> LbResult<()> {
138 self.rt.block_on(self.lb.share_file(id, username, mode))
139 }
140
141 pub fn get_pending_shares(&self) -> LbResult<Vec<File>> {
142 self.rt.block_on(self.lb.get_pending_shares())
143 }
144
145 pub fn delete_pending_share(&self, id: &Uuid) -> LbResult<()> {
146 self.rt.block_on(async { self.lb.reject_share(id).await })
147 }
148
149 pub fn create_link_at_path(&self, path_and_name: &str, target_id: Uuid) -> LbResult<File> {
150 self.rt
151 .block_on(self.lb.create_link_at_path(path_and_name, target_id))
152 }
153
154 pub fn create_at_path(&self, path_and_name: &str) -> LbResult<File> {
155 self.rt.block_on(self.lb.create_at_path(path_and_name))
156 }
157
158 pub fn get_by_path(&self, path: &str) -> LbResult<File> {
159 self.rt.block_on(self.lb.get_by_path(path))
160 }
161
162 pub fn get_path_by_id(&self, id: Uuid) -> LbResult<String> {
163 self.rt.block_on(self.lb.get_path_by_id(id))
164 }
165
166 pub fn list_paths(&self, filter: Option<Filter>) -> LbResult<Vec<String>> {
167 self.rt.block_on(self.lb.list_paths(filter))
168 }
169
170 pub fn get_local_changes(&self) -> LbResult<Vec<Uuid>> {
171 Ok(self.rt.block_on(self.lb.local_changes()))
172 }
173
174 pub fn calculate_work(&self) -> LbResult<SyncStatus> {
175 self.rt.block_on(self.lb.calculate_work())
176 }
177
178 pub fn sync(&self, f: Option<Box<dyn Fn(SyncProgress) + Send>>) -> LbResult<SyncStatus> {
179 self.rt.block_on(self.lb.sync(f))
180 }
181
182 pub fn get_last_synced(&self) -> LbResult<i64> {
183 self.rt.block_on(async {
184 let tx = self.lb.ro_tx().await;
185 let db = tx.db();
186 Ok(db.last_synced.get().copied().unwrap_or(0))
187 })
188 }
189
190 pub fn get_last_synced_human_string(&self) -> LbResult<String> {
191 self.rt.block_on(self.lb.get_last_synced_human())
192 }
193
194 pub fn get_timestamp_human_string(&self, timestamp: i64) -> String {
195 self.lb.get_timestamp_human_string(timestamp)
196 }
197
198 pub fn suggested_docs(&self, settings: RankingWeights) -> LbResult<Vec<Uuid>> {
199 self.rt.block_on(self.lb.suggested_docs(settings))
200 }
201
202 pub fn clear_suggested(&self) -> LbResult<()> {
203 self.rt.block_on(self.lb.clear_suggested())
204 }
205
206 pub fn clear_suggested_id(&self, target_id: Uuid) -> LbResult<()> {
207 self.rt.block_on(self.lb.clear_suggested_id(target_id))
208 }
209
210 pub fn get_usage(&self) -> LbResult<UsageMetrics> {
212 self.rt.block_on(self.lb.get_usage())
213 }
214
215 pub fn get_uncompressed_usage_breakdown(&self) -> LbResult<HashMap<Uuid, usize>> {
216 self.rt.block_on(self.lb.get_uncompressed_usage_breakdown())
217 }
218
219 pub fn get_uncompressed_usage(&self) -> LbResult<UsageItemMetric> {
220 self.rt.block_on(self.lb.get_uncompressed_usage())
221 }
222
223 pub fn import_files<F: Fn(ImportStatus)>(
224 &self, sources: &[PathBuf], dest: Uuid, update_status: &F,
225 ) -> LbResult<()> {
226 self.rt
227 .block_on(self.lb.import_files(sources, dest, update_status))
228 }
229
230 pub fn export_files(
231 &self, id: Uuid, dest: PathBuf, edit: bool,
232 export_progress: &Option<Box<dyn Fn(ExportFileInfo)>>,
233 ) -> LbResult<()> {
234 self.rt
235 .block_on(self.lb.export_file(id, dest, edit, export_progress))
236 }
237
238 pub fn search_file_paths(&self, input: &str) -> LbResult<Vec<SearchResult>> {
239 self.rt
240 .block_on(async { self.lb.search(input, SearchConfig::Paths).await })
241 }
242
243 pub fn search(&self, input: &str, cfg: SearchConfig) -> LbResult<Vec<SearchResult>> {
244 self.rt.block_on(self.lb.search(input, cfg))
245 }
246
247 pub fn validate(&self) -> LbResult<Vec<Warning>> {
248 self.rt.block_on(self.lb.test_repo_integrity())
249 }
250
251 pub fn upgrade_account_stripe(&self, account_tier: StripeAccountTier) -> LbResult<()> {
252 self.rt
253 .block_on(self.lb.upgrade_account_stripe(account_tier))
254 }
255
256 pub fn upgrade_account_google_play(
257 &self, purchase_token: &str, account_id: &str,
258 ) -> LbResult<()> {
259 self.rt.block_on(
260 self.lb
261 .upgrade_account_google_play(purchase_token, account_id),
262 )
263 }
264
265 pub fn upgrade_account_app_store(
266 &self, original_transaction_id: String, app_account_token: String,
267 ) -> LbResult<()> {
268 self.rt.block_on(
269 self.lb
270 .upgrade_account_app_store(original_transaction_id, app_account_token),
271 )
272 }
273
274 pub fn cancel_subscription(&self) -> LbResult<()> {
275 self.rt.block_on(self.lb.cancel_subscription())
276 }
277
278 pub fn get_subscription_info(&self) -> LbResult<Option<SubscriptionInfo>> {
279 self.rt.block_on(self.lb.get_subscription_info())
280 }
281
282 pub fn delete_account(&self) -> LbResult<()> {
283 self.rt.block_on(self.lb.delete_account())
284 }
285
286 pub fn admin_disappear_account(&self, username: &str) -> LbResult<()> {
287 self.rt.block_on(self.lb.disappear_account(username))
288 }
289
290 pub fn admin_disappear_file(&self, id: Uuid) -> LbResult<()> {
291 self.rt.block_on(self.lb.disappear_file(id))
292 }
293
294 pub fn admin_list_users(&self, filter: Option<AccountFilter>) -> LbResult<Vec<Username>> {
295 self.rt.block_on(self.lb.list_users(filter))
296 }
297
298 pub fn admin_get_account_info(&self, identifier: AccountIdentifier) -> LbResult<AccountInfo> {
299 self.rt.block_on(self.lb.get_account_info(identifier))
300 }
301
302 pub fn admin_validate_account(&self, username: &str) -> LbResult<AdminValidateAccount> {
303 self.rt.block_on(self.lb.validate_account(username))
304 }
305
306 pub fn admin_validate_server(&self) -> LbResult<AdminValidateServer> {
307 self.rt.block_on(self.lb.validate_server())
308 }
309
310 pub fn admin_file_info(&self, id: Uuid) -> LbResult<AdminFileInfoResponse> {
311 self.rt.block_on(self.lb.file_info(id))
312 }
313
314 pub fn admin_rebuild_index(&self, index: ServerIndex) -> LbResult<()> {
315 self.rt.block_on(self.lb.rebuild_index(index))
316 }
317
318 pub fn admin_set_user_tier(&self, username: &str, info: AdminSetUserTierInfo) -> LbResult<()> {
319 self.rt.block_on(self.lb.set_user_tier(username, info))
320 }
321
322 pub fn subscribe(&self) -> Receiver<Event> {
323 self.lb.subscribe()
324 }
325
326 pub fn status(&self) -> Status {
327 self.rt.block_on(self.lb.status())
328 }
329
330 pub fn debug_info(&self, os_info: String) -> String {
331 self.rt
332 .block_on(self.lb.debug_info(os_info))
333 .unwrap_or_else(|e| format!("failed to produce debug info: {:?}", e.to_string()))
334 }
335}