/*
* Copyright (c) 2024 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 "napi_utils.h"
#include <cstdlib>
#include <cstring>
#include <initializer_list>
#include <memory>
#include <algorithm>
#include <new>
#include <string>
#include <vector>
#include <unordered_map>
#include "securec.h"
#include "napi/native_api.h"
#include "napi/native_common.h"
#include "node_api.h"
#include "base_context.h"
#include "netstack_log.h"
#import <Foundation/Foundation.h>
namespace OHOS::NetStack::NapiUtils {
static constexpr const char *GLOBAL_JSON = "JSON";
static constexpr const char *GLOBAL_JSON_STRINGIFY = "stringify";
static constexpr const char *GLOBAL_JSON_PARSE = "parse";
static constexpr const char *CODE = "code";
static constexpr const char *MSG = "message";
static std::mutex g_mutex;
static std::mutex g_mutexForModuleId;
static std::unordered_map<uint64_t, std::shared_ptr<UvHandlerQueue>> g_handlerQueueMap;
static const char *const HTTP_UV_SYNC_QUEUE_NAME = "HTTP_UV_SYNC_QUEUE_NAME";
static std::unordered_set<napi_env> unorderedSetEnv;
static std::mutex mutexForEnv;
class WorkData {
public:
WorkData() = delete;
WorkData(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
: env_(env), data_(data), handler_(handler)
{
}
napi_env env_;
void *data_;
void (*handler_)(napi_env env, napi_status status, void *data);
};
bool IsEnvValid(napi_env env)
{
std::lock_guard<std::mutex> lock(mutexForEnv);
auto pos = unorderedSetEnv.find(env);
if (pos == unorderedSetEnv.end()) {
NETSTACK_LOGE("The env is not in the unordered set");
return false;
}
return true;
}
napi_valuetype GetValueType(napi_env env, napi_value value)
{
if (value == nullptr) {
return napi_undefined;
}
napi_valuetype valueType = napi_undefined;
NAPI_CALL_BASE(env, napi_typeof(env, value, &valueType), napi_undefined);
return valueType;
}
bool IsInstanceOf(napi_env env, napi_value object, const std::string &name)
{
if (GetValueType(env, object) != napi_object) {
return false;
}
auto global = GetGlobal(env);
napi_value constructor = GetNamedProperty(env, global, name);
if (GetValueType(env, constructor) == napi_undefined) {
return false;
}
bool isInstance = false;
NAPI_CALL_BASE(env, napi_instanceof(env, object, constructor, &isInstance), false);
return isInstance;
}
/* named property */
bool HasNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
{
if (GetValueType(env, object) != napi_object) {
return false;
}
bool hasProperty = false;
NAPI_CALL_BASE(env, napi_has_named_property(env, object, propertyName.c_str(), &hasProperty), false);
return hasProperty;
}
napi_value GetNamedProperty(napi_env env, napi_value object, const std::string &propertyName)
{
if (GetValueType(env, object) != napi_object) {
return GetUndefined(env);
}
napi_value value = nullptr;
NAPI_CALL(env, napi_get_named_property(env, object, propertyName.c_str(), &value));
return value;
}
void SetNamedProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
{
if (GetValueType(env, object) != napi_object) {
return;
}
napi_set_named_property(env, object, name.c_str(), value);
}
std::vector<std::string> GetPropertyNames(napi_env env, napi_value object)
{
if (GetValueType(env, object) != napi_object) {
return {};
}
std::vector<std::string> ret;
napi_value names = nullptr;
NAPI_CALL_BASE(env, napi_get_property_names(env, object, &names), ret);
uint32_t length = 0;
NAPI_CALL_BASE(env, napi_get_array_length(env, names, &length), ret);
for (uint32_t index = 0; index < length; ++index) {
napi_value name = nullptr;
if (napi_get_element(env, names, index, &name) != napi_ok) {
continue;
}
if (GetValueType(env, name) != napi_string) {
continue;
}
ret.emplace_back(GetStringFromValueUtf8(env, name));
}
return ret;
}
/* UINT32 */
napi_value CreateUint32(napi_env env, uint32_t code)
{
napi_value value = nullptr;
if (napi_create_uint32(env, code, &value) != napi_ok) {
return nullptr;
}
return value;
}
/* UINT64 */
napi_value CreateUint64(napi_env env, uint64_t code)
{
napi_value value = nullptr;
if (napi_create_bigint_uint64(env, code, &value) != napi_ok) {
return nullptr;
}
return value;
}
int64_t GetInt64FromValue(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_number) {
return 0;
}
int64_t ret = 0;
NAPI_CALL_BASE(env, napi_get_value_int64(env, value, &ret), 0);
return ret;
}
int64_t GetInt64Property(napi_env env, napi_value object, const std::string &propertyName)
{
if (!HasNamedProperty(env, object, propertyName)) {
return 0;
}
napi_value value = GetNamedProperty(env, object, propertyName);
return GetInt64FromValue(env, value);
}
uint32_t GetUint32FromValue(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_number) {
return 0;
}
uint32_t ret = 0;
NAPI_CALL_BASE(env, napi_get_value_uint32(env, value, &ret), 0);
return ret;
}
uint32_t GetUint32Property(napi_env env, napi_value object, const std::string &propertyName)
{
if (!HasNamedProperty(env, object, propertyName)) {
return 0;
}
napi_value value = GetNamedProperty(env, object, propertyName);
return GetUint32FromValue(env, value);
}
void SetUint32Property(napi_env env, napi_value object, const std::string &name, uint32_t value)
{
napi_value jsValue = CreateUint32(env, value);
if (GetValueType(env, jsValue) != napi_number) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
void SetUint64Property(napi_env env, napi_value object, const std::string &name, uint64_t value)
{
napi_value jsValue = CreateUint64(env, value);
if (GetValueType(env, jsValue) != napi_bigint) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
/* INT32 */
napi_value CreateInt32(napi_env env, int32_t code)
{
napi_value value = nullptr;
if (napi_create_int32(env, code, &value) != napi_ok) {
return nullptr;
}
return value;
}
int32_t GetInt32FromValue(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_number) {
return 0;
}
int32_t ret = 0;
NAPI_CALL_BASE(env, napi_get_value_int32(env, value, &ret), 0);
return ret;
}
int32_t GetInt32Property(napi_env env, napi_value object, const std::string &propertyName)
{
if (!HasNamedProperty(env, object, propertyName)) {
return 0;
}
napi_value value = GetNamedProperty(env, object, propertyName);
return GetInt32FromValue(env, value);
}
void SetInt32Property(napi_env env, napi_value object, const std::string &name, int32_t value)
{
napi_value jsValue = CreateInt32(env, value);
if (GetValueType(env, jsValue) != napi_number) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
void SetDoubleProperty(napi_env env, napi_value object, const std::string &name, double value)
{
napi_value jsValue;
if (napi_create_double(env, value, &jsValue) != napi_ok) {
return;
}
if (GetValueType(env, jsValue) != napi_number) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
/* String UTF8 */
napi_value CreateStringUtf8(napi_env env, const std::string &str)
{
napi_value value = nullptr;
if (napi_create_string_utf8(env, str.c_str(), strlen(str.c_str()), &value) != napi_ok) {
return nullptr;
}
return value;
}
void GetSecureDataPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName,
SecureData &data)
{
if (!HasNamedProperty(env, object, propertyName)) {
return;
}
napi_value value = GetNamedProperty(env, object, propertyName);
GetSecureDataFromValueUtf8(env, value, data);
}
void GetSecureDataFromValueUtf8(napi_env env, napi_value value, SecureData &data)
{
if (GetValueType(env, value) != napi_string) {
return;
}
size_t stringLength = 0;
NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength));
if (stringLength == 0 || stringLength > SIZE_MAX - 1) {
return;
}
auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
auto mem = malloc(stringLength + 1);
if (mem == nullptr) {
return;
}
std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(mem), deleter);
if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
return;
}
size_t length = 0;
NAPI_CALL_RETURN_VOID(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length));
if (length > 0) {
data.append(str.get(), length);
}
}
std::string GetStringFromValueUtf8(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_string) {
return {};
}
std::string result;
size_t stringLength = 0;
NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, nullptr, 0, &stringLength), result);
if (stringLength == 0) {
return result;
}
auto deleter = [](char *s) { free(reinterpret_cast<void *>(s)); };
std::unique_ptr<char, decltype(deleter)> str(static_cast<char *>(malloc(stringLength + 1)), deleter);
if (memset_s(str.get(), stringLength + 1, 0, stringLength + 1) != EOK) {
return result;
}
size_t length = 0;
NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, value, str.get(), stringLength + 1, &length), result);
if (length > 0) {
result.append(str.get(), length);
}
return result;
}
std::string GetStringPropertyUtf8(napi_env env, napi_value object, const std::string &propertyName)
{
if (!HasNamedProperty(env, object, propertyName)) {
return "";
}
napi_value value = GetNamedProperty(env, object, propertyName);
return GetStringFromValueUtf8(env, value);
}
std::string NapiValueToString(napi_env env, napi_value value)
{
napi_status status;
napi_valuetype valueType;
status = napi_typeof(env, value, &valueType);
if (status != napi_ok) {
return "";
}
switch (valueType) {
case napi_undefined:
case napi_null:
break;
case napi_boolean:
bool boolValue;
status = napi_get_value_bool(env, value, &boolValue);
if (status == napi_ok) {
return boolValue ? "true" : "false";
}
break;
case napi_number:
double doubleValue;
status = napi_get_value_double(env, value, &doubleValue);
if (status == napi_ok) {
if (doubleValue == std::floor(doubleValue)) {
return std::to_string(static_cast<int>(doubleValue));
}
return std::to_string(doubleValue);
}
break;
case napi_string:
return GetStringFromValueUtf8(env, value);
default:
break;
}
return "";
}
void SetStringPropertyUtf8(napi_env env, napi_value object, const std::string &name, const std::string &value)
{
napi_value jsValue = CreateStringUtf8(env, value);
if (GetValueType(env, jsValue) != napi_string) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
/* array buffer */
bool ValueIsArrayBuffer(napi_env env, napi_value value)
{
if (value == nullptr) {
return false;
}
bool isArrayBuffer = false;
NAPI_CALL_BASE(env, napi_is_arraybuffer(env, value, &isArrayBuffer), false);
return isArrayBuffer;
}
void *GetInfoFromArrayBufferValue(napi_env env, napi_value value, size_t *length)
{
if (length == nullptr) {
return nullptr;
}
void *data = nullptr;
NAPI_CALL(env, napi_get_arraybuffer_info(env, value, &data, length));
return data;
}
napi_value CreateArrayBuffer(napi_env env, size_t length, void **data)
{
if (length == 0) {
return nullptr;
}
napi_value result = nullptr;
NAPI_CALL(env, napi_create_arraybuffer(env, length, data, &result));
return result;
}
/* object */
napi_value CreateObject(napi_env env)
{
napi_value object = nullptr;
NAPI_CALL(env, napi_create_object(env, &object));
return object;
}
/* undefined */
napi_value GetUndefined(napi_env env)
{
napi_value undefined = nullptr;
NAPI_CALL(env, napi_get_undefined(env, &undefined));
return undefined;
}
/* function */
napi_value CallFunction(napi_env env, napi_value recv, napi_value func, size_t argc, const napi_value *argv)
{
napi_value res = nullptr;
NAPI_CALL(env, napi_call_function(env, recv, func, argc, argv, &res));
return res;
}
napi_value CreateFunction(napi_env env, const std::string &name, napi_callback func, void *arg)
{
napi_value res = nullptr;
NAPI_CALL(env, napi_create_function(env, name.c_str(), strlen(name.c_str()), func, arg, &res));
return res;
}
/* reference */
napi_ref CreateReference(napi_env env, napi_value callback)
{
napi_ref callbackRef = nullptr;
NAPI_CALL(env, napi_create_reference(env, callback, 1, &callbackRef));
return callbackRef;
}
napi_value GetReference(napi_env env, napi_ref callbackRef)
{
napi_value callback = nullptr;
NAPI_CALL(env, napi_get_reference_value(env, callbackRef, &callback));
return callback;
}
void DeleteReference(napi_env env, napi_ref callbackRef)
{
(void)napi_delete_reference(env, callbackRef);
}
/* boolean */
bool GetBooleanProperty(napi_env env, napi_value object, const std::string &propertyName)
{
if (!HasNamedProperty(env, object, propertyName)) {
return false;
}
napi_value value = GetNamedProperty(env, object, propertyName);
bool ret = false;
NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
return ret;
}
void SetBooleanProperty(napi_env env, napi_value object, const std::string &name, bool value)
{
napi_value jsValue = nullptr;
NAPI_CALL_RETURN_VOID(env, napi_get_boolean(env, value, &jsValue));
if (GetValueType(env, jsValue) != napi_boolean) {
return;
}
napi_set_named_property(env, object, name.c_str(), jsValue);
}
napi_value GetBoolean(napi_env env, bool value)
{
napi_value jsValue = nullptr;
NAPI_CALL(env, napi_get_boolean(env, value, &jsValue));
return jsValue;
}
bool GetBooleanFromValue(napi_env env, napi_value value)
{
if (GetValueType(env, value) != napi_boolean) {
return GetUndefined(env);
}
bool ret = false;
NAPI_CALL_BASE(env, napi_get_value_bool(env, value, &ret), false);
return ret;
}
/* define properties */
void DefineProperties(napi_env env, napi_value object,
const std::initializer_list<napi_property_descriptor> &properties)
{
napi_property_descriptor descriptors[properties.size()];
std::copy(properties.begin(), properties.end(), descriptors);
(void)napi_define_properties(env, object, properties.size(), descriptors);
}
/* array */
napi_value CreateArray(napi_env env, size_t length)
{
if (length == 0) {
napi_value res = nullptr;
NAPI_CALL(env, napi_create_array(env, &res));
return res;
}
napi_value res = nullptr;
NAPI_CALL(env, napi_create_array_with_length(env, length, &res));
return res;
}
void SetArrayElement(napi_env env, napi_value array, uint32_t index, napi_value value)
{
(void)napi_set_element(env, array, index, value);
}
bool IsArray(napi_env env, napi_value value)
{
bool result = false;
NAPI_CALL_BASE(env, napi_is_array(env, value, &result), false);
return result;
}
void SetArrayProperty(napi_env env, napi_value object, const std::string &name, napi_value value)
{
if (!IsArray(env, value)) {
return;
}
napi_set_named_property(env, object, name.c_str(), value);
}
uint32_t GetArrayLength(napi_env env, napi_value arr)
{
uint32_t arrayLength = 0;
NAPI_CALL_BASE(env, napi_get_array_length(env, arr, &arrayLength), 0);
return arrayLength;
}
napi_value GetArrayElement(napi_env env, napi_value arr, uint32_t index)
{
napi_value elementValue = nullptr;
NAPI_CALL(env, napi_get_element(env, arr, index, &elementValue));
return elementValue;
}
/* JSON */
napi_value JsonStringify(napi_env env, napi_value object)
{
napi_value undefined = GetUndefined(env);
if (GetValueType(env, object) != napi_object) {
return undefined;
}
napi_value global = nullptr;
NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
napi_value json = nullptr;
NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
napi_value stringify = nullptr;
NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_STRINGIFY, &stringify), undefined);
if (GetValueType(env, stringify) != napi_function) {
return undefined;
}
napi_value res = nullptr;
napi_value argv[1] = {object};
NAPI_CALL_BASE(env, napi_call_function(env, json, stringify, 1, argv, &res), undefined);
return res;
}
napi_value JsonParse(napi_env env, const std::string &inStr)
{
napi_value undefined = GetUndefined(env);
NSData *rootData = [[NSData alloc] initWithBytes:inStr.c_str() length:inStr.length()];
NSError *error;
id rootObject = [NSJSONSerialization JSONObjectWithData:rootData options:0 error:&error];
if (rootObject == nil) {
NETSTACK_LOGE("parse json not success, maybe file is broken.");
return undefined;
}
auto str = NapiUtils::CreateStringUtf8(env, inStr);
if (GetValueType(env, str) != napi_string) {
return undefined;
}
napi_value global = nullptr;
NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
napi_value json = nullptr;
NAPI_CALL_BASE(env, napi_get_named_property(env, global, GLOBAL_JSON, &json), undefined);
napi_value parse = nullptr;
NAPI_CALL_BASE(env, napi_get_named_property(env, json, GLOBAL_JSON_PARSE, &parse), undefined);
if (GetValueType(env, parse) != napi_function) {
return undefined;
}
napi_value res = nullptr;
napi_value argv[1] = {str};
NAPI_CALL_BASE(env, napi_call_function(env, json, parse, 1, argv, &res), undefined);
return res;
}
/* libuv */
void CreateUvQueueWork(napi_env env, void *data, void(handler)(uv_work_t *, int status))
{
uv_loop_s *loop = nullptr;
if (!IsEnvValid(env)) {
NETSTACK_LOGE("the env is invalid");
return;
}
NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
auto work = new uv_work_t;
work->data = data;
int ret = uv_queue_work_with_qos(
loop, work, [](uv_work_t *) {}, handler, uv_qos_default);
if (ret != 0) {
NETSTACK_LOGE("uv_queue_work_with_qos error = %{public}d, manual delete", ret);
delete static_cast<UvWorkWrapperShared *>(work->data);
delete work;
}
}
/* scope */
napi_handle_scope OpenScope(napi_env env)
{
napi_handle_scope scope = nullptr;
NAPI_CALL(env, napi_open_handle_scope(env, &scope));
return scope;
}
void CloseScope(napi_env env, napi_handle_scope scope)
{
(void)napi_close_handle_scope(env, scope);
}
static void UvQueueWorkCallback(uv_work_t *work, int status)
{
auto workData = static_cast<WorkData *>(work->data);
if (!workData) {
delete work;
return;
}
if (!workData->env_ || !workData->data_ || !workData->handler_) {
delete workData;
delete work;
return;
}
napi_env env = workData->env_;
auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
workData->handler_(workData->env_, static_cast<napi_status>(status), workData->data_);
delete workData;
delete work;
};
void CreateUvQueueWorkEnhanced(napi_env env, void *data, void (*handler)(napi_env env, napi_status status, void *data))
{
uv_loop_s *loop = nullptr;
if (!IsEnvValid(env)) {
NETSTACK_LOGE("the env is invalid");
return;
}
NAPI_CALL_RETURN_VOID(env, napi_get_uv_event_loop(env, &loop));
if (loop == nullptr) {
return;
}
auto workData = new WorkData(env, data, handler);
auto work = new (std::nothrow) uv_work_t;
if (work == nullptr) {
return;
}
work->data = reinterpret_cast<void *>(workData);
int ret = uv_queue_work_with_qos(
loop, work, [](uv_work_t *) {}, UvQueueWorkCallback, uv_qos_default);
if (ret != 0) {
NETSTACK_LOGE("uv_queue_work_with_qos error = %{public}d, manual release", ret);
delete static_cast<WorkData *>(work->data);
delete work;
}
}
/* error */
napi_value CreateErrorMessage(napi_env env, int32_t errorCode, const std::string &errorMessage)
{
napi_value result = nullptr;
result = CreateObject(env);
SetNamedProperty(env, result, CODE, CreateInt32(env, errorCode));
SetNamedProperty(env, result, MSG, CreateStringUtf8(env, errorMessage));
return result;
}
napi_value GetGlobal(napi_env env)
{
napi_value undefined = GetUndefined(env);
napi_value global = nullptr;
NAPI_CALL_BASE(env, napi_get_global(env, &global), undefined);
return global;
}
uint64_t CreateUvHandlerQueue(napi_env env)
{
static std::atomic<uint64_t> id = 1; // start from 1
uint64_t newId = 0;
{
std::lock_guard<std::mutex> lock(g_mutexForModuleId);
newId = id.load();
++id;
}
NETSTACK_LOGI("CreateUvHandlerQueue newId = %{public}s, id = %{public}s",
std::to_string(newId).c_str(), std::to_string(id).c_str());
auto global = GetGlobal(env);
auto queueWrapper = CreateObject(env);
SetNamedProperty(env, global, HTTP_UV_SYNC_QUEUE_NAME, queueWrapper);
{
std::lock_guard lock(g_mutex);
g_handlerQueueMap.emplace(newId, std::make_shared<UvHandlerQueue>());
}
napi_wrap(
env, queueWrapper, reinterpret_cast<void *>(newId),
[](napi_env env, void *data, void *) {
auto id = reinterpret_cast<uint64_t>(data);
std::lock_guard lock(g_mutex);
g_handlerQueueMap.erase(id);
},
nullptr, nullptr);
return newId;
}
napi_value GetValueFromGlobal(napi_env env, const std::string &className)
{
auto global = NapiUtils::GetGlobal(env);
if (NapiUtils::GetValueType(env, global) == napi_undefined) {
return GetUndefined(env);
}
return NapiUtils::GetNamedProperty(env, global, className);
}
static uv_after_work_cb MakeUvCallback()
{
return [](uv_work_t *work, int status) {
if (!work) {
return;
}
std::unique_ptr<uv_work_t> workHandle(work);
if (!work->data) {
return;
}
auto env = reinterpret_cast<napi_env>(work->data);
if (!env) {
return;
}
auto closeScope = [env](napi_handle_scope scope) { NapiUtils::CloseScope(env, scope); };
std::unique_ptr<napi_handle_scope__, decltype(closeScope)> scope(NapiUtils::OpenScope(env), closeScope);
auto queueWrapper = NapiUtils::GetValueFromGlobal(env, HTTP_UV_SYNC_QUEUE_NAME);
if (!queueWrapper) {
return;
}
void *theId = nullptr;
napi_unwrap(env, queueWrapper, &theId);
if (!theId) { // that is why moduleId is started from 1
return;
}
UvHandler handler;
decltype(g_handlerQueueMap.end()) it;
{
std::lock_guard lock(g_mutex);
it = g_handlerQueueMap.find(reinterpret_cast<uint64_t>(theId));
if (it == g_handlerQueueMap.end()) {
return;
}
handler = it->second->Pop();
}
if (handler) {
handler();
}
};
}
void CreateUvQueueWorkByModuleId(napi_env env, const UvHandler &handler, uint64_t id)
{
uv_loop_s *loop = nullptr;
if (!IsEnvValid(env)) {
NETSTACK_LOGE("the env is invalid");
return;
}
napi_get_uv_event_loop(env, &loop);
if (!loop) {
return;
}
decltype(g_handlerQueueMap.end()) it;
{
std::lock_guard lock(g_mutex);
it = g_handlerQueueMap.find(id);
if (it == g_handlerQueueMap.end()) {
return;
}
}
auto work = new uv_work_t;
work->data = env;
it->second->Push(handler);
(void)uv_queue_work_with_qos(
loop, work, [](uv_work_t *) {}, MakeUvCallback(), uv_qos_default);
}
UvHandler UvHandlerQueue::Pop()
{
std::lock_guard lock(mutex);
if (empty()) {
return {};
}
auto s = front();
pop();
return s;
}
void UvHandlerQueue::Push(const UvHandler &handler)
{
std::lock_guard lock(mutex);
push(handler);
}
void HookForEnvCleanup(void *data)
{
std::lock_guard<std::mutex> lock(mutexForEnv);
auto env = static_cast<napi_env>(data);
auto pos = unorderedSetEnv.find(env);
if (pos == unorderedSetEnv.end()) {
NETSTACK_LOGE("The env is not in the unordered set");
return;
}
NETSTACK_LOGD("env clean up, erase from the unordered set");
unorderedSetEnv.erase(pos);
}
void SetEnvValid(napi_env env)
{
std::lock_guard<std::mutex> lock(mutexForEnv);
unorderedSetEnv.emplace(env);
}
//ThrowError
void ThrowError(napi_env env, const std::string &errorCode, const std::string &errorMessage)
{
napi_value code = nullptr;
napi_create_string_utf8(env, errorCode.c_str(), NAPI_AUTO_LENGTH, &code);
napi_value message = nullptr;
napi_create_string_utf8(env, errorMessage.c_str(), NAPI_AUTO_LENGTH, &message);
napi_value error = nullptr;
napi_create_error(env, code, message, &error);
napi_throw(env, error);
}
} // namespace OHOS::NetStack::NapiUtils