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 pub use crate::ipc_conn::{AssetStatus, CloudAsset};
17 use crate::service_impl::error::SyncError;
18 use crate::service_impl::types::{Database, Table};
19 use crate::{ipc_conn, SyncResult};
20 use std::collections::HashMap;
21 
22 /// Cloud Asset loader struct.
23 pub struct CloudAssetLoader<'a> {
24     asset_loader: ipc_conn::AssetLoader,
25     tables: &'a HashMap<String, Table>,
26     // Keep the following fields below for future extension.
27     #[allow(unused)]
28     bundle_name: String,
29 }
30 
31 impl<'a> CloudAssetLoader<'a> {
32     /// Initialize a CloudAssetLoader instance from user id, bundle name, and database.
33     /// Database can be obtained from CloudInfo and CloudSync.
new(user_id: i32, bundle_name: &str, db: &'a Database) -> SyncResult<Self>34     pub fn new(user_id: i32, bundle_name: &str, db: &'a Database) -> SyncResult<Self> {
35         let asset_loader = ipc_conn::AssetLoader::new(user_id)?;
36         Ok(CloudAssetLoader {
37             asset_loader,
38             tables: &db.tables,
39             bundle_name: bundle_name.to_string(),
40         })
41     }
42 
43     /// Take in table name, gid, prefix, and assets, send upload request to the other side of IPC
44     /// connection. Necessary information will be updated in the parameter assets. The cloud storage
45     /// will ask for files from source paths, and this function only returns result and relating infos.
upload( &self, table_name: &str, gid: &str, prefix: &str, assets: &[CloudAsset], ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>>46     pub fn upload(
47         &self,
48         table_name: &str,
49         gid: &str,
50         prefix: &str,
51         assets: &[CloudAsset],
52     ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>> {
53         self.upload_download_inner(
54             table_name,
55             gid,
56             prefix,
57             assets,
58             ipc_conn::AssetLoader::upload,
59         )
60     }
61 
62     /// Take in table name, gid, prefix, and assets, send download request to the other side of IPC
63     /// connection. Necessary information will be updated in the parameter assets. The cloud storage
64     /// will send files to target paths, and this function only returns result and relating infos.
download( &self, table_name: &str, gid: &str, prefix: &str, assets: &[CloudAsset], ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>>65     pub fn download(
66         &self,
67         table_name: &str,
68         gid: &str,
69         prefix: &str,
70         assets: &[CloudAsset],
71     ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>> {
72         self.upload_download_inner(
73             table_name,
74             gid,
75             prefix,
76             assets,
77             ipc_conn::AssetLoader::download,
78         )
79     }
80 
81     /// Remove local file according to the path in the asset passed in.
remove_local_assets(asset: &CloudAsset) -> SyncResult<()>82     pub fn remove_local_assets(asset: &CloudAsset) -> SyncResult<()> {
83         std::fs::remove_file(asset.local_path())?;
84         Ok(())
85     }
86 
upload_download_inner<F>( &self, table_name: &str, gid: &str, prefix: &str, assets: &[CloudAsset], mut f: F, ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>> where F: FnMut( &ipc_conn::AssetLoader, &str, &str, &str, &ipc_conn::CloudAssets, ) -> Result<Vec<Result<CloudAsset, ipc_conn::Error>>, ipc_conn::Error>,87     fn upload_download_inner<F>(
88         &self,
89         table_name: &str,
90         gid: &str,
91         prefix: &str,
92         assets: &[CloudAsset],
93         mut f: F,
94     ) -> SyncResult<Vec<Result<CloudAsset, SyncError>>>
95     where
96         F: FnMut(
97             &ipc_conn::AssetLoader,
98             &str,
99             &str,
100             &str,
101             &ipc_conn::CloudAssets,
102         ) -> Result<Vec<Result<CloudAsset, ipc_conn::Error>>, ipc_conn::Error>,
103     {
104         let mut assets_ipc = ipc_conn::CloudAssets::default();
105         for asset in assets.iter() {
106             if asset.status == AssetStatus::Delete {
107                 CloudAssetLoader::remove_local_assets(asset)?;
108             }
109 
110             assets_ipc.0.push(asset.clone());
111         }
112         let alias = self.get_table_alias(table_name);
113         let ret = f(&self.asset_loader, alias, gid, prefix, &assets_ipc)?;
114         let mut ret_map = vec![];
115         for single_result in ret {
116             ret_map.push(single_result.map_err(|e| e.into()));
117         }
118         Ok(ret_map)
119     }
120 
get_table_alias(&self, table_name: &str) -> &str121     fn get_table_alias(&self, table_name: &str) -> &str {
122         match self.tables.get(table_name) {
123             None => "",
124             Some(t) => t.alias.as_str(),
125         }
126     }
127 }
128