1 /*
2 * Copyright (c) 2022-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 "napi_subscribe.h"
17
18 #include "ans_inner_errors.h"
19 #include "subscribe.h"
20 #include "unsubscribe.h"
21 #include <memory>
22 #include <new>
23 #include "distributed_operation_callback.h"
24 #include "notification_operation_info.h"
25
26 namespace OHOS {
27 namespace NotificationNapi {
NapiDistributeOperationExecuteCallback(napi_env env,void * data)28 void NapiDistributeOperationExecuteCallback(napi_env env, void *data)
29 {
30 ANS_LOGD("called");
31 auto asyncCallbackInfo = static_cast<AsyncOperationCallbackInfo *>(data);
32 if (asyncCallbackInfo == nullptr) {
33 ANS_LOGE("null asyncCallbackInfo");
34 return;
35 }
36 sptr<DistributedOperationCallback> callback = new (std::nothrow) DistributedOperationCallback(*asyncCallbackInfo);
37 if (callback == nullptr) {
38 ANS_LOGE("null callback");
39 return;
40 }
41
42 sptr<NotificationOperationInfo> operationInfo = new (std::nothrow) NotificationOperationInfo();
43 if (operationInfo == nullptr) {
44 ANS_LOGE("null operationInfo");
45 return;
46 }
47 operationInfo->SetHashCode(asyncCallbackInfo->hashCode);
48 if (asyncCallbackInfo->operationInfo.operationType == NotificationConstant::DISTRIBUTE_JUMP_INVALID &&
49 asyncCallbackInfo->operationInfo.withOperationInfo) {
50 operationInfo->SetOperationType(OperationType::DISTRIBUTE_OPERATION_REPLY);
51 operationInfo->SetActionName(asyncCallbackInfo->operationInfo.actionName);
52 operationInfo->SetUserInput(asyncCallbackInfo->operationInfo.userInput);
53 } else if (asyncCallbackInfo->operationInfo.operationType == NotificationConstant::DISTRIBUTE_JUMP_INVALID) {
54 operationInfo->SetOperationType(OperationType::DISTRIBUTE_OPERATION_JUMP);
55 } else if (asyncCallbackInfo->operationInfo.operationType >= NotificationConstant::DISTRIBUTE_JUMP_BY_LIVE_VIEW ||
56 asyncCallbackInfo->operationInfo.operationType == NotificationConstant::DISTRIBUTE_JUMP_BY_NTF ||
57 asyncCallbackInfo->operationInfo.operationType == NotificationConstant::DISTRIBUTE_JUMP_BY_BTN) {
58 operationInfo->SetOperationType(OperationType::DISTRIBUTE_OPERATION_JUMP_BY_TYPE);
59 operationInfo->SetJumpType(asyncCallbackInfo->operationInfo.operationType);
60 operationInfo->SetBtnIndex(asyncCallbackInfo->operationInfo.btnIndex);
61 } else {
62 ANS_LOGE("invalid param, operationType: %{public}d", asyncCallbackInfo->operationInfo.operationType);
63 callback->OnOperationCallback(ERR_ANS_INVALID_PARAM);
64 return;
65 }
66 int32_t result = NotificationHelper::DistributeOperation(operationInfo, callback);
67 if (result != ERR_OK ||
68 operationInfo->GetOperationType() != OperationType::DISTRIBUTE_OPERATION_REPLY) {
69 callback->OnOperationCallback(result);
70 }
71 }
72
NapiDistributeOperationCompleteCallback(napi_env env,napi_status status,void * data)73 void NapiDistributeOperationCompleteCallback(napi_env env, napi_status status, void *data)
74 {
75 ANS_LOGD("called");
76 if (!data) {
77 ANS_LOGE("null data");
78 return;
79 }
80 auto distributeOperationInfo = static_cast<AsyncOperationCallbackInfo *>(data);
81 if (distributeOperationInfo) {
82 napi_delete_async_work(env, distributeOperationInfo->asyncWork);
83 delete distributeOperationInfo;
84 distributeOperationInfo = nullptr;
85 }
86 }
87
ClearEnvCallback(void * data)88 static void ClearEnvCallback(void *data)
89 {
90 ANS_LOGD("Env expired, need to clear env");
91 SubscriberInstance *subscriber = reinterpret_cast<SubscriberInstance *>(data);
92 subscriber->ClearEnv();
93 }
94
NapiSubscribe(napi_env env,napi_callback_info info)95 napi_value NapiSubscribe(napi_env env, napi_callback_info info)
96 {
97 ANS_LOGD("called");
98 napi_ref callback = nullptr;
99 std::shared_ptr<SubscriberInstance> objectInfo = nullptr;
100 NotificationSubscribeInfo subscriberInfo;
101 if (ParseParameters(env, info, subscriberInfo, objectInfo, callback) == nullptr) {
102 Common::NapiThrow(env, ERROR_PARAM_INVALID);
103 return Common::NapiGetUndefined(env);
104 }
105
106 AsyncCallbackInfoSubscribe *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribe {
107 .env = env, .asyncWork = nullptr, .objectInfo = objectInfo, .subscriberInfo = subscriberInfo
108 };
109 if (!asynccallbackinfo) {
110 Common::NapiThrow(env, ERROR_INTERNAL_ERROR);
111 return Common::JSParaError(env, callback);
112 }
113 napi_value promise = nullptr;
114 Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise);
115
116 napi_value resourceName = nullptr;
117 napi_create_string_latin1(env, "subscribeNotification", NAPI_AUTO_LENGTH, &resourceName);
118 // Asynchronous function call
119 napi_create_async_work(env,
120 nullptr,
121 resourceName,
122 [](napi_env env, void *data) {
123 ANS_LOGD("NapiSubscribe work excute.");
124 if (!data) {
125 ANS_LOGE("Invalid asynccallbackinfo!");
126 return;
127 }
128 auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
129 if (asynccallbackinfo) {
130 if (asynccallbackinfo->subscriberInfo.hasSubscribeInfo) {
131 ANS_LOGI("Subscribe with NotificationSubscribeInfo");
132 sptr<OHOS::Notification::NotificationSubscribeInfo> subscribeInfo =
133 new (std::nothrow) OHOS::Notification::NotificationSubscribeInfo();
134 if (subscribeInfo == nullptr) {
135 ANS_LOGE("Invalid subscribeInfo!");
136 asynccallbackinfo->info.errorCode = OHOS::Notification::ErrorCode::ERR_ANS_NO_MEMORY;
137 return;
138 }
139 subscribeInfo->AddAppNames(asynccallbackinfo->subscriberInfo.bundleNames);
140 subscribeInfo->AddAppUserId(asynccallbackinfo->subscriberInfo.userId);
141 subscribeInfo->AddDeviceType(asynccallbackinfo->subscriberInfo.deviceType);
142 subscribeInfo->SetFilterType(asynccallbackinfo->subscriberInfo.filterType);
143 subscribeInfo->SetSlotTypes(asynccallbackinfo->subscriberInfo.slotTypes);
144 asynccallbackinfo->info.errorCode =
145 NotificationHelper::SubscribeNotification(asynccallbackinfo->objectInfo, subscribeInfo);
146 } else {
147 asynccallbackinfo->info.errorCode =
148 NotificationHelper::SubscribeNotification(asynccallbackinfo->objectInfo);
149 }
150 }
151 },
152 [](napi_env env, napi_status status, void *data) {
153 ANS_LOGD("NapiSubscribe work complete.");
154 if (!data) {
155 ANS_LOGE("Invalid asynccallbackinfo!");
156 return;
157 }
158 auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
159 if (asynccallbackinfo) {
160 Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env));
161 if (asynccallbackinfo->info.callback != nullptr) {
162 ANS_LOGD("Delete napiSubscribe callback reference.");
163 napi_delete_reference(env, asynccallbackinfo->info.callback);
164 }
165 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
166 delete asynccallbackinfo;
167 asynccallbackinfo = nullptr;
168 }
169 ANS_LOGD("NapiSubscribe work complete end.");
170 },
171 (void *)asynccallbackinfo,
172 &asynccallbackinfo->asyncWork);
173
174 bool isCallback = asynccallbackinfo->info.isCallback;
175 napi_add_env_cleanup_hook(env, ClearEnvCallback, objectInfo.get());
176 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
177
178 if (isCallback) {
179 ANS_LOGD("null isCallback");
180 return Common::NapiGetNull(env);
181 } else {
182 return promise;
183 }
184 }
185
NapiSubscribeSelf(napi_env env,napi_callback_info info)186 napi_value NapiSubscribeSelf(napi_env env, napi_callback_info info)
187 {
188 ANS_LOGD("called");
189 napi_ref callback = nullptr;
190 std::shared_ptr<SubscriberInstance> objectInfo = nullptr;
191 NotificationSubscribeInfo subscriberInfo;
192 if (ParseParameters(env, info, subscriberInfo, objectInfo, callback) == nullptr) {
193 Common::NapiThrow(env, ERROR_PARAM_INVALID);
194 return Common::NapiGetUndefined(env);
195 }
196
197 AsyncCallbackInfoSubscribe *asynccallbackinfo = new (std::nothrow) AsyncCallbackInfoSubscribe {
198 .env = env, .asyncWork = nullptr, .objectInfo = objectInfo, .subscriberInfo = subscriberInfo
199 };
200 if (!asynccallbackinfo) {
201 Common::NapiThrow(env, ERROR_INTERNAL_ERROR);
202 return Common::JSParaError(env, callback);
203 }
204 napi_value promise = nullptr;
205 Common::PaddingCallbackPromiseInfo(env, callback, asynccallbackinfo->info, promise);
206
207 napi_value resourceName = nullptr;
208 napi_create_string_latin1(env, "subscribeNotificationSelf", NAPI_AUTO_LENGTH, &resourceName);
209 // Asynchronous function call
210 napi_create_async_work(env,
211 nullptr,
212 resourceName,
213 [](napi_env env, void *data) {
214 ANS_LOGD("NapiSubscribeSelf work excute.");
215 if (!data) {
216 ANS_LOGE("Invalid asynccallbackinfo!");
217 return;
218 }
219 auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
220 if (asynccallbackinfo) {
221 asynccallbackinfo->info.errorCode =
222 NotificationHelper::SubscribeNotificationSelf(asynccallbackinfo->objectInfo);
223 }
224 },
225 [](napi_env env, napi_status status, void *data) {
226 ANS_LOGD("NapiSubscribeSelf work complete.");
227 if (!data) {
228 ANS_LOGE("Invalid asynccallbackinfo!");
229 return;
230 }
231 auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoSubscribe *>(data);
232 if (asynccallbackinfo) {
233 Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env));
234 if (asynccallbackinfo->info.callback != nullptr) {
235 ANS_LOGD("Delete napiSubscribeSelf callback reference.");
236 napi_delete_reference(env, asynccallbackinfo->info.callback);
237 }
238 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
239 delete asynccallbackinfo;
240 asynccallbackinfo = nullptr;
241 }
242 ANS_LOGD("NapiSubscribeSelf work complete end.");
243 },
244 (void *)asynccallbackinfo,
245 &asynccallbackinfo->asyncWork);
246
247 bool isCallback = asynccallbackinfo->info.isCallback;
248 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
249
250 if (isCallback) {
251 ANS_LOGD("null isCallback");
252 return Common::NapiGetNull(env);
253 } else {
254 return promise;
255 }
256 }
257
NapiUnsubscribe(napi_env env,napi_callback_info info)258 napi_value NapiUnsubscribe(napi_env env, napi_callback_info info)
259 {
260 ANS_LOGD("called");
261 ParametersInfoUnsubscribe paras;
262 if (ParseParameters(env, info, paras) == nullptr) {
263 Common::NapiThrow(env, ERROR_PARAM_INVALID);
264 return Common::NapiGetUndefined(env);
265 }
266
267 AsyncCallbackInfoUnsubscribe *asynccallbackinfo = new (std::nothrow)
268 AsyncCallbackInfoUnsubscribe {.env = env, .asyncWork = nullptr, .objectInfo = paras.objectInfo};
269 if (!asynccallbackinfo) {
270 Common::NapiThrow(env, ERROR_INTERNAL_ERROR);
271 return Common::JSParaError(env, paras.callback);
272 }
273 napi_value promise = nullptr;
274 Common::PaddingCallbackPromiseInfo(env, paras.callback, asynccallbackinfo->info, promise);
275
276 napi_value resourceName = nullptr;
277 napi_create_string_latin1(env, "unsubscribe", NAPI_AUTO_LENGTH, &resourceName);
278
279 // Asynchronous function call
280 napi_create_async_work(env,
281 nullptr,
282 resourceName,
283 [](napi_env env, void *data) {
284 ANS_LOGD("NapiUnsubscribe work excute.");
285 auto asynccallbackinfo = reinterpret_cast<AsyncCallbackInfoUnsubscribe *>(data);
286 if (asynccallbackinfo) {
287 if (asynccallbackinfo->objectInfo == nullptr) {
288 ANS_LOGE("invalid object info");
289 asynccallbackinfo->info.errorCode = ERR_ANS_INVALID_PARAM;
290 return;
291 }
292
293 bool ret = AddDeletingSubscriber(asynccallbackinfo->objectInfo);
294 if (ret) {
295 asynccallbackinfo->info.errorCode =
296 NotificationHelper::UnSubscribeNotification(asynccallbackinfo->objectInfo);
297 if (asynccallbackinfo->info.errorCode != ERR_OK) {
298 DelDeletingSubscriber(asynccallbackinfo->objectInfo);
299 }
300 } else {
301 asynccallbackinfo->info.errorCode = ERR_ANS_SUBSCRIBER_IS_DELETING;
302 }
303 }
304 },
305 [](napi_env env, napi_status status, void *data) {
306 ANS_LOGD("NapiUnsubscribe work complete.");
307 AsyncCallbackInfoUnsubscribe *asynccallbackinfo = static_cast<AsyncCallbackInfoUnsubscribe *>(data);
308 if (asynccallbackinfo) {
309 Common::CreateReturnValue(env, asynccallbackinfo->info, Common::NapiGetNull(env));
310 if (asynccallbackinfo->info.callback != nullptr) {
311 ANS_LOGD("Delete napiUnsubscribe callback reference.");
312 napi_delete_reference(env, asynccallbackinfo->info.callback);
313 }
314 napi_delete_async_work(env, asynccallbackinfo->asyncWork);
315 delete asynccallbackinfo;
316 asynccallbackinfo = nullptr;
317 }
318 ANS_LOGD("NapiUnsubscribe work complete end.");
319 },
320 (void *)asynccallbackinfo,
321 &asynccallbackinfo->asyncWork);
322
323 bool isCallback = asynccallbackinfo->info.isCallback;
324 napi_queue_async_work_with_qos(env, asynccallbackinfo->asyncWork, napi_qos_user_initiated);
325
326 if (isCallback) {
327 ANS_LOGD("null isCallback");
328 return Common::NapiGetNull(env);
329 } else {
330 return promise;
331 }
332 }
333
AsyncDistributeOperationCall(napi_env env,AsyncOperationCallbackInfo * distributeOperationInfo)334 void AsyncDistributeOperationCall(napi_env env, AsyncOperationCallbackInfo* distributeOperationInfo)
335 {
336 napi_value resourceName = nullptr;
337 napi_create_string_latin1(env, "distributeOperation", NAPI_AUTO_LENGTH, &resourceName);
338
339 // Asynchronous function call
340 napi_create_async_work(env, nullptr, resourceName, NapiDistributeOperationExecuteCallback,
341 NapiDistributeOperationCompleteCallback, (void *)distributeOperationInfo, &distributeOperationInfo->asyncWork);
342 auto result = napi_queue_async_work_with_qos(env, distributeOperationInfo->asyncWork, napi_qos_user_initiated);
343 if (result != napi_ok) {
344 NapiDistributeOperationCompleteCallback(env, result, distributeOperationInfo);
345 NAPI_CALL_RETURN_VOID(env, result);
346 }
347 }
348
NapiDistributeOperation(napi_env env,napi_callback_info info)349 napi_value NapiDistributeOperation(napi_env env, napi_callback_info info)
350 {
351 ANS_LOGD("called");
352 std::string hashCode;
353 napi_value thisVar = nullptr;
354 OperationInfo operationInfo;
355 if (ParseParameters(env, info, hashCode, thisVar, operationInfo) == nullptr) {
356 Common::NapiThrow(env, ERROR_PARAM_INVALID);
357 return Common::NapiGetUndefined(env);
358 }
359
360 napi_value ret = nullptr;
361 napi_deferred deferred;
362 napi_create_promise(env, &deferred, &ret);
363 auto distributeOperationInfo = new (std::nothrow) AsyncOperationCallbackInfo {.env = env,
364 .thisVar = thisVar, .deferred = deferred, .hashCode = hashCode, .operationInfo = operationInfo};
365 if (distributeOperationInfo == nullptr) {
366 Common::NapiThrow(env, ERROR_INTERNAL_ERROR);
367 return Common::NapiGetNull(env);
368 }
369
370 AsyncDistributeOperationCall(env, distributeOperationInfo);
371 return ret;
372 }
373 } // namespace NotificationNapi
374 } // namespace OHOS
375