* Copyright (c) 2022 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "scan_callback.h"
#include "napi/native_node_api.h"
#include "napi_scan_utils.h"
#include "scan_log.h"
#include "scanner_info_helper.h"
namespace OHOS::Scan {
ScanCallback::ScanCallback(napi_env env, napi_ref ref)
: env_(env), ref_(ref), callbackFunction_(nullptr), mutex_(std::make_shared<std::mutex>())
{
}
ScanCallback::ScanCallback(std::function<void(std::vector<ScanDeviceInfo> &infos)> callbackFunction)
: env_(nullptr), ref_(nullptr), callbackFunction_(callbackFunction), mutex_(std::make_shared<std::mutex>())
{
}
ScanCallback::~ScanCallback()
{
auto mutexPtr = mutex_;
std::lock_guard<std::mutex> autoLock(*mutexPtr);
if (env_ == nullptr || ref_ == nullptr) {
return;
}
SCAN_HILOGI("callback has been destroyed");
Param *param = new Param;
param->env = env_;
param->callbackRef = ref_;
auto task = [param]() {
SCAN_HILOGI("napi_send_event ScanCallback DeleteReference");
napi_handle_scope scope = nullptr;
napi_open_handle_scope(param->env, &scope);
if (scope == nullptr) {
NapiScanUtils::DeleteReference(param->env, param->callbackRef);
delete param;
return;
}
napi_ref callbackRef = param->callbackRef;
NapiScanUtils::DeleteReference(param->env, callbackRef);
napi_close_handle_scope(param->env, scope);
delete param;
};
if (napi_send_event(env_, task, napi_eprio_low) != napi_ok) {
SCAN_HILOGE("Failed to send event");
NapiScanUtils::DeleteReference(env_, ref_);
delete param;
}
}
void CallbackParam::InitialCallbackParam(napi_env &env_, napi_ref &ref_, std::shared_ptr<std::mutex> &mutex_)
{
std::lock_guard<std::mutex> lock(*mutex_);
this->env = env_;
this->ref = ref_;
this->mutexPtr = mutex_;
}
void CallbackParam::SetCallbackParam(uint32_t &state, const ScanDeviceInfo &deviceInfo)
{
this->state = state;
this->deviceInfo = deviceInfo;
}
void CallbackParam::SetCallbackSyncParam(uint32_t &state, const ScanDeviceInfoSync &deviceInfoSync)
{
this->state = state;
this->deviceInfoSync = deviceInfoSync;
}
bool ScanCallback::ExecuteNapiEventWork(CallbackParam* param, std::function<void(CallbackParam*)> workFunc)
{
SCAN_CHECK_NULL_AND_RETURN_WITH_FUNC(param, false, __func__);
auto task = [param, workFunc]() {
if (param == nullptr) {
SCAN_HILOGE("param is a nullptr");
return;
}
std::lock_guard<std::mutex> autoLock(*param->mutexPtr);
napi_handle_scope scope = nullptr;
napi_open_handle_scope(param->env, &scope);
if (scope == nullptr) {
delete param;
return;
}
napi_value callbackFunc = NapiScanUtils::GetReference(param->env, param->ref);
if (callbackFunc != nullptr) {
workFunc(param);
SCAN_HILOGI("run napi call deviceInfo callback fun success");
} else {
SCAN_HILOGE("get reference failed");
}
napi_close_handle_scope(param->env, scope);
delete param;
};
napi_status ret = napi_send_event(env_, task, napi_eprio_immediate);
if (ret != napi_ok) {
SCAN_HILOGE("napi_send_event fail");
delete param;
return false;
}
return true;
}
void ScanCallback::NapiCallFunction(CallbackParam* cbParam, size_t argcCount, napi_value* callbackValues)
{
if (cbParam == nullptr) {
SCAN_HILOGE("cbParam is a nullptr");
return;
}
napi_value callbackFunc = NapiScanUtils::GetReference(cbParam->env, cbParam->ref);
if (callbackFunc != nullptr) {
napi_call_function(cbParam->env, nullptr, callbackFunc,
argcCount, callbackValues, nullptr);
}
}
bool ScanCallback::OnCallback(uint32_t state, const ScanDeviceInfo &info)
{
SCAN_HILOGI("Enter OnCallback::ScanDeviceInfo");
CallbackParam *param = new CallbackParam;
param->InitialCallbackParam(env_, ref_, mutex_);
param->SetCallbackParam(state, info);
auto workFunc = [this](CallbackParam* cbParam) {
napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
callbackValues[0] = ScannerInfoHelper::MakeJsObject(cbParam->env, cbParam->deviceInfo);
NapiCallFunction(cbParam, NapiScanUtils::ARGC_ONE, callbackValues);
};
return ExecuteNapiEventWork(param, workFunc);
}
bool ScanCallback::OnCallbackSync(uint32_t state, const ScanDeviceInfoSync &info)
{
SCAN_HILOGD("Enter OnCallback::ScanDeviceInfo");
CallbackParam *param = new CallbackParam;
param->InitialCallbackParam(env_, ref_, mutex_);
param->SetCallbackSyncParam(state, info);
auto workFunc = [this](CallbackParam* cbParam) {
napi_value callbackValues[NapiScanUtils::ARGC_ONE] = { 0 };
callbackValues[0] = ScannerInfoSyncHelper::MakeJsObject(cbParam->env, cbParam->deviceInfoSync);
NapiCallFunction(cbParam, NapiScanUtils::ARGC_ONE, callbackValues);
};
return ExecuteNapiEventWork(param, workFunc);
}
bool ScanCallback::OnGetDevicesList(std::vector<ScanDeviceInfo> &infos)
{
SCAN_HILOGI("Enter OnGetDevicesList");
if (callbackFunction_ == nullptr) {
SCAN_HILOGE("callbackFunction_ is a nullptr");
return false;
}
callbackFunction_(infos);
return true;
}
}