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 #define LOG_TAG "PublishedData"
16 #include "published_data.h"
17 
18 #include "log_print.h"
19 #include "subscriber_managers/published_data_subscriber_manager.h"
20 #include "base64_utils.h"
21 
22 namespace OHOS::DataShare {
HasVersion() const23 bool PublishedData::HasVersion() const
24 {
25     return true;
26 }
27 
GetVersion() const28 int PublishedData::GetVersion() const
29 {
30     return value.GetVersion();
31 }
32 
GetValue() const33 std::string PublishedData::GetValue() const
34 {
35     return DistributedData::Serializable::Marshall(value);
36 }
37 
PublishedData(const PublishedDataNode & node,const int version)38 PublishedData::PublishedData(const PublishedDataNode &node, const int version) : PublishedData(node)
39 {
40     value.SetVersion(version);
41 }
42 
PublishedData(const PublishedDataNode & node)43 PublishedData::PublishedData(const PublishedDataNode &node)
44     : KvData(Id(GenId(node.key, node.bundleName, node.subscriberId), node.userId)), value(node)
45 {
46 }
47 
Query(const std::string & bundleName,int32_t userId)48 std::vector<PublishedData> PublishedData::Query(const std::string &bundleName, int32_t userId)
49 {
50     auto delegate = KvDBDelegate::GetInstance();
51     if (delegate == nullptr) {
52         ZLOGE("db open failed");
53         return std::vector<PublishedData>();
54     }
55     std::vector<std::string> queryResults;
56     int32_t status = delegate->GetBatch(KvDBDelegate::DATA_TABLE,
57         "{\"bundleName\":\"" + bundleName + "\", \"userId\": " + std::to_string(userId) + "}", "{}", queryResults);
58     if (status != E_OK) {
59         ZLOGE("db GetBatch failed, %{public}s %{public}d", bundleName.c_str(), status);
60         return std::vector<PublishedData>();
61     }
62     std::vector<PublishedData> results;
63     for (auto &result : queryResults) {
64         PublishedDataNode data;
65         if (PublishedDataNode::Unmarshall(result, data)) {
66             results.emplace_back(data, userId);
67         }
68     }
69     return results;
70 }
71 
Marshal(DistributedData::Serializable::json & node) const72 bool PublishedDataNode::Marshal(DistributedData::Serializable::json &node) const
73 {
74     bool ret = SetValue(node[GET_NAME(key)], key);
75     ret = ret && SetValue(node[GET_NAME(bundleName)], bundleName);
76     ret = ret && SetValue(node[GET_NAME(subscriberId)], subscriberId);
77     ret = ret && SetValue(node[GET_NAME(value)], value);
78     ret = ret && SetValue(node[GET_NAME(timestamp)], timestamp);
79     ret = ret && SetValue(node[GET_NAME(userId)], userId);
80     return ret && VersionData::Marshal(node);
81 }
82 
Unmarshal(const DistributedData::Serializable::json & node)83 bool PublishedDataNode::Unmarshal(const DistributedData::Serializable::json &node)
84 {
85     bool ret = GetValue(node, GET_NAME(key), key);
86     ret = ret && GetValue(node, GET_NAME(bundleName), bundleName);
87     ret = ret && GetValue(node, GET_NAME(subscriberId), subscriberId);
88     if (ret) {
89         GetValue(node, GET_NAME(value), value);
90         VersionData::Unmarshal(node);
91     }
92     ret = ret && GetValue(node, GET_NAME(timestamp), timestamp);
93     ret = ret && GetValue(node, GET_NAME(userId), userId);
94     return ret;
95 }
96 
PublishedDataNode(const std::string & key,const std::string & bundleName,int64_t subscriberId,const int32_t userId,const Data & value)97 PublishedDataNode::PublishedDataNode(const std::string &key, const std::string &bundleName, int64_t subscriberId,
98     const int32_t userId, const Data &value)
99     : VersionData(-1), key(key), bundleName(bundleName), subscriberId(subscriberId), value(std::move(value)),
100       userId(userId)
101 {
102     auto now = time(nullptr);
103     if (now > 0) {
104         timestamp = now;
105     }
106 }
107 
PublishedDataNode()108 PublishedDataNode::PublishedDataNode() : VersionData(-1) {}
109 
MoveTo(const PublishedDataNode::Data & data)110 std::variant<std::vector<uint8_t>, std::string> PublishedDataNode::MoveTo(const PublishedDataNode::Data &data)
111 {
112     auto *valueStr = std::get_if<std::string>(&data);
113     if (valueStr != nullptr) {
114         return *valueStr;
115     }
116     auto *valueBytes = std::get_if<PublishedDataNode::BytesData>(&data);
117     if (valueBytes != nullptr) {
118         return Base64::Decode(valueBytes->data);
119     }
120     ZLOGE("error");
121     return "";
122 }
123 
MoveTo(std::variant<std::vector<uint8_t>,std::string> & data)124 PublishedDataNode::Data PublishedDataNode::MoveTo(std::variant<std::vector<uint8_t>, std::string> &data)
125 {
126     auto *valueStr = std::get_if<std::string>(&data);
127     if (valueStr != nullptr) {
128         return *valueStr;
129     }
130     auto *valueBytes = std::get_if<std::vector<uint8_t>>(&data);
131     if (valueBytes != nullptr) {
132         std::string valueEncode = Base64::Encode(*valueBytes);
133         return BytesData(std::move(valueEncode));
134     }
135     ZLOGE("error");
136     return "";
137 }
138 
Query(const std::string & filter,PublishedDataNode::Data & publishedData)139 int32_t PublishedData::Query(const std::string &filter, PublishedDataNode::Data &publishedData)
140 {
141     auto delegate = KvDBDelegate::GetInstance();
142     if (delegate == nullptr) {
143         ZLOGE("db open failed");
144         return E_ERROR;
145     }
146     std::string queryResult;
147     int32_t status = delegate->Get(KvDBDelegate::DATA_TABLE, filter, "{}", queryResult);
148     if (status != E_OK) {
149         ZLOGE("db Get failed, %{public}s %{public}d", filter.c_str(), status);
150         return status;
151     }
152     PublishedDataNode data;
153     if (!PublishedDataNode::Unmarshall(queryResult, data)) {
154         ZLOGE("Unmarshall failed, %{private}s", queryResult.c_str());
155         return E_ERROR;
156     }
157     publishedData = std::move(data.value);
158     return E_OK;
159 }
160 
GenId(const std::string & key,const std::string & bundleName,int64_t subscriberId)161 std::string PublishedData::GenId(const std::string &key, const std::string &bundleName, int64_t subscriberId)
162 {
163     return key + "_" + std::to_string(subscriberId) + "_" + bundleName;
164 }
165 
Delete(const std::string & bundleName,const int32_t userId)166 void PublishedData::Delete(const std::string &bundleName, const int32_t userId)
167 {
168     auto delegate = KvDBDelegate::GetInstance();
169     if (delegate == nullptr) {
170         ZLOGE("db open failed");
171         return;
172     }
173     int32_t status = delegate->Delete(KvDBDelegate::DATA_TABLE,
174         "{\"bundleName\":\"" + bundleName + "\", \"userId\": " + std::to_string(userId) + "}");
175     if (status != E_OK) {
176         ZLOGE("db Delete failed, %{public}s %{public}d", bundleName.c_str(), status);
177     }
178 }
179 
ClearAging()180 void PublishedData::ClearAging()
181 {
182     // published data is valid in 240 hours
183     auto lastValidData =
184         std::chrono::system_clock::now() - std::chrono::duration_cast<std::chrono::seconds>(std::chrono::hours(240));
185     auto lastValidTime = std::chrono::system_clock::to_time_t(lastValidData);
186     if (lastValidTime <= 0) {
187         return;
188     }
189     auto delegate = KvDBDelegate::GetInstance();
190     if (delegate == nullptr) {
191         ZLOGE("db open failed");
192         return;
193     }
194     std::vector<std::string> queryResults;
195     int32_t status = delegate->GetBatch(KvDBDelegate::DATA_TABLE, "{}",
196         "{\"id_\": true, \"timestamp\": true, \"key\": true, \"bundleName\": true, \"subscriberId\": true, "
197         "\"userId\": true}",
198         queryResults);
199     if (status != E_OK) {
200         ZLOGE("db GetBatch failed %{public}d", status);
201         return;
202     }
203     int32_t agingSize = 0;
204     for (auto &result : queryResults) {
205         PublishedDataNode data;
206         if (!PublishedDataNode::Unmarshall(result, data)) {
207             ZLOGE("Unmarshall %{public}s failed", result.c_str());
208             continue;
209         }
210         if (data.timestamp < lastValidTime && PublishedDataSubscriberManager::GetInstance()
211             .GetCount(PublishedDataKey(data.key, data.bundleName, data.subscriberId)) == 0) {
212             status = delegate->Delete(KvDBDelegate::DATA_TABLE,
213                 Id(PublishedData::GenId(data.key, data.bundleName, data.subscriberId), data.userId));
214             if (status != E_OK) {
215                 ZLOGE("db Delete failed, %{public}s %{public}s", data.key.c_str(), data.bundleName.c_str());
216             }
217             agingSize++;
218         }
219     }
220     if (agingSize > 0) {
221         ZLOGI("aging count %{public}d", agingSize);
222     }
223     return;
224 }
225 
UpdateTimestamp(const std::string & key,const std::string & bundleName,int64_t subscriberId,const int32_t userId)226 void PublishedData::UpdateTimestamp(
227     const std::string &key, const std::string &bundleName, int64_t subscriberId, const int32_t userId)
228 {
229     auto delegate = KvDBDelegate::GetInstance();
230     if (delegate == nullptr) {
231         ZLOGE("db open failed");
232         return;
233     }
234     std::string queryResult;
235     int32_t status =
236         delegate->Get(KvDBDelegate::DATA_TABLE, Id(GenId(key, bundleName, subscriberId), userId), queryResult);
237     if (status != E_OK) {
238         ZLOGE("db Get failed, %{private}s %{public}d", queryResult.c_str(), status);
239         return;
240     }
241     PublishedDataNode data;
242     if (!PublishedDataNode::Unmarshall(queryResult, data)) {
243         ZLOGE("Unmarshall failed, %{private}s", queryResult.c_str());
244         return;
245     }
246     auto now = time(nullptr);
247     if (now <= 0) {
248         ZLOGE("time failed");
249         return;
250     }
251     data.timestamp = now;
252     status = delegate->Upsert(KvDBDelegate::DATA_TABLE, PublishedData(data));
253     if (status == E_OK) {
254         ZLOGI("update timestamp %{private}s", data.key.c_str());
255     }
256 }
257 
BytesData(std::string && data)258 PublishedDataNode::BytesData::BytesData(std::string &&data) : data(std::move(data))
259 {
260 }
261 
Marshal(DistributedData::Serializable::json & node) const262 bool PublishedDataNode::BytesData::Marshal(DistributedData::Serializable::json &node) const
263 {
264     return SetValue(node[GET_NAME(data)], data);
265 }
266 
Unmarshal(const DistributedData::Serializable::json & node)267 bool PublishedDataNode::BytesData::Unmarshal(const DistributedData::Serializable::json &node)
268 {
269     bool ret = GetValue(node, GET_NAME(data), data);
270     return ret;
271 }
272 } // namespace OHOS::DataShare