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 "js_device_selection_listener.h"
17
18 #include "base/continuationmgr_log.h"
19 #include "js_runtime_utils.h"
20 #include "napi_common_util.h"
21
22 namespace OHOS {
23 namespace DistributedSchedule {
24 using namespace OHOS::AbilityRuntime;
25 namespace {
26 const std::string TAG = "JsDeviceSelectionListener";
27 }
28
OnDeviceConnect(const std::vector<ContinuationResult> & continuationResults)29 void JsDeviceSelectionListener::OnDeviceConnect(const std::vector<ContinuationResult>& continuationResults)
30 {
31 HILOGD("called.");
32 CallJsMethod(EVENT_CONNECT, continuationResults);
33 }
34
OnDeviceDisconnect(const std::vector<ContinuationResult> & continuationResults)35 void JsDeviceSelectionListener::OnDeviceDisconnect(const std::vector<ContinuationResult>& continuationResults)
36 {
37 HILOGD("called.");
38 CallJsMethod(EVENT_DISCONNECT, continuationResults);
39 }
40
AddCallback(const std::string & cbType,napi_value jsListenerObj)41 void JsDeviceSelectionListener::AddCallback(const std::string& cbType, napi_value jsListenerObj)
42 {
43 HILOGD("called.");
44 napi_ref tempRef = nullptr;
45 std::unique_ptr<NativeReference> callbackRef;
46 if (engine_ == nullptr) {
47 HILOGE("engine_ is nullptr");
48 return;
49 }
50 napi_create_reference(engine_, jsListenerObj, 1, &tempRef);
51 callbackRef.reset(reinterpret_cast<NativeReference *>(tempRef));
52 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
53 jsCallBackMap_[cbType] = std::move(callbackRef);
54 HILOGD("jsCallBackMap_ cbType: %{public}s, size: %{public}u!",
55 cbType.c_str(), static_cast<uint32_t>(jsCallBackMap_.size()));
56 }
57
RemoveCallback(const std::string & cbType)58 void JsDeviceSelectionListener::RemoveCallback(const std::string& cbType)
59 {
60 HILOGD("called.");
61 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
62 jsCallBackMap_.erase(cbType);
63 HILOGD("jsCallBackMap_ cbType: %{public}s, size: %{public}u!",
64 cbType.c_str(), static_cast<uint32_t>(jsCallBackMap_.size()));
65 }
66
CallJsMethod(const std::string & methodName,const std::vector<ContinuationResult> & continuationResults)67 void JsDeviceSelectionListener::CallJsMethod(const std::string& methodName,
68 const std::vector<ContinuationResult>& continuationResults)
69 {
70 HILOGD("methodName = %{public}s", methodName.c_str());
71 if (engine_ == nullptr) {
72 HILOGE("engine_ is nullptr");
73 return;
74 }
75 // js callback should run in js thread
76 auto task = [this, methodName, continuationResults] {
77 napi_handle_scope scope = nullptr;
78 napi_open_handle_scope(this->engine_, &scope);
79 if (scope == nullptr) {
80 return;
81 }
82
83 CallJsMethodInner(methodName, continuationResults);
84
85 napi_close_handle_scope(this->engine_, scope);
86 };
87 if (napi_status::napi_ok != napi_send_event(engine_, task, napi_eprio_high)) {
88 HILOGE("send event failed!");
89 }
90 }
91
CallJsMethodInner(const std::string & methodName,const std::vector<ContinuationResult> & continuationResults)92 void JsDeviceSelectionListener::CallJsMethodInner(const std::string& methodName,
93 const std::vector<ContinuationResult>& continuationResults)
94 {
95 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
96 auto it = jsCallBackMap_.find(methodName);
97 if (it == jsCallBackMap_.end()) {
98 HILOGE("Callback method %s not found in jsCallBackMap_", methodName.c_str());
99 return;
100 }
101 napi_value method = jsCallBackMap_[methodName]->GetNapiValue();
102 if (method == nullptr) {
103 HILOGE("Failed to get %{public}s from object", methodName.c_str());
104 return;
105 }
106 napi_value argv[] = { WrapContinuationResultArray(engine_, continuationResults) };
107 napi_call_function(engine_, CreateJsUndefined(engine_), method, ArraySize(argv), argv, nullptr);
108 }
109
CallJsMethod(const std::string & methodName,const std::vector<std::string> & deviceIds)110 void JsDeviceSelectionListener::CallJsMethod(const std::string& methodName, const std::vector<std::string>& deviceIds)
111 {
112 HILOGD("methodName = %{public}s", methodName.c_str());
113 if (engine_ == nullptr) {
114 HILOGE("engine_ is nullptr");
115 return;
116 }
117 // js callback should run in js thread
118 auto task = [this, methodName, deviceIds]() {
119 napi_handle_scope scope = nullptr;
120 napi_open_handle_scope(this->engine_, &scope);
121 if (scope == nullptr) {
122 return;
123 }
124 CallJsMethodInner(methodName, deviceIds);
125
126 napi_close_handle_scope(this->engine_, scope);
127 };
128 if (napi_status::napi_ok != napi_send_event(engine_, task, napi_eprio_high)) {
129 HILOGE("send event failed!");
130 }
131 }
132
CallJsMethodInner(const std::string & methodName,const std::vector<std::string> & deviceIds)133 void JsDeviceSelectionListener::CallJsMethodInner(const std::string& methodName,
134 const std::vector<std::string>& deviceIds)
135 {
136 std::lock_guard<std::mutex> jsCallBackMapLock(jsCallBackMapMutex_);
137 auto it = jsCallBackMap_.find(methodName);
138 if (it == jsCallBackMap_.end()) {
139 HILOGE("Callback method %s not found in jsCallBackMap_", methodName.c_str());
140 return;
141 }
142 napi_value method = jsCallBackMap_[methodName]->GetNapiValue();
143 if (method == nullptr) {
144 HILOGE("Failed to get %{public}s from object", methodName.c_str());
145 return;
146 }
147 napi_value argv[] = { WrapDeviceIdArray(engine_, deviceIds) };
148 napi_call_function(engine_, CreateJsUndefined(engine_), method, ArraySize(argv), argv, nullptr);
149 }
150
WrapContinuationResult(napi_env env,const ContinuationResult & continuationResult)151 napi_value JsDeviceSelectionListener::WrapContinuationResult(napi_env env,
152 const ContinuationResult& continuationResult)
153 {
154 napi_value objValue;
155 napi_create_object(env, &objValue);
156 SetKeyValue(env, objValue, "id", continuationResult.GetDeviceId());
157 SetKeyValue(env, objValue, "type", continuationResult.GetDeviceType());
158 SetKeyValue(env, objValue, "name", continuationResult.GetDeviceName());
159 return objValue;
160 }
161
WrapContinuationResultArray(napi_env env,const std::vector<ContinuationResult> & continuationResults)162 napi_value JsDeviceSelectionListener::WrapContinuationResultArray(napi_env env,
163 const std::vector<ContinuationResult>& continuationResults)
164 {
165 napi_value arrayValue;
166 napi_create_array_with_length(env, continuationResults.size(), &arrayValue);
167 uint32_t index = 0;
168 for (const auto& continuationResult : continuationResults) {
169 napi_set_element(env,
170 arrayValue, index++, WrapContinuationResult(env, continuationResult));
171 }
172 return arrayValue;
173 }
174
WrapDeviceIdArray(napi_env env,const std::vector<std::string> & deviceIds)175 napi_value JsDeviceSelectionListener::WrapDeviceIdArray(napi_env env,
176 const std::vector<std::string>& deviceIds)
177 {
178 napi_value arrayValue;
179 napi_create_array_with_length(env, deviceIds.size(), &arrayValue);
180 uint32_t index = 0;
181 for (const auto& deviceId : deviceIds) {
182 napi_set_element(env, arrayValue, index++, CreateJsValue(env, deviceId));
183 }
184 return arrayValue;
185 }
186
SetKeyValue(napi_env env,const napi_value object,const std::string & strKey,const std::string & strValue) const187 void JsDeviceSelectionListener::SetKeyValue(napi_env env,
188 const napi_value object, const std::string &strKey, const std::string &strValue) const
189 {
190 napi_value attrValue = nullptr;
191 napi_create_string_utf8(env, strValue.c_str(), NAPI_AUTO_LENGTH, &attrValue);
192 napi_set_named_property(env, object, strKey.c_str(), attrValue);
193 }
194 } // namespace DistributedSchedule
195 } // namespace OHOS