1d9f0492fSopenharmony_ci/* 2d9f0492fSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 3d9f0492fSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4d9f0492fSopenharmony_ci * you may not use this file except in compliance with the License. 5d9f0492fSopenharmony_ci * You may obtain a copy of the License at 6d9f0492fSopenharmony_ci * 7d9f0492fSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8d9f0492fSopenharmony_ci * 9d9f0492fSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10d9f0492fSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11d9f0492fSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12d9f0492fSopenharmony_ci * See the License for the specific language governing permissions and 13d9f0492fSopenharmony_ci * limitations under the License. 14d9f0492fSopenharmony_ci */ 15d9f0492fSopenharmony_ci 16d9f0492fSopenharmony_ci#include <functional> 17d9f0492fSopenharmony_ci#include <vector> 18d9f0492fSopenharmony_ci#include "native_parameters_js.h" 19d9f0492fSopenharmony_ci#include "uv.h" 20d9f0492fSopenharmony_ci 21d9f0492fSopenharmony_ciusing namespace OHOS::system; 22d9f0492fSopenharmony_cistatic constexpr int ARGC_NUMBER = 2; 23d9f0492fSopenharmony_cistatic constexpr int BUF_LENGTH = 128; 24d9f0492fSopenharmony_ci 25d9f0492fSopenharmony_cistatic napi_ref g_paramWatchRef; 26d9f0492fSopenharmony_ci 27d9f0492fSopenharmony_ciusing ParamAsyncContext = struct ParamAsyncContext { 28d9f0492fSopenharmony_ci napi_env env = nullptr; 29d9f0492fSopenharmony_ci napi_async_work work = nullptr; 30d9f0492fSopenharmony_ci 31d9f0492fSopenharmony_ci char key[BUF_LENGTH] = { 0 }; 32d9f0492fSopenharmony_ci size_t keyLen = 0; 33d9f0492fSopenharmony_ci char value[BUF_LENGTH] = { 0 }; 34d9f0492fSopenharmony_ci size_t valueLen = 0; 35d9f0492fSopenharmony_ci int32_t timeout = 0; 36d9f0492fSopenharmony_ci napi_deferred deferred = nullptr; 37d9f0492fSopenharmony_ci napi_ref callbackRef = nullptr; 38d9f0492fSopenharmony_ci 39d9f0492fSopenharmony_ci int status = -1; 40d9f0492fSopenharmony_ci std::string getValue; 41d9f0492fSopenharmony_ci}; 42d9f0492fSopenharmony_ci 43d9f0492fSopenharmony_ciusing ParamWatcher = struct ParamWatcher { 44d9f0492fSopenharmony_ci napi_env env = nullptr; 45d9f0492fSopenharmony_ci napi_ref thisVarRef = nullptr; 46d9f0492fSopenharmony_ci char keyPrefix[BUF_LENGTH] = { 0 }; 47d9f0492fSopenharmony_ci size_t keyLen = 0; 48d9f0492fSopenharmony_ci bool notifySwitch = false; 49d9f0492fSopenharmony_ci bool startWatch = false; 50d9f0492fSopenharmony_ci std::mutex mutex {}; 51d9f0492fSopenharmony_ci napi_ref currCallbackRef = nullptr; 52d9f0492fSopenharmony_ci std::map<uint32_t, napi_ref> callbackReferences {}; 53d9f0492fSopenharmony_ci}; 54d9f0492fSopenharmony_ci 55d9f0492fSopenharmony_ciusing ParamWatcherWork = struct ParamWatcherWork { 56d9f0492fSopenharmony_ci napi_async_work work = nullptr; 57d9f0492fSopenharmony_ci ParamWatcher *watcher = nullptr; 58d9f0492fSopenharmony_ci bool startWatch = false; 59d9f0492fSopenharmony_ci}; 60d9f0492fSopenharmony_ci 61d9f0492fSopenharmony_ciusing ParamChangeValue = struct ParamChangeValue { 62d9f0492fSopenharmony_ci uv_work_t work; 63d9f0492fSopenharmony_ci ParamWatcher *watcher; 64d9f0492fSopenharmony_ci std::string key; 65d9f0492fSopenharmony_ci std::string value; 66d9f0492fSopenharmony_ci}; 67d9f0492fSopenharmony_ci 68d9f0492fSopenharmony_ciusing ParamAsyncContextPtr = ParamAsyncContext *; 69d9f0492fSopenharmony_ciusing ParamWatcherPtr = ParamWatcher *; 70d9f0492fSopenharmony_ci 71d9f0492fSopenharmony_cistatic napi_value NapiGetNull(napi_env env) 72d9f0492fSopenharmony_ci{ 73d9f0492fSopenharmony_ci napi_value result = 0; 74d9f0492fSopenharmony_ci napi_get_null(env, &result); 75d9f0492fSopenharmony_ci return result; 76d9f0492fSopenharmony_ci} 77d9f0492fSopenharmony_ci 78d9f0492fSopenharmony_cistatic napi_value GetNapiValue(napi_env env, int val) 79d9f0492fSopenharmony_ci{ 80d9f0492fSopenharmony_ci napi_value result = nullptr; 81d9f0492fSopenharmony_ci napi_create_int32(env, val, &result); 82d9f0492fSopenharmony_ci return result; 83d9f0492fSopenharmony_ci} 84d9f0492fSopenharmony_ci 85d9f0492fSopenharmony_cistatic int GetParamValue(napi_env env, napi_value arg, napi_valuetype valueType, char *buffer, size_t &buffLen) 86d9f0492fSopenharmony_ci{ 87d9f0492fSopenharmony_ci napi_valuetype type = napi_null; 88d9f0492fSopenharmony_ci napi_typeof(env, arg, &type); 89d9f0492fSopenharmony_ci PARAM_JS_CHECK(type == valueType, return -1, "Invalid type %d %d", type, valueType); 90d9f0492fSopenharmony_ci napi_status status = napi_ok; 91d9f0492fSopenharmony_ci if (valueType == napi_string) { 92d9f0492fSopenharmony_ci status = napi_get_value_string_utf8(env, arg, buffer, buffLen, &buffLen); 93d9f0492fSopenharmony_ci } else if (valueType == napi_number) { 94d9f0492fSopenharmony_ci status = napi_get_value_int32(env, arg, reinterpret_cast<int *>(buffer)); 95d9f0492fSopenharmony_ci } 96d9f0492fSopenharmony_ci return status; 97d9f0492fSopenharmony_ci} 98d9f0492fSopenharmony_ci 99d9f0492fSopenharmony_cistatic void WaitCallbackWork(napi_env env, ParamAsyncContextPtr asyncContext) 100d9f0492fSopenharmony_ci{ 101d9f0492fSopenharmony_ci napi_value resource = nullptr; 102d9f0492fSopenharmony_ci napi_create_string_utf8(env, "JSStartupGet", NAPI_AUTO_LENGTH, &resource); 103d9f0492fSopenharmony_ci napi_create_async_work( 104d9f0492fSopenharmony_ci env, nullptr, resource, 105d9f0492fSopenharmony_ci [](napi_env env, void *data) { 106d9f0492fSopenharmony_ci ParamAsyncContext *asyncContext = reinterpret_cast<ParamAsyncContext *>(data); 107d9f0492fSopenharmony_ci asyncContext->status = WaitParameter(asyncContext->key, asyncContext->value, asyncContext->timeout); 108d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp Wait status: %d, key: %s", asyncContext->status, asyncContext->key); 109d9f0492fSopenharmony_ci }, 110d9f0492fSopenharmony_ci [](napi_env env, napi_status status, void *data) { 111d9f0492fSopenharmony_ci ParamAsyncContext *asyncContext = reinterpret_cast<ParamAsyncContext *>(data); 112d9f0492fSopenharmony_ci napi_value result[ARGC_NUMBER] = { 0 }; 113d9f0492fSopenharmony_ci napi_value message = nullptr; 114d9f0492fSopenharmony_ci napi_create_object(env, &result[0]); 115d9f0492fSopenharmony_ci napi_create_int32(env, asyncContext->status, &message); 116d9f0492fSopenharmony_ci napi_set_named_property(env, result[0], "code", message); 117d9f0492fSopenharmony_ci napi_get_undefined(env, &result[1]); // only one param 118d9f0492fSopenharmony_ci 119d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp Wait status: %d, key: %s ", asyncContext->status, asyncContext->key); 120d9f0492fSopenharmony_ci if (asyncContext->deferred) { 121d9f0492fSopenharmony_ci if (asyncContext->status == 0) { 122d9f0492fSopenharmony_ci napi_resolve_deferred(env, asyncContext->deferred, result[1]); 123d9f0492fSopenharmony_ci } else { 124d9f0492fSopenharmony_ci napi_reject_deferred(env, asyncContext->deferred, result[0]); 125d9f0492fSopenharmony_ci } 126d9f0492fSopenharmony_ci } else { 127d9f0492fSopenharmony_ci napi_value callbackRef = nullptr; 128d9f0492fSopenharmony_ci napi_value callResult = nullptr; 129d9f0492fSopenharmony_ci napi_status status = napi_get_reference_value(env, asyncContext->callbackRef, &callbackRef); 130d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0 && callbackRef != nullptr, return, "Failed to get reference "); 131d9f0492fSopenharmony_ci napi_value undefined; 132d9f0492fSopenharmony_ci napi_get_undefined(env, &undefined); 133d9f0492fSopenharmony_ci napi_call_function(env, undefined, callbackRef, ARGC_NUMBER, result, &callResult); 134d9f0492fSopenharmony_ci napi_delete_reference(env, asyncContext->callbackRef); 135d9f0492fSopenharmony_ci } 136d9f0492fSopenharmony_ci napi_delete_async_work(env, asyncContext->work); 137d9f0492fSopenharmony_ci delete asyncContext; 138d9f0492fSopenharmony_ci }, 139d9f0492fSopenharmony_ci reinterpret_cast<void *>(asyncContext), &asyncContext->work); 140d9f0492fSopenharmony_ci napi_queue_async_work(env, asyncContext->work); 141d9f0492fSopenharmony_ci} 142d9f0492fSopenharmony_ci 143d9f0492fSopenharmony_cinapi_value ParamWait(napi_env env, napi_callback_info info) 144d9f0492fSopenharmony_ci{ 145d9f0492fSopenharmony_ci constexpr int PARAM_TIMEOUT_INDEX = 2; 146d9f0492fSopenharmony_ci constexpr int ARGC_THREE_NUMBER = 3; 147d9f0492fSopenharmony_ci size_t argc = ARGC_THREE_NUMBER + 1; 148d9f0492fSopenharmony_ci napi_value argv[ARGC_THREE_NUMBER + 1]; 149d9f0492fSopenharmony_ci napi_value thisVar = nullptr; 150d9f0492fSopenharmony_ci napi_status status = napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr); 151d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == napi_ok, return GetNapiValue(env, status), "Failed to get cb info"); 152d9f0492fSopenharmony_ci PARAM_JS_CHECK(argc >= ARGC_THREE_NUMBER, return GetNapiValue(env, status), "Failed to get argc"); 153d9f0492fSopenharmony_ci 154d9f0492fSopenharmony_ci ParamAsyncContextPtr asyncContext = new ParamAsyncContext(); 155d9f0492fSopenharmony_ci PARAM_JS_CHECK(asyncContext != nullptr, return GetNapiValue(env, status), "Failed to create context"); 156d9f0492fSopenharmony_ci asyncContext->env = env; 157d9f0492fSopenharmony_ci 158d9f0492fSopenharmony_ci // get param key 159d9f0492fSopenharmony_ci asyncContext->keyLen = BUF_LENGTH - 1; 160d9f0492fSopenharmony_ci asyncContext->valueLen = BUF_LENGTH - 1; 161d9f0492fSopenharmony_ci size_t len = sizeof(asyncContext->timeout); 162d9f0492fSopenharmony_ci int ret = GetParamValue(env, argv[0], napi_string, asyncContext->key, asyncContext->keyLen); 163d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, delete asyncContext; 164d9f0492fSopenharmony_ci return GetNapiValue(env, ret), "Invalid param for wait"); 165d9f0492fSopenharmony_ci ret = GetParamValue(env, argv[1], napi_string, asyncContext->value, asyncContext->valueLen); 166d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, delete asyncContext; 167d9f0492fSopenharmony_ci return GetNapiValue(env, ret), "Invalid param for wait"); 168d9f0492fSopenharmony_ci ret = GetParamValue(env, argv[PARAM_TIMEOUT_INDEX], napi_number, (char *)&asyncContext->timeout, len); 169d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, delete asyncContext; 170d9f0492fSopenharmony_ci return GetNapiValue(env, ret), "Invalid param for wait"); 171d9f0492fSopenharmony_ci if (argc > ARGC_THREE_NUMBER) { 172d9f0492fSopenharmony_ci napi_valuetype valueType = napi_null; 173d9f0492fSopenharmony_ci napi_typeof(env, argv[ARGC_THREE_NUMBER], &valueType); 174d9f0492fSopenharmony_ci PARAM_JS_CHECK(valueType == napi_function, delete asyncContext; 175d9f0492fSopenharmony_ci return GetNapiValue(env, ret), "Invalid param for wait callbackRef"); 176d9f0492fSopenharmony_ci napi_create_reference(env, argv[ARGC_THREE_NUMBER], 1, &asyncContext->callbackRef); 177d9f0492fSopenharmony_ci } 178d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp Wait key: %s, value: %s timeout %d.", 179d9f0492fSopenharmony_ci asyncContext->key, asyncContext->value, asyncContext->timeout); 180d9f0492fSopenharmony_ci 181d9f0492fSopenharmony_ci napi_value result = nullptr; 182d9f0492fSopenharmony_ci if (asyncContext->callbackRef == nullptr) { 183d9f0492fSopenharmony_ci napi_create_promise(env, &asyncContext->deferred, &result); 184d9f0492fSopenharmony_ci } else { 185d9f0492fSopenharmony_ci result = GetNapiValue(env, 0); 186d9f0492fSopenharmony_ci } 187d9f0492fSopenharmony_ci WaitCallbackWork(env, asyncContext); 188d9f0492fSopenharmony_ci return result; 189d9f0492fSopenharmony_ci} 190d9f0492fSopenharmony_ci 191d9f0492fSopenharmony_cistatic bool GetFristRefence(ParamWatcherPtr watcher, uint32_t &next) 192d9f0492fSopenharmony_ci{ 193d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 194d9f0492fSopenharmony_ci auto iter = watcher->callbackReferences.begin(); 195d9f0492fSopenharmony_ci if (iter != watcher->callbackReferences.end()) { 196d9f0492fSopenharmony_ci next = watcher->callbackReferences.begin()->first; 197d9f0492fSopenharmony_ci return true; 198d9f0492fSopenharmony_ci } 199d9f0492fSopenharmony_ci return false; 200d9f0492fSopenharmony_ci} 201d9f0492fSopenharmony_ci 202d9f0492fSopenharmony_cistatic napi_ref GetWatcherReference(ParamWatcherPtr watcher, uint32_t next) 203d9f0492fSopenharmony_ci{ 204d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 205d9f0492fSopenharmony_ci auto iter = watcher->callbackReferences.find(next); 206d9f0492fSopenharmony_ci if (iter != watcher->callbackReferences.end()) { 207d9f0492fSopenharmony_ci return iter->second; 208d9f0492fSopenharmony_ci } 209d9f0492fSopenharmony_ci return nullptr; 210d9f0492fSopenharmony_ci} 211d9f0492fSopenharmony_ci 212d9f0492fSopenharmony_cistatic uint32_t GetNextRefence(ParamWatcherPtr watcher, uint32_t &next) 213d9f0492fSopenharmony_ci{ 214d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 215d9f0492fSopenharmony_ci auto iter = watcher->callbackReferences.upper_bound(next); 216d9f0492fSopenharmony_ci if (iter == watcher->callbackReferences.end()) { 217d9f0492fSopenharmony_ci return false; 218d9f0492fSopenharmony_ci } 219d9f0492fSopenharmony_ci next = iter->first; 220d9f0492fSopenharmony_ci return true; 221d9f0492fSopenharmony_ci} 222d9f0492fSopenharmony_ci 223d9f0492fSopenharmony_cistatic void AddWatcherCallback(ParamWatcherPtr watcher, napi_ref callbackRef) 224d9f0492fSopenharmony_ci{ 225d9f0492fSopenharmony_ci static uint32_t watcherId = 0; 226d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 227d9f0492fSopenharmony_ci watcherId++; 228d9f0492fSopenharmony_ci watcher->callbackReferences[watcherId] = callbackRef; 229d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher add watcher callback %s %u.", 230d9f0492fSopenharmony_ci watcher->keyPrefix, watcherId); 231d9f0492fSopenharmony_ci} 232d9f0492fSopenharmony_ci 233d9f0492fSopenharmony_cistatic void DelWatcherCallback(ParamWatcherPtr watcher, uint32_t next) 234d9f0492fSopenharmony_ci{ 235d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher key %s delete callback %u", watcher->keyPrefix, next); 236d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 237d9f0492fSopenharmony_ci watcher->callbackReferences.erase(next); 238d9f0492fSopenharmony_ci} 239d9f0492fSopenharmony_ci 240d9f0492fSopenharmony_cistatic void DelCallbackRef(napi_env env, ParamWatcherPtr watcher, napi_ref callbackRef, uint32_t id) 241d9f0492fSopenharmony_ci{ 242d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 243d9f0492fSopenharmony_ci if (callbackRef == watcher->currCallbackRef) { 244d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher key %s has been callbacked %u.", 245d9f0492fSopenharmony_ci watcher->keyPrefix, id); 246d9f0492fSopenharmony_ci watcher->currCallbackRef = nullptr; 247d9f0492fSopenharmony_ci } else { 248d9f0492fSopenharmony_ci napi_delete_reference(env, callbackRef); 249d9f0492fSopenharmony_ci } 250d9f0492fSopenharmony_ci watcher->callbackReferences.erase(id); 251d9f0492fSopenharmony_ci} 252d9f0492fSopenharmony_ci 253d9f0492fSopenharmony_cistatic void DelCallback(napi_env env, napi_value callback, ParamWatcherPtr watcher) 254d9f0492fSopenharmony_ci{ 255d9f0492fSopenharmony_ci bool isEquals = false; 256d9f0492fSopenharmony_ci uint32_t next = 0; 257d9f0492fSopenharmony_ci bool ret = GetFristRefence(watcher, next); 258d9f0492fSopenharmony_ci while (ret) { 259d9f0492fSopenharmony_ci napi_ref callbackRef = GetWatcherReference(watcher, next); 260d9f0492fSopenharmony_ci if (callbackRef == nullptr) { 261d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher key %s callbackRef has been deleted %d.", watcher->keyPrefix, next); 262d9f0492fSopenharmony_ci DelWatcherCallback(watcher, next); 263d9f0492fSopenharmony_ci } else if (callback != nullptr) { 264d9f0492fSopenharmony_ci napi_value handler = nullptr; 265d9f0492fSopenharmony_ci napi_get_reference_value(env, callbackRef, &handler); 266d9f0492fSopenharmony_ci napi_strict_equals(env, handler, callback, &isEquals); 267d9f0492fSopenharmony_ci if (isEquals) { 268d9f0492fSopenharmony_ci DelCallbackRef(env, watcher, callbackRef, next); 269d9f0492fSopenharmony_ci break; 270d9f0492fSopenharmony_ci } 271d9f0492fSopenharmony_ci } else { 272d9f0492fSopenharmony_ci DelCallbackRef(env, watcher, callbackRef, next); 273d9f0492fSopenharmony_ci } 274d9f0492fSopenharmony_ci ret = GetNextRefence(watcher, next); 275d9f0492fSopenharmony_ci } 276d9f0492fSopenharmony_ci} 277d9f0492fSopenharmony_ci 278d9f0492fSopenharmony_cistatic bool CheckCallbackEqual(napi_env env, napi_value callback, ParamWatcherPtr watcher) 279d9f0492fSopenharmony_ci{ 280d9f0492fSopenharmony_ci bool isEquals = false; 281d9f0492fSopenharmony_ci uint32_t next = 0; 282d9f0492fSopenharmony_ci bool ret = GetFristRefence(watcher, next); 283d9f0492fSopenharmony_ci while (ret) { 284d9f0492fSopenharmony_ci napi_ref callbackRef = GetWatcherReference(watcher, next); 285d9f0492fSopenharmony_ci if (callbackRef != nullptr) { 286d9f0492fSopenharmony_ci napi_value handler = nullptr; 287d9f0492fSopenharmony_ci napi_get_reference_value(env, callbackRef, &handler); 288d9f0492fSopenharmony_ci napi_strict_equals(env, handler, callback, &isEquals); 289d9f0492fSopenharmony_ci if (isEquals) { 290d9f0492fSopenharmony_ci return true; 291d9f0492fSopenharmony_ci } 292d9f0492fSopenharmony_ci } 293d9f0492fSopenharmony_ci ret = GetNextRefence(watcher, next); 294d9f0492fSopenharmony_ci } 295d9f0492fSopenharmony_ci return false; 296d9f0492fSopenharmony_ci} 297d9f0492fSopenharmony_ci 298d9f0492fSopenharmony_cistatic napi_value ParamWatchConstructor(napi_env env, napi_callback_info info) 299d9f0492fSopenharmony_ci{ 300d9f0492fSopenharmony_ci size_t argc = 1; 301d9f0492fSopenharmony_ci napi_value argv[1]; 302d9f0492fSopenharmony_ci napi_value thisVar = nullptr; 303d9f0492fSopenharmony_ci NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr)); 304d9f0492fSopenharmony_ci ParamWatcherPtr watcher = new ParamWatcher(); 305d9f0492fSopenharmony_ci PARAM_JS_CHECK(watcher != nullptr, return NapiGetNull(env), "Failed to create param watcher"); 306d9f0492fSopenharmony_ci napi_status status = napi_create_reference(env, thisVar, 1, &watcher->thisVarRef); 307d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0, delete watcher; 308d9f0492fSopenharmony_ci return NapiGetNull(env), "Failed to create reference %d", status); 309d9f0492fSopenharmony_ci 310d9f0492fSopenharmony_ci napi_wrap( 311d9f0492fSopenharmony_ci env, thisVar, watcher, 312d9f0492fSopenharmony_ci [](napi_env env, void *data, void *hint) { 313d9f0492fSopenharmony_ci ParamWatcherPtr watcher = static_cast<ParamWatcherPtr>(data); 314d9f0492fSopenharmony_ci if (watcher) { 315d9f0492fSopenharmony_ci DelCallback(env, nullptr, watcher); 316d9f0492fSopenharmony_ci WatchParameter(watcher->keyPrefix, nullptr, nullptr); 317d9f0492fSopenharmony_ci delete watcher; 318d9f0492fSopenharmony_ci watcher = nullptr; 319d9f0492fSopenharmony_ci } 320d9f0492fSopenharmony_ci }, 321d9f0492fSopenharmony_ci nullptr, nullptr); 322d9f0492fSopenharmony_ci return thisVar; 323d9f0492fSopenharmony_ci} 324d9f0492fSopenharmony_ci 325d9f0492fSopenharmony_cinapi_value GetWatcher(napi_env env, napi_callback_info info) 326d9f0492fSopenharmony_ci{ 327d9f0492fSopenharmony_ci size_t argc = 1; 328d9f0492fSopenharmony_ci napi_value argv[1]; 329d9f0492fSopenharmony_ci napi_value thisVar = nullptr; 330d9f0492fSopenharmony_ci void *data = nullptr; 331d9f0492fSopenharmony_ci NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)); 332d9f0492fSopenharmony_ci 333d9f0492fSopenharmony_ci napi_value obj = thisVar; 334d9f0492fSopenharmony_ci ParamWatcherPtr watcher = nullptr; 335d9f0492fSopenharmony_ci napi_unwrap(env, thisVar, (void **)&watcher); 336d9f0492fSopenharmony_ci if (watcher == nullptr) { // check if watcher exist 337d9f0492fSopenharmony_ci napi_value constructor = nullptr; 338d9f0492fSopenharmony_ci int status = napi_get_reference_value(env, g_paramWatchRef, &constructor); 339d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0, return NapiGetNull(env), "Failed to get reference"); 340d9f0492fSopenharmony_ci status = napi_new_instance(env, constructor, 0, nullptr, &obj); 341d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0, return NapiGetNull(env), "Failed to create instance for watcher"); 342d9f0492fSopenharmony_ci napi_unwrap(env, obj, (void **)&watcher); 343d9f0492fSopenharmony_ci } 344d9f0492fSopenharmony_ci if (watcher != nullptr) { 345d9f0492fSopenharmony_ci watcher->keyLen = BUF_LENGTH; 346d9f0492fSopenharmony_ci int ret = GetParamValue(env, argv[0], napi_string, watcher->keyPrefix, watcher->keyLen); 347d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, return NapiGetNull(env), "Failed to get key prefix"); 348d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher keyPrefix = %s ", watcher->keyPrefix); 349d9f0492fSopenharmony_ci ret = WatchParameter(watcher->keyPrefix, nullptr, watcher); 350d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, return NapiGetNull(env), "Failed to get watcher ret %d", ret); 351d9f0492fSopenharmony_ci } 352d9f0492fSopenharmony_ci return obj; 353d9f0492fSopenharmony_ci} 354d9f0492fSopenharmony_ci 355d9f0492fSopenharmony_cistatic ParamWatcherPtr GetWatcherInfo(napi_env env, napi_callback_info info, napi_value *callback) 356d9f0492fSopenharmony_ci{ 357d9f0492fSopenharmony_ci size_t argc = ARGC_NUMBER; 358d9f0492fSopenharmony_ci napi_value argv[ARGC_NUMBER]; 359d9f0492fSopenharmony_ci napi_value thisVar = nullptr; 360d9f0492fSopenharmony_ci void *data = nullptr; 361d9f0492fSopenharmony_ci napi_get_cb_info(env, info, &argc, argv, &thisVar, &data); 362d9f0492fSopenharmony_ci 363d9f0492fSopenharmony_ci size_t typeLen = BUF_LENGTH - 1; 364d9f0492fSopenharmony_ci std::vector<char> eventType(typeLen, 0); 365d9f0492fSopenharmony_ci int ret = GetParamValue(env, argv[0], napi_string, eventType.data(), typeLen); 366d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, return nullptr, "Failed to get event type"); 367d9f0492fSopenharmony_ci if (strcmp(eventType.data(), "valueChange") != 0) { 368d9f0492fSopenharmony_ci return nullptr; 369d9f0492fSopenharmony_ci } 370d9f0492fSopenharmony_ci // argv[1]:callbackRef 371d9f0492fSopenharmony_ci if (argc > 1) { 372d9f0492fSopenharmony_ci napi_valuetype valuetype; 373d9f0492fSopenharmony_ci napi_status status = napi_typeof(env, argv[1], &valuetype); 374d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0, return nullptr, "Failed to get type"); 375d9f0492fSopenharmony_ci PARAM_JS_CHECK(valuetype == napi_function, return nullptr, "Invalid type %d", valuetype); 376d9f0492fSopenharmony_ci *callback = argv[1]; 377d9f0492fSopenharmony_ci } 378d9f0492fSopenharmony_ci ParamWatcherPtr watcher = nullptr; 379d9f0492fSopenharmony_ci napi_unwrap(env, thisVar, (void **)&watcher); 380d9f0492fSopenharmony_ci return watcher; 381d9f0492fSopenharmony_ci} 382d9f0492fSopenharmony_ci 383d9f0492fSopenharmony_cistatic void NotifyValueChange(ParamWatcherPtr watcher, uint32_t id, napi_value thisVar, const napi_value result[]) 384d9f0492fSopenharmony_ci{ 385d9f0492fSopenharmony_ci napi_ref callbackRef = GetWatcherReference(watcher, id); 386d9f0492fSopenharmony_ci PARAM_JS_CHECK(callbackRef != nullptr, return, 387d9f0492fSopenharmony_ci "Failed to get callback for %s %d", watcher->keyPrefix, id); 388d9f0492fSopenharmony_ci napi_value callbackFunc = nullptr; 389d9f0492fSopenharmony_ci napi_status status = napi_get_reference_value(watcher->env, callbackRef, &callbackFunc); 390d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0 && callbackFunc != nullptr, return, 391d9f0492fSopenharmony_ci "Failed to get callback for %s %d", watcher->keyPrefix, id); 392d9f0492fSopenharmony_ci { 393d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 394d9f0492fSopenharmony_ci watcher->currCallbackRef = callbackRef; 395d9f0492fSopenharmony_ci } 396d9f0492fSopenharmony_ci 397d9f0492fSopenharmony_ci napi_value callbackResult = nullptr; 398d9f0492fSopenharmony_ci napi_call_function(watcher->env, thisVar, callbackFunc, ARGC_NUMBER, result, &callbackResult); 399d9f0492fSopenharmony_ci 400d9f0492fSopenharmony_ci { 401d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 402d9f0492fSopenharmony_ci if (watcher->currCallbackRef == nullptr) { 403d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher notify key %s callback deleted watcherId %u", 404d9f0492fSopenharmony_ci watcher->keyPrefix, id); 405d9f0492fSopenharmony_ci napi_delete_reference(watcher->env, callbackRef); 406d9f0492fSopenharmony_ci } 407d9f0492fSopenharmony_ci watcher->currCallbackRef = nullptr; 408d9f0492fSopenharmony_ci } 409d9f0492fSopenharmony_ci} 410d9f0492fSopenharmony_ci 411d9f0492fSopenharmony_cistatic void HandleParameterChange(ParamWatcherPtr watcher, const char *key, const char *value) 412d9f0492fSopenharmony_ci{ 413d9f0492fSopenharmony_ci napi_handle_scope scope = nullptr; 414d9f0492fSopenharmony_ci napi_status status = napi_open_handle_scope(watcher->env, &scope); 415d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0, return, "Failed to get reference "); 416d9f0492fSopenharmony_ci napi_value result[ARGC_NUMBER] = { 0 }; 417d9f0492fSopenharmony_ci napi_create_string_utf8(watcher->env, key, strlen(key), &result[0]); 418d9f0492fSopenharmony_ci napi_create_string_utf8(watcher->env, value, strlen(value), &result[1]); 419d9f0492fSopenharmony_ci napi_value thisVar = nullptr; 420d9f0492fSopenharmony_ci status = napi_get_reference_value(watcher->env, watcher->thisVarRef, &thisVar); 421d9f0492fSopenharmony_ci PARAM_JS_CHECK(status == 0 && thisVar != nullptr, napi_close_handle_scope(watcher->env, scope); 422d9f0492fSopenharmony_ci return, "Failed to get reference "); 423d9f0492fSopenharmony_ci uint32_t next = 0; 424d9f0492fSopenharmony_ci bool ret = GetFristRefence(watcher, next); 425d9f0492fSopenharmony_ci while (ret) { 426d9f0492fSopenharmony_ci NotifyValueChange(watcher, next, thisVar, result); 427d9f0492fSopenharmony_ci ret = GetNextRefence(watcher, next); 428d9f0492fSopenharmony_ci } 429d9f0492fSopenharmony_ci napi_close_handle_scope(watcher->env, scope); 430d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher ProcessParamChange %s finish", key); 431d9f0492fSopenharmony_ci} 432d9f0492fSopenharmony_ci 433d9f0492fSopenharmony_cistatic void ProcessParamChange(const char *key, const char *value, void *context) 434d9f0492fSopenharmony_ci{ 435d9f0492fSopenharmony_ci ParamWatcherPtr watcher = static_cast<ParamWatcherPtr>(context); 436d9f0492fSopenharmony_ci PARAM_JS_CHECK(watcher != nullptr && watcher->env != nullptr, return, "Invalid param"); 437d9f0492fSopenharmony_ci PARAM_JS_CHECK(watcher->callbackReferences.size() > 0, return, "No callback for watcher"); 438d9f0492fSopenharmony_ci 439d9f0492fSopenharmony_ci uv_loop_s *loop = nullptr; 440d9f0492fSopenharmony_ci napi_get_uv_event_loop(watcher->env, &loop); 441d9f0492fSopenharmony_ci PARAM_JS_CHECK(loop != nullptr, return, "Failed to get loop for %s", watcher->keyPrefix); 442d9f0492fSopenharmony_ci ParamChangeValue *change = new (std::nothrow) ParamChangeValue; 443d9f0492fSopenharmony_ci PARAM_JS_CHECK(change != nullptr, return, "Failed to get change for %s", watcher->keyPrefix); 444d9f0492fSopenharmony_ci change->work.data = reinterpret_cast<void *>(change); 445d9f0492fSopenharmony_ci change->watcher = watcher; 446d9f0492fSopenharmony_ci change->key = std::string(key); 447d9f0492fSopenharmony_ci change->value = std::string(value); 448d9f0492fSopenharmony_ci int ret = uv_queue_work(loop, &change->work, [] (uv_work_t *work) {}, [] (uv_work_t *work, int result) { 449d9f0492fSopenharmony_ci ParamChangeValue *change = reinterpret_cast<ParamChangeValue *>(work->data); 450d9f0492fSopenharmony_ci HandleParameterChange(change->watcher, change->key.c_str(), change->value.c_str()); 451d9f0492fSopenharmony_ci delete change; 452d9f0492fSopenharmony_ci change = nullptr; 453d9f0492fSopenharmony_ci }); 454d9f0492fSopenharmony_ci PARAM_JS_CHECK(ret == 0, delete change; 455d9f0492fSopenharmony_ci return, "Failed to start work for %s", watcher->keyPrefix); 456d9f0492fSopenharmony_ci} 457d9f0492fSopenharmony_ci 458d9f0492fSopenharmony_cistatic void WatchCallbackWork(napi_env env, ParamWatcherPtr watcher) 459d9f0492fSopenharmony_ci{ 460d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp WatchCallbackWork key: %s", watcher->keyPrefix); 461d9f0492fSopenharmony_ci ParamWatcherWork *worker = new ParamWatcherWork(); 462d9f0492fSopenharmony_ci PARAM_JS_CHECK(worker != nullptr, return, "Failed to create worker "); 463d9f0492fSopenharmony_ci worker->watcher = watcher; 464d9f0492fSopenharmony_ci worker->work = nullptr; 465d9f0492fSopenharmony_ci worker->startWatch = watcher->startWatch; 466d9f0492fSopenharmony_ci 467d9f0492fSopenharmony_ci napi_value resource = nullptr; 468d9f0492fSopenharmony_ci napi_create_string_utf8(env, "JSStartupWatch", NAPI_AUTO_LENGTH, &resource); 469d9f0492fSopenharmony_ci napi_create_async_work(env, nullptr, resource, 470d9f0492fSopenharmony_ci [](napi_env env, void *data) { 471d9f0492fSopenharmony_ci ParamWatcherWork *worker = reinterpret_cast<ParamWatcherWork *>(data); 472d9f0492fSopenharmony_ci PARAM_JS_CHECK(worker != nullptr && worker->watcher != nullptr, return, "Invalid worker "); 473d9f0492fSopenharmony_ci int status = WatchParameter(worker->watcher->keyPrefix, 474d9f0492fSopenharmony_ci worker->startWatch ? ProcessParamChange : nullptr, worker->watcher); 475d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp WatchCallbackWork %s status: %d, key: %s", 476d9f0492fSopenharmony_ci worker->startWatch ? "on" : "off", status, worker->watcher->keyPrefix); 477d9f0492fSopenharmony_ci }, 478d9f0492fSopenharmony_ci [](napi_env env, napi_status status, void *data) { 479d9f0492fSopenharmony_ci ParamWatcherWork *worker = reinterpret_cast<ParamWatcherWork *>(data); 480d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp WatchCallbackWork delete %s key: %s", 481d9f0492fSopenharmony_ci worker->startWatch ? "on" : "off", worker->watcher->keyPrefix); 482d9f0492fSopenharmony_ci napi_delete_async_work(env, worker->work); 483d9f0492fSopenharmony_ci delete worker; 484d9f0492fSopenharmony_ci }, 485d9f0492fSopenharmony_ci reinterpret_cast<void *>(worker), &worker->work); 486d9f0492fSopenharmony_ci napi_queue_async_work(env, worker->work); 487d9f0492fSopenharmony_ci} 488d9f0492fSopenharmony_ci 489d9f0492fSopenharmony_cistatic napi_value SwithWatchOn(napi_env env, napi_callback_info info) 490d9f0492fSopenharmony_ci{ 491d9f0492fSopenharmony_ci napi_value callback = nullptr; 492d9f0492fSopenharmony_ci ParamWatcherPtr watcher = GetWatcherInfo(env, info, &callback); 493d9f0492fSopenharmony_ci PARAM_JS_CHECK(watcher != nullptr, return GetNapiValue(env, -1), "Failed to get watcher switch param"); 494d9f0492fSopenharmony_ci 495d9f0492fSopenharmony_ci if (CheckCallbackEqual(env, callback, watcher)) { 496d9f0492fSopenharmony_ci PARAM_JS_LOGE("JSApp watcher repeater switch on %s", watcher->keyPrefix); 497d9f0492fSopenharmony_ci return 0; 498d9f0492fSopenharmony_ci } 499d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher on %s", watcher->keyPrefix); 500d9f0492fSopenharmony_ci // save callback 501d9f0492fSopenharmony_ci napi_ref callbackRef; 502d9f0492fSopenharmony_ci napi_create_reference(env, callback, 1, &callbackRef); 503d9f0492fSopenharmony_ci AddWatcherCallback(watcher, callbackRef); 504d9f0492fSopenharmony_ci watcher->env = env; 505d9f0492fSopenharmony_ci { 506d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 507d9f0492fSopenharmony_ci if (watcher->startWatch) { 508d9f0492fSopenharmony_ci return GetNapiValue(env, 0); 509d9f0492fSopenharmony_ci } 510d9f0492fSopenharmony_ci watcher->startWatch = true; 511d9f0492fSopenharmony_ci } 512d9f0492fSopenharmony_ci 513d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher add %s", watcher->keyPrefix); 514d9f0492fSopenharmony_ci WatchCallbackWork(env, watcher); 515d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher on %s finish", watcher->keyPrefix); 516d9f0492fSopenharmony_ci return GetNapiValue(env, 0); 517d9f0492fSopenharmony_ci} 518d9f0492fSopenharmony_ci 519d9f0492fSopenharmony_cistatic napi_value SwithWatchOff(napi_env env, napi_callback_info info) 520d9f0492fSopenharmony_ci{ 521d9f0492fSopenharmony_ci napi_value callback = nullptr; 522d9f0492fSopenharmony_ci ParamWatcherPtr watcher = GetWatcherInfo(env, info, &callback); 523d9f0492fSopenharmony_ci PARAM_JS_CHECK(watcher != nullptr, return GetNapiValue(env, -1), "Failed to get watcher"); 524d9f0492fSopenharmony_ci PARAM_JS_LOGV("JSApp watcher off %s", watcher->keyPrefix); 525d9f0492fSopenharmony_ci DelCallback(env, callback, watcher); 526d9f0492fSopenharmony_ci { 527d9f0492fSopenharmony_ci std::lock_guard<std::mutex> lock(watcher->mutex); 528d9f0492fSopenharmony_ci if (watcher->callbackReferences.size() == 0) { 529d9f0492fSopenharmony_ci watcher->startWatch = false; 530d9f0492fSopenharmony_ci WatchCallbackWork(env, watcher); 531d9f0492fSopenharmony_ci } 532d9f0492fSopenharmony_ci } 533d9f0492fSopenharmony_ci return GetNapiValue(env, 0); 534d9f0492fSopenharmony_ci} 535d9f0492fSopenharmony_ci 536d9f0492fSopenharmony_cinapi_value RegisterWatcher(napi_env env, napi_value exports) 537d9f0492fSopenharmony_ci{ 538d9f0492fSopenharmony_ci napi_property_descriptor properties[] = { 539d9f0492fSopenharmony_ci DECLARE_NAPI_FUNCTION("on", SwithWatchOn), 540d9f0492fSopenharmony_ci DECLARE_NAPI_FUNCTION("off", SwithWatchOff), 541d9f0492fSopenharmony_ci }; 542d9f0492fSopenharmony_ci 543d9f0492fSopenharmony_ci napi_value result = nullptr; 544d9f0492fSopenharmony_ci NAPI_CALL(env, 545d9f0492fSopenharmony_ci napi_define_class(env, 546d9f0492fSopenharmony_ci "paramWatcher", 547d9f0492fSopenharmony_ci NAPI_AUTO_LENGTH, 548d9f0492fSopenharmony_ci ParamWatchConstructor, 549d9f0492fSopenharmony_ci nullptr, 550d9f0492fSopenharmony_ci sizeof(properties) / sizeof(*properties), 551d9f0492fSopenharmony_ci properties, 552d9f0492fSopenharmony_ci &result)); 553d9f0492fSopenharmony_ci napi_set_named_property(env, exports, "paramWatcher", result); 554d9f0492fSopenharmony_ci napi_create_reference(env, result, 1, &g_paramWatchRef); 555d9f0492fSopenharmony_ci return exports; 556d9f0492fSopenharmony_ci} 557