!2158 add distributedstorage support

Merge pull request !2158 from 何溯/dev
This commit is contained in:
openharmony_ci
2022-04-15 06:33:07 +00:00
committed by Gitee
22 changed files with 1132 additions and 15 deletions
+2
View File
@@ -26,11 +26,13 @@ template("ace_capability_ohos_source_set") {
sources = [
"clipboard/clipboard_impl.cpp",
"distributed/storage/distributed_storage.cpp",
"preference/storage_impl.cpp",
]
include_dirs = [ "//foundation/distributeddatamgr/appdatamgr/interfaces/innerkits/native_preferences/include/" ]
external_deps = [
"ability_base:want",
"distributeddataobject:distributeddataobject_impl",
"ipc:ipc_core",
"native_appdatamgr:native_preferences",
]
@@ -0,0 +1,270 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "adapter/ohos/capability/distributed/storage/distributed_storage.h"
#include "distributed_object.h"
#include "distributed_objectstore.h"
#include "objectstore_errors.h"
#include "base/log/log.h"
#include "core/common/ace_application_info.h"
namespace OHOS::Ace {
class DistributedObjectWatch final : public OHOS::ObjectStore::ObjectWatcher {
public:
DistributedObjectWatch(const std::string& sessionId, OnDataChangeCallback&& onChange)
{
onChange_ = std::move(onChange);
}
void OnChanged(const std::string& sessionid, const std::vector<std::string>& changedData) override
{
if (onChange_) {
onChange_(sessionid, changedData);
}
}
private:
OnDataChangeCallback onChange_;
};
class DistributedObjectStatusNotifier final : public OHOS::ObjectStore::StatusNotifier {
public:
explicit DistributedObjectStatusNotifier(ObjectStatusNotifyCallback&& onNotify)
{
onNotify_ = std::move(onNotify);
}
void OnChanged(const std::string& sessionId, const std::string& networkId, const std::string& onlineStatus) override
{
LOGI("DistributedObjectStatusNotifier [%{public}s-%{public}s]", sessionId.c_str(), onlineStatus.c_str());
if (onNotify_) {
onNotify_(sessionId, onlineStatus);
}
}
private:
ObjectStatusNotifyCallback onNotify_;
};
DistributedObjectPtr::DistributedObjectPtr(const std::string& sessionId, OnDataChangeCallback&& onChange)
{
std::string bundleName = AceApplicationInfo::GetInstance().GetProcessName();
if (bundleName.empty()) {
LOGE("DistributedObjectStore bundleName is empty!");
return;
}
OHOS::ObjectStore::DistributedObjectStore* store =
OHOS::ObjectStore::DistributedObjectStore::GetInstance(bundleName);
if (store == nullptr) {
LOGE("DistributedObjectStore GetInstance failed!");
return;
}
static std::once_flag onceFlag;
std::call_once(onceFlag, [store]() {
auto callback = [](const std::string& sessionId, const std::string& onlineStatus) {
DistributedStorage::OnStatusNotify(sessionId, onlineStatus);
};
store->SetStatusNotifier(std::make_shared<DistributedObjectStatusNotifier>(callback));
});
uint32_t ret = store->Get(sessionId, object_);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGW("DistributedObjectStore get object[%{private}s] failed, try to create", sessionId.c_str());
object_ = store->CreateObject(sessionId);
if (object_ == nullptr) {
LOGE("DistributedObjectStore CreateObject failed!");
return;
}
}
sessionId_ = sessionId;
watcher_ = std::make_shared<DistributedObjectWatch>(sessionId, std::move(onChange));
ret = store->Watch(object_, watcher_);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("DistributedObjectStore Watch failed!, err=[%{private}u", ret);
}
LOGI("DistributedObjectPtr init success[%{public}s]", sessionId_.c_str());
}
DistributedObjectPtr::~DistributedObjectPtr()
{
if (object_ != nullptr) {
std::string bundleName = AceApplicationInfo::GetInstance().GetProcessName();
OHOS::ObjectStore::DistributedObjectStore* store =
OHOS::ObjectStore::DistributedObjectStore::GetInstance(bundleName);
if (store == nullptr) {
LOGE("DistributedObjectStore GetInstance failed!");
return;
}
uint32_t ret = store->UnWatch(object_);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("DistributedObjectStore UnWatch failed!, err=[%{private}u", ret);
}
ret = OHOS::ObjectStore::SUCCESS;
ret = store->DeleteObject(sessionId_);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("DistributedObjectStore DeleteObject failed!, err=[%{private}u", ret);
}
}
}
OHOS::ObjectStore::DistributedObject* DistributedObjectPtr::GetRawPtr()
{
return object_;
}
std::map<std::string, RefPtr<DistributedStorage>> DistributedStorage::storageMap_;
void DistributedStorage::AddStorage(const std::string& sessionId, RefPtr<DistributedStorage> storage)
{
storageMap_.try_emplace(sessionId, storage);
}
void DistributedStorage::DeleteStorage(const std::string& sessionId)
{
storageMap_.erase(sessionId);
}
void DistributedStorage::OnStatusNotify(const std::string& sessionId, const std::string& status)
{
auto storage = storageMap_.find(sessionId);
if (storage != storageMap_.end()) {
storage->second->NotifyStatus(status);
}
}
bool DistributedStorage::Init(std::function<void(const std::string&)>&& notifyCallback)
{
notifyCallback_ = std::move(notifyCallback);
auto onChangeCallback = [weak = WeakClaim(this)](
const std::string& sessionid, const std::vector<std::string>& changedData) {
auto storage = weak.Upgrade();
for (auto& key : changedData) {
storage->OnDataChange(key);
}
};
objectPtr_ = std::make_unique<DistributedObjectPtr>(sessionId_, std::move(onChangeCallback));
return true;
}
void DistributedStorage::SetString(const std::string& key, const std::string& value)
{
auto ret = objectPtr_->GetRawPtr()->PutString(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Set string failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
}
}
std::string DistributedStorage::GetString(const std::string& key)
{
std::string value;
auto ret = objectPtr_->GetRawPtr()->GetString(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Get string failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
}
return value;
}
void DistributedStorage::SetDouble(const std::string& key, const double value)
{
auto ret = objectPtr_->GetRawPtr()->PutDouble(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Set Double failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
}
}
bool DistributedStorage::GetDouble(const std::string& key, double& value)
{
auto ret = objectPtr_->GetRawPtr()->GetDouble(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Get double failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
return false;
}
return true;
}
void DistributedStorage::SetBoolean(const std::string& key, const bool value)
{
auto ret = objectPtr_->GetRawPtr()->PutBoolean(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Set Boolean failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
}
}
bool DistributedStorage::GetBoolean(const std::string& key, bool& value)
{
auto ret = objectPtr_->GetRawPtr()->GetBoolean(key, value);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Get Boolean failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
return false;
}
return true;
}
Storage::DataType DistributedStorage::GetDataType(const std::string& key)
{
OHOS::ObjectStore::Type type = OHOS::ObjectStore::Type::TYPE_STRING;
auto ret = objectPtr_->GetRawPtr()->GetType(key, type);
if (ret != OHOS::ObjectStore::SUCCESS) {
LOGE("Get type failed! sessionId=[%{private}s], key=[%{private}s], err=[%{private}u", sessionId_.c_str(),
key.c_str(), ret);
return Storage::DataType::NONE;
}
Storage::DataType dataType = Storage::DataType::NONE;
switch (type) {
case OHOS::ObjectStore::Type::TYPE_STRING:
dataType = Storage::DataType::STRING;
break;
case OHOS::ObjectStore::Type::TYPE_BOOLEAN:
dataType = Storage::DataType::BOOLEAN;
break;
case OHOS::ObjectStore::Type::TYPE_DOUBLE:
dataType = Storage::DataType::DOUBLE;
break;
default:
break;
}
return dataType;
}
void DistributedStorage::NotifyStatus(const std::string& status)
{
if (!taskExecutor_) {
return;
}
LOGI("DistributedStorage::NotifyStatus [%{public}s-%{public}s]", sessionId_.c_str(), status.c_str());
taskExecutor_->PostTask(
[weak = WeakClaim(this), status] {
auto storage = weak.Upgrade();
if (storage && storage->notifyCallback_) {
storage->notifyCallback_(status);
}
},
TaskExecutor::TaskType::JS);
}
} // namespace OHOS::Ace
@@ -0,0 +1,82 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_H
#define FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_H
#include <map>
#include "core/common/storage/storage.h"
namespace OHOS::ObjectStore {
class DistributedObject;
class ObjectWatcher;
} // namespace OHOS::ObjectStore
namespace OHOS::Ace {
using OnDataChangeCallback = std::function<void(const std::string&, const std::vector<std::string>&)>;
using ObjectStatusNotifyCallback = std::function<void(const std::string&, const std::string&)>;
class DistributedObjectPtr final {
public:
DistributedObjectPtr(const std::string& sessionId, OnDataChangeCallback&& onChange);
~DistributedObjectPtr();
OHOS::ObjectStore::DistributedObject* GetRawPtr();
private:
std::string sessionId_;
OHOS::ObjectStore::DistributedObject* object_ = nullptr;
std::shared_ptr<OHOS::ObjectStore::ObjectWatcher> watcher_;
};
class DistributedStorage final : public Storage {
DECLARE_ACE_TYPE(DistributedStorage, Storage);
public:
explicit DistributedStorage(const std::string& sessionId, const RefPtr<TaskExecutor>& taskExecutor)
: Storage(taskExecutor), sessionId_(sessionId)
{}
~DistributedStorage() override = default;
bool Init(std::function<void(const std::string&)>&& notifier);
void SetString(const std::string& key, const std::string& value) override;
std::string GetString(const std::string& key) override;
void SetDouble(const std::string& key, const double value) override;
bool GetDouble(const std::string& key, double& value) override;
void SetBoolean(const std::string& key, const bool value) override;
bool GetBoolean(const std::string& key, bool& value) override;
DataType GetDataType(const std::string& key) override;
void Clear() override {}
void Delete(const std::string& key) override {}
void NotifyStatus(const std::string& status);
static void AddStorage(const std::string& sessionId, RefPtr<DistributedStorage> storage);
static void DeleteStorage(const std::string& sessionId);
static void OnStatusNotify(const std::string& sessionId, const std::string& status);
private:
std::unique_ptr<DistributedObjectPtr> objectPtr_;
std::string sessionId_;
std::function<void(const std::string&)> notifyCallback_;
static std::map<std::string, RefPtr<DistributedStorage>> storageMap_;
};
} // namespace OHOS::Ace
#endif // FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_H
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_INTERFACE_H
#define FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_INTERFACE_H
#include "adapter/ohos/capability/distributed/storage/distributed_storage.h"
#include "base/memory/referenced.h"
#include "core/common/storage/storage_interface.h"
namespace OHOS::Ace {
class DistributedStorageInterface final : public StorageInterface {
public:
~DistributedStorageInterface() override = default;
RefPtr<Storage> GetStorage(const std::string& sessionId, std::function<void(const std::string&)>&& notifier,
const RefPtr<TaskExecutor>& taskExecutor) const override
{
auto storage = Referenced::MakeRefPtr<DistributedStorage>(sessionId, taskExecutor);
if (!storage->Init(std::move(notifier))) {
return nullptr;
}
DistributedStorage::AddStorage(sessionId, storage);
return storage;
}
};
} // namespace OHOS::Ace
#endif // FOUNDATION_ACE_ADAPTER_OHOS_CAPABILITY_DISTRIBUTED_STORAGE_DISTRIBUTED_STORAGE_INTERFACE_H
@@ -22,7 +22,7 @@ std::shared_ptr<NativePreferences::Preferences> StorageImpl::GetPreference(const
return NativePreferences::PreferencesHelper::GetPreferences(fileName, errCode_);
}
void StorageImpl::Set(const std::string& key, const std::string& value)
void StorageImpl::SetString(const std::string& key, const std::string& value)
{
std::shared_ptr<NativePreferences::Preferences> pref = GetPreference(fileName_);
if (!pref) {
@@ -34,7 +34,7 @@ void StorageImpl::Set(const std::string& key, const std::string& value)
pref->Flush();
}
std::string StorageImpl::Get(const std::string& key)
std::string StorageImpl::GetString(const std::string& key)
{
std::shared_ptr<NativePreferences::Preferences> pref = GetPreference(fileName_);
if (!pref) {
@@ -37,8 +37,20 @@ public:
};
~StorageImpl() override = default;
void Set(const std::string& key, const std::string& value) override;
std::string Get(const std::string& key) override;
void SetString(const std::string& key, const std::string& value) override;
std::string GetString(const std::string& key) override;
void SetDouble(const std::string& key, const double value) override
{}
bool GetDouble(const std::string& key, double& value) override
{
return false;
}
void SetBoolean(const std::string& key, const bool value) override
{}
bool GetBoolean(const std::string& key, bool& value) override
{
return false;
}
void Clear() override;
void Delete(const std::string& key) override;
@@ -16,9 +16,10 @@
#include "adapter/ohos/entrance/capability_registry.h"
#include "adapter/ohos/capability/clipboard/clipboard_impl.h"
#include "adapter/ohos/capability/distributed/storage/distributed_storage_interface.h"
#include "adapter/ohos/capability/preference/storage_impl.h"
#include "core/common/clipboard/clipboard_proxy.h"
#include "core/common/storage/storage_proxy.h"
#include "adapter/ohos/capability/preference/storage_impl.h"
namespace OHOS::Ace {
@@ -26,6 +27,7 @@ void CapabilityRegistry::Register()
{
ClipboardProxy::GetInstance()->SetDelegate(std::make_unique<ClipboardProxyImpl>());
StorageProxy::GetInstance()->SetDelegate(std::make_unique<StorageProxyImpl>());
StorageProxy::GetInstance()->SetDistributedDelegate(std::make_unique<DistributedStorageInterface>());
}
} // namespace OHOS::Ace
@@ -145,6 +145,7 @@ template("declarative_js_engine") {
"jsview/js_counter.cpp",
"jsview/js_data_panel.cpp",
"jsview/js_datepicker.cpp",
"jsview/js_distributed.cpp",
"jsview/js_divider.cpp",
"jsview/js_ellipse.cpp",
"jsview/js_environment.cpp",
@@ -49,6 +49,7 @@
#include "frameworks/bridge/declarative_frontend/jsview/js_counter.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_data_panel.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_datepicker.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_distributed.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_divider.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_ellipse.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_environment.h"
@@ -1082,6 +1083,7 @@ void JsRegisterViews(BindingTarget globalObj)
JSCustomDialogController::JSBind(globalObj);
JSShareData::JSBind(globalObj);
JSPersistent::JSBind(globalObj);
JSDistributed::JSBind(globalObj);
JSScroller::JSBind(globalObj);
JSProfiler::JSBind(globalObj);
@@ -56,6 +56,7 @@
#include "frameworks/bridge/declarative_frontend/jsview/js_counter.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_data_panel.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_datepicker.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_distributed.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_divider.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_ellipse.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_environment.h"
@@ -876,6 +877,7 @@ void JsRegisterViews(BindingTarget globalObj)
JSBlank::JSBind(globalObj);
JSCalendar::JSBind(globalObj);
JSPersistent::JSBind(globalObj);
JSDistributed::JSBind(globalObj);
JSRadio::JSBind(globalObj);
JSCalendarController::JSBind(globalObj);
JSRenderingContext::JSBind(globalObj);
@@ -1991,6 +1991,157 @@ class PersistentStorage {
}
}
PersistentStorage.Instance_ = undefined;
class DistributedStorage {
constructor(sessionId, statusNotifier) {
this.links_ = new Map();
this.id_ = SubscriberManager.Get().MakeId();
SubscriberManager.Get().add(this);
this.aviliable_ = false;
this.storage_ = new DistributedObject(sessionId, this);
this.notifier_ = statusNotifier;
}
keys() {
let result = [];
const it = this.links_.keys();
let val = it.next();
while (!val.done) {
result.push(val.value);
val = it.next();
}
return result;
}
distributeProp(propName, defaultValue) {
if (this.link(propName, defaultValue)) {
console.debug(`DistributedStorage: writing '${propName}' - '${this.links_.get(propName)}' to storage`);
}
}
distributeProps(properties) {
properties.forEach(property => this.link(property.key, property.defaultValue));
}
link(propName, defaultValue) {
if (defaultValue == null || defaultValue == undefined) {
console.error(`DistributedStorage: linkProp for ${propName} called with 'null' or 'undefined' default value!`);
return false;
}
if (this.links_.get(propName)) {
console.warn(`DistributedStorage: linkProp: ${propName} is already exist`);
return false;
}
let link = AppStorage.GetOrCreate().link(propName, this);
if (link) {
console.debug(`DistributedStorage: linkProp ${propName} in AppStorage, using that`);
this.links_.set(propName, link);
this.setDistributedProp(propName, defaultValue);
}
else {
let returnValue = defaultValue;
if (this.aviliable_) {
let newValue = this.getDistributedProp(propName);
if (newValue == null) {
console.debug(`DistributedStorage: no entry for ${propName}, will initialize with default value`);
this.setDistributedProp(propName, defaultValue);
}
else {
returnValue = newValue;
}
}
link = AppStorage.GetOrCreate().setAndLink(propName, returnValue, this);
this.links_.set(propName, link);
console.debug(`DistributedStorage: created new linkProp prop for ${propName}`);
}
return true;
}
deleteProp(propName) {
let link = this.links_.get(propName);
if (link) {
link.aboutToBeDeleted();
this.links_.delete(propName);
if (this.aviliable_) {
this.storage_.delete(propName);
}
}
else {
console.warn(`DistributedStorage: '${propName}' is not a distributed property warning.`);
}
}
write(key) {
let link = this.links_.get(key);
if (link) {
console.info(`DistributedStorage: write ${key}-${JSON.stringify(link.get())} `);
this.setDistributedProp(key, link.get())
}
}
// public required by the interface, use the static method instead!
aboutToBeDeleted() {
console.debug("DistributedStorage: about to be deleted");
this.links_.forEach((val, key, map) => {
console.debug(`DistributedStorage: removing ${key}`);
val.aboutToBeDeleted();
});
this.links_.clear();
SubscriberManager.Get().delete(this.id());
}
id__() {
return this.id_;
}
propertyHasChanged(info) {
console.info(`DistributedStorage: property changed info:${JSON.stringify(info)} `);
this.write(info);
}
onDataOnChange(propName) {
let link = this.links_.get(propName);
let newValue = this.getDistributedProp(propName);
if (link && newValue != null) {
console.info(`DistributedStorage: dataOnChange[${propName}-${newValue}]`);
link.set(newValue)
}
}
onConnected(status) {
console.info(`DistributedStorage onConnected: status = ${status}`);
if (!this.aviliable_) {
this.syncProp();
this.aviliable_ = true;
}
if (this.notifier_ != null) {
this.notifier_(status);
}
}
syncProp() {
this.links_.forEach((val, key) => {
let newValue = this.getDistributedProp(key);
if (newValue == null) {
this.setDistributedProp(key, val.get());
} else {
val.set(newValue);
}
});
}
setDistributedProp(key, value) {
if (!this.aviliable_) {
console.warn(`DistributedStorage is not aviliable`);
return;
}
if (typeof value == 'object') {
this.storage_.set(key, JSON.stringify(value));
return;
}
this.storage_.set(key, value);
}
getDistributedProp(key) {
let value = this.storage_.get(key);
if (typeof value == 'string') {
try {
let returnValue = JSON.parse(value);
return returnValue;
}
finally {
return value;
}
}
return value;
}
}
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -38,6 +38,7 @@
#include "frameworks/bridge/declarative_frontend/jsview/js_checkbox.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_checkboxgroup.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_clipboard.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_distributed.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_hyperlink.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_offscreen_rendering_context.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_path2d.h"
@@ -771,6 +772,7 @@ void JsRegisterViews(BindingTarget globalObj)
JSPanHandler::JSBind(globalObj);
JsDragFunction::JSBind(globalObj);
JSPersistent::JSBind(globalObj);
JSDistributed::JSBind(globalObj);
JSClipboard::JSBind(globalObj);
JSProfiler::JSBind(globalObj);
@@ -0,0 +1,239 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "bridge/declarative_frontend/jsview/js_distributed.h"
#include "base/memory/referenced.h"
#include "bridge/declarative_frontend/jsview/js_view_common_def.h"
#include "core/common/ace_engine.h"
#include "core/common/container.h"
#include "core/common/container_scope.h"
#include "frameworks/bridge/declarative_frontend/engine/js_ref_ptr.h"
#include "frameworks/bridge/declarative_frontend/jsview/js_container_base.h"
namespace OHOS::Ace::Framework {
void JSDistributed::JSBind(BindingTarget globalObj)
{
JSClass<JSDistributed>::Declare("DistributedObject");
JSClass<JSDistributed>::CustomMethod("set", &JSDistributed::Set);
JSClass<JSDistributed>::CustomMethod("get", &JSDistributed::Get);
JSClass<JSDistributed>::CustomMethod("delete", &JSDistributed::Delete);
JSClass<JSDistributed>::Bind(globalObj, JSDistributed::ConstructorCallback, JSDistributed::DestructorCallback);
}
void JSDistributed::ConstructorCallback(const JSCallbackInfo& args)
{
std::string sessionId;
if (args.Length() > 0 && args[0]->IsString() && args[1]->IsObject()) {
sessionId = args[0]->ToString();
LOGE("sessionId %{public}s", sessionId.c_str());
auto distributed = Referenced::MakeRefPtr<JSDistributed>(sessionId);
distributed->IncRefCount();
distributed->Init(JSRef<JSObject>::Cast(args[1]), sessionId);
args.SetReturnValue(Referenced::RawPtr(distributed));
}
}
void JSDistributed::DestructorCallback(JSDistributed* distributed)
{
if (distributed != nullptr) {
distributed->DecRefCount();
}
}
void JSDistributed::Set(const JSCallbackInfo& args)
{
#if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
LOGW("[Engine Log] Unable to use the DistributedStorage in the Previewer. Perform this operation on the "
"emulator or a real device instead.");
return;
#endif
if (args.Length() < 2) {
LOGW("fail to set distributed data");
return;
}
if (!stroage_) {
LOGW("distributed stroage is null, faid to set distributed data");
return;
}
std::string key = args[0]->ToString();
if (args[1]->IsBoolean()) {
auto val = args[1]->ToBoolean();
LOGW("JSDistributed::Set [%{public}s--%{public}d]", key.c_str(), val);
stroage_->SetBoolean(key, val);
return;
}
if (args[1]->IsNumber()) {
auto val = args[1]->ToNumber<double>();
LOGW("JSDistributed::Set [%{public}s--%{public}lf]", key.c_str(), val);
stroage_->SetDouble(key, val);
return;
}
if (args[1]->IsString()) {
auto val = args[1]->ToString();
LOGW("JSDistributed::Set [%{public}s--%{public}s]", key.c_str(), val.c_str());
stroage_->SetString(key, val);
return;
}
LOGW("JSDistributed::Set type not support [%{public}s]", key.c_str());
}
void JSDistributed::Get(const JSCallbackInfo& args)
{
#if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
LOGW("[Engine Log] Unable to use the DistributedStorage in the Previewer. Perform this operation on the "
"emulator or a real device instead.");
return;
#endif
if (args.Length() < 1) {
LOGW("fail to Get distributed data");
return;
}
std::string key = args[0]->ToString();
LOGW("JSDistributed::Get [%{public}s]", key.c_str());
if (!stroage_) {
LOGW("distributed stroage is null, faid to set distributed data");
return;
}
auto dataType = stroage_->GetDataType(key);
JSVal returnValue = JSVal();
switch (dataType) {
case Storage::DataType::STRING: {
auto value = stroage_->GetString(key);
if (!value.empty()) {
returnValue = JSVal(ToJSValue(value));
LOGE("Get distributed data success, key = [%{public}s] value = [%{public}s]", key.c_str(),
value.c_str());
}
break;
}
case Storage::DataType::DOUBLE: {
double value = 0.0;
if (stroage_->GetDouble(key, value)) {
returnValue = JSVal(ToJSValue(value));
LOGE("Get distributed data success, key = [%{public}s] value = [%{public}lf]", key.c_str(), value);
}
break;
}
case Storage::DataType::BOOLEAN: {
bool value = false;
if (stroage_->GetBoolean(key, value)) {
returnValue = JSVal(ToJSValue(value));
LOGE("Get distributed data success, key = [%{public}s] value = [%{public}d]", key.c_str(), value);
}
break;
}
default:
break;
}
if (returnValue.IsEmpty()) {
LOGE("fail to Get distributed data, key = [%{public}s]", key.c_str());
return;
}
auto returnPtr = JSRef<JSVal>::Make(returnValue);
args.SetReturnValue(returnPtr);
}
void JSDistributed::Delete(const JSCallbackInfo& args)
{
#if defined(WINDOWS_PLATFORM) || defined(MAC_PLATFORM)
LOGW("[Engine Log] Unable to use the DistributedStorage in the Previewer. Perform this operation on the "
"emulator or a real device instead.");
return;
#endif
if (args.Length() < 1) {
LOGW("fail to Delete distributed data");
return;
}
std::string key = args[0]->ToString();
stroage_->Delete(key);
}
void JSDistributed::Init(const JSRef<JSObject>& object, const std::string& sessionId)
{
JSRef<JSVal> jsVal = object->GetProperty("onDataOnChange");
if (!jsVal->IsFunction()) {
LOGE("JSDistributed, get func onDataOnChange failed.");
return;
}
onDataOnChange_ = JSRef<JSFunc>::Cast(jsVal);
jsVal = object->GetProperty("onConnected");
if (!jsVal->IsFunction()) {
LOGE("JSDistributed, get func onConnected failed.");
return;
}
onConnected_ = JSRef<JSFunc>::Cast(jsVal);
object_ = object;
auto instanceId = ContainerScope::CurrentId();
auto notifier = [weak = WeakClaim(this), instanceId](const std::string& onlineStatus) {
ContainerScope scope(instanceId);
auto distributed = weak.Upgrade();
distributed->OnStatusNotify(onlineStatus);
};
auto container = Container::Current();
if (!container) {
LOGW("container is null");
return;
}
auto executor = container->GetTaskExecutor();
stroage_ = StorageProxy::GetInstance()->GetStorage(sessionId, notifier, executor);
auto onChangeCallback = [weak = WeakClaim(this), weakExecutor = WeakPtr<TaskExecutor>(executor), instanceId](
const std::string& key) {
auto taskExecutor_ = weakExecutor.Upgrade();
if (!taskExecutor_) {
return;
}
taskExecutor_->PostTask(
[weak, key, instanceId] {
ContainerScope scope(instanceId);
auto distributed = weak.Upgrade();
if (distributed) {
distributed->OnDataOnChanged(key);
}
},
TaskExecutor::TaskType::JS);
};
stroage_->SetDataOnChangeCallback(std::move(onChangeCallback));
}
void JSDistributed::OnDataOnChanged(const std::string& key)
{
LOGI("distributed date on change key = [%{public}s]", key.c_str());
auto params = ConvertToJSValues(key);
onDataOnChange_->Call(object_, params.size(), params.data());
}
void JSDistributed::OnStatusNotify(const std::string& onlineStatus)
{
LOGI("distributed OnStatusNotify = [%{public}s]", onlineStatus.c_str());
auto params = ConvertToJSValues(onlineStatus);
onConnected_->Call(object_, params.size(), params.data());
}
} // namespace OHOS::Ace::Framework
@@ -0,0 +1,55 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_DISTRIBUTED_H
#define FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_DISTRIBUTED_H
#include "base/memory/referenced.h"
#include "bridge/declarative_frontend/engine/bindings.h"
#include "core/common/storage/storage_proxy.h"
#include "frameworks/bridge/declarative_frontend/engine/js_types.h"
namespace OHOS::Ace::Framework {
class JSDistributed final : public Referenced {
public:
JSDistributed(const std::string& sessionId) : sessionId_(sessionId) {}
void Set(const JSCallbackInfo& args);
void Get(const JSCallbackInfo& args);
void Delete(const JSCallbackInfo& args);
static void ConstructorCallback(const JSCallbackInfo& args);
static void DestructorCallback(JSDistributed* obj);
static void JSBind(BindingTarget globalObj);
void Init(const JSRef<JSObject>& object, const std::string& sessionId);
void OnDataOnChanged(const std::string& key);
void OnStatusNotify(const std::string& onlineStatus);
private:
std::string sessionId_;
JSRef<JSFunc> onDataOnChange_;
JSRef<JSFunc> onConnected_;
JSRef<JSObject> object_;
RefPtr<Storage> stroage_;
};
} // namespace OHOS::Ace::Framework
#endif // FRAMEWORKS_BRIDGE_DECLARATIVE_FRONTEND_JS_VIEW_JS_DISTRIBUTED_H
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -75,7 +75,7 @@ void JSPersistent::Set(const JSCallbackInfo& args)
if(!StorageProxy::GetInstance()->GetStorage(executor)) {
return;
}
StorageProxy::GetInstance()->GetStorage(executor)->Set(key, value);
StorageProxy::GetInstance()->GetStorage(executor)->SetString(key, value);
LOGD("cross window notify, containerId=%{private}d", container->GetInstanceId());
AceEngine::Get().NotifyContainers(
[currInstanceId = container->GetInstanceId(), key, value](const RefPtr<Container>& container) {
@@ -103,7 +103,7 @@ void JSPersistent::Get(const JSCallbackInfo& args)
return;
}
auto executor = container->GetTaskExecutor();
std::string value = StorageProxy::GetInstance()->GetStorage(executor)->Get(key);
std::string value = StorageProxy::GetInstance()->GetStorage(executor)->GetString(key);
auto returnValue = JSVal(ToJSValue(value));
auto returnPtr = JSRef<JSVal>::Make(returnValue);
args.SetReturnValue(returnPtr);
@@ -0,0 +1,192 @@
/*
* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class DistributedStorage implements IMultiPropertiesChangeSubscriber {
private storage_: IStorage;
private id_: number;
private links_: Map<string, ObservedPropertyAbstract<any>>;
private aviliable_: boolean;
private notifier_: (status: string) => void;
public constructor(sessionId: string, notifier: (status: string) => void) {
this.links_ = new Map<string, ObservedPropertyAbstract<any>>();
this.id_ = SubscriberManager.Get().MakeId();
SubscriberManager.Get().add(this);
this.aviliable_ = false;
this.notifier_ = notifier;
}
public keys(): Array<string> {
let result = [];
const it = this.links_.keys();
let val = it.next();
while (!val.done) {
result.push(val.value);
val = it.next();
}
return result;
}
public distributeProp<T>(propName: string, defaultValue: T): void {
if (this.link(propName, defaultValue)) {
console.debug(`DistributedStorage: writing '${propName}' - '${this.links_.get(propName)}' to storage`);
}
}
public distributeProps(properties: {
key: string,
defaultValue: any
}[]): void {
properties.forEach(property => this.link(property.key, property.defaultValue));
}
public link<T>(propName: string, defaultValue: T): boolean {
if (defaultValue == null || defaultValue == undefined) {
console.error(`DistributedStorage: linkProp for ${propName} called with 'null' or 'undefined' default value!`);
return false;
}
if (this.links_.get(propName)) {
console.warn(`DistributedStorage: linkProp: ${propName} is already exist`);
return false;
}
let link = AppStorage.GetOrCreate().link(propName, this);
if (link) {
console.debug(`DistributedStorage: linkProp ${propName} in AppStorage, using that`);
this.links_.set(propName, link);
this.setDistributedProp(propName, defaultValue);
}
else {
let returnValue = defaultValue;
if (this.aviliable_) {
let newValue = this.getDistributedProp(propName);
if (newValue == null) {
console.debug(`DistributedStorage: no entry for ${propName}, will initialize with default value`);
this.setDistributedProp(propName, defaultValue);
}
else {
returnValue = newValue;
}
}
link = AppStorage.GetOrCreate().setAndLink(propName, returnValue, this);
this.links_.set(propName, link);
console.debug(`DistributedStorage: created new linkProp prop for ${propName}`);
}
return true;
}
public deleteProp(propName: string): void {
let link = this.links_.get(propName);
if (link) {
link.aboutToBeDeleted();
this.links_.delete(propName);
if (this.aviliable_) {
this.storage_.delete(propName);
}
} else {
console.warn(`DistributedStorage: '${propName}' is not a distributed property warning.`);
}
}
private write(key: string): void {
let link = this.links_.get(key);
if (link) {
this.setDistributedProp(key, link.get());
}
}
// public required by the interface, use the static method instead!
public aboutToBeDeleted(): void {
console.debug("DistributedStorage: about to be deleted");
this.links_.forEach((val, key, map) => {
console.debug(`DistributedStorage: removing ${key}`);
val.aboutToBeDeleted();
});
this.links_.clear();
SubscriberManager.Get().delete(this.id());
}
public id__(): number {
return this.id_;
}
public propertyHasChanged(info?: PropertyInfo): void {
console.debug("DistributedStorage: property changed");
this.write(info);
}
public onDataOnChange(propName: string): void {
let link = this.links_.get(propName);
let newValue = this.getDistributedProp(propName);
if (link && newValue != null) {
console.info(`DistributedStorage: dataOnChange[${propName}-${newValue}]`);
link.set(newValue)
}
}
public onConnected(status): void {
console.info(`DistributedStorage onConnected: status = ${status}`);
if (!this.aviliable_) {
this.syncProp();
this.aviliable_ = true;
}
if (this.notifier_ != null) {
this.notifier_(status);
}
}
private syncProp(): void {
this.links_.forEach((val, key) => {
let newValue = this.getDistributedProp(key);
if (newValue == null) {
this.setDistributedProp(key, val.get());
} else {
val.set(newValue);
}
});
}
private setDistributedProp(key, value): void {
if (!this.aviliable_) {
console.warn(`DistributedStorage is not aviliable`);
return;
}
console.error(`DistributedStorage value is object ${key}-${JSON.stringify(value)}`);
if (typeof value == 'object') {
this.storage_.set(key, JSON.stringify(value));
return;
}
this.storage_.set(key, value);
}
private getDistributedProp(key): any {
let value = this.storage_.get(key);
if (typeof value == 'string') {
try {
let returnValue = JSON.parse(value);
return returnValue;
}
finally {
return value;
}
}
return value;
}
};
@@ -22,6 +22,7 @@
"src/lib/view_native.d.ts",
"src/lib/view.ts",
"src/lib/persistent_storage.ts",
"src/lib/distributed_storage.ts",
"src/lib/environment.ts",
"src/lib/i_environment_backend.ts",
"src/index.ts",
@@ -22,6 +22,7 @@
"src/lib/view_native.d.ts",
"src/lib/view.ts",
"src/lib/persistent_storage.ts",
"src/lib/distributed_storage.ts",
"src/lib/environment.ts",
"src/lib/i_environment_backend.ts",
"src/index.ts",
+36 -3
View File
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -25,16 +25,49 @@ class Storage : public AceType {
DECLARE_ACE_TYPE(Storage, AceType);
public:
enum class DataType : uint32_t {
NONE = 0,
STRING,
DOUBLE,
BOOLEAN,
};
using DataOnChange = std::function<void(const std::string& key)>;
~Storage() override = default;
virtual void Set(const std::string& key, const std::string& value) = 0;
virtual std::string Get(const std::string& key) = 0;
virtual void SetString(const std::string& key, const std::string& value) = 0;
virtual std::string GetString(const std::string& key) = 0;
virtual void SetDouble(const std::string& key, const double value) = 0;
virtual bool GetDouble(const std::string& key, double& value) = 0;
virtual void SetBoolean(const std::string& key, const bool value) = 0;
virtual bool GetBoolean(const std::string& key, bool& value) = 0;
virtual DataType GetDataType(const std::string& key)
{
return DataType::NONE;
}
virtual void Clear() = 0;
virtual void Delete(const std::string& key) = 0;
void SetDataOnChangeCallback(DataOnChange&& dataOnChange)
{
dataOnChange_ = std::move(dataOnChange);
}
void OnDataChange(const std::string& key)
{
if (dataOnChange_) {
dataOnChange_(key);
}
}
protected:
explicit Storage(const RefPtr<TaskExecutor>& taskExecutor) : taskExecutor_(taskExecutor) {}
Storage() = default;
RefPtr<TaskExecutor> taskExecutor_;
DataOnChange dataOnChange_;
};
} // namespace OHOS::Ace
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -26,7 +26,16 @@ class StorageInterface {
public:
virtual ~StorageInterface() = default;
virtual RefPtr<Storage> GetStorage(const RefPtr<TaskExecutor>& taskExecutor) const = 0;
virtual RefPtr<Storage> GetStorage(const RefPtr<TaskExecutor>& taskExecutor) const
{
return nullptr;
}
virtual RefPtr<Storage> GetStorage(const std::string& sessionId, std::function<void(const std::string&)>&& notifier,
const RefPtr<TaskExecutor>& taskExecutor) const
{
return nullptr;
}
};
} // namespace OHOS::Ace
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -32,6 +32,11 @@ void StorageProxy::SetDelegate(std::unique_ptr<StorageInterface>&& delegate)
delegate_ = std::move(delegate);
}
void StorageProxy::SetDistributedDelegate(std::unique_ptr<StorageInterface>&& delegate)
{
distributedDelegate_ = std::move(delegate);
}
RefPtr<Storage> StorageProxy::GetStorage(const RefPtr<TaskExecutor>& taskExecutor) const
{
if (!delegate_) {
@@ -40,4 +45,13 @@ RefPtr<Storage> StorageProxy::GetStorage(const RefPtr<TaskExecutor>& taskExecuto
return delegate_->GetStorage(taskExecutor);
}
RefPtr<Storage> StorageProxy::GetStorage(const std::string& sessionId,
std::function<void(const std::string&)>&& notifier, const RefPtr<TaskExecutor>& taskExecutor) const
{
if (!distributedDelegate_) {
return nullptr;
}
return distributedDelegate_->GetStorage(sessionId, std::move(notifier), taskExecutor);
}
} // namespace OHOS::Ace
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Huawei Device Co., Ltd.
* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -25,12 +25,16 @@ class ACE_EXPORT StorageProxy : public StorageInterface {
public:
ACE_EXPORT static StorageProxy* GetInstance();
void SetDelegate(std::unique_ptr<StorageInterface>&& delegate);
void SetDistributedDelegate(std::unique_ptr<StorageInterface>&& delegate);
RefPtr<Storage> GetStorage(const RefPtr<TaskExecutor>& taskExecutor) const override;
RefPtr<Storage> GetStorage(const std::string& sessionId, std::function<void(const std::string&)>&& notifier,
const RefPtr<TaskExecutor>& taskExecutor) const override;
StorageProxy() = default;
~StorageProxy() = default;
private:
std::unique_ptr<StorageInterface> delegate_;
std::unique_ptr<StorageInterface> distributedDelegate_;
static StorageProxy* inst_;
};