1 /*
2 * Copyright (c) 2022 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 #include "adapter/ohos/capability/distributed/storage/distributed_storage.h"
17
18 #include "distributed_object.h"
19 #include "distributed_objectstore.h"
20 #include "objectstore_errors.h"
21
22 #include "base/log/log.h"
23 #include "base/utils/utils.h"
24 #include "core/common/ace_application_info.h"
25
26 namespace OHOS::Ace {
27
28 class DistributedObjectWatcher final : public OHOS::ObjectStore::ObjectWatcher {
29 public:
DistributedObjectWatcher(OnDataChangeCallback && onChange)30 explicit DistributedObjectWatcher(OnDataChangeCallback&& onChange)
31 {
32 onChange_ = std::move(onChange);
33 }
34
OnChanged(const std::string & sessionid,const std::vector<std::string> & changedData)35 void OnChanged(const std::string& sessionid, const std::vector<std::string>& changedData) override
36 {
37 CHECK_NULL_VOID_NOLOG(onChange_);
38 onChange_(sessionid, changedData);
39 }
40
41 private:
42 OnDataChangeCallback onChange_;
43 };
44
45 class DistributedObjectStatusNotifier final : public OHOS::ObjectStore::StatusNotifier {
46 public:
DistributedObjectStatusNotifier(ObjectStatusNotifyCallback && onNotify)47 explicit DistributedObjectStatusNotifier(ObjectStatusNotifyCallback&& onNotify)
48 {
49 onNotify_ = std::move(onNotify);
50 }
OnChanged(const std::string & sessionId,const std::string & networkId,const std::string & onlineStatus)51 void OnChanged(const std::string& sessionId, const std::string& networkId, const std::string& onlineStatus) override
52 {
53 LOGI("DistributedObjectStatusNotifier [%{public}s-%{public}s]", sessionId.c_str(), onlineStatus.c_str());
54 CHECK_NULL_VOID_NOLOG(onNotify_);
55 onNotify_(sessionId, onlineStatus);
56 }
57
58 private:
59 ObjectStatusNotifyCallback onNotify_;
60 };
61
DistributedObjectPtr(const std::string & sessionId,OnDataChangeCallback && onChange)62 DistributedObjectPtr::DistributedObjectPtr(const std::string& sessionId, OnDataChangeCallback&& onChange)
63 {
64 std::string bundleName = AceApplicationInfo::GetInstance().GetProcessName();
65 if (bundleName.empty()) {
66 LOGE("DistributedObjectStore bundleName is empty!");
67 return;
68 }
69 OHOS::ObjectStore::DistributedObjectStore* store =
70 OHOS::ObjectStore::DistributedObjectStore::GetInstance(bundleName);
71 CHECK_NULL_VOID(store);
72 static std::once_flag onceFlag;
73 std::call_once(onceFlag, [store]() {
74 auto callback = [](const std::string& sessionId, const std::string& onlineStatus) {
75 DistributedStorage::OnStatusNotify(sessionId, onlineStatus);
76 };
77 store->SetStatusNotifier(std::make_shared<DistributedObjectStatusNotifier>(callback));
78 });
79
80 uint32_t ret = store->Get(sessionId, &object_);
81 if (ret != OHOS::ObjectStore::SUCCESS) {
82 LOGW("DistributedObjectStore get object[%{private}s] failed, try to create", sessionId.c_str());
83 object_ = store->CreateObject(sessionId);
84 CHECK_NULL_VOID(object_);
85 }
86
87 sessionId_ = sessionId;
88 watcher_ = std::make_shared<DistributedObjectWatcher>(std::move(onChange));
89 ret = store->Watch(object_, watcher_);
90 if (ret != OHOS::ObjectStore::SUCCESS) {
91 LOGE("DistributedObjectStore Watch failed!, err=[%{private}u", ret);
92 }
93 LOGI("DistributedObjectPtr init success[%{public}s]", sessionId_.c_str());
94 invalid_ = false;
95 }
96
~DistributedObjectPtr()97 DistributedObjectPtr::~DistributedObjectPtr()
98 {
99 if (object_ != nullptr) {
100 std::string bundleName = AceApplicationInfo::GetInstance().GetProcessName();
101 OHOS::ObjectStore::DistributedObjectStore* store =
102 OHOS::ObjectStore::DistributedObjectStore::GetInstance(bundleName);
103 CHECK_NULL_VOID(store);
104 uint32_t ret = store->UnWatch(object_);
105 if (ret != OHOS::ObjectStore::SUCCESS) {
106 LOGE("DistributedObjectStore UnWatch failed!, err=[%{private}u]", ret);
107 }
108 ret = store->DeleteObject(sessionId_);
109 if (ret != OHOS::ObjectStore::SUCCESS) {
110 LOGE("DistributedObjectStore DeleteObject failed!, err=[%{private}u]", ret);
111 }
112 }
113 DistributedStorage::DeleteStorage(sessionId_);
114 }
115
GetRawPtr()116 OHOS::ObjectStore::DistributedObject* DistributedObjectPtr::GetRawPtr()
117 {
118 return object_;
119 }
120
121 std::map<std::string, RefPtr<DistributedStorage>> DistributedStorage::storageMap_;
122
AddStorage(const std::string & sessionId,RefPtr<DistributedStorage> storage)123 void DistributedStorage::AddStorage(const std::string& sessionId, RefPtr<DistributedStorage> storage)
124 {
125 storageMap_.try_emplace(sessionId, storage);
126 }
127
DeleteStorage(const std::string & sessionId)128 void DistributedStorage::DeleteStorage(const std::string& sessionId)
129 {
130 storageMap_.erase(sessionId);
131 }
132
OnStatusNotify(const std::string & sessionId,const std::string & status)133 void DistributedStorage::OnStatusNotify(const std::string& sessionId, const std::string& status)
134 {
135 auto storage = storageMap_.find(sessionId);
136 if (storage != storageMap_.end()) {
137 storage->second->NotifyStatus(status);
138 }
139 }
140
Init(std::function<void (const std::string &)> && notifyCallback)141 bool DistributedStorage::Init(std::function<void(const std::string&)>&& notifyCallback)
142 {
143 notifyCallback_ = std::move(notifyCallback);
144 auto onChangeCallback = [weak = WeakClaim(this)](
145 const std::string& sessionid, const std::vector<std::string>& changedData) {
146 auto storage = weak.Upgrade();
147 for (auto& key : changedData) {
148 storage->OnDataChange(key);
149 }
150 };
151 objectPtr_ = std::make_unique<DistributedObjectPtr>(sessionId_, std::move(onChangeCallback));
152
153 return true;
154 }
155
SetString(const std::string & key,const std::string & value)156 void DistributedStorage::SetString(const std::string& key, const std::string& value)
157 {
158 if (objectPtr_->IsInvalid()) {
159 LOGE("Set string failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
160 sessionId_.c_str(), key.c_str());
161 return;
162 }
163
164 auto ret = objectPtr_->GetRawPtr()->PutString(key, value);
165 if (ret != OHOS::ObjectStore::SUCCESS) {
166 LOGE("Set string failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
167 key.c_str(), ret);
168 }
169 }
170
GetString(const std::string & key)171 std::string DistributedStorage::GetString(const std::string& key)
172 {
173 if (objectPtr_->IsInvalid()) {
174 LOGE("Get string failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
175 sessionId_.c_str(), key.c_str());
176 return "";
177 }
178 std::string value;
179 auto ret = objectPtr_->GetRawPtr()->GetString(key, value);
180 if (ret != OHOS::ObjectStore::SUCCESS) {
181 LOGE("Get string failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
182 key.c_str(), ret);
183 }
184 return value;
185 }
186
SetDouble(const std::string & key,const double value)187 void DistributedStorage::SetDouble(const std::string& key, const double value)
188 {
189 if (objectPtr_->IsInvalid()) {
190 LOGE("Set double failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
191 sessionId_.c_str(), key.c_str());
192 return;
193 }
194 auto ret = objectPtr_->GetRawPtr()->PutDouble(key, value);
195 if (ret != OHOS::ObjectStore::SUCCESS) {
196 LOGE("Set double failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
197 key.c_str(), ret);
198 }
199 }
200
GetDouble(const std::string & key,double & value)201 bool DistributedStorage::GetDouble(const std::string& key, double& value)
202 {
203 if (objectPtr_->IsInvalid()) {
204 LOGE("Get double failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
205 sessionId_.c_str(), key.c_str());
206 return false;
207 }
208 auto ret = objectPtr_->GetRawPtr()->GetDouble(key, value);
209 if (ret != OHOS::ObjectStore::SUCCESS) {
210 LOGE("Get double failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
211 key.c_str(), ret);
212 return false;
213 }
214 return true;
215 }
216
SetBoolean(const std::string & key,const bool value)217 void DistributedStorage::SetBoolean(const std::string& key, const bool value)
218 {
219 if (objectPtr_->IsInvalid()) {
220 LOGE("Set boolean failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
221 sessionId_.c_str(), key.c_str());
222 return;
223 }
224 auto ret = objectPtr_->GetRawPtr()->PutBoolean(key, value);
225 if (ret != OHOS::ObjectStore::SUCCESS) {
226 LOGE("Set boolean failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
227 key.c_str(), ret);
228 }
229 }
230
GetBoolean(const std::string & key,bool & value)231 bool DistributedStorage::GetBoolean(const std::string& key, bool& value)
232 {
233 if (objectPtr_->IsInvalid()) {
234 LOGE("Get boolean failed, distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
235 sessionId_.c_str(), key.c_str());
236 return false;
237 }
238 auto ret = objectPtr_->GetRawPtr()->GetBoolean(key, value);
239 if (ret != OHOS::ObjectStore::SUCCESS) {
240 LOGE("Get boolean failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
241 key.c_str(), ret);
242 return false;
243 }
244 return true;
245 }
246
GetDataType(const std::string & key)247 Storage::DataType DistributedStorage::GetDataType(const std::string& key)
248 {
249 if (objectPtr_->IsInvalid()) {
250 LOGE("Get type failed! distributed object is invalid! sessionId=[%{private}s], key=[%{private}s]",
251 sessionId_.c_str(), key.c_str());
252 return Storage::DataType::NONE;
253 }
254 OHOS::ObjectStore::Type type = OHOS::ObjectStore::Type::TYPE_STRING;
255 auto ret = objectPtr_->GetRawPtr()->GetType(key, type);
256
257 if (ret != OHOS::ObjectStore::SUCCESS) {
258 LOGE("Get type failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u]", sessionId_.c_str(),
259 key.c_str(), ret);
260 return Storage::DataType::NONE;
261 }
262
263 Storage::DataType dataType = Storage::DataType::NONE;
264 switch (type) {
265 case OHOS::ObjectStore::Type::TYPE_STRING:
266 dataType = Storage::DataType::STRING;
267 break;
268 case OHOS::ObjectStore::Type::TYPE_BOOLEAN:
269 dataType = Storage::DataType::BOOLEAN;
270 break;
271 case OHOS::ObjectStore::Type::TYPE_DOUBLE:
272 dataType = Storage::DataType::DOUBLE;
273 break;
274 default:
275 break;
276 }
277 return dataType;
278 }
279
NotifyStatus(const std::string & status)280 void DistributedStorage::NotifyStatus(const std::string& status)
281 {
282 CHECK_NULL_VOID_NOLOG(taskExecutor_);
283 LOGI("DistributedStorage::NotifyStatus [%{public}s-%{public}s]", sessionId_.c_str(), status.c_str());
284 taskExecutor_->PostTask(
285 [weak = WeakClaim(this), status] {
286 auto storage = weak.Upgrade();
287 if (storage && storage->notifyCallback_) {
288 storage->notifyCallback_(status);
289 }
290 },
291 TaskExecutor::TaskType::JS);
292 }
293
294 } // namespace OHOS::Ace