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 bool hasAcceptableInfo = false;
69 NAPI_CALL_BASE(env, napi_has_named_property(env, in, "acceptableInfo", &hasAcceptableInfo), false);
70 if (hasAcceptableInfo) {
71 napi_value jsDataLoadInfo = nullptr;
72 NAPI_CALL_BASE(env, napi_get_named_property(env, in, "acceptableInfo", &jsDataLoadInfo), false);
73 NAPI_CALL_BASE(env, NapiDataUtils::GetValue(env, jsDataLoadInfo, getDataParams.acceptableInfo), false);
74 }
75 return true;
76 }
77
SetProgressListener(napi_env env,GetDataParams & getDataParams,napi_value callback,const std::string & key)78 bool GetDataParamsNapi::SetProgressListener(napi_env env, GetDataParams &getDataParams,
79 napi_value callback, const std::string &key)
80 {
81 LOG_DEBUG(UDMF_KITS_NAPI, "Start.");
82 tsfns.Compute(key, [&](const std::string &key, napi_threadsafe_function &tsfn) {
83 if (tsfn != nullptr) {
84 LOG_WARN(UDMF_KITS_NAPI, "Listener has existed!");
85 napi_release_threadsafe_function(tsfn, napi_tsfn_release);
86 tsfn = nullptr;
87 }
88 napi_value workName;
89 napi_create_string_utf8(env, "threadsafe_function", NAPI_AUTO_LENGTH, &workName);
90 auto status = napi_create_threadsafe_function(env, callback, nullptr, workName, 0, 1, nullptr,
91 nullptr, nullptr, CallProgressListener, &tsfn);
92 if (status != napi_ok) {
93 LOG_ERROR(UDMF_KITS_NAPI, "napi_create_threadsafe_function failed, status=%{public}d", status);
94 return false;
95 }
96 return true;
97 });
98
99 getDataParams.progressListener = [key](ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data) {
100 bool listenerExist = tsfns.ComputeIfPresent(key, [&](const std::string &key, napi_threadsafe_function &tsfn) {
101 auto listenerArgs = CreateListenerArgs(progressInfo, data);
102 if (listenerArgs == nullptr) {
103 return false;
104 }
105 auto status = napi_call_threadsafe_function(tsfn, listenerArgs, napi_tsfn_blocking);
106 if (status != napi_ok) {
107 LOG_ERROR(UDMF_KITS_NAPI, "napi_call_threadsafe_function failed, status=%{public}d", status);
108 return false;
109 }
110 if (progressInfo.progress >= PROGRESS_ALL_FINISHED ||
111 progressInfo.progress < PROGRESS_INIT) {
112 napi_release_threadsafe_function(tsfn, napi_tsfn_release);
113 return false;
114 }
115 return true;
116 });
117 if (!listenerExist) {
118 LOG_INFO(UDMF_KITS_NAPI, "No listener exist.");
119 }
120 };
121 return true;
122 }
123
CallProgressListener(napi_env env,napi_value callback,void * context,void * data)124 void GetDataParamsNapi::CallProgressListener(napi_env env, napi_value callback, void *context, void *data)
125 {
126 ListenerArgs* listenerArgs = static_cast<ListenerArgs*>(data);
127 napi_value param[ListenerArgs::ARGV_SIZE];
128
129 NapiDataUtils::SetValue(env, listenerArgs->progressInfo, param[0]);
130
131 if (listenerArgs->unifiedData == nullptr) {
132 NapiDataUtils::SetValue(env, nullptr, param[1]);
133 } else {
134 std::shared_ptr<UnifiedData> unifiedData = std::make_shared<UnifiedData>();
135 unifiedData->SetRecords(listenerArgs->unifiedData->GetRecords());
136 UnifiedDataNapi::NewInstance(env, unifiedData, param[1]);
137 }
138
139 auto status = napi_call_function(env, nullptr, callback, ListenerArgs::ARGV_SIZE, param, nullptr);
140 if (status != napi_ok) {
141 LOG_ERROR(UDMF_KITS_NAPI, "napi_call_function failed, status=%{public}d", status);
142 }
143
144 DeleteListenerArgs(listenerArgs);
145 }
146
CreateListenerArgs(ProgressInfo progressInfo,std::shared_ptr<UnifiedData> data)147 GetDataParamsNapi::ListenerArgs* GetDataParamsNapi::CreateListenerArgs(
148 ProgressInfo progressInfo, std::shared_ptr<UnifiedData> data)
149 {
150 auto listenerArgs = new (std::nothrow) ListenerArgs;
151 if (listenerArgs == nullptr) {
152 LOG_ERROR(UDMF_KITS_NAPI, "No memory for listenerArgs malloc");
153 return nullptr;
154 }
155 listenerArgs->progressInfo = progressInfo;
156 listenerArgs->unifiedData = nullptr;
157 if (data != nullptr) {
158 listenerArgs->unifiedData = new (std::nothrow) UnifiedData;
159 if (listenerArgs->unifiedData == nullptr) {
160 LOG_ERROR(UDMF_KITS_NAPI, "No memory for unifiedData malloc");
161 delete listenerArgs;
162 return nullptr;
163 }
164 listenerArgs->unifiedData->SetRecords(data->GetRecords());
165 }
166 return listenerArgs;
167 }
168
DeleteListenerArgs(ListenerArgs * listenerArgs)169 void GetDataParamsNapi::DeleteListenerArgs(ListenerArgs *listenerArgs)
170 {
171 if (listenerArgs->unifiedData != nullptr) {
172 delete listenerArgs->unifiedData;
173 listenerArgs->unifiedData = nullptr;
174 }
175 delete listenerArgs;
176 listenerArgs = nullptr;
177 }
178
179 } // namespace UDMF
180 } // namespace OHOS