napi_value aws_napi_http_stream_new()

in source/http_stream.c [227:345]


napi_value aws_napi_http_stream_new(napi_env env, napi_callback_info info) {
    struct aws_allocator *allocator = aws_napi_get_allocator();
    napi_value result = NULL;

    napi_value node_args[5];
    size_t num_args = AWS_ARRAY_SIZE(node_args);
    napi_value *arg = &node_args[0];
    AWS_NAPI_CALL(env, napi_get_cb_info(env, info, &num_args, node_args, NULL, NULL), {
        napi_throw_error(env, NULL, "Failed to retrieve callback information");
        return NULL;
    });
    if (num_args != AWS_ARRAY_SIZE(node_args)) {
        napi_throw_error(env, NULL, "http_stream_new needs exactly 5 arguments");
        return NULL;
    }

    struct http_connection_binding *connection_binding = NULL;
    napi_value node_binding = *arg++;
    AWS_NAPI_CALL(env, napi_get_value_external(env, node_binding, (void **)&connection_binding), {
        napi_throw_error(env, NULL, "Unable to extract connection from external");
        return NULL;
    });

    napi_value node_request = *arg++;
    struct aws_http_message *request = aws_napi_http_message_unwrap(env, node_request);
    /* adding a refcount for the request, which will be released as the stream object from JS land get destroyed */
    aws_http_message_acquire(request);

    napi_value node_on_complete = *arg++;
    napi_value node_on_response = *arg++;
    napi_value node_on_body = *arg++;

    struct http_stream_binding *binding = aws_mem_calloc(allocator, 1, sizeof(struct http_stream_binding));
    if (!binding) {
        aws_napi_throw_last_error(env);
        goto failed_binding_alloc;
    }

    binding->allocator = allocator;
    binding->request = request;
    aws_atomic_init_int(&binding->pending_length, 0);

    AWS_NAPI_CALL(
        env,
        aws_napi_create_threadsafe_function(
            env, node_on_complete, "aws_http_stream_on_complete", s_on_complete_call, binding, &binding->on_complete),
        {
            napi_throw_error(env, NULL, "on_complete must be a callback");
            goto failed_callbacks;
        });

    if (!aws_napi_is_null_or_undefined(env, node_on_response)) {
        AWS_NAPI_CALL(
            env,
            aws_napi_create_threadsafe_function(
                env,
                node_on_response,
                "aws_http_stream_on_response",
                s_on_response_call,
                binding,
                &binding->on_response),
            {
                napi_throw_error(env, NULL, "Unable to bind on_response callback");
                goto failed_callbacks;
            });
    }

    if (!aws_napi_is_null_or_undefined(env, node_on_body)) {
        AWS_NAPI_CALL(
            env,
            aws_napi_create_threadsafe_function(
                env, node_on_body, "aws_http_stream_on_body", s_on_body_call, binding, &binding->on_body),
            {
                napi_throw_error(env, NULL, "Unable to bind on_body callback");
                goto failed_callbacks;
            });
    }

    struct aws_http_make_request_options request_options = {
        .self_size = sizeof(struct aws_http_make_request_options),
        .request = request,
        .user_data = binding,
        .on_response_headers = s_on_response_headers,
        .on_response_header_block_done = s_on_response_header_block_done,
        .on_response_body = s_on_response_body,
        .on_complete = s_on_complete,
    };

    /* becomes the native_handle for the JS object */
    AWS_NAPI_CALL(env, napi_create_external(env, binding, s_http_stream_binding_finalize, NULL, &result), {
        napi_throw_error(env, NULL, "Unable to create stream external");
        goto failed_external;
    });

    struct aws_http_connection *connection = aws_napi_get_http_connection(connection_binding);
    binding->stream = aws_http_connection_make_request(connection, &request_options);

    if (!binding->stream) {
        napi_throw_error(env, NULL, "Unable to create native aws_http_stream");
        result = NULL;
        goto failed_request;
    }

    goto done;

failed_request:
failed_external:
failed_callbacks:
    if (binding) {
        AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_complete, napi_tsfn_abort));
        AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_response, napi_tsfn_abort));
        AWS_NAPI_ENSURE(env, aws_napi_release_threadsafe_function(binding->on_body, napi_tsfn_abort));
    }
    aws_mem_release(allocator, binding);
failed_binding_alloc:
done:

    return result;
}