1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define LOG_TAG "GetDataParamsNapi"
17 #include "get_data_params_napi.h"
18
19 #include "logger.h"
20 #include "napi_data_utils.h"
21 #include "unified_data_napi.h"
22
23 namespace OHOS {
24 namespace UDMF {
25 static constexpr int32_t PROGRESS_INIT = 0;
26 static constexpr int32_t PROGRESS_ALL_FINISHED = 100;
27 ConcurrentMap<std::string, napi_threadsafe_function> GetDataParamsNapi::tsfns;
28
Convert2NativeValue(napi_env env,napi_value in,GetDataParams & getDataParams,const std::string & key)29 bool GetDataParamsNapi::Convert2NativeValue(napi_env env, napi_value in,
30 GetDataParams &getDataParams, const std::string &key)
31 {
32 LOG_DEBUG(UDMF_KITS_NAPI, "Start.");
33
34 napi_value jsProgressIndicator = nullptr;
35 NAPI_CALL_BASE(env, napi_get_named_property(env, in, "progressIndicator", &jsProgressIndicator), false);
36 int32_t progressIndicator = static_cast<int32_t>(ProgressIndicator::NONE);
37 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsProgressIndicator, progressIndicator), false);
38 getDataParams.progressIndicator = static_cast<ProgressIndicator>(progressIndicator);
39
40 napi_value JsListener = nullptr;
41 NAPI_CALL_BASE(env, napi_get_named_property(env, in, "dataProgressListener", &JsListener), false);
42 napi_valuetype valueType = napi_undefined;
43 NAPI_CALL_BASE(env, napi_typeof(env, JsListener, &valueType), false);
44 NAPI_ASSERT_BASE(env, valueType == napi_function, "progressListener type must be DataProgressListener", false);
45 if (!SetProgressListener(env, getDataParams, JsListener, key)) {
46 LOG_ERROR(UDMF_KITS_NAPI, "SetProgressListener failed.");
47 return false;
48 }
49
50 bool hasDestUri = false;
51 NAPI_CALL_BASE(env, napi_has_named_property(env, in, "destUri", &hasDestUri), false);
52 if (hasDestUri) {
53 napi_value jsDestUri = nullptr;
54 NAPI_CALL_BASE(env, napi_get_named_property(env, in, "destUri", &jsDestUri), false);
55 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsDestUri, getDataParams.destUri), false);
56 }
57
58 bool hasFileConflictOptions = false;
59 NAPI_CALL_BASE(env, napi_has_named_property(env, in, "fileConflictOptions", &hasFileConflictOptions), false);
60 if (hasFileConflictOptions) {
61 napi_value jsFileConflictOptions = nullptr;
62 NAPI_CALL_BASE(env, napi_get_named_property(env, in, "fileConflictOptions", &jsFileConflictOptions), false);
63 int32_t fileConflictOptions = static_cast<int32_t>(FileConflictOptions::OVERWRITE);
64 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsFileConflictOptions, fileConflictOptions), false);
65 getDataParams.fileConflictOptions = static_cast<FileConflictOptions>(fileConflictOptions);
66 }
67
68 return true;
69 }
70
SetProgressListener(napi_env env,GetDataParams & getDataParams,napi_value callback,const std::string & key)71 bool GetDataParamsNapi::SetProgressListener(napi_env env, GetDataParams &getDataParams,
72 napi_value callback, const std::string &key)
73 {
74 LOG_DEBUG(UDMF_KITS_NAPI, "Start.");
75 tsfns.Compute(key, [&](const std::string &key, napi_threadsafe_function &tsfn) {
76 if (tsfn != nullptr) {
77 LOG_WARN(UDMF_KITS_NAPI, "Listener has existed!");
78 napi_release_threadsafe_function(tsfn, napi_tsfn_release);
79 tsfn = nullptr;
80 }
81 napi_value workName;
82 napi_create_string_utf8(env, "threadsafe_function", NAPI_AUTO_LENGTH, &workName);
83 auto status = napi_create_threadsafe_function(env, callback, nullptr, workName, 0, 1, nullptr,
84 nullptr, nullptr, CallProgressListener, &tsfn);
85 if (status != napi_ok) {
86 LOG_ERROR(UDMF_KITS_NAPI, "napi_create_threadsafe_function failed, status=%{public}d", status);
87 return false;
88 }
89 return true;
90 });
91
92 getDataParams.progressListener = [key](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) {
93 bool listenerExist = tsfns.ComputeIfPresent(key, [&](const std::string &key, napi_threadsafe_function &tsfn) {
94 auto listenerArgs = CreateListenerArgs(progressInfo, data);
95 if (listenerArgs == nullptr) {
96 return false;
97 }
98 auto status = napi_call_threadsafe_function(tsfn, listenerArgs, napi_tsfn_blocking);
99 if (status != napi_ok) {
100 LOG_ERROR(UDMF_KITS_NAPI, "napi_call_threadsafe_function failed, status=%{public}d", status);
101 return false;
102 }
103 if (progressInfo.progress >= PROGRESS_ALL_FINISHED ||
104 progressInfo.progress < PROGRESS_INIT) {
105 napi_release_threadsafe_function(tsfn, napi_tsfn_release);
106 return false;
107 }
108 return true;
109 });
110 if (!listenerExist) {
111 LOG_INFO(UDMF_KITS_NAPI, "No listener exist.");
112 }
113 };
114 return true;
115 }
116
CallProgressListener(napi_env env,napi_value callback,void * context,void * data)117 void GetDataParamsNapi::CallProgressListener(napi_env env, napi_value callback, void *context, void *data)
118 {
119 ListenerArgs* listenerArgs = static_cast<ListenerArgs*>(data);
120 napi_value param[ListenerArgs::ARGV_SIZE];
121
122 NapiDataUtils::SetValue(env, listenerArgs->progressInfo, param[0]);
123
124 if (listenerArgs->unifiedData == nullptr) {
125 NapiDataUtils::SetValue(env, nullptr, param[1]);
126 } else {
127 std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>();
128 unifiedData->SetRecords(listenerArgs->unifiedData->GetRecords());
129 UnifiedDataNapi::NewInstance(env, unifiedData, param[1]);
130 }
131
132 auto status = napi_call_function(env, nullptr, callback, ListenerArgs::ARGV_SIZE, param, nullptr);
133 if (status != napi_ok) {
134 LOG_ERROR(UDMF_KITS_NAPI, "napi_call_function failed, status=%{public}d", status);
135 }
136
137 DeleteListenerArgs(listenerArgs);
138 }
139
CreateListenerArgs(ProgressInfo progressInfo,std::shared_ptr<UnifiedData> data)140 GetDataParamsNapi::ListenerArgs* GetDataParamsNapi::CreateListenerArgs(
141 ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data)
142 {
143 auto listenerArgs = new (std::nothrow) ListenerArgs;
144 if (listenerArgs == nullptr) {
145 LOG_ERROR(UDMF_KITS_NAPI, "No memory for listenerArgs malloc");
146 return nullptr;
147 }
148 listenerArgs->progressInfo = progressInfo;
149 listenerArgs->unifiedData = nullptr;
150 if (data != nullptr) {
151 listenerArgs->unifiedData = new (std::nothrow) UnifiedData;
152 if (listenerArgs->unifiedData == nullptr) {
153 LOG_ERROR(UDMF_KITS_NAPI, "No memory for unifiedData malloc");
154 delete listenerArgs;
155 return nullptr;
156 }
157 listenerArgs->unifiedData->SetRecords(data->GetRecords());
158 }
159 return listenerArgs;
160 }
161
DeleteListenerArgs(ListenerArgs * listenerArgs)162 void GetDataParamsNapi::DeleteListenerArgs(ListenerArgs *listenerArgs)
163 {
164 if (listenerArgs->unifiedData != nullptr) {
165 delete listenerArgs->unifiedData;
166 listenerArgs->unifiedData = nullptr;
167 }
168 delete listenerArgs;
169 listenerArgs = nullptr;
170 }
171
172 } // namespace UDMF
173 } // namespace OHOS