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