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 "devicestatus_event.h"
17
18 #include <js_native_api.h>
19 #include <map>
20 #include <uv.h>
21
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24
25 #include "devicestatus_common.h"
26
27 using namespace OHOS::Msdp;
28
DeviceStatusEvent(napi_env env)29 DeviceStatusEvent::DeviceStatusEvent(napi_env env)
30 {
31 env_ = env;
32 }
33
~DeviceStatusEvent()34 DeviceStatusEvent::~DeviceStatusEvent()
35 {
36 eventOnceMap_.clear();
37 eventMap_.clear();
38 }
39
On(int32_t eventType,napi_value handler,bool isOnce)40 bool DeviceStatusEvent::On(int32_t eventType, napi_value handler, bool isOnce)
41 {
42 DEV_HILOGD(JS_NAPI, "On for event:%{public}d, isOnce:%{public}d", eventType, isOnce);
43 napi_handle_scope scope = nullptr;
44 napi_open_handle_scope(env_, &scope);
45 if (scope == nullptr) {
46 DEV_HILOGE(JS_NAPI, "scope is nullptr");
47 return false;
48 }
49 napi_ref onHandlerRef;
50 napi_status status = napi_ok;
51 if (isOnce) {
52 auto iter = eventOnceMap_.find(eventType);
53 if (iter == eventOnceMap_.end()) {
54 DEV_HILOGD(JS_NAPI, "eventType:%{public}d not exists", eventType);
55 eventOnceMap_[eventType] = std::list<std::shared_ptr<DeviceStatusEventListener>>();
56 }
57 auto listener = std::make_shared<DeviceStatusEventListener>();
58 status = napi_create_reference(env_, handler, 1, &onHandlerRef);
59 if (status != napi_ok) {
60 DEV_HILOGE(JS_NAPI, "Failed to create reference");
61 napi_close_handle_scope(env_, scope);
62 return false;
63 }
64 listener->onHandlerRef = onHandlerRef;
65 eventOnceMap_[eventType].push_back(listener);
66 DEV_HILOGI(JS_NAPI, "Add once handler to list %{public}d", eventType);
67 } else {
68 auto iter = eventMap_.find(eventType);
69 if (iter == eventMap_.end()) {
70 DEV_HILOGD(JS_NAPI, "eventType:%{public}d not exists", eventType);
71 eventMap_[eventType] = std::list<std::shared_ptr<DeviceStatusEventListener>>();
72 }
73 auto listener = std::make_shared<DeviceStatusEventListener>();
74 status = napi_create_reference(env_, handler, 1, &onHandlerRef);
75 if (status != napi_ok) {
76 DEV_HILOGE(JS_NAPI, "Failed to create reference");
77 napi_close_handle_scope(env_, scope);
78 return false;
79 }
80 listener->onHandlerRef = onHandlerRef;
81 eventMap_[eventType].push_back(listener);
82 DEV_HILOGI(JS_NAPI, "Add handler to list %{public}d", eventType);
83 }
84 napi_close_handle_scope(env_, scope);
85 return true;
86 }
87
Off(int32_t eventType,napi_value handler)88 bool DeviceStatusEvent::Off(int32_t eventType, napi_value handler)
89 {
90 DEV_HILOGD(JS_NAPI, "DeviceStatusEvent off in for event:%{public}d", eventType);
91
92 auto iter = eventMap_.find(eventType);
93 if (iter == eventMap_.end()) {
94 DEV_HILOGE(JS_NAPI, "eventType %{public}d not find", eventType);
95 return false;
96 }
97 bool equal = false;
98 napi_value result = nullptr;
99
100 for (auto listener : eventMap_[eventType]) {
101 napi_status status = napi_get_reference_value(env_, listener->onHandlerRef, &result);
102 if (status != napi_ok) {
103 DEV_HILOGE(JS_NAPI, "Failed to get_reference_value");
104 return false;
105 }
106 status = napi_strict_equals(env_, result, handler, &equal);
107 if (status != napi_ok) {
108 DEV_HILOGE(JS_NAPI, "Failed to strict_equals");
109 return false;
110 }
111 if (equal) {
112 DEV_HILOGI(JS_NAPI, "delete handler from list %{public}d", eventType);
113 status = napi_delete_reference(env_, listener->onHandlerRef);
114 if (status != napi_ok) {
115 DEV_HILOGW(JS_NAPI, "Delete failed");
116 }
117 eventMap_[eventType].remove(listener);
118 break;
119 }
120 }
121 DEV_HILOGI(JS_NAPI, "%{public}zu listeners in the list of %{public}d",
122 eventMap_[eventType].size(), eventType);
123 return eventMap_[eventType].empty();
124 }
125
OffOnce(int32_t eventType,napi_value handler)126 bool DeviceStatusEvent::OffOnce(int32_t eventType, napi_value handler)
127 {
128 DEV_HILOGD(JS_NAPI, "DeviceStatusEvent OffOnce in for event:%{public}d", eventType);
129
130 auto iter = eventOnceMap_.find(eventType);
131 if (iter == eventOnceMap_.end()) {
132 DEV_HILOGE(JS_NAPI, "eventType %{public}d not find", eventType);
133 return false;
134 }
135 bool equal = false;
136 napi_value result = nullptr;
137 for (auto listener : eventOnceMap_[eventType]) {
138 napi_get_reference_value(env_, listener->onHandlerRef, &result);
139 napi_strict_equals(env_, result, handler, &equal);
140 if (equal) {
141 DEV_HILOGI(JS_NAPI, "delete once handler from list %{public}d", eventType);
142 napi_status status = napi_delete_reference(env_, listener->onHandlerRef);
143 if (status != napi_ok) {
144 DEV_HILOGW(JS_NAPI, "Delete failed");
145 }
146 eventOnceMap_[eventType].remove(listener);
147 break;
148 }
149 }
150 DEV_HILOGI(JS_NAPI, "%{public}zu listeners in the once list of %{public}d",
151 eventOnceMap_[eventType].size(), eventType);
152 return eventMap_[eventType].empty();
153 }
154
CheckRet(int32_t eventType,size_t argc,int32_t value,std::shared_ptr<DeviceStatusEventListener> & typeHandler)155 void DeviceStatusEvent::CheckRet(int32_t eventType, size_t argc, int32_t value,
156 std::shared_ptr<DeviceStatusEventListener> &typeHandler)
157 {
158 napi_handle_scope scope = nullptr;
159 napi_open_handle_scope(env_, &scope);
160 if (scope == nullptr) {
161 DEV_HILOGE(JS_NAPI, "scope is nullptr");
162 return;
163 }
164 napi_value handler = nullptr;
165 napi_status status = napi_ok;
166 status = napi_get_reference_value(env_, typeHandler->onHandlerRef, &handler);
167 if (status != napi_ok) {
168 DEV_HILOGE(JS_NAPI, "OnEvent handler for %{public}d failed, status:%{public}d", eventType, status);
169 napi_close_handle_scope(env_, scope);
170 return;
171 }
172 napi_value result;
173 SendRet(eventType, value, result);
174 napi_value callResult = nullptr;
175 DEV_HILOGD(JS_NAPI, "Report to hap");
176 status = napi_call_function(env_, nullptr, handler, argc, &result, &callResult);
177 if (status != napi_ok) {
178 DEV_HILOGE(JS_NAPI, "CheckRet:napi_call_function for %{public}d failed, status:%{public}d", eventType, status);
179 napi_close_handle_scope(env_, scope);
180 return;
181 }
182 napi_close_handle_scope(env_, scope);
183 }
184
SendRet(int32_t eventType,int32_t value,napi_value & result)185 void DeviceStatusEvent::SendRet(int32_t eventType, int32_t value, napi_value &result)
186 {
187 napi_status status = napi_create_object(env_, &result);
188 if (status != napi_ok) {
189 DEV_HILOGE(JS_NAPI, "Failed to create object");
190 return;
191 }
192 DEV_HILOGD(JS_NAPI, "eventType:%{public}d,value:%{public}d", eventType, value);
193 napi_value tmpValue = nullptr;
194 status = napi_create_int32(env_, eventType, &tmpValue);
195 if (status != napi_ok) {
196 DEV_HILOGE(JS_NAPI, "Failed to create object");
197 return;
198 }
199 status = napi_set_named_property(env_, result, "type", tmpValue);
200 if (status != napi_ok) {
201 DEV_HILOGE(JS_NAPI, "Failed to set name");
202 return;
203 }
204 if (value >= static_cast<int32_t>(DevicestatusDataUtils::DevicestatusValue::VALUE_INVALID)
205 && value <= static_cast<int32_t>(DevicestatusDataUtils::DevicestatusValue::VALUE_EXIT)) {
206 status = napi_create_int32(env_, value, &tmpValue);
207 if (status != napi_ok) {
208 DEV_HILOGE(JS_NAPI, "Failed to get int32");
209 return;
210 }
211 }
212 status = napi_set_named_property(env_, result, "value", tmpValue);
213 if (status != napi_ok) {
214 DEV_HILOGE(JS_NAPI, "Failed to set_named");
215 return;
216 }
217 }
218
OnEvent(int32_t eventType,size_t argc,int32_t value,bool isOnce)219 void DeviceStatusEvent::OnEvent(int32_t eventType, size_t argc, int32_t value, bool isOnce)
220 {
221 DEV_HILOGD(JS_NAPI, "OnEvent for %{public}d, isOnce:%{public}d", eventType, isOnce);
222 napi_handle_scope scope = nullptr;
223 napi_open_handle_scope(env_, &scope);
224 if (scope == nullptr) {
225 DEV_HILOGE(JS_NAPI, "scope is nullptr");
226 return;
227 }
228
229 std::map<int32_t, std::list<std::shared_ptr<DeviceStatusEventListener>>>::iterator typeHandler;
230 if (isOnce) {
231 typeHandler = eventOnceMap_.find(eventType);
232 if (typeHandler == eventOnceMap_.end()) {
233 DEV_HILOGE(JS_NAPI, "OnEvent eventType %{public}d not find", eventType);
234 napi_close_handle_scope(env_, scope);
235 return;
236 }
237 } else {
238 typeHandler = eventMap_.find(eventType);
239 if (typeHandler == eventMap_.end()) {
240 DEV_HILOGE(JS_NAPI, "OnEvent:eventType %{public}d not find", eventType);
241 napi_close_handle_scope(env_, scope);
242 return;
243 }
244 }
245 DEV_HILOGD(JS_NAPI, "%{public}zu callbacks of eventType %{public}d are sent",
246 typeHandler->second.size(), eventType);
247 for (auto handler : typeHandler->second) {
248 CheckRet(eventType, argc, value, handler);
249 }
250 napi_close_handle_scope(env_, scope);
251 DEV_HILOGD(JS_NAPI, "Exit");
252 }
253
ClearEventMap()254 void DeviceStatusEvent::ClearEventMap()
255 {
256 for (auto iter : eventMap_) {
257 for (auto eventListener : iter.second) {
258 napi_status status = napi_delete_reference(env_, eventListener->onHandlerRef);
259 if (status != napi_ok) {
260 DEV_HILOGW(JS_NAPI, "Failed to delete reference");
261 }
262 }
263 }
264 for (auto iter : eventOnceMap_) {
265 for (auto eventListener : iter.second) {
266 napi_status status = napi_delete_reference(env_, eventListener->onHandlerRef);
267 if (status != napi_ok) {
268 DEV_HILOGW(JS_NAPI, "Failed to delete reference");
269 napi_delete_reference(env_, eventListener->onHandlerRef);
270 }
271 }
272 }
273 eventMap_.clear();
274 eventOnceMap_.clear();
275 }
276