forked from nodejs/node-addon-api
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathasync_progress_queue_worker.cc
248 lines (208 loc) · 6.89 KB
/
async_progress_queue_worker.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
#include "napi.h"
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <thread>
#if (NAPI_VERSION > 3)
using namespace Napi;
namespace {
struct ProgressData {
int32_t progress;
};
class TestWorkerWithNoCb : public AsyncProgressQueueWorker<ProgressData> {
public:
static void DoWork(const CallbackInfo& info) {
switch (info.Length()) {
case 1: {
Function cb = info[0].As<Function>();
TestWorkerWithNoCb* worker = new TestWorkerWithNoCb(info.Env(), cb);
worker->Queue();
} break;
case 2: {
std::string resName = info[0].As<String>();
Function cb = info[1].As<Function>();
TestWorkerWithNoCb* worker =
new TestWorkerWithNoCb(info.Env(), resName.c_str(), cb);
worker->Queue();
} break;
case 3: {
std::string resName = info[0].As<String>();
Object resObject = info[1].As<Object>();
Function cb = info[2].As<Function>();
TestWorkerWithNoCb* worker =
new TestWorkerWithNoCb(info.Env(), resName.c_str(), resObject, cb);
worker->Queue();
} break;
default:
break;
}
}
protected:
void Execute(const ExecutionProgress& progress) override {
ProgressData data{1};
progress.Send(&data, 1);
}
void OnProgress(const ProgressData*, size_t /* count */) override {
_cb.Call({});
}
private:
TestWorkerWithNoCb(Napi::Env env, Function cb)
: AsyncProgressQueueWorker(env) {
_cb.Reset(cb, 1);
}
TestWorkerWithNoCb(Napi::Env env, const char* resourceName, Function cb)
: AsyncProgressQueueWorker(env, resourceName) {
_cb.Reset(cb, 1);
}
TestWorkerWithNoCb(Napi::Env env,
const char* resourceName,
const Object& resourceObject,
Function cb)
: AsyncProgressQueueWorker(env, resourceName, resourceObject) {
_cb.Reset(cb, 1);
}
FunctionReference _cb;
};
class TestWorkerWithRecv : public AsyncProgressQueueWorker<ProgressData> {
public:
static void DoWork(const CallbackInfo& info) {
switch (info.Length()) {
case 2: {
Object recv = info[0].As<Object>();
Function cb = info[1].As<Function>();
TestWorkerWithRecv* worker = new TestWorkerWithRecv(recv, cb);
worker->Queue();
} break;
case 3: {
Object recv = info[0].As<Object>();
Function cb = info[1].As<Function>();
std::string resName = info[2].As<String>();
TestWorkerWithRecv* worker =
new TestWorkerWithRecv(recv, cb, resName.c_str());
worker->Queue();
} break;
case 4: {
Object recv = info[0].As<Object>();
Function cb = info[1].As<Function>();
std::string resName = info[2].As<String>();
Object resObject = info[3].As<Object>();
TestWorkerWithRecv* worker =
new TestWorkerWithRecv(recv, cb, resName.c_str(), resObject);
worker->Queue();
} break;
default:
break;
}
}
protected:
void Execute(const ExecutionProgress&) override {}
void OnProgress(const ProgressData*, size_t /* count */) override {}
private:
TestWorkerWithRecv(const Object& recv, const Function& cb)
: AsyncProgressQueueWorker(recv, cb) {}
TestWorkerWithRecv(const Object& recv,
const Function& cb,
const char* resourceName)
: AsyncProgressQueueWorker(recv, cb, resourceName) {}
TestWorkerWithRecv(const Object& recv,
const Function& cb,
const char* resourceName,
const Object& resourceObject)
: AsyncProgressQueueWorker(recv, cb, resourceName, resourceObject) {}
};
class TestWorkerWithCb : public AsyncProgressQueueWorker<ProgressData> {
public:
static void DoWork(const CallbackInfo& info) {
switch (info.Length()) {
case 1: {
Function cb = info[0].As<Function>();
TestWorkerWithCb* worker = new TestWorkerWithCb(cb);
worker->Queue();
} break;
case 2: {
Function cb = info[0].As<Function>();
std::string asyncResName = info[1].As<String>();
TestWorkerWithCb* worker =
new TestWorkerWithCb(cb, asyncResName.c_str());
worker->Queue();
} break;
default:
break;
}
}
protected:
void Execute(const ExecutionProgress&) override {}
void OnProgress(const ProgressData*, size_t /* count */) override {}
private:
TestWorkerWithCb(Function cb) : AsyncProgressQueueWorker(cb) {}
TestWorkerWithCb(Function cb, const char* res_name)
: AsyncProgressQueueWorker(cb, res_name) {}
};
class TestWorker : public AsyncProgressQueueWorker<ProgressData> {
public:
static Napi::Value CreateWork(const CallbackInfo& info) {
int32_t times = info[0].As<Number>().Int32Value();
Function cb = info[1].As<Function>();
Function progress = info[2].As<Function>();
TestWorker* worker = new TestWorker(
cb, progress, "TestResource", Object::New(info.Env()), times);
return Napi::External<TestWorker>::New(info.Env(), worker);
}
static void QueueWork(const CallbackInfo& info) {
auto wrap = info[0].As<Napi::External<TestWorker>>();
auto worker = wrap.Data();
worker->Queue();
}
protected:
void Execute(const ExecutionProgress& progress) override {
using namespace std::chrono_literals;
std::this_thread::sleep_for(1s);
if (_times < 0) {
SetError("test error");
} else {
progress.Signal();
}
ProgressData data{0};
for (int32_t idx = 0; idx < _times; idx++) {
data.progress = idx;
progress.Send(&data, 1);
}
}
void OnProgress(const ProgressData* data, size_t count) override {
Napi::Env env = Env();
_test_case_count++;
if (!_js_progress_cb.IsEmpty()) {
if (_test_case_count == 1) {
if (count != 0) {
SetError("expect 0 count of data on 1st call");
}
} else {
Number progress = Number::New(env, data->progress);
_js_progress_cb.Call(Receiver().Value(), {progress});
}
}
}
private:
TestWorker(Function cb,
Function progress,
const char* resource_name,
const Object& resource,
int32_t times)
: AsyncProgressQueueWorker(cb, resource_name, resource), _times(times) {
_js_progress_cb.Reset(progress, 1);
}
int32_t _times;
size_t _test_case_count = 0;
FunctionReference _js_progress_cb;
};
} // namespace
Object InitAsyncProgressQueueWorker(Env env) {
Object exports = Object::New(env);
exports["createWork"] = Function::New(env, TestWorker::CreateWork);
exports["queueWork"] = Function::New(env, TestWorker::QueueWork);
exports["runWorkerNoCb"] = Function::New(env, TestWorkerWithNoCb::DoWork);
exports["runWorkerWithRecv"] = Function::New(env, TestWorkerWithRecv::DoWork);
exports["runWorkerWithCb"] = Function::New(env, TestWorkerWithCb::DoWork);
return exports;
}
#endif