• 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 "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