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 #define LOG_TAG "RdbAssetLoader"
17 #include "rdb_asset_loader.h"
18
19 #include <variant>
20
21 #include "error/general_error.h"
22 #include "log_print.h"
23 #include "rdb_cloud.h"
24 #include "store/general_value.h"
25 #include "value_proxy.h"
26
27 using namespace DistributedDB;
28 using ValueProxy = OHOS::DistributedData::ValueProxy;
29 namespace OHOS::DistributedRdb {
RdbAssetLoader(std::shared_ptr<DistributedData::AssetLoader> cloudAssetLoader,BindAssets bindAssets)30 RdbAssetLoader::RdbAssetLoader(std::shared_ptr<DistributedData::AssetLoader> cloudAssetLoader, BindAssets bindAssets)
31 : assetLoader_(std::move(cloudAssetLoader)), snapshots_(std::move(bindAssets))
32 {
33 }
34
Download(const std::string & tableName,const std::string & gid,const Type & prefix,std::map<std::string,Assets> & assets)35 DBStatus RdbAssetLoader::Download(const std::string &tableName, const std::string &gid, const Type &prefix,
36 std::map<std::string, Assets> &assets)
37 {
38 DistributedData::VBucket downLoadAssets = ValueProxy::Convert(assets);
39 std::set<std::string> skipAssets;
40 std::set<std::string> deleteAssets;
41 PostEvent(skipAssets, downLoadAssets, DistributedData::AssetEvent::DOWNLOAD, deleteAssets);
42 DistributedDB::Type prefixTemp = prefix;
43 auto error = assetLoader_->Download(tableName, gid, ValueProxy::Convert(std::move(prefixTemp)), downLoadAssets);
44 PostEvent(skipAssets, downLoadAssets, DistributedData::AssetEvent::DOWNLOAD_FINISHED, deleteAssets);
45 assets = ValueProxy::Convert(std::move(downLoadAssets));
46 return skipAssets.empty() ? RdbCloud::ConvertStatus(static_cast<DistributedData::GeneralError>(error))
47 : CLOUD_RECORD_EXIST_CONFLICT;
48 }
49
BatchDownload(const std::string & tableName,std::vector<AssetRecord> & downloadAssets)50 void RdbAssetLoader::BatchDownload(const std::string &tableName, std::vector<AssetRecord> &downloadAssets)
51 {
52 std::vector<AssetsRecord> assetsRecords = Convert(std::move(downloadAssets));
53 std::set<std::string> skipAssets;
54 std::set<std::string> deleteAssets;
55 PostEvent(skipAssets, assetsRecords, DistributedData::AssetEvent::DOWNLOAD, deleteAssets);
56 assetLoader_->Download(tableName, assetsRecords);
57 PostEvent(skipAssets, assetsRecords, DistributedData::AssetEvent::DOWNLOAD_FINISHED, deleteAssets);
58 downloadAssets = Convert(std::move(assetsRecords));
59 }
60
Convert(std::vector<AssetRecord> && downloadAssets)61 std::vector<RdbAssetLoader::AssetsRecord> RdbAssetLoader::Convert(std::vector<AssetRecord> &&downloadAssets)
62 {
63 std::vector<AssetsRecord> assetsRecords;
64 for (auto &assetRecord : downloadAssets) {
65 AssetsRecord assetsRecord;
66 assetsRecord.gid = std::move(assetRecord.gid);
67 DistributedDB::Type prefixTemp = assetRecord.prefix;
68 assetsRecord.prefix = ValueProxy::Convert(std::move(prefixTemp));
69 assetsRecord.assets = ValueProxy::Convert(std::move(assetRecord.assets));
70 assetsRecords.emplace_back(std::move(assetsRecord));
71 }
72 return assetsRecords;
73 }
74
UpdateStatus(AssetRecord & assetRecord,const VBucket & assets)75 void RdbAssetLoader::UpdateStatus(AssetRecord &assetRecord, const VBucket &assets)
76 {
77 for (const auto &[key, value] : assets) {
78 auto downloadAssets = std::get_if<DistributedData::Assets>(&value);
79 if (downloadAssets == nullptr) {
80 assetRecord.status = DBStatus::CLOUD_ERROR;
81 continue;
82 }
83 for (const auto &asset : *downloadAssets) {
84 if (assetRecord.status != DBStatus::OK) {
85 return;
86 }
87 assetRecord.status = ConvertStatus(static_cast<AssetStatus>(asset.status));
88 }
89 }
90 }
91
Convert(std::vector<AssetsRecord> && assetsRecords)92 std::vector<IAssetLoader::AssetRecord> RdbAssetLoader::Convert(std::vector<AssetsRecord> &&assetsRecords)
93 {
94 std::vector<AssetRecord> assetRecords;
95 for (auto &assetsRecord : assetsRecords) {
96 AssetRecord assetRecord{
97 .gid = std::move(assetsRecord.gid),
98 };
99 UpdateStatus(assetRecord, assetsRecord.assets);
100 assetRecord.assets = ValueProxy::Convert(std::move(assetsRecord.assets));
101 assetRecords.emplace_back(std::move(assetRecord));
102 }
103 return assetRecords;
104 }
105
ConvertStatus(AssetStatus error)106 DBStatus RdbAssetLoader::ConvertStatus(AssetStatus error)
107 {
108 switch (error) {
109 case AssetStatus::STATUS_NORMAL:
110 case AssetStatus::STATUS_DOWNLOADING:
111 return DBStatus::OK;
112 case AssetStatus::STATUS_SKIP_ASSET:
113 return DBStatus::SKIP_ASSET;
114 default:
115 ZLOGE("error:0x%{public}x", error);
116 break;
117 }
118 return DBStatus::CLOUD_ERROR;
119 }
120
RemoveLocalAssets(const std::vector<Asset> & assets)121 DBStatus RdbAssetLoader::RemoveLocalAssets(const std::vector<Asset> &assets)
122 {
123 DistributedData::VBucket deleteAssets = ValueProxy::Convert(std::map<std::string, Assets>{{ "", assets }});
124 auto error = assetLoader_->RemoveLocalAssets("", "", {}, deleteAssets);
125 return RdbCloud::ConvertStatus(static_cast<DistributedData::GeneralError>(error));
126 }
127
CancelDownload()128 DBStatus RdbAssetLoader::CancelDownload()
129 {
130 if (assetLoader_ == nullptr) {
131 ZLOGE("assetLoader is nullptr");
132 return DBStatus::DB_ERROR;
133 }
134 auto error = assetLoader_->CancelDownload();
135 return RdbCloud::ConvertStatus(static_cast<DistributedData::GeneralError>(error));
136 }
137
PostEvent(std::set<std::string> & skipAssets,std::vector<AssetsRecord> & assetsRecords,DistributedData::AssetEvent eventId,std::set<std::string> & deleteAssets)138 void RdbAssetLoader::PostEvent(std::set<std::string> &skipAssets, std::vector<AssetsRecord> &assetsRecords,
139 DistributedData::AssetEvent eventId, std::set<std::string> &deleteAssets)
140 {
141 for (auto &assetsRecord : assetsRecords) {
142 for (auto &asset : assetsRecord.assets) {
143 auto *downLoadAssets = Traits::get_if<DistributedData::Assets>(&asset.second);
144 if (downLoadAssets == nullptr) {
145 return;
146 }
147 PostEvent(eventId, *downLoadAssets, skipAssets, deleteAssets);
148 }
149 }
150 }
151
PostEvent(std::set<std::string> & skipAssets,std::map<std::string,DistributedData::Value> & assets,DistributedData::AssetEvent eventId,std::set<std::string> & deleteAssets)152 void RdbAssetLoader::PostEvent(std::set<std::string>& skipAssets, std::map<std::string, DistributedData::Value>& assets,
153 DistributedData::AssetEvent eventId, std::set<std::string>& deleteAssets)
154 {
155 for (auto& asset : assets) {
156 auto* downLoadAssets = Traits::get_if<DistributedData::Assets>(&asset.second);
157 if (downLoadAssets == nullptr) {
158 return;
159 }
160 PostEvent(eventId, *downLoadAssets, skipAssets, deleteAssets);
161 }
162 }
163
PostEvent(DistributedData::AssetEvent eventId,DistributedData::Assets & assets,std::set<std::string> & skipAssets,std::set<std::string> & deleteAssets)164 void RdbAssetLoader::PostEvent(DistributedData::AssetEvent eventId, DistributedData::Assets& assets,
165 std::set<std::string>& skipAssets, std::set<std::string>& deleteAssets)
166 {
167 for (auto& downLoadAsset : assets) {
168 if (downLoadAsset.status == DistributedData::Asset::STATUS_DELETE) {
169 deleteAssets.insert(downLoadAsset.uri);
170 continue;
171 }
172 if (snapshots_ == nullptr) {
173 continue;
174 }
175 auto it = snapshots_->find(downLoadAsset.uri);
176 if (it == snapshots_->end() || it->second == nullptr) {
177 continue;
178 }
179 auto snapshot = it->second;
180 if (eventId == DistributedData::DOWNLOAD) {
181 snapshot->Download(downLoadAsset);
182 if (snapshot->GetAssetStatus(downLoadAsset) == DistributedData::STATUS_WAIT_DOWNLOAD) {
183 skipAssets.insert(downLoadAsset.uri);
184 }
185 } else {
186 auto skipPos = skipAssets.find(downLoadAsset.uri);
187 auto deletePos = deleteAssets.find(downLoadAsset.uri);
188 if (skipPos != skipAssets.end() || deletePos != deleteAssets.end()) {
189 continue;
190 }
191 snapshot->Downloaded(downLoadAsset);
192 }
193 }
194 }
195 } // namespace OHOS::DistributedRdb