django-vue3-admin-web/node_modules/aws-crt/source/module.c
2025-10-20 21:21:14 +08:00

1619 lines
54 KiB
C

/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include "auth.h"
#include "checksums.h"
#include "crypto.h"
#include "event_stream.h"
#include "http_connection.h"
#include "http_connection_manager.h"
#include "http_headers.h"
#include "http_message.h"
#include "http_stream.h"
#include "io.h"
#include "logger.h"
#include "mqtt5_client.h"
#include "mqtt_client.h"
#include "mqtt_client_connection.h"
#include "mqtt_request_response.h"
#include <aws/cal/cal.h>
#include <aws/common/clock.h>
#include <aws/common/environment.h>
#include <aws/common/logging.h>
#include <aws/common/mutex.h>
#include <aws/common/ref_count.h>
#include <aws/common/rw_lock.h>
#include <aws/common/system_info.h>
#include <aws/event-stream/event_stream.h>
#include <aws/io/event_loop.h>
#include <aws/io/tls_channel_handler.h>
#include <aws/http/http.h>
#include <aws/auth/auth.h>
#include <uv.h>
/*
* This is a multi-line comment to ensure that the static assert does not collide with the static asserts in
* aws/common/macro.h.
*
*/
AWS_STATIC_ASSERT(NAPI_VERSION >= 4);
#define AWS_DEFINE_ERROR_INFO_CRT_NODEJS(CODE, STR) AWS_DEFINE_ERROR_INFO(CODE, STR, "aws-crt-nodejs")
/* TODO:
* Hardcoded enum value for `napi_no_external_buffers_allowed`.
* The enum `napi_no_external_buffers_allowed` is introduced in node21 and backport
* to node 14.21.2, 16.19.0, 18.13.0.
* Use `napi_no_external_buffers_allowed` for external buffer related changes after bump to node 21 */
#define NAPI_NO_EXTERNAL_BUFFER_ENUM_VALUE 22
static bool s_tsfn_enabled = false;
static struct aws_rw_lock s_tsfn_lock;
/* clang-format off */
static struct aws_error_info s_errors[] = {
AWS_DEFINE_ERROR_INFO_CRT_NODEJS(
AWS_CRT_NODEJS_ERROR_THREADSAFE_FUNCTION_NULL_NAPI_ENV,
"There was an attempt to execute a thread-safe napi function binding with a null napi environment. This is usually due to the function binding being released by a shutdown/cleanup process while the execution is waiting in the queue."),
AWS_DEFINE_ERROR_INFO_CRT_NODEJS(
AWS_CRT_NODEJS_ERROR_NAPI_FAILURE,
"A N-API API call failed"),
AWS_DEFINE_ERROR_INFO_CRT_NODEJS(
AWS_CRT_NODEJS_ERROR_EVENT_STREAM_USER_CLOSE,
"User invoked close on an eventstream connection."),
};
/* clang-format on */
static struct aws_error_info_list s_error_list = {
.error_list = s_errors,
.count = sizeof(s_errors) / sizeof(struct aws_error_info),
};
static struct aws_log_subject_info s_log_subject_infos[] = {
DEFINE_LOG_SUBJECT_INFO(AWS_LS_NODEJS_CRT_GENERAL, "node", "General Node/N-API events"),
};
static struct aws_log_subject_info_list s_log_subject_list = {
.subject_list = s_log_subject_infos,
.count = AWS_ARRAY_SIZE(s_log_subject_infos),
};
static uv_loop_t *s_node_uv_loop = NULL;
static struct aws_event_loop *s_node_uv_event_loop = NULL;
static struct aws_event_loop_group *s_node_uv_elg = NULL;
static struct aws_host_resolver *s_default_host_resolver = NULL;
static struct aws_client_bootstrap *s_default_client_bootstrap = NULL;
int aws_napi_attach_object_property_boolean(napi_value object, napi_env env, const char *key_name, bool value) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_boolean = NULL;
AWS_NAPI_CALL(env, napi_get_boolean(env, value, &napi_boolean), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_boolean), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
int aws_napi_attach_object_property_optional_boolean(
napi_value object,
napi_env env,
const char *key_name,
const bool *value) {
if (value == NULL) {
return AWS_OP_SUCCESS;
}
return aws_napi_attach_object_property_boolean(object, env, key_name, *value);
}
/*
* IEEE fp double analysis says 2 ^ 53 is the maximum sequential value we could support, but the napi docs for
* napi_create_int64() say (2 ^ 53 - 1) so we'll use their more conservative bound.
*/
#define MAX_ALLOWED_UINT64_T_TO_DOUBLE ((((uint64_t)1) << 53) - 1)
int aws_napi_attach_object_property_u64(napi_value object, napi_env env, const char *key_name, uint64_t value) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
if (value > MAX_ALLOWED_UINT64_T_TO_DOUBLE) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_i64 = NULL;
AWS_NAPI_CALL(env, napi_create_int64(env, (int64_t)value, &napi_i64), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_i64), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
int aws_napi_attach_object_property_optional_u64(
napi_value object,
napi_env env,
const char *key_name,
const uint64_t *value) {
if (value == NULL) {
return AWS_OP_SUCCESS;
}
return aws_napi_attach_object_property_u64(object, env, key_name, *value);
}
int aws_napi_attach_object_property_u32(napi_value object, napi_env env, const char *key_name, uint32_t value) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_u32 = NULL;
AWS_NAPI_CALL(
env, napi_create_uint32(env, value, &napi_u32), { return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE); });
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_u32), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
int aws_napi_attach_object_property_optional_u32(
napi_value object,
napi_env env,
const char *key_name,
const uint32_t *value) {
if (value == NULL) {
return AWS_OP_SUCCESS;
}
return aws_napi_attach_object_property_u32(object, env, key_name, *value);
}
int aws_napi_attach_object_property_i32(napi_value object, napi_env env, const char *key_name, int32_t value) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_i32 = NULL;
AWS_NAPI_CALL(
env, napi_create_int32(env, value, &napi_i32), { return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE); });
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_i32), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
int aws_napi_attach_object_property_u16(napi_value object, napi_env env, const char *key_name, uint16_t value) {
return aws_napi_attach_object_property_u32(object, env, key_name, (uint32_t)value);
}
int aws_napi_attach_object_property_optional_u16(
napi_value object,
napi_env env,
const char *key_name,
const uint16_t *value) {
if (value == NULL) {
return AWS_OP_SUCCESS;
}
return aws_napi_attach_object_property_u16(object, env, key_name, *value);
}
int aws_napi_attach_object_property_string(
napi_value object,
napi_env env,
const char *key_name,
struct aws_byte_cursor value) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_string = NULL;
AWS_NAPI_CALL(env, napi_create_string_utf8(env, (const char *)(value.ptr), value.len, &napi_string), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_string), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
int aws_napi_attach_object_property_optional_string(
napi_value object,
napi_env env,
const char *key_name,
const struct aws_byte_cursor *value) {
if (value == NULL) {
return AWS_OP_SUCCESS;
}
return aws_napi_attach_object_property_string(object, env, key_name, *value);
}
static void s_finalize_external_binary_byte_buf(napi_env env, void *finalize_data, void *finalize_hint) {
(void)env;
(void)finalize_data;
struct aws_byte_buf *buffer = finalize_hint;
if (buffer == NULL) {
return;
}
struct aws_allocator *allocator = buffer->allocator;
aws_byte_buf_clean_up(buffer);
aws_mem_release(allocator, buffer);
}
int aws_napi_attach_object_property_binary_as_finalizable_external(
napi_value object,
napi_env env,
const char *key_name,
struct aws_byte_buf *data_buffer) {
if (key_name == NULL) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_value napi_binary = NULL;
AWS_NAPI_ENSURE(
env,
aws_napi_create_external_arraybuffer(
env,
data_buffer->buffer,
data_buffer->len,
s_finalize_external_binary_byte_buf,
data_buffer,
&napi_binary));
AWS_NAPI_CALL(env, napi_set_named_property(env, object, key_name, napi_binary), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property(
napi_env env,
napi_value object,
const char *name,
napi_valuetype type,
napi_value *result) {
if (name == NULL) {
return AWS_NGNPR_NO_VALUE;
}
bool has_property = false;
if (napi_has_named_property(env, object, name, &has_property) || !has_property) {
return AWS_NGNPR_NO_VALUE;
}
napi_value property = NULL;
if (napi_get_named_property(env, object, name, &property)) {
return AWS_NGNPR_NO_VALUE;
}
if (type != napi_undefined) {
napi_valuetype property_type = napi_undefined;
if (napi_typeof(env, property, &property_type)) {
return AWS_NGNPR_INVALID_VALUE;
}
if (property_type != type) {
return AWS_NGNPR_INVALID_VALUE;
}
}
*result = property;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_uint16(
napi_env env,
napi_value object,
const char *name,
uint16_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < 0 || int_value > UINT16_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (uint16_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_uint32(
napi_env env,
napi_value object,
const char *name,
uint32_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < 0 || int_value > UINT32_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (uint32_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_uint64(
napi_env env,
napi_value object,
const char *name,
uint64_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < 0) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (uint64_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_uint8(
napi_env env,
napi_value object,
const char *name,
uint8_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < 0 || int_value > UINT8_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (uint8_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_int8(
napi_env env,
napi_value object,
const char *name,
int8_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < INT8_MIN || int_value > INT8_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (int8_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_int16(
napi_env env,
napi_value object,
const char *name,
int16_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < INT16_MIN || int_value > INT16_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (int16_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_int32(
napi_env env,
napi_value object,
const char *name,
int32_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
int64_t int_value = 0;
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, &int_value), { return AWS_NGNPR_INVALID_VALUE; });
if (int_value < INT32_MIN || int_value > INT32_MAX) {
return AWS_NGNPR_INVALID_VALUE;
}
*result = (int32_t)int_value;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_int64(
napi_env env,
napi_value object,
const char *name,
int64_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_number, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
AWS_NAPI_CALL(env, napi_get_value_int64(env, node_result, result), { return AWS_NGNPR_INVALID_VALUE; });
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_boolean(
napi_env env,
napi_value object,
const char *name,
bool *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_boolean, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
AWS_NAPI_CALL(env, napi_get_value_bool(env, node_result, result), { return AWS_NGNPR_INVALID_VALUE; });
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_boolean_as_uint8(
napi_env env,
napi_value object,
const char *name,
uint8_t *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, napi_boolean, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
bool bool_result = false;
AWS_NAPI_CALL(env, napi_get_value_bool(env, node_result, &bool_result), { return AWS_NGNPR_INVALID_VALUE; });
*result = bool_result ? 1 : 0;
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_as_bytebuf(
napi_env env,
napi_value object,
const char *name,
napi_valuetype type,
struct aws_byte_buf *result) {
napi_value node_result;
enum aws_napi_get_named_property_result get_property_result =
aws_napi_get_named_property(env, object, name, type, &node_result);
if (get_property_result != AWS_NGNPR_VALID_VALUE) {
return get_property_result;
}
AWS_NAPI_CALL(env, aws_byte_buf_init_from_napi(result, env, node_result), { return AWS_NGNPR_INVALID_VALUE; });
return AWS_NGNPR_VALID_VALUE;
}
enum aws_napi_get_named_property_result aws_napi_get_named_property_buffer_length(
napi_env env,
napi_value object,
const char *name,
napi_valuetype type,
size_t *length_out) {
struct aws_byte_buf buffer;
AWS_ZERO_STRUCT(buffer);
enum aws_napi_get_named_property_result result =
aws_napi_get_named_property_as_bytebuf(env, object, name, type, &buffer);
if (result == AWS_NGNPR_VALID_VALUE) {
*length_out = buffer.len;
}
aws_byte_buf_clean_up(&buffer);
return result;
}
static int s_typed_array_element_type_to_byte_length(napi_typedarray_type type, size_t *element_length) {
switch (type) {
case napi_int8_array:
case napi_uint8_array:
case napi_uint8_clamped_array:
*element_length = 1;
return AWS_OP_SUCCESS;
case napi_int16_array:
case napi_uint16_array:
*element_length = 2;
return AWS_OP_SUCCESS;
case napi_int32_array:
case napi_uint32_array:
case napi_float32_array:
*element_length = 4;
return AWS_OP_SUCCESS;
case napi_float64_array:
case 9: /*napi_bigint64_array */
case 10: /*napi_biguint64_array*/
*element_length = 8;
return AWS_OP_SUCCESS;
}
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
napi_status aws_byte_buf_init_from_napi(struct aws_byte_buf *buf, napi_env env, napi_value node_str) {
AWS_ASSERT(buf);
napi_valuetype type = napi_undefined;
AWS_NAPI_CALL(env, napi_typeof(env, node_str, &type), { return status; });
if (type == napi_string) {
size_t length = 0;
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, node_str, NULL, 0, &length), { return status; });
/* Node requires that the null terminator be written */
if (aws_byte_buf_init(buf, aws_napi_get_allocator(), length + 1)) {
return napi_generic_failure;
}
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, node_str, (char *)buf->buffer, buf->capacity, &buf->len), {
return status;
});
AWS_ASSERT(length == buf->len);
return napi_ok;
} else if (type == napi_object) {
bool is_expected = false;
/* Try ArrayBuffer */
AWS_NAPI_CALL(env, napi_is_arraybuffer(env, node_str, &is_expected), { return status; });
if (is_expected) {
napi_status status = napi_get_arraybuffer_info(env, node_str, (void **)&buf->buffer, &buf->len);
buf->capacity = buf->len;
return status;
}
/* Try DataView */
AWS_NAPI_CALL(env, napi_is_dataview(env, node_str, &is_expected), { return status; });
if (is_expected) {
napi_status status = napi_get_dataview_info(env, node_str, &buf->len, (void **)&buf->buffer, NULL, NULL);
buf->capacity = buf->len;
return status;
}
/* Try TypedArray */
AWS_NAPI_CALL(env, napi_is_typedarray(env, node_str, &is_expected), { return status; });
if (is_expected) {
napi_typedarray_type array_type = napi_uint8_array;
size_t length = 0;
AWS_NAPI_CALL(
env, napi_get_typedarray_info(env, node_str, &array_type, &length, (void **)&buf->buffer, NULL, NULL), {
return status;
});
size_t element_size = 0;
if (s_typed_array_element_type_to_byte_length(array_type, &element_size)) {
return napi_invalid_arg;
}
buf->len = length * element_size;
buf->capacity = buf->len;
return napi_ok;
}
}
return napi_invalid_arg;
}
int aws_napi_value_get_storage_length(napi_env env, napi_value value, size_t *storage_length) {
napi_valuetype type = napi_undefined;
AWS_NAPI_CALL(env, napi_typeof(env, value, &type), { return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE); });
if (type == napi_string) {
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, value, NULL, 0, storage_length), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
} else if (type == napi_object) {
/* Try ArrayBuffer */
bool is_array_buffer = false;
AWS_NAPI_CALL(env, napi_is_arraybuffer(env, value, &is_array_buffer), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_array_buffer) {
void *buffer = NULL;
AWS_NAPI_CALL(env, napi_get_arraybuffer_info(env, value, &buffer, storage_length), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
/* Try DataView */
bool is_data_view = false;
AWS_NAPI_CALL(env, napi_is_dataview(env, value, &is_data_view), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_data_view) {
AWS_NAPI_CALL(env, napi_get_dataview_info(env, value, storage_length, NULL, NULL, NULL), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
return AWS_OP_SUCCESS;
}
/* Try TypedArray */
bool is_typed_array = false;
AWS_NAPI_CALL(env, napi_is_typedarray(env, value, &is_typed_array), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_typed_array) {
napi_typedarray_type array_type = napi_uint8_array;
size_t length = 0;
AWS_NAPI_CALL(env, napi_get_typedarray_info(env, value, &array_type, &length, NULL, NULL, NULL), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
size_t element_size = 0;
if (s_typed_array_element_type_to_byte_length(array_type, &element_size)) {
return napi_invalid_arg;
}
*storage_length = length * element_size;
return AWS_OP_SUCCESS;
}
}
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
int aws_napi_value_bytebuf_append(
napi_env env,
napi_value value,
struct aws_byte_buf *output_buffer,
struct aws_byte_cursor *bytes_written_cursor) {
AWS_ZERO_STRUCT(*bytes_written_cursor);
napi_valuetype type = napi_undefined;
AWS_NAPI_CALL(env, napi_typeof(env, value, &type), { return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT); });
size_t open_bytes = output_buffer->capacity - output_buffer->len;
uint8_t *open_space = output_buffer->buffer + output_buffer->len;
if (type == napi_string) {
size_t bytes_written = 0;
AWS_NAPI_CALL(env, napi_get_value_string_utf8(env, value, (char *)open_space, open_bytes, &bytes_written), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
/* technically, we might have been truncated, but there's no way to tell */
bytes_written_cursor->ptr = open_space;
bytes_written_cursor->len = bytes_written;
output_buffer->len += bytes_written;
return AWS_OP_SUCCESS;
} else if (type == napi_object) {
/* Try ArrayBuffer */
bool is_array_buffer = false;
AWS_NAPI_CALL(env, napi_is_arraybuffer(env, value, &is_array_buffer), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_array_buffer) {
void *buffer = NULL;
size_t buffer_length = 0;
AWS_NAPI_CALL(env, napi_get_arraybuffer_info(env, value, &buffer, &buffer_length), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
bytes_written_cursor->ptr = buffer;
bytes_written_cursor->len = buffer_length;
return aws_byte_buf_append_and_update(output_buffer, bytes_written_cursor);
}
/* Try DataView */
bool is_data_view = false;
AWS_NAPI_CALL(env, napi_is_dataview(env, value, &is_data_view), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_data_view) {
void *buffer = NULL;
size_t buffer_length = 0;
AWS_NAPI_CALL(env, napi_get_dataview_info(env, value, &buffer_length, &buffer, NULL, NULL), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
bytes_written_cursor->ptr = buffer;
bytes_written_cursor->len = buffer_length;
return aws_byte_buf_append_and_update(output_buffer, bytes_written_cursor);
}
bool is_typed_array = false;
AWS_NAPI_CALL(env, napi_is_typedarray(env, value, &is_typed_array), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
if (is_typed_array) {
napi_typedarray_type array_type = napi_uint8_array;
size_t length = 0;
uint8_t *buffer = NULL;
AWS_NAPI_CALL(
env, napi_get_typedarray_info(env, value, &array_type, &length, (void **)&buffer, NULL, NULL), {
return aws_raise_error(AWS_CRT_NODEJS_ERROR_NAPI_FAILURE);
});
size_t element_size = 0;
if (s_typed_array_element_type_to_byte_length(array_type, &element_size)) {
return napi_invalid_arg;
}
bytes_written_cursor->ptr = buffer;
bytes_written_cursor->len = element_size * length;
return aws_byte_buf_append_and_update(output_buffer, bytes_written_cursor);
}
}
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
struct aws_string *aws_string_new_from_napi(napi_env env, napi_value node_str) {
struct aws_byte_buf temp_buf;
if (aws_byte_buf_init_from_napi(&temp_buf, env, node_str)) {
return NULL;
}
struct aws_string *string = aws_string_new_from_array(aws_napi_get_allocator(), temp_buf.buffer, temp_buf.len);
aws_byte_buf_clean_up(&temp_buf);
return string;
}
napi_status aws_napi_create_dataview_from_byte_cursor(
napi_env env,
const struct aws_byte_cursor *cur,
napi_value *result) {
void *data = NULL;
napi_value arraybuffer;
AWS_NAPI_CALL(env, napi_create_arraybuffer(env, cur->len, &data, &arraybuffer), { return status; });
struct aws_byte_buf arraybuffer_buf = aws_byte_buf_from_empty_array(data, cur->len);
struct aws_byte_cursor input = *cur;
if (!aws_byte_buf_write_from_whole_cursor(&arraybuffer_buf, input)) {
return napi_generic_failure;
}
AWS_NAPI_CALL(env, napi_create_dataview(env, cur->len, arraybuffer, 0, result), { return status; });
return napi_ok;
}
bool aws_napi_is_null_or_undefined(napi_env env, napi_value value) {
napi_valuetype type = napi_undefined;
if (napi_ok != napi_typeof(env, value, &type)) {
return true;
}
return type == napi_null || type == napi_undefined;
}
int aws_napi_get_property_array_size(
napi_env env,
napi_value object,
const char *property_name,
size_t *array_size_out) {
napi_value napi_array = NULL;
enum aws_napi_get_named_property_result get_result =
aws_napi_get_named_property(env, object, property_name, napi_object, &napi_array);
if (get_result == AWS_NGNPR_NO_VALUE) {
*array_size_out = 0;
return AWS_OP_SUCCESS;
} else if (get_result == AWS_NGNPR_INVALID_VALUE) {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
}
uint32_t array_size = 0;
AWS_NAPI_CALL(env, napi_get_array_length(env, napi_array, &array_size), {
return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
});
*array_size_out = (size_t)array_size;
return AWS_OP_SUCCESS;
}
void s_aws_enable_threadsafe_function(void) {
aws_rw_lock_wlock(&s_tsfn_lock);
s_tsfn_enabled = true;
aws_rw_lock_wunlock(&s_tsfn_lock);
}
void s_aws_disable_threadsafe_function(void) {
aws_rw_lock_wlock(&s_tsfn_lock);
s_tsfn_enabled = false;
aws_rw_lock_wunlock(&s_tsfn_lock);
}
napi_value aws_napi_disable_threadsafe_function(napi_env env, napi_callback_info info) {
(void)info;
if (env == NULL) {
aws_raise_error(AWS_CRT_NODEJS_ERROR_THREADSAFE_FUNCTION_NULL_NAPI_ENV);
return NULL;
}
s_aws_disable_threadsafe_function();
return NULL;
}
void aws_napi_throw_last_error(napi_env env) {
const int error_code = aws_last_error();
napi_throw_error(env, aws_error_str(error_code), aws_error_debug_str(error_code));
}
void aws_napi_throw_last_error_with_context(napi_env env, const char *context) {
const int error_code = aws_last_error();
char full_msg[1024];
snprintf(
full_msg,
AWS_ARRAY_SIZE(full_msg),
"%s : (%s - %s)",
context,
aws_error_str(error_code),
aws_error_debug_str(error_code));
napi_throw_error(env, aws_error_str(error_code), full_msg);
}
struct uv_loop_s *aws_napi_get_node_uv_loop(void) {
return s_node_uv_loop;
}
struct aws_event_loop *aws_napi_get_node_event_loop(void) {
return s_node_uv_event_loop;
}
struct aws_event_loop_group *aws_napi_get_node_elg(void) {
return s_node_uv_elg;
}
struct aws_client_bootstrap *aws_napi_get_default_client_bootstrap(void) {
return s_default_client_bootstrap;
}
/* The napi_status enum has grown, and is not bound by N-API versioning */
#if defined(__clang__) || defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wswitch"
#endif
const char *aws_napi_status_to_str(napi_status status) {
const char *reason = "UNKNOWN";
switch (status) {
case napi_ok:
reason = "OK";
break;
case napi_invalid_arg:
reason = "napi_invalid_arg: an invalid argument was supplied";
break;
case napi_object_expected:
reason = "napi_object_expected";
break;
case napi_string_expected:
reason = "napi_name_expected";
break;
case napi_name_expected:
reason = "napi_name_expected";
break;
case napi_function_expected:
reason = "napi_function_expected";
break;
case napi_number_expected:
reason = "napi_number_expected";
break;
case napi_boolean_expected:
reason = "napi_boolean_expected";
break;
case napi_array_expected:
reason = "napi_array_expected";
break;
case napi_generic_failure:
reason = "napi_generic_failure";
break;
case napi_pending_exception:
reason = "napi_pending_exception";
break;
case napi_cancelled:
reason = "napi_cancelled";
break;
case napi_escape_called_twice:
reason = "napi_escape_called_twice";
break;
case napi_handle_scope_mismatch:
reason = "napi_handle_scope_mismatch";
break;
case napi_callback_scope_mismatch:
reason = "napi_callback_scope_mismatch";
break;
case napi_queue_full:
reason = "napi_queue_full";
break;
case napi_closing:
reason = "napi_closing";
break;
case napi_bigint_expected:
reason = "napi_bigint_expected";
break;
case NAPI_NO_EXTERNAL_BUFFER_ENUM_VALUE:
reason = "napi_no_external_buffers_allowed";
break;
}
return reason;
}
#if defined(__clang__) || defined(__GNUC__)
# pragma GCC diagnostic pop
#endif
static void s_handle_failed_callback(napi_env env, napi_value function, napi_status reason) {
/* Figure out if there's an exception pending, if so, no callbacks will ever succeed again until it's cleared */
bool pending_exception = reason == napi_pending_exception;
AWS_NAPI_ENSURE(env, napi_is_exception_pending(env, &pending_exception));
/* if there's no pending exception, but failure occurred, log what we can find and get out */
if (!pending_exception) {
const napi_extended_error_info *node_error_info = NULL;
AWS_NAPI_ENSURE(env, napi_get_last_error_info(env, &node_error_info));
AWS_NAPI_LOGF_ERROR(
"Extended error info: engine_error_code=%u error_code=%s error_message=%s",
node_error_info->engine_error_code,
aws_napi_status_to_str(node_error_info->error_code),
node_error_info->error_message);
return;
}
/* get the current exception and report it, and clear it so that execution can continue */
napi_value node_exception = NULL;
AWS_NAPI_ENSURE(env, napi_get_and_clear_last_exception(env, &node_exception));
/* figure out what the exception is */
bool is_error = false;
AWS_NAPI_ENSURE(env, napi_is_error(env, node_exception, &is_error));
/*
* Convert the function to a string. If it's a lambda, this will produce the source of the lambda, if
* it's a class function or free function, it will produce the name
*/
napi_value node_function_str = NULL;
AWS_NAPI_ENSURE(env, napi_coerce_to_string(env, function, &node_function_str));
struct aws_string *function_str = aws_string_new_from_napi(env, node_function_str);
if (function_str) {
AWS_NAPI_LOGF_ERROR("Calling %s", aws_string_c_str(function_str));
}
/* If it's an Error, extract info from it and log it */
if (is_error) {
/* get the Error.message field */
napi_value node_message = NULL;
AWS_NAPI_ENSURE(env, napi_get_named_property(env, node_exception, "message", &node_message));
/* extract and log the message */
struct aws_string *message = aws_string_new_from_napi(env, node_message);
if (message) {
AWS_NAPI_LOGF_ERROR("Error: %s", aws_string_bytes(message));
aws_string_destroy(message);
} else {
AWS_NAPI_LOGF_ERROR("aws_string_new_from_napi(exception.message) failed");
return;
}
/* get the Error.stack field */
napi_value node_stack = NULL;
AWS_NAPI_ENSURE(env, napi_get_named_property(env, node_exception, "stack", &node_stack));
/* extract and log the stack trace */
struct aws_string *stacktrace = aws_string_new_from_napi(env, node_stack);
if (stacktrace) {
AWS_NAPI_LOGF_ERROR("Stack:\n%s", aws_string_bytes(stacktrace));
aws_string_destroy(stacktrace);
} else {
AWS_NAPI_LOGF_ERROR("aws_string_new_from_napi(exception.stack) failed");
return;
}
/* the Error has been reported and cleared, that's all we can do */
return;
}
/* The last thing thrown was some other sort of object/primitive, so convert it to a string and log it */
napi_value node_error_str = NULL;
AWS_NAPI_ENSURE(env, napi_coerce_to_string(env, node_exception, &node_error_str));
struct aws_string *error_str = aws_string_new_from_napi(env, node_error_str);
if (error_str) {
AWS_NAPI_LOGF_ERROR("Error: %s", aws_string_bytes(error_str));
} else {
AWS_NAPI_LOGF_ERROR("aws_string_new_from_napi(ToString(exception)) failed");
return;
}
}
napi_status aws_napi_create_external_arraybuffer(
napi_env env,
void *external_data,
size_t byte_length,
napi_finalize finalize_cb,
void *finalize_hint,
napi_value *result) {
napi_status external_buffer_status =
napi_create_external_arraybuffer(env, external_data, byte_length, finalize_cb, finalize_hint, result);
if (external_buffer_status == NAPI_NO_EXTERNAL_BUFFER_ENUM_VALUE) {
// The external buffer is disabled, manually copy the external_data into Node
void *napi_buf_data = NULL;
napi_status create_arraybuffer_status = napi_create_arraybuffer(env, byte_length, &napi_buf_data, result);
if (create_arraybuffer_status != napi_ok) {
AWS_NAPI_LOGF_ERROR(
"napi_create_arraybuffer (in aws_napi_create_external_arraybuffer) failed with : %s",
aws_napi_status_to_str(create_arraybuffer_status));
return create_arraybuffer_status;
}
memcpy(napi_buf_data, external_data, byte_length);
// As the data has been copied into the Node, invoke the finalize callback to make sure the
// data is released.
finalize_cb(env, finalize_hint, finalize_hint);
}
return napi_ok;
}
napi_status aws_napi_dispatch_threadsafe_function(
napi_env env,
napi_threadsafe_function tsfn,
napi_value this_ptr,
napi_value function,
size_t argc,
napi_value *argv) {
aws_rw_lock_rlock(&s_tsfn_lock);
napi_status result = napi_ok;
if (s_tsfn_enabled) {
napi_status call_status = napi_ok;
if (!this_ptr) {
AWS_NAPI_ENSURE(env, napi_get_undefined(env, &this_ptr));
}
AWS_NAPI_CALL(env, napi_call_function(env, this_ptr, function, argc, argv, NULL), {
call_status = status;
s_handle_failed_callback(env, function, status);
});
/* main thread can exit now */
napi_unref_threadsafe_function(env, tsfn);
/* Must always decrement the ref count, or the function will be pinned */
napi_status release_status = napi_release_threadsafe_function(tsfn, napi_tsfn_release);
result = (call_status != napi_ok) ? call_status : release_status;
}
aws_rw_lock_runlock(&s_tsfn_lock);
return result;
}
napi_status aws_napi_create_threadsafe_function(
napi_env env,
napi_value function,
const char *name,
napi_threadsafe_function_call_js call_js,
void *context,
napi_threadsafe_function *result) {
napi_value resource_name = NULL;
AWS_NAPI_ENSURE(env, napi_create_string_utf8(env, name, NAPI_AUTO_LENGTH, &resource_name));
return napi_create_threadsafe_function(
env,
function,
NULL /*async_resource*/,
resource_name,
0 /*max_queue_size - 0 means no limit*/,
1 /*initial_thread_count*/,
NULL /*thread_finalize_data*/,
NULL /*thread_finalize_cb*/,
context,
call_js,
result);
}
napi_status aws_napi_release_threadsafe_function(
napi_threadsafe_function function,
napi_threadsafe_function_release_mode mode) {
napi_status result = napi_ok;
aws_rw_lock_rlock(&s_tsfn_lock);
if (s_tsfn_enabled && function) {
result = napi_release_threadsafe_function(function, mode);
}
aws_rw_lock_runlock(&s_tsfn_lock);
return result;
}
napi_status aws_napi_acquire_threadsafe_function(napi_threadsafe_function function) {
napi_status result = napi_ok;
aws_rw_lock_rlock(&s_tsfn_lock);
if (s_tsfn_enabled && function) {
result = napi_acquire_threadsafe_function(function);
}
aws_rw_lock_runlock(&s_tsfn_lock);
return result;
}
napi_status aws_napi_unref_threadsafe_function(napi_env env, napi_threadsafe_function function) {
napi_status result = napi_ok;
aws_rw_lock_rlock(&s_tsfn_lock);
if (s_tsfn_enabled && function) {
result = napi_unref_threadsafe_function(env, function);
}
aws_rw_lock_runlock(&s_tsfn_lock);
return result;
}
napi_status aws_napi_queue_threadsafe_function(napi_threadsafe_function function, void *user_data) {
napi_status result = napi_ok;
aws_rw_lock_rlock(&s_tsfn_lock);
if (s_tsfn_enabled && function) {
/* increase the ref count, gets decreased when the call completes */
AWS_NAPI_ENSURE(NULL, napi_acquire_threadsafe_function(function));
result = napi_call_threadsafe_function(function, user_data, napi_tsfn_nonblocking);
}
aws_rw_lock_runlock(&s_tsfn_lock);
return result;
}
AWS_STATIC_STRING_FROM_LITERAL(s_mem_tracing_env_var, "AWS_CRT_MEMORY_TRACING");
static struct aws_allocator *s_allocator = NULL;
struct aws_allocator *aws_napi_get_allocator(void) {
if (AWS_UNLIKELY(s_allocator == NULL)) {
struct aws_string *value = NULL;
if (aws_get_environment_value(aws_default_allocator(), s_mem_tracing_env_var, &value) || value == NULL) {
return s_allocator = aws_default_allocator();
}
int level = atoi(aws_string_c_str(value));
if (level < AWS_MEMTRACE_NONE || level > AWS_MEMTRACE_STACKS) {
/* this can't go through logging, because it happens before logging is set up */
fprintf(
stderr,
"AWS_CRT_MEMORY_TRACING is set to invalid value: %s, must be 0 (none), 1 (bytes), or 2 (stacks)",
aws_string_bytes(value));
level = AWS_MEMTRACE_NONE;
}
s_allocator = aws_mem_tracer_new(aws_default_allocator(), NULL, level, 16);
}
return s_allocator;
}
napi_value aws_napi_native_memory(napi_env env, napi_callback_info info) {
(void)info;
napi_value node_allocated = NULL;
size_t allocated = 0;
if (aws_napi_get_allocator() != aws_default_allocator()) {
allocated = aws_mem_tracer_bytes(aws_napi_get_allocator());
}
AWS_NAPI_CALL(env, napi_create_int64(env, allocated, &node_allocated), { return NULL; });
return node_allocated;
}
napi_value aws_napi_native_memory_dump(napi_env env, napi_callback_info info) {
(void)info;
(void)env;
if (aws_napi_get_allocator() != aws_default_allocator()) {
aws_mem_tracer_dump(aws_napi_get_allocator());
}
return NULL;
}
#if defined(_WIN32)
# include <windows.h>
static LONG WINAPI s_print_stack_trace(struct _EXCEPTION_POINTERS *exception_pointers) {
aws_backtrace_print(stderr, exception_pointers);
return EXCEPTION_EXECUTE_HANDLER;
}
#elif defined(AWS_HAVE_EXECINFO)
# include <signal.h>
static void s_print_stack_trace(int sig, siginfo_t *sig_info, void *user_data) {
(void)sig;
(void)sig_info;
(void)user_data;
aws_backtrace_print(stderr, sig_info);
exit(-1);
}
#endif
static void s_install_crash_handler(void) {
#if defined(_WIN32)
SetUnhandledExceptionFilter(s_print_stack_trace);
#elif defined(AWS_HAVE_EXECINFO)
struct sigaction sa;
memset(&sa, 0, sizeof(struct sigaction));
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NODEFER;
sa.sa_sigaction = s_print_stack_trace;
sigaction(SIGSEGV, &sa, NULL);
sigaction(SIGABRT, &sa, NULL);
sigaction(SIGILL, &sa, NULL);
sigaction(SIGBUS, &sa, NULL);
#endif
}
static void s_uninstall_crash_handler(void) {
#if defined(_WIN32)
SetUnhandledExceptionFilter(NULL);
#elif defined(AWS_HAVE_EXECINFO)
sigaction(SIGSEGV, NULL, NULL);
sigaction(SIGABRT, NULL, NULL);
sigaction(SIGILL, NULL, NULL);
sigaction(SIGBUS, NULL, NULL);
#endif
}
static struct aws_mutex s_module_lock = AWS_MUTEX_INIT;
static uint32_t s_module_initialize_count = 0;
static void s_napi_context_finalize(napi_env env, void *user_data, void *finalize_hint) {
(void)env;
(void)finalize_hint;
aws_mutex_lock(&s_module_lock);
AWS_FATAL_ASSERT(s_module_initialize_count > 0);
--s_module_initialize_count;
if (s_module_initialize_count == 0) {
aws_client_bootstrap_release(s_default_client_bootstrap);
s_default_client_bootstrap = NULL;
aws_host_resolver_release(s_default_host_resolver);
s_default_host_resolver = NULL;
aws_event_loop_group_release(s_node_uv_elg);
s_node_uv_elg = NULL;
aws_thread_join_all_managed();
aws_unregister_log_subject_info_list(&s_log_subject_list);
aws_unregister_error_info(&s_error_list);
aws_event_stream_library_clean_up();
aws_auth_library_clean_up();
aws_mqtt_library_clean_up();
s_uninstall_crash_handler();
// clean up threadsafe function lock
aws_rw_lock_clean_up(&s_tsfn_lock);
}
struct aws_napi_context *ctx = user_data;
aws_napi_logger_destroy(ctx->logger);
struct aws_allocator *ctx_allocator = ctx->allocator;
aws_mem_release(ctx->allocator, ctx);
if (s_module_initialize_count == 0) {
if (ctx_allocator != aws_default_allocator()) {
if (s_allocator == ctx_allocator) {
s_allocator = NULL;
}
aws_mem_tracer_destroy(ctx_allocator);
}
}
aws_mutex_unlock(&s_module_lock);
}
static struct aws_napi_context *s_napi_context_new(struct aws_allocator *allocator, napi_env env, napi_value exports) {
struct aws_napi_context *ctx = aws_mem_calloc(allocator, 1, sizeof(struct aws_napi_context));
AWS_FATAL_ASSERT(ctx && "Failed to initialize napi context");
ctx->allocator = allocator;
/* bind the context to exports, thus binding its lifetime to that object */
AWS_NAPI_ENSURE(env, napi_wrap(env, exports, ctx, s_napi_context_finalize, NULL, NULL));
ctx->logger = aws_napi_logger_new(allocator, env);
return ctx;
}
/** Helper for creating and registering a function */
static bool s_create_and_register_function(
napi_env env,
napi_value exports,
napi_callback fn,
const char *fn_name,
size_t fn_name_len) {
napi_value napi_fn;
AWS_NAPI_CALL(env, napi_create_function(env, fn_name, fn_name_len, fn, NULL, &napi_fn), {
napi_throw_error(env, NULL, "Unable to wrap native function");
return false;
});
AWS_NAPI_CALL(env, napi_set_named_property(env, exports, fn_name, napi_fn), {
napi_throw_error(env, NULL, "Unable to populate exports");
return false;
});
return true;
}
#if defined(__clang__) || defined(__GNUC__)
/* Suppress compiler warnings about NAPI_MODULE_INIT().
* See: https://github.com/nodejs/node/pull/49103 */
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
#endif
/* napi_value */ NAPI_MODULE_INIT() /* (napi_env env, napi_value exports) */ {
aws_mutex_lock(&s_module_lock);
struct aws_allocator *allocator = aws_napi_get_allocator();
if (s_module_initialize_count == 0) {
aws_rw_lock_init(&s_tsfn_lock);
s_aws_enable_threadsafe_function();
s_install_crash_handler();
aws_mqtt_library_init(allocator);
aws_auth_library_init(allocator);
aws_event_stream_library_init(allocator);
aws_register_error_info(&s_error_list);
aws_register_log_subject_info_list(&s_log_subject_list);
/* Initialize the event loop group */
/*
* We don't currently support multi-init of the module, but we should.
* Things that would need to be solved:
* (1) global objects (event loop group, logger, allocator, more)
* (2) multi-init/multi-cleanup of aws-c-*
* (3) allocator cross-talk/lifetimes
*/
AWS_FATAL_ASSERT(s_node_uv_elg == NULL);
s_node_uv_elg = aws_event_loop_group_new_default(allocator, 1, NULL);
AWS_FATAL_ASSERT(s_node_uv_elg != NULL);
/*
* Default host resolver and client bootstrap to use if none specific at the javascript level. In most
* cases the user doesn't even need to know about these, so let's let them leave it out completely.
*/
AWS_FATAL_ASSERT(s_default_host_resolver == NULL);
struct aws_host_resolver_default_options resolver_options = {
.max_entries = 64,
.el_group = s_node_uv_elg,
};
s_default_host_resolver = aws_host_resolver_new_default(allocator, &resolver_options);
AWS_FATAL_ASSERT(s_default_host_resolver != NULL);
AWS_FATAL_ASSERT(s_default_client_bootstrap == NULL);
struct aws_client_bootstrap_options bootstrap_options = {
.event_loop_group = s_node_uv_elg,
.host_resolver = s_default_host_resolver,
};
s_default_client_bootstrap = aws_client_bootstrap_new(allocator, &bootstrap_options);
AWS_FATAL_ASSERT(s_default_client_bootstrap != NULL);
}
++s_module_initialize_count;
aws_mutex_unlock(&s_module_lock);
/* context is bound to exports, will be cleaned up by finalizer */
s_napi_context_new(allocator, env, exports);
napi_value null;
napi_get_null(env, &null);
#define CREATE_AND_REGISTER_FN(fn) \
if (!s_create_and_register_function(env, exports, aws_napi_##fn, #fn, sizeof(#fn))) { \
return null; \
}
/* Common */
CREATE_AND_REGISTER_FN(native_memory)
CREATE_AND_REGISTER_FN(native_memory_dump)
CREATE_AND_REGISTER_FN(error_code_to_string)
CREATE_AND_REGISTER_FN(error_code_to_name)
CREATE_AND_REGISTER_FN(disable_threadsafe_function)
/* IO */
CREATE_AND_REGISTER_FN(io_logging_enable)
CREATE_AND_REGISTER_FN(is_alpn_available)
CREATE_AND_REGISTER_FN(io_client_bootstrap_new)
CREATE_AND_REGISTER_FN(io_tls_ctx_new)
CREATE_AND_REGISTER_FN(io_tls_connection_options_new);
CREATE_AND_REGISTER_FN(io_socket_options_new)
CREATE_AND_REGISTER_FN(io_input_stream_new)
CREATE_AND_REGISTER_FN(io_input_stream_append)
CREATE_AND_REGISTER_FN(io_pkcs11_lib_new)
CREATE_AND_REGISTER_FN(io_pkcs11_lib_close)
/* MQTT Request Response */
CREATE_AND_REGISTER_FN(mqtt_request_response_client_new_from_5)
CREATE_AND_REGISTER_FN(mqtt_request_response_client_new_from_311)
CREATE_AND_REGISTER_FN(mqtt_request_response_client_close)
CREATE_AND_REGISTER_FN(mqtt_request_response_client_submit_request)
CREATE_AND_REGISTER_FN(mqtt_streaming_operation_new)
CREATE_AND_REGISTER_FN(mqtt_streaming_operation_open)
CREATE_AND_REGISTER_FN(mqtt_streaming_operation_close)
/* MQTT5 Client */
CREATE_AND_REGISTER_FN(mqtt5_client_new)
CREATE_AND_REGISTER_FN(mqtt5_client_start)
CREATE_AND_REGISTER_FN(mqtt5_client_stop)
CREATE_AND_REGISTER_FN(mqtt5_client_subscribe)
CREATE_AND_REGISTER_FN(mqtt5_client_unsubscribe)
CREATE_AND_REGISTER_FN(mqtt5_client_publish)
CREATE_AND_REGISTER_FN(mqtt5_client_get_queue_statistics)
CREATE_AND_REGISTER_FN(mqtt5_client_close)
/* MQTT Client */
CREATE_AND_REGISTER_FN(mqtt_client_new)
/* MQTT Client Connection */
CREATE_AND_REGISTER_FN(mqtt_client_connection_new)
CREATE_AND_REGISTER_FN(mqtt_client_connection_connect)
CREATE_AND_REGISTER_FN(mqtt_client_connection_reconnect)
CREATE_AND_REGISTER_FN(mqtt_client_connection_publish)
CREATE_AND_REGISTER_FN(mqtt_client_connection_subscribe)
CREATE_AND_REGISTER_FN(mqtt_client_connection_on_message)
CREATE_AND_REGISTER_FN(mqtt_client_connection_on_closed)
CREATE_AND_REGISTER_FN(mqtt_client_connection_unsubscribe)
CREATE_AND_REGISTER_FN(mqtt_client_connection_disconnect)
CREATE_AND_REGISTER_FN(mqtt_client_connection_close)
CREATE_AND_REGISTER_FN(mqtt_client_connection_get_queue_statistics)
/* Crypto */
CREATE_AND_REGISTER_FN(hash_md5_new)
CREATE_AND_REGISTER_FN(hash_sha1_new)
CREATE_AND_REGISTER_FN(hash_sha256_new)
CREATE_AND_REGISTER_FN(hash_update)
CREATE_AND_REGISTER_FN(hash_digest)
CREATE_AND_REGISTER_FN(hash_md5_compute)
CREATE_AND_REGISTER_FN(hash_sha1_compute)
CREATE_AND_REGISTER_FN(hash_sha256_compute)
CREATE_AND_REGISTER_FN(hmac_sha256_new)
CREATE_AND_REGISTER_FN(hmac_update)
CREATE_AND_REGISTER_FN(hmac_digest)
CREATE_AND_REGISTER_FN(hmac_sha256_compute)
/* Checksums */
CREATE_AND_REGISTER_FN(checksums_crc32)
CREATE_AND_REGISTER_FN(checksums_crc32c)
CREATE_AND_REGISTER_FN(checksums_crc64nvme)
/* HTTP */
CREATE_AND_REGISTER_FN(http_proxy_options_new)
CREATE_AND_REGISTER_FN(http_connection_new)
CREATE_AND_REGISTER_FN(http_connection_close)
CREATE_AND_REGISTER_FN(http_stream_new)
CREATE_AND_REGISTER_FN(http_stream_activate)
CREATE_AND_REGISTER_FN(http_stream_close)
CREATE_AND_REGISTER_FN(http_connection_manager_new)
CREATE_AND_REGISTER_FN(http_connection_manager_close)
CREATE_AND_REGISTER_FN(http_connection_manager_acquire)
CREATE_AND_REGISTER_FN(http_connection_manager_release)
/* Event stream */
CREATE_AND_REGISTER_FN(event_stream_client_connection_new)
CREATE_AND_REGISTER_FN(event_stream_client_connection_connect)
CREATE_AND_REGISTER_FN(event_stream_client_connection_close)
CREATE_AND_REGISTER_FN(event_stream_client_connection_close_internal)
CREATE_AND_REGISTER_FN(event_stream_client_connection_send_protocol_message)
CREATE_AND_REGISTER_FN(event_stream_client_stream_new)
CREATE_AND_REGISTER_FN(event_stream_client_stream_close)
CREATE_AND_REGISTER_FN(event_stream_client_stream_activate)
CREATE_AND_REGISTER_FN(event_stream_client_stream_send_message)
#undef CREATE_AND_REGISTER_FN
AWS_NAPI_ENSURE(env, aws_napi_http_headers_bind(env, exports));
AWS_NAPI_ENSURE(env, aws_napi_http_message_bind(env, exports));
AWS_NAPI_ENSURE(env, aws_napi_auth_bind(env, exports));
return exports;
}