1 /*
2  * Copyright (c) 2023 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 use crate::c_adapter::basic_rust_types::{HashMapCffi, VectorCffi};
17 use crate::c_adapter::cloud_ext_types::*;
18 use crate::c_adapter::*;
19 use crate::ipc_conn;
20 use crate::service_impl::error::SyncError;
21 use crate::service_impl::{asset_loader, cloud_db, cloud_service};
22 use std::ffi::{c_int, c_longlong, c_uchar, c_uint};
23 use std::io::ErrorKind;
24 use std::ptr::null_mut;
25 
26 /// CloudAssetLoader pointer passed to C side.
27 /// The lifetime 'static is only used to pass compiler check.
28 pub type OhCloudExtCloudAssetLoader = SafeCffiWrapper<asset_loader::CloudAssetLoader<'static>>;
29 /// CloudDatabase pointer passed to C side.
30 pub type OhCloudExtCloudDatabase = SafeCffiWrapper<cloud_db::CloudDatabase>;
31 /// CloudSync pointer passed to C side.
32 pub type OhCloudExtCloudSync = SafeCffiWrapper<cloud_service::CloudSync>;
33 
map_ipc_err(e: &ipc_conn::Error) -> c_int34 fn map_ipc_err(e: &ipc_conn::Error) -> c_int {
35     match e {
36         ipc_conn::Error::CreateMsgParcelFailed
37         | ipc_conn::Error::GetProxyObjectFailed
38         | ipc_conn::Error::SendRequestFailed => ERRNO_IPC_CONN_ERROR,
39         ipc_conn::Error::ReadMsgParcelFailed | ipc_conn::Error::WriteMsgParcelFailed => {
40             ERRNO_IPC_RW_ERROR
41         }
42         ipc_conn::Error::InvalidCloudStatus => ERRNO_CLOUD_INVALID_STATUS,
43         ipc_conn::Error::InvalidSpaceStatus => ERRNO_NO_SPACE_FOR_ASSET,
44         ipc_conn::Error::UnlockFailed => ERRNO_UNLOCKED,
45         ipc_conn::Error::DownloadFailed => ERRNO_ASSET_DOWNLOAD_FAILURE,
46         ipc_conn::Error::UploadFailed => ERRNO_ASSET_UPLOAD_FAILURE,
47         ipc_conn::Error::InvalidFieldType => ERRNO_INVALID_INPUT_TYPE,
48         ipc_conn::Error::NetworkError => ERRNO_NETWORK_ERROR,
49         ipc_conn::Error::CloudDisabled => ERRNO_CLOUD_DISABLE,
50         ipc_conn::Error::LockedByOthers => ERRNO_LOCKED_BY_OTHERS,
51         ipc_conn::Error::RecordLimitExceeded => ERRNO_RECORD_LIMIT_EXCEEDED,
52         ipc_conn::Error::NoSpaceForAsset => ERRNO_NO_SPACE_FOR_ASSET,
53         ipc_conn::Error::UnknownError => ERRNO_UNKNOWN,
54         ipc_conn::Error::Success => ERRNO_SUCCESS,
55     }
56 }
57 
map_single_sync_err(e: &SyncError) -> c_int58 pub(crate) fn map_single_sync_err(e: &SyncError) -> c_int {
59     match e {
60         SyncError::Unknown => ERRNO_UNKNOWN,
61         SyncError::NoSuchTableInDb => ERRNO_NO_SUCH_TABLE_IN_DB,
62         SyncError::NotAnAsset => ERRNO_INVALID_INPUT_TYPE,
63         SyncError::AssetDownloadFailure => ERRNO_ASSET_DOWNLOAD_FAILURE,
64         SyncError::AssetUploadFailure => ERRNO_ASSET_UPLOAD_FAILURE,
65         SyncError::SessionUnlocked => ERRNO_UNLOCKED,
66         SyncError::Unsupported => ERRNO_UNSUPPORTED,
67         SyncError::IPCError(ipc_e) => map_ipc_err(ipc_e),
68         // Not deal here to involve vec in every branch
69         SyncError::IPCErrors(_) => ERRNO_IPC_ERRORS,
70         SyncError::IO(io_e) => match io_e.kind() {
71             ErrorKind::ConnectionRefused
72             | ErrorKind::ConnectionReset
73             | ErrorKind::ConnectionAborted
74             | ErrorKind::NotConnected
75             | ErrorKind::AddrInUse
76             | ErrorKind::AddrNotAvailable
77             | ErrorKind::BrokenPipe
78             | ErrorKind::UnexpectedEof => ERRNO_NETWORK_ERROR,
79             ErrorKind::OutOfMemory => ERRNO_NO_SPACE_FOR_ASSET,
80             _ => ERRNO_OTHER_IO_ERROR,
81         },
82     }
83 }
84 
85 /// Create an CloudAssetLoader instance by bundle name and database pointer. This function only borrows
86 /// database, so this pointer won't be taken by CloudAssetLoader. Users should free it if the database
87 /// is no longer in need.
88 #[no_mangle]
OhCloudExtCloudAssetLoaderNew( user_id: c_int, bundle_name: *const c_uchar, name_len: c_uint, db: *const OhCloudExtDatabase, ) -> *mut OhCloudExtCloudAssetLoader89 pub unsafe extern "C" fn OhCloudExtCloudAssetLoaderNew(
90     user_id: c_int,
91     bundle_name: *const c_uchar,
92     name_len: c_uint,
93     db: *const OhCloudExtDatabase,
94 ) -> *mut OhCloudExtCloudAssetLoader {
95     if bundle_name.is_null() || db.is_null() {
96         return null_mut();
97     }
98 
99     let bundle_name_bytes = &*slice_from_raw_parts(bundle_name, name_len as usize);
100     let bundle_name = std::str::from_utf8_unchecked(bundle_name_bytes);
101     let db = match OhCloudExtDatabase::get_inner_ref(db, SafetyCheckId::Database) {
102         None => return null_mut(),
103         Some(v) => v,
104     };
105 
106     match asset_loader::CloudAssetLoader::new(user_id, bundle_name, db) {
107         Ok(loader) => {
108             OhCloudExtCloudAssetLoader::new(loader, SafetyCheckId::CloudAssetLoader).into_ptr()
109         }
110         Err(_) => null_mut(),
111     }
112 }
113 
114 /// Information needed when upload or download assets through CloudAssetLoader.
115 #[repr(C)]
116 pub struct OhCloudExtUpDownloadInfo {
117     table_name: *const c_uchar,
118     table_name_len: c_uint,
119     gid: *const c_uchar,
120     gid_len: c_uint,
121     prefix: *const c_uchar,
122     prefix_len: c_uint,
123 }
124 
125 /// Upload assets, with table name, gid, and prefix. This function only mutably borrows
126 /// assets, so this pointer won't be taken by CloudAssetLoader. Users should free it if the hashmap of
127 /// assets is no longer in need.
128 ///
129 /// Assets should be in type HashMap<String, Value>.
130 #[no_mangle]
OhCloudExtCloudAssetLoaderUpload( loader: *mut OhCloudExtCloudAssetLoader, info: *const OhCloudExtUpDownloadInfo, assets: *mut OhCloudExtVector, ) -> c_int131 pub unsafe extern "C" fn OhCloudExtCloudAssetLoaderUpload(
132     loader: *mut OhCloudExtCloudAssetLoader,
133     info: *const OhCloudExtUpDownloadInfo,
134     assets: *mut OhCloudExtVector,
135 ) -> c_int {
136     if loader.is_null() || info.is_null() || assets.is_null() {
137         return ERRNO_NULLPTR;
138     }
139     let info = &*info;
140     let loader =
141         match OhCloudExtCloudAssetLoader::get_inner_mut(loader, SafetyCheckId::CloudAssetLoader) {
142             None => return ERRNO_WRONG_TYPE,
143             Some(v) => v,
144         };
145     let table_name_bytes = &*slice_from_raw_parts(info.table_name, info.table_name_len as usize);
146     let table_name = std::str::from_utf8_unchecked(table_name_bytes);
147 
148     let gid_bytes = &*slice_from_raw_parts(info.gid, info.gid_len as usize);
149     let gid = std::str::from_utf8_unchecked(gid_bytes);
150 
151     let prefix_bytes = &*slice_from_raw_parts(info.prefix, info.prefix_len as usize);
152     let prefix = std::str::from_utf8_unchecked(prefix_bytes);
153 
154     let assets = match OhCloudExtVector::get_inner_ref(assets, SafetyCheckId::Vector) {
155         None => return ERRNO_WRONG_TYPE,
156         Some(v) => v,
157     };
158     let assets = match assets {
159         VectorCffi::CloudAsset(re) => re,
160         _ => return ERRNO_INVALID_INPUT_TYPE,
161     };
162     match loader.upload(table_name, gid, prefix, assets) {
163         Ok(_) => ERRNO_SUCCESS,
164         Err(e) => map_single_sync_err(&e),
165     }
166 }
167 
168 /// Download assets, with table name, gid, and prefix. This function only mutably borrows
169 /// assets, so this pointer won't be taken by CloudAssetLoader. Users should free it if the hashmap of
170 /// assets is no longer in need.
171 ///
172 /// Assets should be in type HashMap<String, Value>.
173 #[no_mangle]
OhCloudExtCloudAssetLoaderDownload( loader: *mut OhCloudExtCloudAssetLoader, info: *const OhCloudExtUpDownloadInfo, assets: *mut OhCloudExtVector, ) -> c_int174 pub unsafe extern "C" fn OhCloudExtCloudAssetLoaderDownload(
175     loader: *mut OhCloudExtCloudAssetLoader,
176     info: *const OhCloudExtUpDownloadInfo,
177     assets: *mut OhCloudExtVector,
178 ) -> c_int {
179     if loader.is_null() || info.is_null() || assets.is_null() {
180         return ERRNO_NULLPTR;
181     }
182     let info = &*info;
183     let loader =
184         match OhCloudExtCloudAssetLoader::get_inner_mut(loader, SafetyCheckId::CloudAssetLoader) {
185             None => return ERRNO_WRONG_TYPE,
186             Some(v) => v,
187         };
188     let table_name_bytes = &*slice_from_raw_parts(info.table_name, info.table_name_len as usize);
189     let table_name = std::str::from_utf8_unchecked(table_name_bytes);
190 
191     let gid_bytes = &*slice_from_raw_parts(info.gid, info.gid_len as usize);
192     let gid = std::str::from_utf8_unchecked(gid_bytes);
193 
194     let prefix_bytes = &*slice_from_raw_parts(info.prefix, info.prefix_len as usize);
195     let prefix = std::str::from_utf8_unchecked(prefix_bytes);
196 
197     let assets = match OhCloudExtVector::get_inner_ref(assets, SafetyCheckId::Vector) {
198         None => return ERRNO_WRONG_TYPE,
199         Some(v) => v,
200     };
201 
202     let assets = match assets {
203         VectorCffi::CloudAsset(re) => re,
204         _ => return ERRNO_INVALID_INPUT_TYPE,
205     };
206 
207     match loader.download(table_name, gid, prefix, assets) {
208         Ok(_) => ERRNO_SUCCESS,
209         Err(e) => map_single_sync_err(&e),
210     }
211 }
212 
213 /// Remove local asset. This function will use file system and remove a local file. This function
214 /// only mutably borrows asset, so this pointer won't be taken by CloudAssetLoader. Users should free
215 /// it if the asset is no longer in need.
216 #[no_mangle]
OhCloudExtCloudAssetLoaderRemoveLocalAssets( asset: *const OhCloudExtCloudAsset, ) -> c_int217 pub unsafe extern "C" fn OhCloudExtCloudAssetLoaderRemoveLocalAssets(
218     asset: *const OhCloudExtCloudAsset,
219 ) -> c_int {
220     if asset.is_null() {
221         return ERRNO_NULLPTR;
222     }
223     let asset = match OhCloudExtCloudAsset::get_inner_ref(asset, SafetyCheckId::CloudAsset) {
224         None => return ERRNO_WRONG_TYPE,
225         Some(v) => v,
226     };
227     match asset_loader::CloudAssetLoader::remove_local_assets(asset) {
228         Ok(()) => ERRNO_SUCCESS,
229         Err(e) => map_single_sync_err(&e),
230     }
231 }
232 
233 /// Free an CloudAssetLoader pointer.
234 #[no_mangle]
OhCloudExtCloudAssetLoaderFree(src: *mut OhCloudExtCloudAssetLoader)235 pub unsafe extern "C" fn OhCloudExtCloudAssetLoaderFree(src: *mut OhCloudExtCloudAssetLoader) {
236     let _ = OhCloudExtCloudAssetLoader::from_ptr(src, SafetyCheckId::CloudAssetLoader);
237 }
238 
239 /// Initialize a CloudDatabase instance with bundle name and database. The database passed in will
240 /// be stored in CloudDatabase, so its management will be transferred and it should not be freed
241 /// by the users.
242 #[no_mangle]
OhCloudExtCloudDbNew( user_id: c_int, bundle_name: *const c_uchar, name_len: c_uint, database: *mut OhCloudExtDatabase, ) -> *mut OhCloudExtCloudDatabase243 pub unsafe extern "C" fn OhCloudExtCloudDbNew(
244     user_id: c_int,
245     bundle_name: *const c_uchar,
246     name_len: c_uint,
247     database: *mut OhCloudExtDatabase,
248 ) -> *mut OhCloudExtCloudDatabase {
249     if database.is_null() || bundle_name.is_null() {
250         return null_mut();
251     }
252     let database = match OhCloudExtDatabase::get_inner(database, SafetyCheckId::Database) {
253         None => return null_mut(),
254         Some(v) => v,
255     };
256 
257     let bundle_name_bytes = &*slice_from_raw_parts(bundle_name, name_len as usize);
258     let bundle_name = std::str::from_utf8_unchecked(bundle_name_bytes);
259 
260     if let Ok(db) = cloud_db::CloudDatabase::new(user_id, bundle_name, database) {
261         let ptr = OhCloudExtCloudDatabase::new(db, SafetyCheckId::CloudDatabase).into_ptr();
262         return ptr;
263     }
264     null_mut()
265 }
266 
267 /// Sql that will passed to CloudDatabase and executed.
268 #[repr(C)]
269 pub struct OhCloudExtSql {
270     table: *const c_uchar,
271     table_len: c_uint,
272     sql: *const c_uchar,
273     sql_len: c_uint,
274 }
275 
276 /// Execute sql on a CloudDatabase.
277 #[no_mangle]
OhCloudExtCloudDbExecuteSql( cdb: *mut OhCloudExtCloudDatabase, sql: *const OhCloudExtSql, extend: *mut OhCloudExtHashMap, ) -> c_int278 pub unsafe extern "C" fn OhCloudExtCloudDbExecuteSql(
279     cdb: *mut OhCloudExtCloudDatabase,
280     sql: *const OhCloudExtSql,
281     extend: *mut OhCloudExtHashMap,
282 ) -> c_int {
283     if cdb.is_null() || sql.is_null() || extend.is_null() {
284         return ERRNO_NULLPTR;
285     }
286     let sql = &*sql;
287     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
288         None => return ERRNO_WRONG_TYPE,
289         Some(v) => v,
290     };
291 
292     let table_bytes = &*slice_from_raw_parts(sql.table, sql.table_len as usize);
293     let table = std::str::from_utf8_unchecked(table_bytes);
294 
295     let sql_bytes = &*slice_from_raw_parts(sql.sql, sql.sql_len as usize);
296     let sql = std::str::from_utf8_unchecked(sql_bytes);
297 
298     let extend = match OhCloudExtHashMap::get_inner_mut(extend, SafetyCheckId::HashMap) {
299         None => return ERRNO_WRONG_TYPE,
300         Some(v) => v,
301     };
302     let extend = &mut (*match extend {
303         HashMapCffi::Value(re) => re,
304         _ => return ERRNO_INVALID_INPUT_TYPE,
305     });
306     match cdb.execute(table, sql, extend) {
307         Ok(()) => ERRNO_SUCCESS,
308         Err(e) => map_single_sync_err(&e),
309     }
310 }
311 
312 /// Insert records into a CloudDatabase, with table name, and two Vector of HashMap<String, Value>.
313 /// Those two vectors passed in are only borrowed, and they should be freed by `VectorFree` if they
314 /// are no longer in use.
315 #[no_mangle]
OhCloudExtCloudDbBatchInsert( cdb: *mut OhCloudExtCloudDatabase, table: *const c_uchar, table_len: c_uint, value: *const OhCloudExtVector, extend: *mut OhCloudExtVector, ) -> c_int316 pub unsafe extern "C" fn OhCloudExtCloudDbBatchInsert(
317     cdb: *mut OhCloudExtCloudDatabase,
318     table: *const c_uchar,
319     table_len: c_uint,
320     value: *const OhCloudExtVector,
321     extend: *mut OhCloudExtVector,
322 ) -> c_int {
323     if cdb.is_null() || table.is_null() || value.is_null() || extend.is_null() {
324         return ERRNO_NULLPTR;
325     }
326     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
327         None => return ERRNO_WRONG_TYPE,
328         Some(v) => v,
329     };
330 
331     let table_bytes = &*slice_from_raw_parts(table, table_len as usize);
332     let table = std::str::from_utf8_unchecked(table_bytes);
333 
334     let value = match OhCloudExtVector::get_inner_ref(value, SafetyCheckId::Vector) {
335         None => return ERRNO_WRONG_TYPE,
336         Some(v) => v,
337     };
338     let value_vec = match value {
339         VectorCffi::HashMapValue(val) => val,
340         _ => return ERRNO_INVALID_INPUT_TYPE,
341     };
342     let extend = match OhCloudExtVector::get_inner_mut(extend, SafetyCheckId::Vector) {
343         None => return ERRNO_WRONG_TYPE,
344         Some(v) => v,
345     };
346     let extend_vec = match extend {
347         VectorCffi::HashMapValue(val) => val,
348         _ => return ERRNO_INVALID_INPUT_TYPE,
349     };
350 
351     match cdb.batch_insert(table, value_vec, extend_vec) {
352         Ok(_) => ERRNO_SUCCESS,
353         Err(e) => map_single_sync_err(&e),
354     }
355 }
356 
357 /// Update records in a CloudDatabase, with table name, and two Vector of HashMap<String, Value>.
358 /// Those two vectors passed in are only borrowed, and they should be freed by `VectorFree` if they
359 /// are no longer in use.
360 #[no_mangle]
OhCloudExtCloudDbBatchUpdate( cdb: *mut OhCloudExtCloudDatabase, table: *const c_uchar, table_len: c_uint, value: *const OhCloudExtVector, extend: *mut OhCloudExtVector, ) -> c_int361 pub unsafe extern "C" fn OhCloudExtCloudDbBatchUpdate(
362     cdb: *mut OhCloudExtCloudDatabase,
363     table: *const c_uchar,
364     table_len: c_uint,
365     value: *const OhCloudExtVector,
366     extend: *mut OhCloudExtVector,
367 ) -> c_int {
368     if cdb.is_null() || table.is_null() || value.is_null() || extend.is_null() {
369         return ERRNO_NULLPTR;
370     }
371     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
372         None => return ERRNO_WRONG_TYPE,
373         Some(v) => v,
374     };
375     let table_bytes = &*slice_from_raw_parts(table, table_len as usize);
376     let table = std::str::from_utf8_unchecked(table_bytes);
377 
378     let value = match OhCloudExtVector::get_inner_ref(value, SafetyCheckId::Vector) {
379         None => return ERRNO_WRONG_TYPE,
380         Some(v) => v,
381     };
382     let value_vec = match value {
383         VectorCffi::HashMapValue(val) => val,
384         _ => return ERRNO_INVALID_INPUT_TYPE,
385     };
386     let extend = match OhCloudExtVector::get_inner_mut(extend, SafetyCheckId::Vector) {
387         None => return ERRNO_WRONG_TYPE,
388         Some(v) => v,
389     };
390     let extend_vec = match extend {
391         VectorCffi::HashMapValue(val) => val,
392         _ => return ERRNO_INVALID_INPUT_TYPE,
393     };
394 
395     match cdb.batch_update(table, value_vec, extend_vec) {
396         Ok(_) => ERRNO_SUCCESS,
397         Err(e) => map_single_sync_err(&e),
398     }
399 }
400 
401 /// Delete records from a CloudDatabase, with table name, and a Vector of HashMap<String, Value>.
402 /// The vector passed in are only borrowed, and it should be freed by `VectorFree` if it
403 /// is no longer in use.
404 #[no_mangle]
OhCloudExtCloudDbBatchDelete( cdb: *mut OhCloudExtCloudDatabase, table: *const c_uchar, table_len: c_uint, extend: *mut OhCloudExtVector, ) -> c_int405 pub unsafe extern "C" fn OhCloudExtCloudDbBatchDelete(
406     cdb: *mut OhCloudExtCloudDatabase,
407     table: *const c_uchar,
408     table_len: c_uint,
409     extend: *mut OhCloudExtVector,
410 ) -> c_int {
411     if cdb.is_null() || table.is_null() || extend.is_null() {
412         return ERRNO_NULLPTR;
413     }
414     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
415         None => return ERRNO_WRONG_TYPE,
416         Some(v) => v,
417     };
418     let table_bytes = &*slice_from_raw_parts(table, table_len as usize);
419     let table = std::str::from_utf8_unchecked(table_bytes);
420 
421     let extend = match OhCloudExtVector::get_inner_mut(extend, SafetyCheckId::Vector) {
422         None => return ERRNO_WRONG_TYPE,
423         Some(v) => v,
424     };
425     let extend_vec = match extend {
426         VectorCffi::HashMapValue(val) => val,
427         _ => return ERRNO_INVALID_INPUT_TYPE,
428     };
429 
430     match cdb.batch_delete(table, extend_vec) {
431         Ok(_) => ERRNO_SUCCESS,
432         Err(e) => map_single_sync_err(&e),
433     }
434 }
435 
436 /// Query info that will passed to CloudDatabase.
437 #[repr(C)]
438 pub struct OhCloudExtQueryInfo {
439     table: *const c_uchar,
440     table_len: c_uint,
441     cursor: *const c_uchar,
442     cursor_len: c_uint,
443 }
444 
445 /// Query records from a CloudDatabase, with table name and cursor. Return a CloudData pointer, which
446 /// should be freed by `CloudDataFree` if it's no longer in use.
447 #[no_mangle]
OhCloudExtCloudDbBatchQuery( cdb: *mut OhCloudExtCloudDatabase, info: *const OhCloudExtQueryInfo, out: *mut *const OhCloudExtCloudDbData, ) -> c_int448 pub unsafe extern "C" fn OhCloudExtCloudDbBatchQuery(
449     cdb: *mut OhCloudExtCloudDatabase,
450     info: *const OhCloudExtQueryInfo,
451     out: *mut *const OhCloudExtCloudDbData,
452 ) -> c_int {
453     if cdb.is_null() || info.is_null() || out.is_null() {
454         return -1;
455     }
456     let info = &*info;
457     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
458         None => return ERRNO_WRONG_TYPE,
459         Some(v) => v,
460     };
461 
462     let table_bytes = &*slice_from_raw_parts(info.table, info.table_len as usize);
463     let table = std::str::from_utf8_unchecked(table_bytes);
464 
465     let cursor_bytes = &*slice_from_raw_parts(info.cursor, info.cursor_len as usize);
466     let cursor = std::str::from_utf8_unchecked(cursor_bytes);
467 
468     match cdb.batch_query(table, cursor) {
469         Ok(cloud_data) => {
470             *out = OhCloudExtCloudDbData::new(cloud_data, SafetyCheckId::CloudDbData).into_ptr();
471             ERRNO_SUCCESS
472         }
473         Err(e) => map_single_sync_err(&e),
474     }
475 }
476 
477 /// Lock a CloudDatabase. Return expire time.
478 #[no_mangle]
OhCloudExtCloudDbLock( cdb: *mut OhCloudExtCloudDatabase, expire: *mut c_int, ) -> c_int479 pub unsafe extern "C" fn OhCloudExtCloudDbLock(
480     cdb: *mut OhCloudExtCloudDatabase,
481     expire: *mut c_int,
482 ) -> c_int {
483     if cdb.is_null() || expire.is_null() {
484         return ERRNO_NULLPTR;
485     }
486     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
487         None => return ERRNO_WRONG_TYPE,
488         Some(v) => v,
489     };
490     match cdb.lock() {
491         Ok(time) => {
492             *expire = time;
493             ERRNO_SUCCESS
494         }
495         Err(e) => map_single_sync_err(&e),
496     }
497 }
498 
499 /// Unlock a CloudDatabase.
500 #[no_mangle]
OhCloudExtCloudDbUnlock(cdb: *mut OhCloudExtCloudDatabase) -> c_int501 pub unsafe extern "C" fn OhCloudExtCloudDbUnlock(cdb: *mut OhCloudExtCloudDatabase) -> c_int {
502     if cdb.is_null() {
503         return ERRNO_NULLPTR;
504     }
505     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
506         None => return ERRNO_WRONG_TYPE,
507         Some(v) => v,
508     };
509     match cdb.unlock() {
510         Ok(()) => ERRNO_SUCCESS,
511         Err(e) => map_single_sync_err(&e),
512     }
513 }
514 
515 /// Heartbeat function of a CloudDatabase. Extend the current locking session.
516 #[no_mangle]
OhCloudExtCloudDbHeartbeat(cdb: *mut OhCloudExtCloudDatabase) -> c_int517 pub unsafe extern "C" fn OhCloudExtCloudDbHeartbeat(cdb: *mut OhCloudExtCloudDatabase) -> c_int {
518     if cdb.is_null() {
519         return ERRNO_NULLPTR;
520     }
521     let cdb = match OhCloudExtCloudDatabase::get_inner_mut(cdb, SafetyCheckId::CloudDatabase) {
522         None => return ERRNO_WRONG_TYPE,
523         Some(v) => v,
524     };
525     match cdb.heartbeat() {
526         Ok(()) => ERRNO_SUCCESS,
527         Err(e) => map_single_sync_err(&e),
528     }
529 }
530 
531 /// Free a CloudDatabase pointer.
532 #[no_mangle]
OhCloudExtCloudDbFree(cdb: *mut OhCloudExtCloudDatabase)533 pub unsafe extern "C" fn OhCloudExtCloudDbFree(cdb: *mut OhCloudExtCloudDatabase) {
534     let _ = OhCloudExtCloudDatabase::from_ptr(cdb, SafetyCheckId::CloudDatabase);
535 }
536 
537 /// Create a CloudSync instance by user id.
538 #[no_mangle]
OhCloudExtCloudSyncNew(user_id: c_int) -> *mut OhCloudExtCloudSync539 pub unsafe extern "C" fn OhCloudExtCloudSyncNew(user_id: c_int) -> *mut OhCloudExtCloudSync {
540     if let Ok(service) = cloud_service::CloudSync::new(user_id) {
541         return OhCloudExtCloudSync::new(service, SafetyCheckId::CloudSync).into_ptr();
542     }
543     null_mut()
544 }
545 
546 /// Get service info from a CloudSync pointer. Return a CloudInfo pointer, which
547 /// should be freed by `CloudInfoFree` if it's no longer in use.
548 #[no_mangle]
OhCloudExtCloudSyncGetServiceInfo( server: *mut OhCloudExtCloudSync, info: *mut *const OhCloudExtCloudInfo, ) -> c_int549 pub unsafe extern "C" fn OhCloudExtCloudSyncGetServiceInfo(
550     server: *mut OhCloudExtCloudSync,
551     info: *mut *const OhCloudExtCloudInfo,
552 ) -> c_int {
553     if server.is_null() || info.is_null() {
554         return ERRNO_NULLPTR;
555     }
556     let cloud_server = match OhCloudExtCloudSync::get_inner_mut(server, SafetyCheckId::CloudSync) {
557         None => return ERRNO_WRONG_TYPE,
558         Some(v) => v,
559     };
560     match cloud_server.get_service_info() {
561         Ok(cloud_info) => {
562             *info = OhCloudExtCloudInfo::new(cloud_info, SafetyCheckId::CloudInfo).into_ptr();
563             ERRNO_SUCCESS
564         }
565         Err(e) => map_single_sync_err(&e),
566     }
567 }
568 
569 /// Get app schema from a CloudSync pointer, with a bundle name. Return a SchemaMeta pointer, which
570 /// should be freed by `SchemaMetaFree` if it's no longer in use.
571 #[no_mangle]
OhCloudExtCloudSyncGetAppSchema( server: *mut OhCloudExtCloudSync, bundle_name: *const c_uchar, bundle_name_len: c_uint, schema: *mut *const OhCloudExtSchemaMeta, ) -> c_int572 pub unsafe extern "C" fn OhCloudExtCloudSyncGetAppSchema(
573     server: *mut OhCloudExtCloudSync,
574     bundle_name: *const c_uchar,
575     bundle_name_len: c_uint,
576     schema: *mut *const OhCloudExtSchemaMeta,
577 ) -> c_int {
578     if server.is_null() || bundle_name.is_null() || schema.is_null() {
579         return ERRNO_NULLPTR;
580     }
581     let cloud_server = match OhCloudExtCloudSync::get_inner_mut(server, SafetyCheckId::CloudSync) {
582         None => return ERRNO_WRONG_TYPE,
583         Some(v) => v,
584     };
585 
586     let bundle_name_bytes = &*slice_from_raw_parts(bundle_name, bundle_name_len as usize);
587     let bundle_name = std::str::from_utf8_unchecked(bundle_name_bytes);
588 
589     match cloud_server.get_app_schema(bundle_name) {
590         Ok(schema_meta) => {
591             *schema = OhCloudExtSchemaMeta::new(schema_meta, SafetyCheckId::SchemaMeta).into_ptr();
592             ERRNO_SUCCESS
593         }
594         Err(e) => map_single_sync_err(&e),
595     }
596 }
597 
598 /// Pass a batch of subscription orders to a CloudSync pointer, with target database information
599 /// and expected expire time. Database information should be in type HashMap<String, Vec<Database>>.
600 /// Return a Hashmap of subscription relations, in the form HashMap<String, RelationSet>, and Vector
601 /// of errors in c_int, if failure happens. The Hashmap and Vector returned should be freed by
602 /// `HashMapFree` and `VectorFree` respectively, if not in use anymore.
603 #[no_mangle]
OhCloudExtCloudSyncSubscribe( server: *mut OhCloudExtCloudSync, dbs: *const OhCloudExtHashMap, expire: c_longlong, relations: *mut *const OhCloudExtHashMap, err: *mut *const OhCloudExtVector, ) -> c_int604 pub unsafe extern "C" fn OhCloudExtCloudSyncSubscribe(
605     server: *mut OhCloudExtCloudSync,
606     dbs: *const OhCloudExtHashMap,
607     expire: c_longlong,
608     relations: *mut *const OhCloudExtHashMap,
609     err: *mut *const OhCloudExtVector,
610 ) -> c_int {
611     if server.is_null() || dbs.is_null() || relations.is_null() || err.is_null() {
612         return ERRNO_NULLPTR;
613     }
614 
615     let cloud_server = match OhCloudExtCloudSync::get_inner_mut(server, SafetyCheckId::CloudSync) {
616         None => return ERRNO_WRONG_TYPE,
617         Some(v) => v,
618     };
619 
620     let dbs = match OhCloudExtHashMap::get_inner_ref(dbs, SafetyCheckId::HashMap) {
621         None => return ERRNO_WRONG_TYPE,
622         Some(v) => v,
623     };
624     let dbs = match dbs {
625         HashMapCffi::VecDatabase(databases) => databases,
626         _ => return ERRNO_INVALID_INPUT_TYPE,
627     };
628 
629     match cloud_server.subscribe(dbs, expire) {
630         Ok(ret) => {
631             let result = HashMapCffi::RelationSet(ret);
632             *relations = OhCloudExtHashMap::new(result, SafetyCheckId::HashMap).into_ptr();
633             *err = null_mut();
634             ERRNO_SUCCESS
635         }
636         Err(e) => {
637             let errno = map_single_sync_err(&e);
638             if errno == ERRNO_IPC_ERRORS {
639                 if let SyncError::IPCErrors(vec) = e {
640                     let ret = VectorCffi::I32(vec.iter().map(map_ipc_err).collect());
641                     *err = OhCloudExtVector::new(ret, SafetyCheckId::Vector).into_ptr();
642                 }
643             }
644             errno
645         }
646     }
647 }
648 
649 /// Pass a batch of unsubscription orders to a CloudSync pointer, with target relations.
650 /// Relations should be in type HashMap<String, Vec<String>>, with bundle name as keys, vector of
651 /// subscription ids as value. Return a Vector of errors in c_int, if failure happens. The Vector
652 /// returned should be freed by `VectorFree` respectively, if not in use anymore.
653 #[no_mangle]
OhCloudExtCloudSyncUnsubscribe( server: *mut OhCloudExtCloudSync, relations: *const OhCloudExtHashMap, err: *mut *const OhCloudExtVector, ) -> c_int654 pub unsafe extern "C" fn OhCloudExtCloudSyncUnsubscribe(
655     server: *mut OhCloudExtCloudSync,
656     relations: *const OhCloudExtHashMap,
657     err: *mut *const OhCloudExtVector,
658 ) -> c_int {
659     if server.is_null() || relations.is_null() || err.is_null() {
660         return ERRNO_NULLPTR;
661     }
662 
663     let cloud_server = match OhCloudExtCloudSync::get_inner_mut(server, SafetyCheckId::CloudSync) {
664         None => return ERRNO_WRONG_TYPE,
665         Some(v) => v,
666     };
667 
668     let relations = match OhCloudExtHashMap::get_inner_ref(relations, SafetyCheckId::HashMap) {
669         None => return ERRNO_WRONG_TYPE,
670         Some(v) => v,
671     };
672     let relations = match relations {
673         HashMapCffi::VecString(res) => res,
674         _ => return ERRNO_INVALID_INPUT_TYPE,
675     };
676 
677     match cloud_server.unsubscribe(relations) {
678         Ok(()) => ERRNO_SUCCESS,
679         Err(e) => {
680             let errno = map_single_sync_err(&e);
681             if errno == ERRNO_IPC_ERRORS {
682                 if let SyncError::IPCErrors(vec) = e {
683                     let ret = VectorCffi::I32(vec.iter().map(map_ipc_err).collect());
684                     *err = OhCloudExtVector::new(ret, SafetyCheckId::Vector).into_ptr();
685                 }
686             }
687             errno
688         }
689     }
690 }
691 
692 /// Free a CloudSync pointer.
693 #[no_mangle]
OhCloudExtCloudSyncFree(server: *mut OhCloudExtCloudSync)694 pub unsafe extern "C" fn OhCloudExtCloudSyncFree(server: *mut OhCloudExtCloudSync) {
695     let _ = OhCloudExtCloudSync::from_ptr(server, SafetyCheckId::CloudSync);
696 }
697