1 /*
2 * Copyright (c) 2021-2023 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 #include "local_live_view_subscribe.h"
17 #include "notification_button_option.h"
18 #include "ans_inner_errors.h"
19 #include <mutex>
20 #include <uv.h>
21
22 namespace OHOS {
23 namespace NotificationNapi {
24 const int32_t SUBSRIBE_MAX_PARA = 2;
25 const std::string RESPONSE = "onResponse";
26
27 struct LocalLiveViewReceiveDataWorker {
28 napi_env env = nullptr;
29 napi_ref ref = nullptr;
30 int32_t notificationId;
31 sptr<NotificationButtonOption> buttonOption;
32 LocalLiveViewSubscriberInstance *subscriber = nullptr;
33 };
34
LocalLiveViewSubscriberInstance()35 LocalLiveViewSubscriberInstance::LocalLiveViewSubscriberInstance()
36 {}
37
~LocalLiveViewSubscriberInstance()38 LocalLiveViewSubscriberInstance::~LocalLiveViewSubscriberInstance()
39 {
40 if (responseCallbackInfo_.ref != nullptr) {
41 napi_delete_reference(responseCallbackInfo_.env, responseCallbackInfo_.ref);
42 }
43 }
44
OnDied()45 void LocalLiveViewSubscriberInstance::OnDied()
46 {
47 ANS_LOGD("enter");
48 }
49
OnConnected()50 void LocalLiveViewSubscriberInstance::OnConnected()
51 {
52 ANS_LOGD("enter");
53 }
54
OnDisconnected()55 void LocalLiveViewSubscriberInstance::OnDisconnected()
56 {
57 ANS_LOGD("enter");
58 }
59
UvQueueWorkOnResponse(uv_work_t * work,int status)60 void UvQueueWorkOnResponse(uv_work_t *work, int status)
61 {
62 ANS_LOGI("OnResponse uv_work_t start");
63
64 if (work == nullptr) {
65 ANS_LOGE("work is nullptr");
66 return;
67 }
68
69 auto dataWorkerData = reinterpret_cast<LocalLiveViewReceiveDataWorker *>(work->data);
70 if (dataWorkerData == nullptr) {
71 ANS_LOGD("dataWorkerData is null.");
72 delete work;
73 work = nullptr;
74 return;
75 }
76 napi_value buttonOption = nullptr;
77 napi_value buttonName = nullptr;
78 napi_handle_scope scope;
79 napi_value notificationId = nullptr;
80 napi_open_handle_scope(dataWorkerData->env, &scope);
81 if (scope == nullptr) {
82 ANS_LOGE("Scope is null");
83 return;
84 }
85
86 // notificationId: number
87 napi_create_int32(dataWorkerData->env, dataWorkerData->notificationId, ¬ificationId);
88
89 napi_create_object(dataWorkerData->env, &buttonOption);
90 napi_create_string_utf8(dataWorkerData->env, dataWorkerData->buttonOption->GetButtonName().c_str(),
91 NAPI_AUTO_LENGTH, &buttonName);
92 napi_set_named_property(dataWorkerData->env, buttonOption, "buttonName", buttonName);
93
94 Common::SetCallbackArg2(dataWorkerData->env, dataWorkerData->ref, notificationId, buttonOption);
95 napi_close_handle_scope(dataWorkerData->env, scope);
96
97 delete dataWorkerData;
98 dataWorkerData = nullptr;
99 delete work;
100 }
101
OnResponse(int32_t notificationId,sptr<NotificationButtonOption> buttonOption)102 void LocalLiveViewSubscriberInstance::OnResponse(int32_t notificationId, sptr<NotificationButtonOption> buttonOption)
103 {
104 ANS_LOGD("enter");
105
106 if (responseCallbackInfo_.ref == nullptr) {
107 ANS_LOGI("response callback unset");
108 return;
109 }
110
111 if (buttonOption == nullptr) {
112 ANS_LOGE("buttonOption is null");
113 return;
114 }
115
116 ANS_LOGI("OnResponse NotificationId = %{public}d", notificationId);
117 ANS_LOGI("OnResponse buttonOption size = %{public}s", buttonOption->GetButtonName().c_str());
118
119 uv_loop_s *loop = nullptr;
120 napi_get_uv_event_loop(responseCallbackInfo_.env, &loop);
121 if (loop == nullptr) {
122 ANS_LOGE("loop instance is nullptr");
123 return;
124 }
125
126 LocalLiveViewReceiveDataWorker *dataWorker = new (std::nothrow) LocalLiveViewReceiveDataWorker();
127 if (dataWorker == nullptr) {
128 ANS_LOGE("DataWorker is nullptr.");
129 return;
130 }
131
132 dataWorker->notificationId = notificationId;
133 dataWorker->buttonOption = buttonOption;
134 dataWorker->env = responseCallbackInfo_.env;
135 dataWorker->ref = responseCallbackInfo_.ref;
136
137 uv_work_t *work = new (std::nothrow) uv_work_t;
138 if (work == nullptr) {
139 ANS_LOGE("new work failed");
140 delete dataWorker;
141 dataWorker = nullptr;
142 return;
143 }
144
145 work->data = reinterpret_cast<void *>(dataWorker);
146
147 int ret = uv_queue_work_with_qos(loop, work, [](uv_work_t *work) {},
148 UvQueueWorkOnResponse, uv_qos_user_initiated);
149 if (ret != 0) {
150 delete dataWorker;
151 dataWorker = nullptr;
152 delete work;
153 work = nullptr;
154 }
155 }
156
SetResponseCallbackInfo(const napi_env & env,const napi_ref & ref)157 void LocalLiveViewSubscriberInstance::SetResponseCallbackInfo(const napi_env &env, const napi_ref &ref)
158 {
159 responseCallbackInfo_.env = env;
160 responseCallbackInfo_.ref = ref;
161 }
162
SetCallbackInfo(const napi_env & env,const std::string & type,const napi_ref & ref)163 void LocalLiveViewSubscriberInstance::SetCallbackInfo(const napi_env &env, const std::string &type, const napi_ref &ref)
164 {
165 if (type == RESPONSE) {
166 SetResponseCallbackInfo(env, ref);
167 } else {
168 ANS_LOGW("type is error");
169 }
170 }
171
HasNotificationSubscriber(const napi_env & env,const napi_value & value,LocalLiveViewSubscriberInstancesInfo & subscriberInfo)172 bool HasNotificationSubscriber(const napi_env &env, const napi_value &value,
173 LocalLiveViewSubscriberInstancesInfo &subscriberInfo)
174 {
175 std::lock_guard<std::mutex> lock(mutex_);
176 for (auto vec : subscriberInstances_) {
177 napi_value callback = nullptr;
178 napi_get_reference_value(env, vec.ref, &callback);
179 bool isEquals = false;
180 napi_strict_equals(env, value, callback, &isEquals);
181 if (isEquals) {
182 subscriberInfo = vec;
183 return true;
184 }
185 }
186 return false;
187 }
188
GetNotificationSubscriber(const napi_env & env,const napi_value & value,LocalLiveViewSubscriberInstancesInfo & subscriberInfo)189 napi_value GetNotificationSubscriber(
190 const napi_env &env, const napi_value &value, LocalLiveViewSubscriberInstancesInfo &subscriberInfo)
191 {
192 ANS_LOGD("enter");
193 bool hasProperty = false;
194 napi_valuetype valuetype = napi_undefined;
195 napi_ref result = nullptr;
196
197 subscriberInfo.subscriber = new (std::nothrow) LocalLiveViewSubscriberInstance();
198 if (subscriberInfo.subscriber == nullptr) {
199 ANS_LOGE("subscriber is null");
200 return nullptr;
201 }
202
203 napi_create_reference(env, value, 1, &subscriberInfo.ref);
204
205 // onResponse?
206 NAPI_CALL(env, napi_has_named_property(env, value, "onResponse", &hasProperty));
207 if (hasProperty) {
208 napi_value onResponse = nullptr;
209 napi_get_named_property(env, value, "onResponse", &onResponse);
210 NAPI_CALL(env, napi_typeof(env, onResponse, &valuetype));
211 if (valuetype != napi_function) {
212 ANS_LOGE("Wrong argument type. Function expected.");
213 std::string msg = "Incorrect parameter types.The type of param must be function.";
214 Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
215 return nullptr;
216 }
217 napi_create_reference(env, onResponse, 1, &result);
218 subscriberInfo.subscriber->SetCallbackInfo(env, RESPONSE, result);
219 }
220
221 return Common::NapiGetNull(env);
222 }
223
AddSubscriberInstancesInfo(const napi_env & env,const LocalLiveViewSubscriberInstancesInfo & subscriberInfo)224 bool AddSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstancesInfo &subscriberInfo)
225 {
226 ANS_LOGD("enter");
227 if (subscriberInfo.ref == nullptr) {
228 ANS_LOGE("subscriberInfo.ref is null");
229 return false;
230 }
231 if (subscriberInfo.subscriber == nullptr) {
232 ANS_LOGE("subscriberInfo.subscriber is null");
233 return false;
234 }
235 std::lock_guard<std::mutex> lock(mutex_);
236 subscriberInstances_.emplace_back(subscriberInfo);
237
238 return true;
239 }
240
DelSubscriberInstancesInfo(const napi_env & env,const LocalLiveViewSubscriberInstance * subscriber)241 bool DelSubscriberInstancesInfo(const napi_env &env, const LocalLiveViewSubscriberInstance *subscriber)
242 {
243 ANS_LOGD("enter");
244 if (subscriber == nullptr) {
245 ANS_LOGE("subscriber is null");
246 return false;
247 }
248
249 std::lock_guard<std::mutex> lock(mutex_);
250 for (auto it = subscriberInstances_.begin(); it != subscriberInstances_.end(); ++it) {
251 if ((*it).subscriber == subscriber) {
252 if ((*it).ref != nullptr) {
253 napi_delete_reference(env, (*it).ref);
254 }
255 DelDeletingSubscriber((*it).subscriber);
256 delete (*it).subscriber;
257 (*it).subscriber = nullptr;
258 subscriberInstances_.erase(it);
259 return true;
260 }
261 }
262 return false;
263 }
ParseParameters(const napi_env & env,const napi_callback_info & info,LocalLiveViewSubscriberInstance * & subscriber,napi_ref & callback)264 napi_value ParseParameters(const napi_env &env, const napi_callback_info &info,
265 LocalLiveViewSubscriberInstance *&subscriber, napi_ref &callback)
266 {
267 ANS_LOGD("enter");
268
269 size_t argc = SUBSRIBE_MAX_PARA;
270 napi_value argv[SUBSRIBE_MAX_PARA] = {nullptr};
271 napi_value thisVar = nullptr;
272 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
273 if (argc < 1) {
274 ANS_LOGE("Wrong number of arguments");
275 Common::NapiThrow(env, ERROR_PARAM_INVALID, MANDATORY_PARAMETER_ARE_LEFT_UNSPECIFIED);
276 return nullptr;
277 }
278
279 napi_valuetype valuetype = napi_undefined;
280
281 // argv[0]:LocalLiveViewButton
282 NAPI_CALL(env, napi_typeof(env, argv[PARAM0], &valuetype));
283 if (valuetype != napi_object) {
284 ANS_LOGE("Wrong argument type for arg0. LocalLiveViewButton object expected.");
285 std::string msg = "Incorrect parameter types.The type of param must be LocalLiveViewButton.";
286 Common::NapiThrow(env, ERROR_PARAM_INVALID, msg);
287 return nullptr;
288 }
289
290 LocalLiveViewSubscriberInstancesInfo subscriberInstancesInfo;
291 if (!HasNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo)) {
292 if (GetNotificationSubscriber(env, argv[PARAM0], subscriberInstancesInfo) == nullptr) {
293 ANS_LOGE("LocalLiveViewButton parse failed");
294 Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
295 if (subscriberInstancesInfo.subscriber) {
296 delete subscriberInstancesInfo.subscriber;
297 subscriberInstancesInfo.subscriber = nullptr;
298 }
299 return nullptr;
300 }
301 if (!AddSubscriberInstancesInfo(env, subscriberInstancesInfo)) {
302 ANS_LOGE("AddSubscriberInstancesInfo add failed");
303 Common::NapiThrow(env, ERROR_PARAM_INVALID, PARAMETER_VERIFICATION_FAILED);
304 if (subscriberInstancesInfo.subscriber) {
305 delete subscriberInstancesInfo.subscriber;
306 subscriberInstancesInfo.subscriber = nullptr;
307 }
308 return nullptr;
309 }
310 }
311 subscriber = subscriberInstancesInfo.subscriber;
312
313 // argv[1]:callback
314 if (argc >= SUBSRIBE_MAX_PARA) {
315 NAPI_CALL(env, napi_typeof(env, argv[PARAM1], &valuetype));
316 if (valuetype != napi_function) {
317 ANS_LOGE("Callback is not function enforce promise.");
318 return Common::NapiGetNull(env);
319 }
320 napi_create_reference(env, argv[PARAM1], 1, &callback);
321 }
322
323 return Common::NapiGetNull(env);
324 }
325
AddDeletingSubscriber(LocalLiveViewSubscriberInstance * subscriber)326 bool AddDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber)
327 {
328 std::lock_guard<std::mutex> lock(delMutex_);
329 auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber);
330 if (iter != DeletingSubscriber.end()) {
331 return false;
332 }
333
334 DeletingSubscriber.push_back(subscriber);
335 return true;
336 }
337
DelDeletingSubscriber(LocalLiveViewSubscriberInstance * subscriber)338 void DelDeletingSubscriber(LocalLiveViewSubscriberInstance *subscriber)
339 {
340 std::lock_guard<std::mutex> lock(delMutex_);
341 auto iter = std::find(DeletingSubscriber.begin(), DeletingSubscriber.end(), subscriber);
342 if (iter != DeletingSubscriber.end()) {
343 DeletingSubscriber.erase(iter);
344 }
345 }
346
347 } // namespace NotificationNapi
348 } // namespace OHOS
349