• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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