node-addon-api 1.7.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.travis.yml +4 -7
- package/CHANGELOG.md +99 -0
- package/README.md +6 -3
- package/doc/array_buffer.md +1 -1
- package/doc/async_context.md +10 -0
- package/doc/async_operations.md +1 -1
- package/doc/async_progress_worker.md +344 -0
- package/doc/async_worker.md +23 -22
- package/doc/basic_types.md +8 -0
- package/doc/class_property_descriptor.md +2 -3
- package/doc/cmake-js.md +58 -9
- package/doc/date.md +68 -0
- package/doc/object.md +34 -0
- package/doc/object_wrap.md +13 -2
- package/doc/prebuild_tools.md +1 -1
- package/doc/threadsafe_function.md +18 -1
- package/doc/value.md +9 -0
- package/napi-inl.h +402 -87
- package/napi.h +138 -18
- package/package.json +212 -46
- package/src/node_api.cc +9 -3
package/napi-inl.h
CHANGED
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
// Note: Do not include this file directly! Include "napi.h" instead.
|
|
11
11
|
|
|
12
|
+
#include <algorithm>
|
|
13
|
+
#include <atomic>
|
|
12
14
|
#include <cstring>
|
|
15
|
+
#include <mutex>
|
|
13
16
|
#include <type_traits>
|
|
14
17
|
|
|
15
18
|
namespace Napi {
|
|
@@ -17,6 +20,8 @@ namespace Napi {
|
|
|
17
20
|
// Helpers to handle functions exposed from C++.
|
|
18
21
|
namespace details {
|
|
19
22
|
|
|
23
|
+
extern std::atomic_bool needs_objectwrap_destructor_fix;
|
|
24
|
+
|
|
20
25
|
// Attach a data item to an object and delete it when the object gets
|
|
21
26
|
// garbage-collected.
|
|
22
27
|
// TODO: Replace this code with `napi_add_finalizer()` whenever it becomes
|
|
@@ -24,16 +29,23 @@ namespace details {
|
|
|
24
29
|
template <typename FreeType>
|
|
25
30
|
static inline napi_status AttachData(napi_env env,
|
|
26
31
|
napi_value obj,
|
|
27
|
-
FreeType* data
|
|
32
|
+
FreeType* data,
|
|
33
|
+
napi_finalize finalizer = nullptr,
|
|
34
|
+
void* hint = nullptr) {
|
|
35
|
+
napi_status status;
|
|
36
|
+
if (finalizer == nullptr) {
|
|
37
|
+
finalizer = [](napi_env /*env*/, void* data, void* /*hint*/) {
|
|
38
|
+
delete static_cast<FreeType*>(data);
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
#if (NAPI_VERSION < 5)
|
|
28
42
|
napi_value symbol, external;
|
|
29
|
-
|
|
43
|
+
status = napi_create_symbol(env, nullptr, &symbol);
|
|
30
44
|
if (status == napi_ok) {
|
|
31
45
|
status = napi_create_external(env,
|
|
32
46
|
data,
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
},
|
|
36
|
-
nullptr,
|
|
47
|
+
finalizer,
|
|
48
|
+
hint,
|
|
37
49
|
&external);
|
|
38
50
|
if (status == napi_ok) {
|
|
39
51
|
napi_property_descriptor desc = {
|
|
@@ -49,6 +61,9 @@ static inline napi_status AttachData(napi_env env,
|
|
|
49
61
|
status = napi_define_properties(env, obj, 1, &desc);
|
|
50
62
|
}
|
|
51
63
|
}
|
|
64
|
+
#else // NAPI_VERSION >= 5
|
|
65
|
+
status = napi_add_finalizer(env, obj, data, finalizer, hint, nullptr);
|
|
66
|
+
#endif
|
|
52
67
|
return status;
|
|
53
68
|
}
|
|
54
69
|
|
|
@@ -239,11 +254,16 @@ struct AccessorCallbackData {
|
|
|
239
254
|
// Module registration
|
|
240
255
|
////////////////////////////////////////////////////////////////////////////////
|
|
241
256
|
|
|
242
|
-
#define NODE_API_MODULE(modname, regfunc)
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
257
|
+
#define NODE_API_MODULE(modname, regfunc) \
|
|
258
|
+
namespace Napi { \
|
|
259
|
+
namespace details { \
|
|
260
|
+
std::atomic_bool needs_objectwrap_destructor_fix(false); \
|
|
261
|
+
} \
|
|
262
|
+
} \
|
|
263
|
+
napi_value __napi_ ## regfunc(napi_env env, \
|
|
264
|
+
napi_value exports) { \
|
|
265
|
+
return Napi::RegisterModule(env, exports, regfunc); \
|
|
266
|
+
} \
|
|
247
267
|
NAPI_MODULE(modname, __napi_ ## regfunc)
|
|
248
268
|
|
|
249
269
|
// Adapt the NAPI_MODULE registration function:
|
|
@@ -252,6 +272,12 @@ struct AccessorCallbackData {
|
|
|
252
272
|
inline napi_value RegisterModule(napi_env env,
|
|
253
273
|
napi_value exports,
|
|
254
274
|
ModuleRegisterCallback registerCallback) {
|
|
275
|
+
const napi_node_version* nver = Napi::VersionManagement::GetNodeVersion(env);
|
|
276
|
+
Napi::details::needs_objectwrap_destructor_fix =
|
|
277
|
+
(nver->major < 10 ||
|
|
278
|
+
(nver->major == 10 && nver->minor < 15) ||
|
|
279
|
+
(nver->major == 10 && nver->minor == 15 && nver->patch < 3));
|
|
280
|
+
|
|
255
281
|
return details::WrapCallback([&] {
|
|
256
282
|
return napi_value(registerCallback(Napi::Env(env),
|
|
257
283
|
Napi::Object(env, exports)));
|
|
@@ -371,14 +397,28 @@ inline bool Value::IsNumber() const {
|
|
|
371
397
|
return Type() == napi_number;
|
|
372
398
|
}
|
|
373
399
|
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
|
|
400
|
+
// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
|
|
401
|
+
// Once it is no longer experimental guard with the NAPI_VERSION in which it is
|
|
402
|
+
// released instead.
|
|
403
|
+
#ifdef NAPI_EXPERIMENTAL
|
|
377
404
|
inline bool Value::IsBigInt() const {
|
|
378
405
|
return Type() == napi_bigint;
|
|
379
406
|
}
|
|
380
407
|
#endif // NAPI_EXPERIMENTAL
|
|
381
408
|
|
|
409
|
+
#if (NAPI_VERSION > 4)
|
|
410
|
+
inline bool Value::IsDate() const {
|
|
411
|
+
if (IsEmpty()) {
|
|
412
|
+
return false;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
bool result;
|
|
416
|
+
napi_status status = napi_is_date(_env, _value, &result);
|
|
417
|
+
NAPI_THROW_IF_FAILED(_env, status, false);
|
|
418
|
+
return result;
|
|
419
|
+
}
|
|
420
|
+
#endif
|
|
421
|
+
|
|
382
422
|
inline bool Value::IsString() const {
|
|
383
423
|
return Type() == napi_string;
|
|
384
424
|
}
|
|
@@ -595,9 +635,10 @@ inline double Number::DoubleValue() const {
|
|
|
595
635
|
return result;
|
|
596
636
|
}
|
|
597
637
|
|
|
598
|
-
//
|
|
599
|
-
//
|
|
600
|
-
|
|
638
|
+
// Currently experimental guard with the definition of NAPI_EXPERIMENTAL.
|
|
639
|
+
// Once it is no longer experimental guard with the NAPI_VERSION in which it is
|
|
640
|
+
// released instead.
|
|
641
|
+
#ifdef NAPI_EXPERIMENTAL
|
|
601
642
|
////////////////////////////////////////////////////////////////////////////////
|
|
602
643
|
// BigInt Class
|
|
603
644
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -660,6 +701,37 @@ inline void BigInt::ToWords(int* sign_bit, size_t* word_count, uint64_t* words)
|
|
|
660
701
|
}
|
|
661
702
|
#endif // NAPI_EXPERIMENTAL
|
|
662
703
|
|
|
704
|
+
#if (NAPI_VERSION > 4)
|
|
705
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
706
|
+
// Date Class
|
|
707
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
708
|
+
|
|
709
|
+
inline Date Date::New(napi_env env, double val) {
|
|
710
|
+
napi_value value;
|
|
711
|
+
napi_status status = napi_create_date(env, val, &value);
|
|
712
|
+
NAPI_THROW_IF_FAILED(env, status, Date());
|
|
713
|
+
return Date(env, value);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
inline Date::Date() : Value() {
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
inline Date::Date(napi_env env, napi_value value) : Value(env, value) {
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
inline Date::operator double() const {
|
|
723
|
+
return ValueOf();
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
inline double Date::ValueOf() const {
|
|
727
|
+
double result;
|
|
728
|
+
napi_status status = napi_get_date_value(
|
|
729
|
+
_env, _value, &result);
|
|
730
|
+
NAPI_THROW_IF_FAILED(_env, status, 0);
|
|
731
|
+
return result;
|
|
732
|
+
}
|
|
733
|
+
#endif
|
|
734
|
+
|
|
663
735
|
////////////////////////////////////////////////////////////////////////////////
|
|
664
736
|
// Name class
|
|
665
737
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1126,6 +1198,40 @@ inline bool Object::InstanceOf(const Function& constructor) const {
|
|
|
1126
1198
|
return result;
|
|
1127
1199
|
}
|
|
1128
1200
|
|
|
1201
|
+
template <typename Finalizer, typename T>
|
|
1202
|
+
inline void Object::AddFinalizer(Finalizer finalizeCallback, T* data) {
|
|
1203
|
+
details::FinalizeData<T, Finalizer>* finalizeData =
|
|
1204
|
+
new details::FinalizeData<T, Finalizer>({ finalizeCallback, nullptr });
|
|
1205
|
+
napi_status status =
|
|
1206
|
+
details::AttachData(_env,
|
|
1207
|
+
*this,
|
|
1208
|
+
data,
|
|
1209
|
+
details::FinalizeData<T, Finalizer>::Wrapper,
|
|
1210
|
+
finalizeData);
|
|
1211
|
+
if (status != napi_ok) {
|
|
1212
|
+
delete finalizeData;
|
|
1213
|
+
NAPI_THROW_IF_FAILED_VOID(_env, status);
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
template <typename Finalizer, typename T, typename Hint>
|
|
1218
|
+
inline void Object::AddFinalizer(Finalizer finalizeCallback,
|
|
1219
|
+
T* data,
|
|
1220
|
+
Hint* finalizeHint) {
|
|
1221
|
+
details::FinalizeData<T, Finalizer, Hint>* finalizeData =
|
|
1222
|
+
new details::FinalizeData<T, Finalizer, Hint>({ finalizeCallback, finalizeHint });
|
|
1223
|
+
napi_status status =
|
|
1224
|
+
details::AttachData(_env,
|
|
1225
|
+
*this,
|
|
1226
|
+
data,
|
|
1227
|
+
details::FinalizeData<T, Finalizer, Hint>::WrapperWithHint,
|
|
1228
|
+
finalizeData);
|
|
1229
|
+
if (status != napi_ok) {
|
|
1230
|
+
delete finalizeData;
|
|
1231
|
+
NAPI_THROW_IF_FAILED_VOID(_env, status);
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1129
1235
|
////////////////////////////////////////////////////////////////////////////////
|
|
1130
1236
|
// External class
|
|
1131
1237
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1950,47 +2056,43 @@ inline Error Error::New(napi_env env) {
|
|
|
1950
2056
|
status = napi_get_last_error_info(env, &info);
|
|
1951
2057
|
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_last_error_info");
|
|
1952
2058
|
|
|
1953
|
-
if (
|
|
1954
|
-
|
|
2059
|
+
if (info->error_code == napi_pending_exception) {
|
|
2060
|
+
status = napi_get_and_clear_last_exception(env, &error);
|
|
2061
|
+
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
|
|
2062
|
+
}
|
|
2063
|
+
else {
|
|
2064
|
+
const char* error_message = info->error_message != nullptr ?
|
|
2065
|
+
info->error_message : "Error in native callback";
|
|
2066
|
+
|
|
2067
|
+
bool isExceptionPending;
|
|
2068
|
+
status = napi_is_exception_pending(env, &isExceptionPending);
|
|
2069
|
+
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_is_exception_pending");
|
|
2070
|
+
|
|
2071
|
+
if (isExceptionPending) {
|
|
1955
2072
|
status = napi_get_and_clear_last_exception(env, &error);
|
|
1956
2073
|
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_get_and_clear_last_exception");
|
|
1957
2074
|
}
|
|
1958
|
-
else {
|
|
1959
|
-
const char* error_message = info->error_message != nullptr ?
|
|
1960
|
-
info->error_message : "Error in native callback";
|
|
1961
2075
|
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
switch (info->error_code) {
|
|
1981
|
-
case napi_object_expected:
|
|
1982
|
-
case napi_string_expected:
|
|
1983
|
-
case napi_boolean_expected:
|
|
1984
|
-
case napi_number_expected:
|
|
1985
|
-
status = napi_create_type_error(env, nullptr, message, &error);
|
|
1986
|
-
break;
|
|
1987
|
-
default:
|
|
1988
|
-
status = napi_create_error(env, nullptr, message, &error);
|
|
1989
|
-
break;
|
|
1990
|
-
}
|
|
1991
|
-
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
|
|
1992
|
-
}
|
|
2076
|
+
napi_value message;
|
|
2077
|
+
status = napi_create_string_utf8(
|
|
2078
|
+
env,
|
|
2079
|
+
error_message,
|
|
2080
|
+
std::strlen(error_message),
|
|
2081
|
+
&message);
|
|
2082
|
+
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_string_utf8");
|
|
2083
|
+
|
|
2084
|
+
switch (info->error_code) {
|
|
2085
|
+
case napi_object_expected:
|
|
2086
|
+
case napi_string_expected:
|
|
2087
|
+
case napi_boolean_expected:
|
|
2088
|
+
case napi_number_expected:
|
|
2089
|
+
status = napi_create_type_error(env, nullptr, message, &error);
|
|
2090
|
+
break;
|
|
2091
|
+
default:
|
|
2092
|
+
status = napi_create_error(env, nullptr, message, &error);
|
|
2093
|
+
break;
|
|
1993
2094
|
}
|
|
2095
|
+
NAPI_FATAL_IF_FAILED(status, "Error::New", "napi_create_error");
|
|
1994
2096
|
}
|
|
1995
2097
|
|
|
1996
2098
|
return Error(env, error);
|
|
@@ -2880,14 +2982,37 @@ inline ObjectWrap<T>::ObjectWrap(const Napi::CallbackInfo& callbackInfo) {
|
|
|
2880
2982
|
napi_value wrapper = callbackInfo.This();
|
|
2881
2983
|
napi_status status;
|
|
2882
2984
|
napi_ref ref;
|
|
2883
|
-
|
|
2884
|
-
status = napi_wrap(env, wrapper, instance, FinalizeCallback, nullptr, &ref);
|
|
2985
|
+
status = napi_wrap(env, wrapper, this, FinalizeCallback, nullptr, &ref);
|
|
2885
2986
|
NAPI_THROW_IF_FAILED_VOID(env, status);
|
|
2886
2987
|
|
|
2887
|
-
Reference<Object>* instanceRef =
|
|
2988
|
+
Reference<Object>* instanceRef = this;
|
|
2888
2989
|
*instanceRef = Reference<Object>(env, ref);
|
|
2889
2990
|
}
|
|
2890
2991
|
|
|
2992
|
+
template <typename T>
|
|
2993
|
+
inline ObjectWrap<T>::~ObjectWrap() {
|
|
2994
|
+
// If the JS object still exists at this point, remove the finalizer added
|
|
2995
|
+
// through `napi_wrap()`.
|
|
2996
|
+
if (!IsEmpty()) {
|
|
2997
|
+
Object object = Value();
|
|
2998
|
+
// It is not valid to call `napi_remove_wrap()` with an empty `object`.
|
|
2999
|
+
// This happens e.g. during garbage collection.
|
|
3000
|
+
if (!object.IsEmpty() && _construction_failed) {
|
|
3001
|
+
napi_remove_wrap(Env(), object, nullptr);
|
|
3002
|
+
|
|
3003
|
+
if (Napi::details::needs_objectwrap_destructor_fix) {
|
|
3004
|
+
// If construction failed we delete the reference via
|
|
3005
|
+
// `napi_remove_wrap()`, not via `napi_delete_reference()` in the
|
|
3006
|
+
// `Reference<Object>` destructor. This will prevent the
|
|
3007
|
+
// `Reference<Object>` destructor from doing a double delete of this
|
|
3008
|
+
// reference.
|
|
3009
|
+
_ref = nullptr;
|
|
3010
|
+
_env = nullptr;
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
|
|
2891
3016
|
template<typename T>
|
|
2892
3017
|
inline T* ObjectWrap<T>::Unwrap(Object wrapper) {
|
|
2893
3018
|
T* unwrapped;
|
|
@@ -3261,6 +3386,9 @@ inline ClassPropertyDescriptor<T> ObjectWrap<T>::InstanceValue(
|
|
|
3261
3386
|
return desc;
|
|
3262
3387
|
}
|
|
3263
3388
|
|
|
3389
|
+
template <typename T>
|
|
3390
|
+
inline void ObjectWrap<T>::Finalize(Napi::Env /*env*/) {}
|
|
3391
|
+
|
|
3264
3392
|
template <typename T>
|
|
3265
3393
|
inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
|
|
3266
3394
|
napi_env env,
|
|
@@ -3275,10 +3403,21 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
|
|
|
3275
3403
|
return nullptr;
|
|
3276
3404
|
}
|
|
3277
3405
|
|
|
3278
|
-
T* instance;
|
|
3279
3406
|
napi_value wrapper = details::WrapCallback([&] {
|
|
3280
3407
|
CallbackInfo callbackInfo(env, info);
|
|
3281
|
-
instance = new T(callbackInfo);
|
|
3408
|
+
T* instance = new T(callbackInfo);
|
|
3409
|
+
#ifdef NAPI_CPP_EXCEPTIONS
|
|
3410
|
+
instance->_construction_failed = false;
|
|
3411
|
+
#else
|
|
3412
|
+
if (callbackInfo.Env().IsExceptionPending()) {
|
|
3413
|
+
// We need to clear the exception so that removing the wrap might work.
|
|
3414
|
+
Error e = callbackInfo.Env().GetAndClearPendingException();
|
|
3415
|
+
delete instance;
|
|
3416
|
+
e.ThrowAsJavaScriptException();
|
|
3417
|
+
} else {
|
|
3418
|
+
instance->_construction_failed = false;
|
|
3419
|
+
}
|
|
3420
|
+
# endif // NAPI_CPP_EXCEPTIONS
|
|
3282
3421
|
return callbackInfo.This();
|
|
3283
3422
|
});
|
|
3284
3423
|
|
|
@@ -3402,8 +3541,9 @@ inline napi_value ObjectWrap<T>::InstanceSetterCallbackWrapper(
|
|
|
3402
3541
|
}
|
|
3403
3542
|
|
|
3404
3543
|
template <typename T>
|
|
3405
|
-
inline void ObjectWrap<T>::FinalizeCallback(napi_env
|
|
3406
|
-
T
|
|
3544
|
+
inline void ObjectWrap<T>::FinalizeCallback(napi_env env, void* data, void* /*hint*/) {
|
|
3545
|
+
ObjectWrap<T>* instance = static_cast<ObjectWrap<T>*>(data);
|
|
3546
|
+
instance->Finalize(Napi::Env(env));
|
|
3407
3547
|
delete instance;
|
|
3408
3548
|
}
|
|
3409
3549
|
|
|
@@ -3421,7 +3561,10 @@ inline HandleScope::HandleScope(Napi::Env env) : _env(env) {
|
|
|
3421
3561
|
}
|
|
3422
3562
|
|
|
3423
3563
|
inline HandleScope::~HandleScope() {
|
|
3424
|
-
napi_close_handle_scope(_env, _scope);
|
|
3564
|
+
napi_status status = napi_close_handle_scope(_env, _scope);
|
|
3565
|
+
NAPI_FATAL_IF_FAILED(status,
|
|
3566
|
+
"HandleScope::~HandleScope",
|
|
3567
|
+
"napi_close_handle_scope");
|
|
3425
3568
|
}
|
|
3426
3569
|
|
|
3427
3570
|
inline HandleScope::operator napi_handle_scope() const {
|
|
@@ -3446,7 +3589,10 @@ inline EscapableHandleScope::EscapableHandleScope(Napi::Env env) : _env(env) {
|
|
|
3446
3589
|
}
|
|
3447
3590
|
|
|
3448
3591
|
inline EscapableHandleScope::~EscapableHandleScope() {
|
|
3449
|
-
napi_close_escapable_handle_scope(_env, _scope);
|
|
3592
|
+
napi_status status = napi_close_escapable_handle_scope(_env, _scope);
|
|
3593
|
+
NAPI_FATAL_IF_FAILED(status,
|
|
3594
|
+
"EscapableHandleScope::~EscapableHandleScope",
|
|
3595
|
+
"napi_close_escapable_handle_scope");
|
|
3450
3596
|
}
|
|
3451
3597
|
|
|
3452
3598
|
inline EscapableHandleScope::operator napi_escapable_handle_scope() const {
|
|
@@ -3482,7 +3628,10 @@ inline CallbackScope::CallbackScope(napi_env env, napi_async_context context)
|
|
|
3482
3628
|
}
|
|
3483
3629
|
|
|
3484
3630
|
inline CallbackScope::~CallbackScope() {
|
|
3485
|
-
napi_close_callback_scope(_env, _scope);
|
|
3631
|
+
napi_status status = napi_close_callback_scope(_env, _scope);
|
|
3632
|
+
NAPI_FATAL_IF_FAILED(status,
|
|
3633
|
+
"CallbackScope::~CallbackScope",
|
|
3634
|
+
"napi_close_callback_scope");
|
|
3486
3635
|
}
|
|
3487
3636
|
|
|
3488
3637
|
inline CallbackScope::operator napi_callback_scope() const {
|
|
@@ -3542,6 +3691,10 @@ inline AsyncContext::operator napi_async_context() const {
|
|
|
3542
3691
|
return _context;
|
|
3543
3692
|
}
|
|
3544
3693
|
|
|
3694
|
+
inline Napi::Env AsyncContext::Env() const {
|
|
3695
|
+
return Napi::Env(_env);
|
|
3696
|
+
}
|
|
3697
|
+
|
|
3545
3698
|
////////////////////////////////////////////////////////////////////////////////
|
|
3546
3699
|
// AsyncWorker class
|
|
3547
3700
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -3919,35 +4072,28 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
|
|
|
3919
4072
|
}
|
|
3920
4073
|
|
|
3921
4074
|
inline ThreadSafeFunction::ThreadSafeFunction()
|
|
3922
|
-
: _tsfn(
|
|
4075
|
+
: _tsfn() {
|
|
3923
4076
|
}
|
|
3924
4077
|
|
|
3925
4078
|
inline ThreadSafeFunction::ThreadSafeFunction(
|
|
3926
4079
|
napi_threadsafe_function tsfn)
|
|
3927
|
-
: _tsfn(
|
|
4080
|
+
: _tsfn(tsfn) {
|
|
3928
4081
|
}
|
|
3929
4082
|
|
|
3930
|
-
inline ThreadSafeFunction::
|
|
3931
|
-
|
|
3932
|
-
other._tsfn.reset();
|
|
3933
|
-
}
|
|
3934
|
-
|
|
3935
|
-
inline ThreadSafeFunction& ThreadSafeFunction::operator =(
|
|
3936
|
-
ThreadSafeFunction&& other) {
|
|
3937
|
-
if (*_tsfn != nullptr) {
|
|
3938
|
-
Error::Fatal("ThreadSafeFunction::operator =",
|
|
3939
|
-
"You cannot assign a new TSFN because existing one is still alive.");
|
|
3940
|
-
return *this;
|
|
3941
|
-
}
|
|
3942
|
-
_tsfn = std::move(other._tsfn);
|
|
3943
|
-
other._tsfn.reset();
|
|
3944
|
-
return *this;
|
|
4083
|
+
inline ThreadSafeFunction::operator napi_threadsafe_function() const {
|
|
4084
|
+
return _tsfn;
|
|
3945
4085
|
}
|
|
3946
4086
|
|
|
3947
4087
|
inline napi_status ThreadSafeFunction::BlockingCall() const {
|
|
3948
4088
|
return CallInternal(nullptr, napi_tsfn_blocking);
|
|
3949
4089
|
}
|
|
3950
4090
|
|
|
4091
|
+
template <>
|
|
4092
|
+
inline napi_status ThreadSafeFunction::BlockingCall(
|
|
4093
|
+
void* data) const {
|
|
4094
|
+
return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_blocking);
|
|
4095
|
+
}
|
|
4096
|
+
|
|
3951
4097
|
template <typename Callback>
|
|
3952
4098
|
inline napi_status ThreadSafeFunction::BlockingCall(
|
|
3953
4099
|
Callback callback) const {
|
|
@@ -3967,6 +4113,12 @@ inline napi_status ThreadSafeFunction::NonBlockingCall() const {
|
|
|
3967
4113
|
return CallInternal(nullptr, napi_tsfn_nonblocking);
|
|
3968
4114
|
}
|
|
3969
4115
|
|
|
4116
|
+
template <>
|
|
4117
|
+
inline napi_status ThreadSafeFunction::NonBlockingCall(
|
|
4118
|
+
void* data) const {
|
|
4119
|
+
return napi_call_threadsafe_function(_tsfn, data, napi_tsfn_nonblocking);
|
|
4120
|
+
}
|
|
4121
|
+
|
|
3970
4122
|
template <typename Callback>
|
|
3971
4123
|
inline napi_status ThreadSafeFunction::NonBlockingCall(
|
|
3972
4124
|
Callback callback) const {
|
|
@@ -3982,22 +4134,37 @@ inline napi_status ThreadSafeFunction::NonBlockingCall(
|
|
|
3982
4134
|
return CallInternal(new CallbackWrapper(wrapper), napi_tsfn_nonblocking);
|
|
3983
4135
|
}
|
|
3984
4136
|
|
|
4137
|
+
inline void ThreadSafeFunction::Ref(napi_env env) const {
|
|
4138
|
+
if (_tsfn != nullptr) {
|
|
4139
|
+
napi_status status = napi_ref_threadsafe_function(env, _tsfn);
|
|
4140
|
+
NAPI_THROW_IF_FAILED_VOID(env, status);
|
|
4141
|
+
}
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
inline void ThreadSafeFunction::Unref(napi_env env) const {
|
|
4145
|
+
if (_tsfn != nullptr) {
|
|
4146
|
+
napi_status status = napi_unref_threadsafe_function(env, _tsfn);
|
|
4147
|
+
NAPI_THROW_IF_FAILED_VOID(env, status);
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
|
|
3985
4151
|
inline napi_status ThreadSafeFunction::Acquire() const {
|
|
3986
|
-
return napi_acquire_threadsafe_function(
|
|
4152
|
+
return napi_acquire_threadsafe_function(_tsfn);
|
|
3987
4153
|
}
|
|
3988
4154
|
|
|
3989
4155
|
inline napi_status ThreadSafeFunction::Release() {
|
|
3990
|
-
return napi_release_threadsafe_function(
|
|
4156
|
+
return napi_release_threadsafe_function(_tsfn, napi_tsfn_release);
|
|
3991
4157
|
}
|
|
3992
4158
|
|
|
3993
4159
|
inline napi_status ThreadSafeFunction::Abort() {
|
|
3994
|
-
return napi_release_threadsafe_function(
|
|
4160
|
+
return napi_release_threadsafe_function(_tsfn, napi_tsfn_abort);
|
|
3995
4161
|
}
|
|
3996
4162
|
|
|
3997
4163
|
inline ThreadSafeFunction::ConvertibleContext
|
|
3998
4164
|
ThreadSafeFunction::GetContext() const {
|
|
3999
4165
|
void* context;
|
|
4000
|
-
napi_get_threadsafe_function_context(
|
|
4166
|
+
napi_status status = napi_get_threadsafe_function_context(_tsfn, &context);
|
|
4167
|
+
NAPI_FATAL_IF_FAILED(status, "ThreadSafeFunction::GetContext", "napi_get_threadsafe_function_context");
|
|
4001
4168
|
return ConvertibleContext({ context });
|
|
4002
4169
|
}
|
|
4003
4170
|
|
|
@@ -4020,10 +4187,10 @@ inline ThreadSafeFunction ThreadSafeFunction::New(napi_env env,
|
|
|
4020
4187
|
|
|
4021
4188
|
ThreadSafeFunction tsfn;
|
|
4022
4189
|
auto* finalizeData = new details::ThreadSafeFinalize<ContextType, Finalizer,
|
|
4023
|
-
FinalizerDataType>({ data, finalizeCallback, tsfn._tsfn
|
|
4190
|
+
FinalizerDataType>({ data, finalizeCallback, &tsfn._tsfn });
|
|
4024
4191
|
napi_status status = napi_create_threadsafe_function(env, callback, resource,
|
|
4025
4192
|
Value::From(env, resourceName), maxQueueSize, initialThreadCount,
|
|
4026
|
-
finalizeData, wrapper, context, CallJS, tsfn._tsfn
|
|
4193
|
+
finalizeData, wrapper, context, CallJS, &tsfn._tsfn);
|
|
4027
4194
|
if (status != napi_ok) {
|
|
4028
4195
|
delete finalizeData;
|
|
4029
4196
|
NAPI_THROW_IF_FAILED(env, status, ThreadSafeFunction());
|
|
@@ -4036,7 +4203,7 @@ inline napi_status ThreadSafeFunction::CallInternal(
|
|
|
4036
4203
|
CallbackWrapper* callbackWrapper,
|
|
4037
4204
|
napi_threadsafe_function_call_mode mode) const {
|
|
4038
4205
|
napi_status status = napi_call_threadsafe_function(
|
|
4039
|
-
|
|
4206
|
+
_tsfn, callbackWrapper, mode);
|
|
4040
4207
|
if (status != napi_ok && callbackWrapper != nullptr) {
|
|
4041
4208
|
delete callbackWrapper;
|
|
4042
4209
|
}
|
|
@@ -4061,6 +4228,154 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
|
|
|
4061
4228
|
Function(env, jsCallback).Call({});
|
|
4062
4229
|
}
|
|
4063
4230
|
}
|
|
4231
|
+
|
|
4232
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4233
|
+
// Async Progress Worker class
|
|
4234
|
+
////////////////////////////////////////////////////////////////////////////////
|
|
4235
|
+
|
|
4236
|
+
template<class T>
|
|
4237
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback)
|
|
4238
|
+
: AsyncProgressWorker(callback, "generic") {
|
|
4239
|
+
}
|
|
4240
|
+
|
|
4241
|
+
template<class T>
|
|
4242
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
|
|
4243
|
+
const char* resource_name)
|
|
4244
|
+
: AsyncProgressWorker(callback, resource_name, Object::New(callback.Env())) {
|
|
4245
|
+
}
|
|
4246
|
+
|
|
4247
|
+
template<class T>
|
|
4248
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Function& callback,
|
|
4249
|
+
const char* resource_name,
|
|
4250
|
+
const Object& resource)
|
|
4251
|
+
: AsyncProgressWorker(Object::New(callback.Env()),
|
|
4252
|
+
callback,
|
|
4253
|
+
resource_name,
|
|
4254
|
+
resource) {
|
|
4255
|
+
}
|
|
4256
|
+
|
|
4257
|
+
template<class T>
|
|
4258
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
|
|
4259
|
+
const Function& callback)
|
|
4260
|
+
: AsyncProgressWorker(receiver, callback, "generic") {
|
|
4261
|
+
}
|
|
4262
|
+
|
|
4263
|
+
template<class T>
|
|
4264
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
|
|
4265
|
+
const Function& callback,
|
|
4266
|
+
const char* resource_name)
|
|
4267
|
+
: AsyncProgressWorker(receiver,
|
|
4268
|
+
callback,
|
|
4269
|
+
resource_name,
|
|
4270
|
+
Object::New(callback.Env())) {
|
|
4271
|
+
}
|
|
4272
|
+
|
|
4273
|
+
template<class T>
|
|
4274
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(const Object& receiver,
|
|
4275
|
+
const Function& callback,
|
|
4276
|
+
const char* resource_name,
|
|
4277
|
+
const Object& resource)
|
|
4278
|
+
: AsyncWorker(receiver, callback, resource_name, resource),
|
|
4279
|
+
_asyncdata(nullptr),
|
|
4280
|
+
_asyncsize(0) {
|
|
4281
|
+
_tsfn = ThreadSafeFunction::New(callback.Env(), callback, resource_name, 1, 1);
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
#if NAPI_VERSION > 4
|
|
4285
|
+
template<class T>
|
|
4286
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env)
|
|
4287
|
+
: AsyncProgressWorker(env, "generic") {
|
|
4288
|
+
}
|
|
4289
|
+
|
|
4290
|
+
template<class T>
|
|
4291
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
|
|
4292
|
+
const char* resource_name)
|
|
4293
|
+
: AsyncProgressWorker(env, resource_name, Object::New(env)) {
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
template<class T>
|
|
4297
|
+
inline AsyncProgressWorker<T>::AsyncProgressWorker(Napi::Env env,
|
|
4298
|
+
const char* resource_name,
|
|
4299
|
+
const Object& resource)
|
|
4300
|
+
: AsyncWorker(env, resource_name, resource),
|
|
4301
|
+
_asyncdata(nullptr),
|
|
4302
|
+
_asyncsize(0) {
|
|
4303
|
+
// TODO: Once the changes to make the callback optional for threadsafe
|
|
4304
|
+
// functions are no longer optional we can remove the dummy Function here.
|
|
4305
|
+
Function callback;
|
|
4306
|
+
_tsfn = ThreadSafeFunction::New(env, callback, resource_name, 1, 1);
|
|
4307
|
+
}
|
|
4308
|
+
#endif
|
|
4309
|
+
|
|
4310
|
+
template<class T>
|
|
4311
|
+
inline AsyncProgressWorker<T>::~AsyncProgressWorker() {
|
|
4312
|
+
// Abort pending tsfn call.
|
|
4313
|
+
// Don't send progress events after we've already completed.
|
|
4314
|
+
_tsfn.Abort();
|
|
4315
|
+
{
|
|
4316
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
4317
|
+
_asyncdata = nullptr;
|
|
4318
|
+
_asyncsize = 0;
|
|
4319
|
+
}
|
|
4320
|
+
_tsfn.Release();
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
template<class T>
|
|
4324
|
+
inline void AsyncProgressWorker<T>::Execute() {
|
|
4325
|
+
ExecutionProgress progress(this);
|
|
4326
|
+
Execute(progress);
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
template<class T>
|
|
4330
|
+
inline void AsyncProgressWorker<T>::WorkProgress_(Napi::Env /* env */, Napi::Function /* jsCallback */, void* _data) {
|
|
4331
|
+
AsyncProgressWorker* self = static_cast<AsyncProgressWorker*>(_data);
|
|
4332
|
+
|
|
4333
|
+
T* data;
|
|
4334
|
+
size_t size;
|
|
4335
|
+
{
|
|
4336
|
+
std::lock_guard<std::mutex> lock(self->_mutex);
|
|
4337
|
+
data = self->_asyncdata;
|
|
4338
|
+
size = self->_asyncsize;
|
|
4339
|
+
self->_asyncdata = nullptr;
|
|
4340
|
+
self->_asyncsize = 0;
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
self->OnProgress(data, size);
|
|
4344
|
+
delete[] data;
|
|
4345
|
+
}
|
|
4346
|
+
|
|
4347
|
+
template<class T>
|
|
4348
|
+
inline void AsyncProgressWorker<T>::SendProgress_(const T* data, size_t count) {
|
|
4349
|
+
T* new_data = new T[count];
|
|
4350
|
+
std::copy(data, data + count, new_data);
|
|
4351
|
+
|
|
4352
|
+
T* old_data;
|
|
4353
|
+
{
|
|
4354
|
+
std::lock_guard<std::mutex> lock(_mutex);
|
|
4355
|
+
old_data = _asyncdata;
|
|
4356
|
+
_asyncdata = new_data;
|
|
4357
|
+
_asyncsize = count;
|
|
4358
|
+
}
|
|
4359
|
+
_tsfn.NonBlockingCall(this, WorkProgress_);
|
|
4360
|
+
|
|
4361
|
+
delete[] old_data;
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
template<class T>
|
|
4365
|
+
inline void AsyncProgressWorker<T>::Signal() const {
|
|
4366
|
+
_tsfn.NonBlockingCall(this, WorkProgress_);
|
|
4367
|
+
}
|
|
4368
|
+
|
|
4369
|
+
template<class T>
|
|
4370
|
+
inline void AsyncProgressWorker<T>::ExecutionProgress::Signal() const {
|
|
4371
|
+
_worker->Signal();
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
template<class T>
|
|
4375
|
+
inline void AsyncProgressWorker<T>::ExecutionProgress::Send(const T* data, size_t count) const {
|
|
4376
|
+
_worker->SendProgress_(data, count);
|
|
4377
|
+
}
|
|
4378
|
+
|
|
4064
4379
|
#endif
|
|
4065
4380
|
|
|
4066
4381
|
////////////////////////////////////////////////////////////////////////////////
|