18bf80f4bSopenharmony_ci/*
28bf80f4bSopenharmony_ci * Copyright (C) 2024 Huawei Device Co., Ltd.
38bf80f4bSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
48bf80f4bSopenharmony_ci * you may not use this file except in compliance with the License.
58bf80f4bSopenharmony_ci * You may obtain a copy of the License at
68bf80f4bSopenharmony_ci *
78bf80f4bSopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
88bf80f4bSopenharmony_ci *
98bf80f4bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
108bf80f4bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
118bf80f4bSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
128bf80f4bSopenharmony_ci * See the License for the specific language governing permissions and
138bf80f4bSopenharmony_ci * limitations under the License.
148bf80f4bSopenharmony_ci */
158bf80f4bSopenharmony_ci
168bf80f4bSopenharmony_ci#include "PropertyProxy.h"
178bf80f4bSopenharmony_ci
188bf80f4bSopenharmony_ci#include <meta/api/make_callback.h>
198bf80f4bSopenharmony_ci#include <meta/interface/intf_task_queue_registry.h>
208bf80f4bSopenharmony_ci#include <napi_api.h>
218bf80f4bSopenharmony_ci#include "BaseObjectJS.h"
228bf80f4bSopenharmony_ci
238bf80f4bSopenharmony_ciclass PropCtx {
248bf80f4bSopenharmony_ci    PropertyProxy* proxy_;
258bf80f4bSopenharmony_ci    BASE_NS::string memb_;
268bf80f4bSopenharmony_ci
278bf80f4bSopenharmony_cipublic:
288bf80f4bSopenharmony_ci    PropCtx(PropertyProxy* p, BASE_NS::string m);
298bf80f4bSopenharmony_ci    ~PropCtx();
308bf80f4bSopenharmony_ci    napi_value GetValue(NapiApi::FunctionContext<>& info);
318bf80f4bSopenharmony_ci    void SetValue(NapiApi::FunctionContext<>& info);
328bf80f4bSopenharmony_ci};
338bf80f4bSopenharmony_ci
348bf80f4bSopenharmony_ciPropCtx::PropCtx(PropertyProxy* p, BASE_NS::string m)
358bf80f4bSopenharmony_ci{
368bf80f4bSopenharmony_ci    proxy_ = p;
378bf80f4bSopenharmony_ci    memb_ = m;
388bf80f4bSopenharmony_ci}
398bf80f4bSopenharmony_ciPropCtx::~PropCtx()
408bf80f4bSopenharmony_ci{
418bf80f4bSopenharmony_ci}
428bf80f4bSopenharmony_cinapi_value PropCtx::GetValue(NapiApi::FunctionContext<>& info)
438bf80f4bSopenharmony_ci{
448bf80f4bSopenharmony_ci    return proxy_->GetValue(info, memb_);
458bf80f4bSopenharmony_ci}
468bf80f4bSopenharmony_civoid PropCtx::SetValue(NapiApi::FunctionContext<>& info)
478bf80f4bSopenharmony_ci{
488bf80f4bSopenharmony_ci    proxy_->SetValue(info, memb_);
498bf80f4bSopenharmony_ci}
508bf80f4bSopenharmony_ci
518bf80f4bSopenharmony_civoid PropertyProxy::UpdateLocal()
528bf80f4bSopenharmony_ci{
538bf80f4bSopenharmony_ci    // should execute in engine thread.
548bf80f4bSopenharmony_ci    duh.Lock();
558bf80f4bSopenharmony_ci    UpdateLocalValues();
568bf80f4bSopenharmony_ci    duh.Unlock();
578bf80f4bSopenharmony_ci}
588bf80f4bSopenharmony_ciint32_t PropertyProxy::UpdateRemote()
598bf80f4bSopenharmony_ci{
608bf80f4bSopenharmony_ci    // executed in engine thread (ie. happens between frames)
618bf80f4bSopenharmony_ci    duh.Lock();
628bf80f4bSopenharmony_ci    // make sure the handler is not called..
638bf80f4bSopenharmony_ci    prop_->OnChanged()->RemoveHandler(changeToken_);
648bf80f4bSopenharmony_ci
658bf80f4bSopenharmony_ci    UpdateRemoteValues();
668bf80f4bSopenharmony_ci
678bf80f4bSopenharmony_ci    // add it back.
688bf80f4bSopenharmony_ci    changeToken_ = prop_->OnChanged()->AddHandler(changeHandler_);
698bf80f4bSopenharmony_ci    updateToken_ = nullptr;
708bf80f4bSopenharmony_ci    duh.Unlock();
718bf80f4bSopenharmony_ci
728bf80f4bSopenharmony_ci    return 0;
738bf80f4bSopenharmony_ci}
748bf80f4bSopenharmony_ci
758bf80f4bSopenharmony_civoid PropertyProxy::ScheduleUpdate()
768bf80f4bSopenharmony_ci{
778bf80f4bSopenharmony_ci    // create a task to engine queue to sync the property.
788bf80f4bSopenharmony_ci    if (updateToken_ == nullptr) {
798bf80f4bSopenharmony_ci        // sync not queued, so queue sync.
808bf80f4bSopenharmony_ci        updateToken_ = META_NS::GetTaskQueueRegistry().GetTaskQueue(ENGINE_THREAD)->AddTask(updateTask_);
818bf80f4bSopenharmony_ci    }
828bf80f4bSopenharmony_ci}
838bf80f4bSopenharmony_ci
848bf80f4bSopenharmony_ciPropertyProxy::PropertyProxy(META_NS::IProperty::Ptr prop) : prop_(prop)
858bf80f4bSopenharmony_ci{
868bf80f4bSopenharmony_ci    changeHandler_ = META_NS::MakeCallback<META_NS::IOnChanged>(this, &PropertyProxy::UpdateLocal);
878bf80f4bSopenharmony_ci    changeToken_ = prop_->OnChanged()->AddHandler(changeHandler_);
888bf80f4bSopenharmony_ci    updateTask_ = META_NS::MakeCallback<META_NS::ITaskQueueTask>(this, &PropertyProxy::UpdateRemote);
898bf80f4bSopenharmony_ci}
908bf80f4bSopenharmony_civoid PropertyProxy::SyncGet()
918bf80f4bSopenharmony_ci{
928bf80f4bSopenharmony_ci    // initialize current values.
938bf80f4bSopenharmony_ci    ExecSyncTask([this]() {
948bf80f4bSopenharmony_ci        // executed in engine thread
958bf80f4bSopenharmony_ci        UpdateLocal();
968bf80f4bSopenharmony_ci        return META_NS::IAny::Ptr {};
978bf80f4bSopenharmony_ci    });
988bf80f4bSopenharmony_ci}
998bf80f4bSopenharmony_ciPropertyProxy::~PropertyProxy()
1008bf80f4bSopenharmony_ci{
1018bf80f4bSopenharmony_ci    if (prop_) {
1028bf80f4bSopenharmony_ci        prop_->OnChanged()->RemoveHandler(changeToken_);
1038bf80f4bSopenharmony_ci    }
1048bf80f4bSopenharmony_ci
1058bf80f4bSopenharmony_ci    for (auto t : accessors) {
1068bf80f4bSopenharmony_ci        delete t;
1078bf80f4bSopenharmony_ci    }
1088bf80f4bSopenharmony_ci}
1098bf80f4bSopenharmony_ci
1108bf80f4bSopenharmony_civoid PropertyProxy::Create(napi_env env, const BASE_NS::string jsName)
1118bf80f4bSopenharmony_ci{
1128bf80f4bSopenharmony_ci    NapiApi::MyInstanceState* mis;
1138bf80f4bSopenharmony_ci    napi_get_instance_data(env, (void**)&mis);
1148bf80f4bSopenharmony_ci    auto ref = NapiApi::Object(env, mis->getRef());
1158bf80f4bSopenharmony_ci    auto cl = ref.Get(jsName.c_str());
1168bf80f4bSopenharmony_ci    if (cl) {
1178bf80f4bSopenharmony_ci        napi_value value;
1188bf80f4bSopenharmony_ci        napi_new_instance(env, cl, 0, nullptr, &value);
1198bf80f4bSopenharmony_ci        obj = NapiApi::StrongRef { NapiApi::Object(env, value) };
1208bf80f4bSopenharmony_ci    } else {
1218bf80f4bSopenharmony_ci        CORE_LOG_F("Could not create property object for %s", jsName.c_str());
1228bf80f4bSopenharmony_ci    }
1238bf80f4bSopenharmony_ci}
1248bf80f4bSopenharmony_ci
1258bf80f4bSopenharmony_civoid PropertyProxy::Hook(const BASE_NS::string member)
1268bf80f4bSopenharmony_ci{
1278bf80f4bSopenharmony_ci    auto* accessor = new PropCtx(this, member.c_str());
1288bf80f4bSopenharmony_ci    accessors.push_back(accessor);
1298bf80f4bSopenharmony_ci    auto value = obj.GetValue();
1308bf80f4bSopenharmony_ci
1318bf80f4bSopenharmony_ci    napi_property_descriptor desc { member.c_str(), nullptr, nullptr,
1328bf80f4bSopenharmony_ci
1338bf80f4bSopenharmony_ci        [](napi_env e, napi_callback_info i) -> napi_value {
1348bf80f4bSopenharmony_ci            NapiApi::FunctionContext<> info(e, i);
1358bf80f4bSopenharmony_ci            auto pc = (PropCtx*)info.GetData();
1368bf80f4bSopenharmony_ci            return pc->GetValue(info);
1378bf80f4bSopenharmony_ci        },
1388bf80f4bSopenharmony_ci        [](napi_env e, napi_callback_info i) -> napi_value {
1398bf80f4bSopenharmony_ci            NapiApi::FunctionContext<> info(e, i);
1408bf80f4bSopenharmony_ci            auto pc = (PropCtx*)info.GetData();
1418bf80f4bSopenharmony_ci            pc->SetValue(info);
1428bf80f4bSopenharmony_ci            return {};
1438bf80f4bSopenharmony_ci        },
1448bf80f4bSopenharmony_ci        nullptr, napi_default_jsproperty, (void*)accessor };
1458bf80f4bSopenharmony_ci    napi_status status = napi_define_properties(obj.GetEnv(), value, 1, &desc);
1468bf80f4bSopenharmony_ci}
1478bf80f4bSopenharmony_ciPropertyProxy::operator napi_value()
1488bf80f4bSopenharmony_ci{
1498bf80f4bSopenharmony_ci    return obj.GetValue();
1508bf80f4bSopenharmony_ci}
1518bf80f4bSopenharmony_ci
1528bf80f4bSopenharmony_ciNapiApi::Value<NapiApi::Object> PropertyProxy::Value()
1538bf80f4bSopenharmony_ci{
1548bf80f4bSopenharmony_ci    return { obj.GetEnv(), obj.GetValue() };
1558bf80f4bSopenharmony_ci}
1568bf80f4bSopenharmony_ci
1578bf80f4bSopenharmony_ciconst META_NS::IProperty::Ptr& PropertyProxy::GetProperty() const
1588bf80f4bSopenharmony_ci{
1598bf80f4bSopenharmony_ci    return prop_;
1608bf80f4bSopenharmony_ci}
161