|
4 | 4 |
|
5 | 5 | using namespace Napi;
|
6 | 6 |
|
7 |
| -namespace { |
| 7 | +namespace simple { |
8 | 8 |
|
9 | 9 | // Full type of our ThreadSafeFunctionEx
|
10 | 10 | using TSFN = ThreadSafeFunctionEx<>;
|
@@ -62,10 +62,194 @@ TSFNWrap::TSFNWrap(const CallbackInfo &info)
|
62 | 62 | );
|
63 | 63 | #endif
|
64 | 64 | }
|
65 |
| -} // namespace |
| 65 | +} // namespace simple |
66 | 66 |
|
| 67 | +namespace existing { |
| 68 | + |
| 69 | +struct DataType { |
| 70 | + Promise::Deferred deferred; |
| 71 | + bool reject; |
| 72 | +}; |
| 73 | + |
| 74 | +// CallJs callback function provided to `napi_create_threadsafe_function`. It is |
| 75 | +// _NOT_ used by `Napi::ThreadSafeFunctionEx<>`. |
| 76 | +static void CallJs(napi_env env, napi_value jsCallback, void * /*context*/, |
| 77 | + void *data) { |
| 78 | + DataType *casted = static_cast<DataType *>(data); |
| 79 | + if (env != nullptr) { |
| 80 | + if (data != nullptr) { |
| 81 | + napi_value undefined; |
| 82 | + napi_status status = napi_get_undefined(env, &undefined); |
| 83 | + NAPI_THROW_IF_FAILED(env, status); |
| 84 | + if (casted->reject) { |
| 85 | + casted->deferred.Reject(undefined); |
| 86 | + } else { |
| 87 | + casted->deferred.Resolve(undefined); |
| 88 | + } |
| 89 | + } |
| 90 | + } |
| 91 | + if (casted != nullptr) { |
| 92 | + delete casted; |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | +// Full type of our ThreadSafeFunctionEx |
| 97 | +using TSFN = ThreadSafeFunctionEx<void, DataType>; |
| 98 | + |
| 99 | +// A JS-accessible wrap that holds a TSFN. |
| 100 | +class ExistingTSFNWrap : public ObjectWrap<ExistingTSFNWrap> { |
| 101 | +public: |
| 102 | + static Object Init(Napi::Env env, Object exports); |
| 103 | + ExistingTSFNWrap(const CallbackInfo &info); |
| 104 | + |
| 105 | + Napi::Value Release(const CallbackInfo &) { |
| 106 | + _tsfn.Release(); |
| 107 | + return _deferred.Promise(); |
| 108 | + }; |
| 109 | + |
| 110 | + Napi::Value Call(const CallbackInfo &info) { |
| 111 | + auto *data = |
| 112 | + new DataType{Promise::Deferred::New(info.Env()), info[0].ToBoolean()}; |
| 113 | + _tsfn.NonBlockingCall(data); |
| 114 | + return data->deferred.Promise(); |
| 115 | + }; |
| 116 | + |
| 117 | +private: |
| 118 | + TSFN _tsfn; |
| 119 | + Promise::Deferred _deferred; |
| 120 | +}; |
| 121 | + |
| 122 | +Object ExistingTSFNWrap::Init(Napi::Env env, Object exports) { |
| 123 | + Function func = |
| 124 | + DefineClass(env, "ExistingTSFNWrap", |
| 125 | + {InstanceMethod("call", &ExistingTSFNWrap::Call), |
| 126 | + InstanceMethod("release", &ExistingTSFNWrap::Release)}); |
| 127 | + |
| 128 | + exports.Set("ExistingTSFNWrap", func); |
| 129 | + return exports; |
| 130 | +} |
| 131 | + |
| 132 | +ExistingTSFNWrap::ExistingTSFNWrap(const CallbackInfo &info) |
| 133 | + : ObjectWrap<ExistingTSFNWrap>(info), |
| 134 | + _deferred(Promise::Deferred::New(info.Env())) { |
| 135 | + |
| 136 | + auto env = info.Env(); |
| 137 | +#if NAPI_VERSION == 4 |
| 138 | + napi_threadsafe_function napi_tsfn; |
| 139 | + auto status = napi_create_threadsafe_function( |
| 140 | + info.Env(), TSFN::DefaultFunctionFactory(env), nullptr, |
| 141 | + String::From(info.Env(), "Test"), 0, 1, nullptr, nullptr, nullptr, CallJs, |
| 142 | + &napi_tsfn); |
| 143 | + if (status != napi_ok) { |
| 144 | + NAPI_THROW_IF_FAILED(env, status); |
| 145 | + } |
| 146 | + // A threadsafe function on N-API 4 still requires a callback function. |
| 147 | + _tsfn = TSFN(napi_tsfn); |
| 148 | +#else |
| 149 | + napi_threadsafe_function napi_tsfn; |
| 150 | + auto status = napi_create_threadsafe_function( |
| 151 | + info.Env(), nullptr, nullptr, String::From(info.Env(), "Test"), 0, 1, |
| 152 | + nullptr, nullptr, nullptr, CallJs, &napi_tsfn); |
| 153 | + if (status != napi_ok) { |
| 154 | + NAPI_THROW_IF_FAILED(env, status); |
| 155 | + } |
| 156 | + _tsfn = TSFN(napi_tsfn); |
| 157 | +#endif |
| 158 | +} |
| 159 | +} // namespace existing |
| 160 | + |
| 161 | +namespace empty { |
| 162 | +#if NAPI_VERSION > 4 |
| 163 | + |
| 164 | +using Context = void; |
| 165 | + |
| 166 | +struct DataType { |
| 167 | + Promise::Deferred deferred; |
| 168 | + bool reject; |
| 169 | +}; |
| 170 | + |
| 171 | +// CallJs callback function |
| 172 | +static void CallJs(Napi::Env env, Function jsCallback, Context * /*context*/, |
| 173 | + DataType *data) { |
| 174 | + if (env != nullptr) { |
| 175 | + if (data != nullptr) { |
| 176 | + if (data->reject) { |
| 177 | + data->deferred.Reject(env.Undefined()); |
| 178 | + } else { |
| 179 | + data->deferred.Resolve(env.Undefined()); |
| 180 | + } |
| 181 | + } |
| 182 | + } |
| 183 | + if (data != nullptr) { |
| 184 | + delete data; |
| 185 | + } |
| 186 | +} |
| 187 | + |
| 188 | +// Full type of our ThreadSafeFunctionEx |
| 189 | +using EmptyTSFN = ThreadSafeFunctionEx<void, DataType, CallJs>; |
| 190 | + |
| 191 | +// A JS-accessible wrap that holds a TSFN. |
| 192 | +class EmptyTSFNWrap : public ObjectWrap<EmptyTSFNWrap> { |
| 193 | +public: |
| 194 | + static Object Init(Napi::Env env, Object exports); |
| 195 | + EmptyTSFNWrap(const CallbackInfo &info); |
| 196 | + |
| 197 | + Napi::Value Release(const CallbackInfo &) { |
| 198 | + _tsfn.Release(); |
| 199 | + return _deferred.Promise(); |
| 200 | + }; |
| 201 | + |
| 202 | + Napi::Value Call(const CallbackInfo &info) { |
| 203 | + if (info.Length() == 0 || !info[0].IsBoolean()) { |
| 204 | + NAPI_THROW( |
| 205 | + Napi::TypeError::New(info.Env(), "Expected argument 0 to be boolean"), |
| 206 | + Value()); |
| 207 | + } |
| 208 | + |
| 209 | + auto *data = |
| 210 | + new DataType{Promise::Deferred::New(info.Env()), info[0].ToBoolean()}; |
| 211 | + _tsfn.NonBlockingCall(data); |
| 212 | + return data->deferred.Promise(); |
| 213 | + }; |
| 214 | + |
| 215 | +private: |
| 216 | + EmptyTSFN _tsfn; |
| 217 | + Promise::Deferred _deferred; |
| 218 | +}; |
| 219 | + |
| 220 | +Object EmptyTSFNWrap::Init(Napi::Env env, Object exports) { |
| 221 | + Function func = |
| 222 | + DefineClass(env, "EmptyTSFNWrap", |
| 223 | + {InstanceMethod("call", &EmptyTSFNWrap::Call), |
| 224 | + InstanceMethod("release", &EmptyTSFNWrap::Release)}); |
| 225 | + |
| 226 | + exports.Set("EmptyTSFNWrap", func); |
| 227 | + return exports; |
| 228 | +} |
| 229 | + |
| 230 | +EmptyTSFNWrap::EmptyTSFNWrap(const CallbackInfo &info) |
| 231 | + : ObjectWrap<EmptyTSFNWrap>(info), |
| 232 | + _deferred(Promise::Deferred::New(info.Env())) { |
| 233 | + |
| 234 | + auto env = info.Env(); |
| 235 | + _tsfn = EmptyTSFN::New(env, // napi_env env, |
| 236 | + "Test", // ResourceString resourceName, |
| 237 | + 0, // size_t maxQueueSize, |
| 238 | + 1 // size_t initialThreadCount |
| 239 | + ); |
| 240 | +} |
| 241 | +#endif |
| 242 | +} // namespace empty |
67 | 243 | Object InitThreadSafeFunctionExSimple(Env env) {
|
68 |
| - return TSFNWrap::Init(env, Object::New(env)); |
| 244 | + |
| 245 | +#if NAPI_VERSION > 4 |
| 246 | + return empty::EmptyTSFNWrap::Init( |
| 247 | + env, existing::ExistingTSFNWrap::Init( |
| 248 | + env, simple::TSFNWrap::Init(env, Object::New(env)))); |
| 249 | +#else |
| 250 | + return existing::ExistingTSFNWrap::Init( |
| 251 | + env, simple::TSFNWrap::Init(env, Object::New(env))); |
| 252 | +#endif |
69 | 253 | }
|
70 | 254 |
|
71 | 255 | #endif
|
0 commit comments