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