@reboot-dev/reboot 0.42.0 → 0.44.0
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/package.json +2 -2
- package/reboot_native.cc +498 -667
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/zod-to-proto.js +47 -36
package/reboot_native.cc
CHANGED
|
@@ -27,20 +27,18 @@ namespace py = pybind11;
|
|
|
27
27
|
|
|
28
28
|
// Helper when debugging, left for future optimization work.
|
|
29
29
|
struct Timer {
|
|
30
|
-
Timer(const char* name)
|
|
31
|
-
: name_(name) {
|
|
30
|
+
Timer(const char* name) : name_(name) {
|
|
32
31
|
start_ = std::chrono::high_resolution_clock::now();
|
|
33
32
|
}
|
|
34
33
|
|
|
35
34
|
void elapsed(const char* step = nullptr) const {
|
|
36
35
|
auto end = std::chrono::high_resolution_clock::now();
|
|
37
|
-
auto duration =
|
|
38
|
-
end - start_);
|
|
36
|
+
auto duration =
|
|
37
|
+
std::chrono::duration_cast<std::chrono::milliseconds>(end - start_);
|
|
39
38
|
std::stringstream ss;
|
|
40
39
|
ss << name_
|
|
41
40
|
<< (step != nullptr ? " at " + std::string(step) : std::string(""))
|
|
42
|
-
<< " took " << duration.count() << "ms"
|
|
43
|
-
<< std::endl;
|
|
41
|
+
<< " took " << duration.count() << "ms" << std::endl;
|
|
44
42
|
std::cout << ss.str();
|
|
45
43
|
}
|
|
46
44
|
|
|
@@ -87,9 +85,9 @@ struct PythonNodeAdaptor {
|
|
|
87
85
|
if (const py::error_already_set* e_py =
|
|
88
86
|
dynamic_cast<const py::error_already_set*>(&e)) {
|
|
89
87
|
// This is a Python exception. Is it an `InputError`?
|
|
90
|
-
if (e_py->matches(
|
|
91
|
-
|
|
92
|
-
|
|
88
|
+
if (e_py->matches(
|
|
89
|
+
py::module::import("rebootdev.aio.exceptions")
|
|
90
|
+
.attr("InputError"))) {
|
|
93
91
|
// This is an InputError, which means it reports a mistake in the input
|
|
94
92
|
// provided by the developer. We want to print _only_ the user-friendly
|
|
95
93
|
// error message in the exception, without intimidating stack traces.
|
|
@@ -104,15 +102,13 @@ struct PythonNodeAdaptor {
|
|
|
104
102
|
// help diagnose the problem.
|
|
105
103
|
std::cerr << "Unexpected library exception: " << e_py->what()
|
|
106
104
|
<< std::endl
|
|
107
|
-
<< "Please report this bug to the maintainers!"
|
|
108
|
-
<< std::endl;
|
|
105
|
+
<< "Please report this bug to the maintainers!" << std::endl;
|
|
109
106
|
}
|
|
110
107
|
} else {
|
|
111
108
|
// This is a C++ exception; something went wrong in the C++ code. Request
|
|
112
109
|
// that the developer reports the issue.
|
|
113
|
-
std::cerr
|
|
114
|
-
|
|
115
|
-
<< "Please report this bug to the maintainers!" << std::endl;
|
|
110
|
+
std::cerr << "Unexpected adapter exception: " << e.what() << std::endl
|
|
111
|
+
<< "Please report this bug to the maintainers!" << std::endl;
|
|
116
112
|
}
|
|
117
113
|
}
|
|
118
114
|
|
|
@@ -224,11 +220,8 @@ struct PythonNodeAdaptor {
|
|
|
224
220
|
try {
|
|
225
221
|
function(env);
|
|
226
222
|
} catch (const std::exception& e) {
|
|
227
|
-
std::cerr
|
|
228
|
-
|
|
229
|
-
<< "\n"
|
|
230
|
-
<< "Please report this bug to the maintainers!"
|
|
231
|
-
<< std::endl;
|
|
223
|
+
std::cerr << "Unexpected exception: " << e.what() << "\n"
|
|
224
|
+
<< "Please report this bug to the maintainers!" << std::endl;
|
|
232
225
|
}
|
|
233
226
|
}
|
|
234
227
|
}
|
|
@@ -263,10 +256,7 @@ struct PythonNodeAdaptor {
|
|
|
263
256
|
// into Python or expecting calls from Python.
|
|
264
257
|
std::atomic<int> references{0};
|
|
265
258
|
|
|
266
|
-
Napi::TypedThreadSafeFunction<
|
|
267
|
-
void,
|
|
268
|
-
void,
|
|
269
|
-
_RunNodeFunctions>
|
|
259
|
+
Napi::TypedThreadSafeFunction<void, void, _RunNodeFunctions>
|
|
270
260
|
thread_safe_function;
|
|
271
261
|
std::mutex node_functions_mutex_;
|
|
272
262
|
std::list<std::function<void(Napi::Env&)>> node_functions_;
|
|
@@ -294,9 +284,7 @@ struct NapiReferenceDeleter {
|
|
|
294
284
|
template <typename T>
|
|
295
285
|
void operator()(Napi::Reference<T>* reference) {
|
|
296
286
|
adaptor->ScheduleCallbackOnNodeEventLoopLowPriority(
|
|
297
|
-
[reference](Napi::Env) {
|
|
298
|
-
delete reference;
|
|
299
|
-
});
|
|
287
|
+
[reference](Napi::Env) { delete reference; });
|
|
300
288
|
}
|
|
301
289
|
};
|
|
302
290
|
|
|
@@ -335,13 +323,9 @@ using NapiSafeObjectReference = NapiSafeReference<Napi::Object>;
|
|
|
335
323
|
// also includes our C++ <-> Python class wrappers for storing NAPI
|
|
336
324
|
// objects in Python to properly handle memory management.
|
|
337
325
|
PYBIND11_EMBEDDED_MODULE(reboot_native, m) {
|
|
338
|
-
py::class_<NapiSafeFunctionReference>(
|
|
339
|
-
m,
|
|
340
|
-
"NapiSafeFunctionReference");
|
|
326
|
+
py::class_<NapiSafeFunctionReference>(m, "NapiSafeFunctionReference");
|
|
341
327
|
|
|
342
|
-
py::class_<NapiSafeObjectReference>(
|
|
343
|
-
m,
|
|
344
|
-
"NapiSafeObjectReference");
|
|
328
|
+
py::class_<NapiSafeObjectReference>(m, "NapiSafeObjectReference");
|
|
345
329
|
}
|
|
346
330
|
|
|
347
331
|
|
|
@@ -354,9 +338,7 @@ Napi::External<py::object> make_napi_external(
|
|
|
354
338
|
py_object,
|
|
355
339
|
[](Napi::Env, py::object* py_object) {
|
|
356
340
|
adaptor->ScheduleCallbackOnPythonEventLoopLowPriority(
|
|
357
|
-
[py_object]() {
|
|
358
|
-
delete py_object;
|
|
359
|
-
});
|
|
341
|
+
[py_object]() { delete py_object; });
|
|
360
342
|
});
|
|
361
343
|
|
|
362
344
|
if (type_tag != nullptr) {
|
|
@@ -379,126 +361,119 @@ void _RunNodeFunctions(
|
|
|
379
361
|
void PythonNodeAdaptor::Initialize(
|
|
380
362
|
Napi::Env& env,
|
|
381
363
|
const Napi::Function& js_callback) {
|
|
382
|
-
thread_safe_function =
|
|
383
|
-
void,
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
364
|
+
thread_safe_function =
|
|
365
|
+
Napi::TypedThreadSafeFunction<void, void, _RunNodeFunctions>::New(
|
|
366
|
+
/* Environment: */
|
|
367
|
+
env,
|
|
368
|
+
/* JS callback: */ js_callback,
|
|
369
|
+
/* Resource name: */ "reboot_native",
|
|
370
|
+
/* Max queue size (0 = unlimited): */ 0,
|
|
371
|
+
/* Initial thread count: */ 1,
|
|
372
|
+
/* Context: */ (void*) nullptr,
|
|
373
|
+
// Finalizer:
|
|
374
|
+
[this](Napi::Env env, void*, void*) {
|
|
375
|
+
// Set that we've been finalized so that we don't use
|
|
376
|
+
// `thread_safe_function` again, see comment in
|
|
377
|
+
// `ScheduleCallbackOnNodeEventLoop`.
|
|
378
|
+
thread_safe_function_finalized = true;
|
|
379
|
+
},
|
|
380
|
+
/* Finalizer data: */ (void*) nullptr);
|
|
399
381
|
|
|
400
382
|
// We start with our thread safe function unreferenced so that
|
|
401
383
|
// if the user's code never calls into us we won't keep Node
|
|
402
384
|
// from exiting.
|
|
403
385
|
thread_safe_function.Unref(env);
|
|
404
386
|
|
|
405
|
-
thread = std::thread(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
setenv("REBOOT_NODEJS", "true", 1);
|
|
416
|
-
|
|
417
|
-
py::initialize_interpreter();
|
|
418
|
-
|
|
419
|
-
try {
|
|
420
|
-
py::object module = py::module::import("rebootdev.nodejs.python");
|
|
421
|
-
|
|
422
|
-
module.attr("launch_subprocess_server") = py::cpp_function(
|
|
423
|
-
[](py::str py_base64_args) {
|
|
424
|
-
py::object py_future =
|
|
425
|
-
py::module::import("asyncio").attr("Future")();
|
|
426
|
-
|
|
427
|
-
adaptor->ScheduleCallbackOnNodeEventLoop(
|
|
428
|
-
[base64_args = std::string(py_base64_args),
|
|
429
|
-
py_future = new py::object(py_future)](Napi::Env env) {
|
|
430
|
-
try {
|
|
431
|
-
Napi::Number js_pid =
|
|
432
|
-
js_launchSubprocessServer
|
|
433
|
-
->Call(
|
|
434
|
-
{Napi::String::New(env, base64_args)})
|
|
435
|
-
.As<Napi::Number>();
|
|
436
|
-
|
|
437
|
-
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
438
|
-
[py_future, pid = js_pid.Int64Value()]() {
|
|
439
|
-
bool cancelled =
|
|
440
|
-
py_future->attr("cancelled")()
|
|
441
|
-
.cast<bool>();
|
|
442
|
-
if (!cancelled) {
|
|
443
|
-
py_future->attr("set_result")(pid);
|
|
444
|
-
}
|
|
445
|
-
delete py_future;
|
|
446
|
-
});
|
|
447
|
-
} catch (const Napi::Error& e) {
|
|
448
|
-
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
449
|
-
[py_future, what = e.what()]() {
|
|
450
|
-
bool cancelled =
|
|
451
|
-
py_future->attr("cancelled")()
|
|
452
|
-
.cast<bool>();
|
|
453
|
-
if (!cancelled) {
|
|
454
|
-
py_future->attr("set_exception")(
|
|
455
|
-
py::module::import("builtins")
|
|
456
|
-
.attr("Exception")(
|
|
457
|
-
what));
|
|
458
|
-
}
|
|
459
|
-
delete py_future;
|
|
460
|
-
});
|
|
461
|
-
}
|
|
462
|
-
});
|
|
387
|
+
thread = std::thread([this]() {
|
|
388
|
+
// Set environment variables _before_ initializing the
|
|
389
|
+
// interpreter because it may cache the variables. Also, some
|
|
390
|
+
// of the variables need to be set before we start importing
|
|
391
|
+
// anything.
|
|
392
|
+
//
|
|
393
|
+
// Don't try and manipulate signals when running within Node!
|
|
394
|
+
setenv("REBOOT_SIGNALS_AVAILABLE", "false", 1);
|
|
395
|
+
// Specify that we are running from within `node`.
|
|
396
|
+
setenv("REBOOT_NODEJS", "true", 1);
|
|
463
397
|
|
|
464
|
-
|
|
465
|
-
});
|
|
398
|
+
py::initialize_interpreter();
|
|
466
399
|
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
std::list<std::function<void()>> functions;
|
|
470
|
-
std::vector<std::pair<py::object*, std::string>> futures;
|
|
400
|
+
try {
|
|
401
|
+
py::object module = py::module::import("rebootdev.nodejs.python");
|
|
471
402
|
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
}
|
|
403
|
+
module.attr("launch_subprocess_server") =
|
|
404
|
+
py::cpp_function([](py::str py_base64_args) {
|
|
405
|
+
py::object py_future =
|
|
406
|
+
py::module::import("asyncio").attr("Future")();
|
|
477
407
|
|
|
478
|
-
|
|
408
|
+
adaptor->ScheduleCallbackOnNodeEventLoop(
|
|
409
|
+
[base64_args = std::string(py_base64_args),
|
|
410
|
+
py_future = new py::object(py_future)](Napi::Env env) {
|
|
479
411
|
try {
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
412
|
+
Napi::Number js_pid =
|
|
413
|
+
js_launchSubprocessServer
|
|
414
|
+
->Call({Napi::String::New(env, base64_args)})
|
|
415
|
+
.As<Napi::Number>();
|
|
416
|
+
|
|
417
|
+
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
418
|
+
[py_future, pid = js_pid.Int64Value()]() {
|
|
419
|
+
bool cancelled =
|
|
420
|
+
py_future->attr("cancelled")().cast<bool>();
|
|
421
|
+
if (!cancelled) {
|
|
422
|
+
py_future->attr("set_result")(pid);
|
|
423
|
+
}
|
|
424
|
+
delete py_future;
|
|
425
|
+
});
|
|
426
|
+
} catch (const Napi::Error& e) {
|
|
427
|
+
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
428
|
+
[py_future, what = e.what()]() {
|
|
429
|
+
bool cancelled =
|
|
430
|
+
py_future->attr("cancelled")().cast<bool>();
|
|
431
|
+
if (!cancelled) {
|
|
432
|
+
py_future->attr("set_exception")(
|
|
433
|
+
py::module::import("builtins")
|
|
434
|
+
.attr("Exception")(what));
|
|
435
|
+
}
|
|
436
|
+
delete py_future;
|
|
437
|
+
});
|
|
483
438
|
}
|
|
484
|
-
}
|
|
485
|
-
|
|
439
|
+
});
|
|
440
|
+
|
|
441
|
+
return py_future;
|
|
442
|
+
});
|
|
486
443
|
|
|
487
|
-
|
|
488
|
-
|
|
444
|
+
module.attr("run_functions") = py::cpp_function([this]() {
|
|
445
|
+
std::list<std::function<void()>> functions;
|
|
446
|
+
std::vector<std::pair<py::object*, std::string>> futures;
|
|
489
447
|
|
|
490
|
-
|
|
448
|
+
{
|
|
449
|
+
std::unique_lock<std::mutex> lock(mutex);
|
|
450
|
+
functions = std::move(python_functions);
|
|
451
|
+
should_signal_fd_ = true;
|
|
452
|
+
}
|
|
491
453
|
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
454
|
+
for (auto&& function : functions) {
|
|
455
|
+
try {
|
|
456
|
+
function();
|
|
457
|
+
} catch (std::exception& e) {
|
|
458
|
+
PythonNodeAdaptor::HandleException(e);
|
|
496
459
|
}
|
|
497
|
-
} catch (const std::exception& e) {
|
|
498
|
-
std::cout << e.what() << std::endl;
|
|
499
|
-
throw;
|
|
500
460
|
}
|
|
501
461
|
});
|
|
462
|
+
|
|
463
|
+
py::object event_loop_thread = module.attr("EventLoopThread")(read_fd_);
|
|
464
|
+
|
|
465
|
+
py::gil_scoped_release release;
|
|
466
|
+
|
|
467
|
+
while (true) {
|
|
468
|
+
std::this_thread::sleep_until(
|
|
469
|
+
std::chrono::time_point<std::chrono::system_clock>::max());
|
|
470
|
+
continue;
|
|
471
|
+
}
|
|
472
|
+
} catch (const std::exception& e) {
|
|
473
|
+
std::cout << e.what() << std::endl;
|
|
474
|
+
throw;
|
|
475
|
+
}
|
|
476
|
+
});
|
|
502
477
|
}
|
|
503
478
|
|
|
504
479
|
|
|
@@ -555,21 +530,19 @@ template <typename F, typename T = std::invoke_result_t<F>>
|
|
|
555
530
|
T RunCallbackOnPythonEventLoop(F&& f) {
|
|
556
531
|
std::promise<T> promise;
|
|
557
532
|
|
|
558
|
-
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
}
|
|
572
|
-
});
|
|
533
|
+
adaptor->ScheduleCallbackOnPythonEventLoop([&f, &promise]() {
|
|
534
|
+
try {
|
|
535
|
+
if constexpr (std::is_void<T>::value) {
|
|
536
|
+
f();
|
|
537
|
+
promise.set_value();
|
|
538
|
+
} else {
|
|
539
|
+
promise.set_value(f());
|
|
540
|
+
}
|
|
541
|
+
} catch (const std::exception& e) {
|
|
542
|
+
promise.set_exception(
|
|
543
|
+
std::make_exception_ptr(std::runtime_error(e.what())));
|
|
544
|
+
}
|
|
545
|
+
});
|
|
573
546
|
|
|
574
547
|
return promise.get_future().get();
|
|
575
548
|
}
|
|
@@ -598,8 +571,7 @@ T RunCallbackOnNodeEventLoop(F&& f, bool warn = false) {
|
|
|
598
571
|
.Call({e.Value(), Napi::String::New(env, "\n")});
|
|
599
572
|
}
|
|
600
573
|
promise.set_exception(
|
|
601
|
-
std::make_exception_ptr(
|
|
602
|
-
std::runtime_error(e.what())));
|
|
574
|
+
std::make_exception_ptr(std::runtime_error(e.what())));
|
|
603
575
|
} catch (const std::exception& e) {
|
|
604
576
|
if (warn) {
|
|
605
577
|
env.Global()
|
|
@@ -612,8 +584,7 @@ T RunCallbackOnNodeEventLoop(F&& f, bool warn = false) {
|
|
|
612
584
|
Napi::String::New(env, "\n")});
|
|
613
585
|
}
|
|
614
586
|
promise.set_exception(
|
|
615
|
-
std::make_exception_ptr(
|
|
616
|
-
std::runtime_error(e.what())));
|
|
587
|
+
std::make_exception_ptr(std::runtime_error(e.what())));
|
|
617
588
|
}
|
|
618
589
|
});
|
|
619
590
|
|
|
@@ -658,8 +629,7 @@ Napi::Promise NodePromiseFromPythonCallback(
|
|
|
658
629
|
} catch (const std::exception& e) {
|
|
659
630
|
// TODO: is this code unreachable because Node.js
|
|
660
631
|
// will properly always only pass us a `Napi::Error`?
|
|
661
|
-
js_deferred->Reject(
|
|
662
|
-
Napi::Error::New(env, e.what()).Value());
|
|
632
|
+
js_deferred->Reject(Napi::Error::New(env, e.what()).Value());
|
|
663
633
|
} catch (...) {
|
|
664
634
|
// TODO: is this code unreachable because Node.js
|
|
665
635
|
// will properly always only pass us a `Napi::Error`?
|
|
@@ -678,16 +648,14 @@ Napi::Promise NodePromiseFromPythonCallback(
|
|
|
678
648
|
});
|
|
679
649
|
|
|
680
650
|
// Allow Node to exit after we've resolved or rejected the promise.
|
|
681
|
-
auto js_resolve_reject =
|
|
682
|
-
env,
|
|
683
|
-
[](const Napi::CallbackInfo& info) {
|
|
651
|
+
auto js_resolve_reject =
|
|
652
|
+
Napi::Function::New(env, [](const Napi::CallbackInfo& info) {
|
|
684
653
|
adaptor->AllowNodeToExit(info.Env());
|
|
685
654
|
});
|
|
686
655
|
|
|
687
|
-
js_promise
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
.Call(js_promise, {js_resolve_reject, js_resolve_reject});
|
|
656
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
657
|
+
js_promise,
|
|
658
|
+
{js_resolve_reject, js_resolve_reject});
|
|
691
659
|
|
|
692
660
|
return js_promise;
|
|
693
661
|
}
|
|
@@ -719,10 +687,10 @@ Napi::Promise NodePromiseFromPythonFuture(
|
|
|
719
687
|
auto js_promise = js_deferred->Promise();
|
|
720
688
|
|
|
721
689
|
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
722
|
-
[python_future_callback =
|
|
723
|
-
python_future_callback),
|
|
724
|
-
python_done_callback =
|
|
725
|
-
python_done_callback),
|
|
690
|
+
[python_future_callback =
|
|
691
|
+
std::forward<PythonFutureCallback>(python_future_callback),
|
|
692
|
+
python_done_callback =
|
|
693
|
+
std::forward<PythonDoneCallback>(python_done_callback),
|
|
726
694
|
node_callback = std::forward<NodeCallback>(node_callback),
|
|
727
695
|
js_deferred = std::move(js_deferred)]() mutable {
|
|
728
696
|
try {
|
|
@@ -730,8 +698,8 @@ Napi::Promise NodePromiseFromPythonFuture(
|
|
|
730
698
|
py::object py_future = python_future_callback();
|
|
731
699
|
|
|
732
700
|
py_future.attr("add_done_callback")(py::cpp_function(
|
|
733
|
-
[python_done_callback =
|
|
734
|
-
python_done_callback),
|
|
701
|
+
[python_done_callback =
|
|
702
|
+
std::forward<PythonDoneCallback>(python_done_callback),
|
|
735
703
|
node_callback = std::forward<NodeCallback>(node_callback),
|
|
736
704
|
js_deferred = std::move(js_deferred),
|
|
737
705
|
// NOTE: need to keep a reference to `py_future` so that it
|
|
@@ -766,9 +734,8 @@ Napi::Promise NodePromiseFromPythonFuture(
|
|
|
766
734
|
js_deferred = std::move(js_deferred),
|
|
767
735
|
result = std::move(result)](Napi::Env env) mutable {
|
|
768
736
|
// TODO: try / catch around `node_callback`.
|
|
769
|
-
auto js_result =
|
|
770
|
-
env,
|
|
771
|
-
std::move(result));
|
|
737
|
+
auto js_result =
|
|
738
|
+
node_callback(env, std::move(result));
|
|
772
739
|
js_deferred->Resolve(js_result);
|
|
773
740
|
});
|
|
774
741
|
}
|
|
@@ -787,16 +754,14 @@ Napi::Promise NodePromiseFromPythonFuture(
|
|
|
787
754
|
});
|
|
788
755
|
|
|
789
756
|
// Allow Node to exit after we've resolved or rejected the promise.
|
|
790
|
-
auto js_resolve_reject =
|
|
791
|
-
env,
|
|
792
|
-
[](const Napi::CallbackInfo& info) {
|
|
757
|
+
auto js_resolve_reject =
|
|
758
|
+
Napi::Function::New(env, [](const Napi::CallbackInfo& info) {
|
|
793
759
|
adaptor->AllowNodeToExit(info.Env());
|
|
794
760
|
});
|
|
795
761
|
|
|
796
|
-
js_promise
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
.Call(js_promise, {js_resolve_reject, js_resolve_reject});
|
|
762
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
763
|
+
js_promise,
|
|
764
|
+
{js_resolve_reject, js_resolve_reject});
|
|
800
765
|
|
|
801
766
|
return js_promise;
|
|
802
767
|
}
|
|
@@ -815,9 +780,7 @@ Napi::Promise NodePromiseFromPythonFuture(
|
|
|
815
780
|
// TODO: check that `py_result` is `None`.
|
|
816
781
|
return std::nullopt;
|
|
817
782
|
},
|
|
818
|
-
[](Napi::Env env, std::nullopt_t) {
|
|
819
|
-
return env.Null();
|
|
820
|
-
});
|
|
783
|
+
[](Napi::Env env, std::nullopt_t) { return env.Null(); });
|
|
821
784
|
}
|
|
822
785
|
|
|
823
786
|
|
|
@@ -838,8 +801,8 @@ Napi::Promise NodePromiseFromPythonTask(
|
|
|
838
801
|
env,
|
|
839
802
|
[name,
|
|
840
803
|
create_task = std::move(create_task),
|
|
841
|
-
python_task_callback =
|
|
842
|
-
python_task_callback)]() mutable {
|
|
804
|
+
python_task_callback =
|
|
805
|
+
std::forward<PythonTaskCallback>(python_task_callback)]() mutable {
|
|
843
806
|
py::object py_task = std::apply(
|
|
844
807
|
[&name, &python_task_callback](
|
|
845
808
|
const std::string& import,
|
|
@@ -875,9 +838,7 @@ Napi::Promise NodePromiseFromPythonTask(
|
|
|
875
838
|
// TODO: check that `py_result` is `None`.
|
|
876
839
|
return std::nullopt;
|
|
877
840
|
},
|
|
878
|
-
[](Napi::Env env, std::nullopt_t) {
|
|
879
|
-
return env.Null();
|
|
880
|
-
});
|
|
841
|
+
[](Napi::Env env, std::nullopt_t) { return env.Null(); });
|
|
881
842
|
}
|
|
882
843
|
|
|
883
844
|
|
|
@@ -900,11 +861,9 @@ Napi::Promise NodePromiseFromPythonTaskWithContext(
|
|
|
900
861
|
std::string("rebootdev.nodejs.python"),
|
|
901
862
|
std::string("create_task_with_context"),
|
|
902
863
|
py_context),
|
|
903
|
-
[js_context,
|
|
904
|
-
python_task_callback =
|
|
905
|
-
|
|
906
|
-
return python_task_callback();
|
|
907
|
-
},
|
|
864
|
+
[js_context, // Ensures `py_context` remains valid.
|
|
865
|
+
python_task_callback = std::forward<PythonTaskCallback>(
|
|
866
|
+
python_task_callback)]() mutable { return python_task_callback(); },
|
|
908
867
|
std::forward<PythonDoneCallback>(python_done_callback),
|
|
909
868
|
std::forward<NodeCallback>(node_callback));
|
|
910
869
|
}
|
|
@@ -925,9 +884,7 @@ Napi::Promise NodePromiseFromPythonTaskWithContext(
|
|
|
925
884
|
// TODO: check that `py_result` is `None`.
|
|
926
885
|
return std::nullopt;
|
|
927
886
|
},
|
|
928
|
-
[](Napi::Env env, std::nullopt_t) {
|
|
929
|
-
return env.Null();
|
|
930
|
-
});
|
|
887
|
+
[](Napi::Env env, std::nullopt_t) { return env.Null(); });
|
|
931
888
|
}
|
|
932
889
|
|
|
933
890
|
|
|
@@ -952,64 +909,58 @@ py::object PythonFutureFromNodePromise(
|
|
|
952
909
|
try {
|
|
953
910
|
Napi::Object js_promise = node_promise_callback(env);
|
|
954
911
|
|
|
955
|
-
js_promise
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
.attr("Exception")(
|
|
1008
|
-
message));
|
|
1009
|
-
}
|
|
1010
|
-
delete py_future;
|
|
1011
|
-
});
|
|
1012
|
-
})});
|
|
912
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
913
|
+
js_promise,
|
|
914
|
+
{Napi::Function::New(
|
|
915
|
+
env,
|
|
916
|
+
[node_promise_resolved_callback =
|
|
917
|
+
std::forward<NodePromiseResolvedCallback>(
|
|
918
|
+
node_promise_resolved_callback),
|
|
919
|
+
python_callback =
|
|
920
|
+
std::forward<PythonCallback>(python_callback),
|
|
921
|
+
py_future](const Napi::CallbackInfo& info) mutable {
|
|
922
|
+
// TODO: put a try/catch around
|
|
923
|
+
// `node_promise_resolved_callback` to handle
|
|
924
|
+
// any errors.
|
|
925
|
+
|
|
926
|
+
auto result =
|
|
927
|
+
node_promise_resolved_callback(info.Env(), info[0]);
|
|
928
|
+
|
|
929
|
+
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
930
|
+
[python_callback =
|
|
931
|
+
std::forward<PythonCallback>(python_callback),
|
|
932
|
+
py_future,
|
|
933
|
+
result = std::move(result)]() mutable {
|
|
934
|
+
bool cancelled =
|
|
935
|
+
py_future->attr("cancelled")().cast<bool>();
|
|
936
|
+
if (!cancelled) {
|
|
937
|
+
// TODO: put a try/catch around
|
|
938
|
+
// `python_callback` to handle any
|
|
939
|
+
// errors.
|
|
940
|
+
py_future->attr("set_result")(
|
|
941
|
+
python_callback(std::move(result)));
|
|
942
|
+
}
|
|
943
|
+
delete py_future;
|
|
944
|
+
});
|
|
945
|
+
}),
|
|
946
|
+
Napi::Function::New(
|
|
947
|
+
env,
|
|
948
|
+
[py_future](const Napi::CallbackInfo& info) {
|
|
949
|
+
std::string message =
|
|
950
|
+
message_from_js_error(info[0].As<Napi::Object>());
|
|
951
|
+
|
|
952
|
+
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
953
|
+
[py_future, message = std::move(message)]() {
|
|
954
|
+
bool cancelled =
|
|
955
|
+
py_future->attr("cancelled")().cast<bool>();
|
|
956
|
+
if (!cancelled) {
|
|
957
|
+
py_future->attr("set_exception")(
|
|
958
|
+
py::module::import("builtins")
|
|
959
|
+
.attr("Exception")(message));
|
|
960
|
+
}
|
|
961
|
+
delete py_future;
|
|
962
|
+
});
|
|
963
|
+
})});
|
|
1013
964
|
} catch (const std::exception& e) {
|
|
1014
965
|
// NOTE: we're just catching exception here vs `Napi::Error`
|
|
1015
966
|
// since all we care about is `what()` but we're making sure
|
|
@@ -1021,31 +972,28 @@ py::object PythonFutureFromNodePromise(
|
|
|
1021
972
|
|
|
1022
973
|
std::string message = e.what();
|
|
1023
974
|
|
|
1024
|
-
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
});
|
|
975
|
+
adaptor->ScheduleCallbackOnPythonEventLoop([py_future,
|
|
976
|
+
message = std::move(
|
|
977
|
+
message)]() {
|
|
978
|
+
bool cancelled = py_future->attr("cancelled")().cast<bool>();
|
|
979
|
+
if (!cancelled) {
|
|
980
|
+
py_future->attr("set_exception")(
|
|
981
|
+
py::module::import("builtins").attr("Exception")(message));
|
|
982
|
+
}
|
|
983
|
+
delete py_future;
|
|
984
|
+
});
|
|
1035
985
|
} catch (...) {
|
|
1036
986
|
// TODO: is this code unreachable because Node.js
|
|
1037
987
|
// will properly always only pass us a `Napi::Error`?
|
|
1038
|
-
adaptor->ScheduleCallbackOnPythonEventLoop(
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
delete py_future;
|
|
1048
|
-
});
|
|
988
|
+
adaptor->ScheduleCallbackOnPythonEventLoop([py_future]() {
|
|
989
|
+
bool cancelled = py_future->attr("cancelled")().cast<bool>();
|
|
990
|
+
if (!cancelled) {
|
|
991
|
+
py_future->attr("set_exception")(
|
|
992
|
+
py::module::import("builtins")
|
|
993
|
+
.attr("Exception")("Unknown error"));
|
|
994
|
+
}
|
|
995
|
+
delete py_future;
|
|
996
|
+
});
|
|
1049
997
|
}
|
|
1050
998
|
});
|
|
1051
999
|
|
|
@@ -1053,19 +1001,14 @@ py::object PythonFutureFromNodePromise(
|
|
|
1053
1001
|
}
|
|
1054
1002
|
|
|
1055
1003
|
|
|
1056
|
-
template <
|
|
1057
|
-
typename NodePromiseCallback,
|
|
1058
|
-
typename NodePromiseResolvedCallback>
|
|
1004
|
+
template <typename NodePromiseCallback, typename NodePromiseResolvedCallback>
|
|
1059
1005
|
py::object PythonFutureFromNodePromise(
|
|
1060
1006
|
NodePromiseCallback&& node_promise_callback,
|
|
1061
1007
|
NodePromiseResolvedCallback&& node_promise_resolved_callback) {
|
|
1062
1008
|
return PythonFutureFromNodePromise(
|
|
1063
1009
|
std::forward<NodePromiseCallback>(node_promise_callback),
|
|
1064
|
-
std::forward<NodePromiseResolvedCallback>(
|
|
1065
|
-
|
|
1066
|
-
[](auto&& result) {
|
|
1067
|
-
return std::move(result);
|
|
1068
|
-
});
|
|
1010
|
+
std::forward<NodePromiseResolvedCallback>(node_promise_resolved_callback),
|
|
1011
|
+
[](auto&& result) { return std::move(result); });
|
|
1069
1012
|
}
|
|
1070
1013
|
|
|
1071
1014
|
|
|
@@ -1074,12 +1017,8 @@ py::object PythonFutureFromNodePromise(
|
|
|
1074
1017
|
NodePromiseCallback&& node_promise_callback) {
|
|
1075
1018
|
return PythonFutureFromNodePromise(
|
|
1076
1019
|
std::forward<NodePromiseCallback>(node_promise_callback),
|
|
1077
|
-
[](Napi::Env, Napi::Value) {
|
|
1078
|
-
|
|
1079
|
-
},
|
|
1080
|
-
[](auto&&) {
|
|
1081
|
-
return py::none();
|
|
1082
|
-
});
|
|
1020
|
+
[](Napi::Env, Napi::Value) { return std::nullopt; },
|
|
1021
|
+
[](auto&&) { return py::none(); });
|
|
1083
1022
|
}
|
|
1084
1023
|
|
|
1085
1024
|
|
|
@@ -1105,11 +1044,10 @@ void ImportPy(const Napi::CallbackInfo& info) {
|
|
|
1105
1044
|
std::string module = info[0].As<Napi::String>().Utf8Value();
|
|
1106
1045
|
std::string base64_encoded_rbt_py = info[1].As<Napi::String>().Utf8Value();
|
|
1107
1046
|
|
|
1108
|
-
RunCallbackOnPythonEventLoop(
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
});
|
|
1047
|
+
RunCallbackOnPythonEventLoop([&module, &base64_encoded_rbt_py]() {
|
|
1048
|
+
py::module::import("rebootdev.nodejs.python")
|
|
1049
|
+
.attr("import_py")(module, base64_encoded_rbt_py);
|
|
1050
|
+
});
|
|
1113
1051
|
}
|
|
1114
1052
|
|
|
1115
1053
|
|
|
@@ -1134,19 +1072,16 @@ napi_type_tag MakeTypeTag(const std::string& module, const std::string& type) {
|
|
|
1134
1072
|
}
|
|
1135
1073
|
|
|
1136
1074
|
|
|
1137
|
-
static const napi_type_tag reboot_aio_tests_Reboot =
|
|
1138
|
-
"reboot.aio.tests",
|
|
1139
|
-
"Reboot");
|
|
1075
|
+
static const napi_type_tag reboot_aio_tests_Reboot =
|
|
1076
|
+
MakeTypeTag("reboot.aio.tests", "Reboot");
|
|
1140
1077
|
|
|
1141
1078
|
|
|
1142
|
-
static const napi_type_tag reboot_aio_applications_Application =
|
|
1143
|
-
"reboot.aio.applications",
|
|
1144
|
-
"Application");
|
|
1079
|
+
static const napi_type_tag reboot_aio_applications_Application =
|
|
1080
|
+
MakeTypeTag("reboot.aio.applications", "Application");
|
|
1145
1081
|
|
|
1146
1082
|
|
|
1147
|
-
static const napi_type_tag reboot_aio_external_ExternalContext =
|
|
1148
|
-
"rebootdev.aio.external",
|
|
1149
|
-
"ExternalContext");
|
|
1083
|
+
static const napi_type_tag reboot_aio_external_ExternalContext =
|
|
1084
|
+
MakeTypeTag("rebootdev.aio.external", "ExternalContext");
|
|
1150
1085
|
|
|
1151
1086
|
|
|
1152
1087
|
Napi::Value python3Path(const Napi::CallbackInfo& info) {
|
|
@@ -1173,16 +1108,13 @@ std::string uint8array_to_str(const Napi::Uint8Array& arr) {
|
|
|
1173
1108
|
|
|
1174
1109
|
|
|
1175
1110
|
Napi::Value Reboot_constructor(const Napi::CallbackInfo& info) {
|
|
1176
|
-
py::object* py_reboot = RunCallbackOnPythonEventLoop(
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
});
|
|
1111
|
+
py::object* py_reboot = RunCallbackOnPythonEventLoop([]() {
|
|
1112
|
+
py::object tests = py::module::import("reboot.aio.tests");
|
|
1113
|
+
return new py::object(tests.attr("Reboot")());
|
|
1114
|
+
});
|
|
1181
1115
|
|
|
1182
|
-
Napi::External<py::object> js_external_reboot =
|
|
1183
|
-
info.Env(),
|
|
1184
|
-
py_reboot,
|
|
1185
|
-
&reboot_aio_tests_Reboot);
|
|
1116
|
+
Napi::External<py::object> js_external_reboot =
|
|
1117
|
+
make_napi_external(info.Env(), py_reboot, &reboot_aio_tests_Reboot);
|
|
1186
1118
|
|
|
1187
1119
|
return js_external_reboot;
|
|
1188
1120
|
}
|
|
@@ -1216,27 +1148,21 @@ Napi::Value Reboot_createExternalContext(const Napi::CallbackInfo& info) {
|
|
|
1216
1148
|
}
|
|
1217
1149
|
|
|
1218
1150
|
py::object* py_context = RunCallbackOnPythonEventLoop(
|
|
1219
|
-
[py_reboot,
|
|
1220
|
-
&name,
|
|
1221
|
-
&idempotency_seed,
|
|
1222
|
-
&bearer_token,
|
|
1223
|
-
app_internal]() {
|
|
1151
|
+
[py_reboot, &name, &idempotency_seed, &bearer_token, app_internal]() {
|
|
1224
1152
|
py::object py_idempotency_seed = py::none();
|
|
1225
1153
|
if (idempotency_seed.has_value()) {
|
|
1226
|
-
py_idempotency_seed =
|
|
1227
|
-
py::
|
|
1228
|
-
.attr("UUID")(py::str(*idempotency_seed));
|
|
1154
|
+
py_idempotency_seed = py::module::import("uuid").attr("UUID")(
|
|
1155
|
+
py::str(*idempotency_seed));
|
|
1229
1156
|
}
|
|
1230
1157
|
py::object py_bearer_token = py::none();
|
|
1231
1158
|
if (bearer_token.has_value()) {
|
|
1232
1159
|
py_bearer_token = py::str(*bearer_token);
|
|
1233
1160
|
}
|
|
1234
|
-
return new py::object(
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
"app_internal"_a = app_internal));
|
|
1161
|
+
return new py::object(py_reboot->attr("create_external_context")(
|
|
1162
|
+
"name"_a = name,
|
|
1163
|
+
"idempotency_seed"_a = py_idempotency_seed,
|
|
1164
|
+
"bearer_token"_a = py_bearer_token,
|
|
1165
|
+
"app_internal"_a = app_internal));
|
|
1240
1166
|
});
|
|
1241
1167
|
|
|
1242
1168
|
Napi::External<py::object> js_external_context = make_napi_external(
|
|
@@ -1244,17 +1170,14 @@ Napi::Value Reboot_createExternalContext(const Napi::CallbackInfo& info) {
|
|
|
1244
1170
|
py_context,
|
|
1245
1171
|
&reboot_aio_external_ExternalContext);
|
|
1246
1172
|
|
|
1247
|
-
return js_from_native_external
|
|
1248
|
-
.
|
|
1249
|
-
|
|
1250
|
-
{js_external_context});
|
|
1173
|
+
return js_from_native_external.Call(
|
|
1174
|
+
info.Env().Global(),
|
|
1175
|
+
{js_external_context});
|
|
1251
1176
|
}
|
|
1252
1177
|
|
|
1253
1178
|
|
|
1254
1179
|
// NOTE: must be called within _Node_.
|
|
1255
|
-
Napi::Promise make_js_cancelled(
|
|
1256
|
-
Napi::Env& env,
|
|
1257
|
-
py::object* py_cancelled) {
|
|
1180
|
+
Napi::Promise make_js_cancelled(Napi::Env& env, py::object* py_cancelled) {
|
|
1258
1181
|
return NodePromiseFromPythonFuture(
|
|
1259
1182
|
"make_js_cancelled",
|
|
1260
1183
|
env,
|
|
@@ -1303,8 +1226,7 @@ py::object make_py_authorizer(NapiSafeObjectReference js_authorizer) {
|
|
|
1303
1226
|
py::object py_cancelled,
|
|
1304
1227
|
std::string bytes_call) {
|
|
1305
1228
|
NapiSafeObjectReference* js_authorizer_reference =
|
|
1306
|
-
self.attr("_js_authorizer")
|
|
1307
|
-
.cast<NapiSafeObjectReference*>();
|
|
1229
|
+
self.attr("_js_authorizer").cast<NapiSafeObjectReference*>();
|
|
1308
1230
|
|
|
1309
1231
|
return PythonFutureFromNodePromise(
|
|
1310
1232
|
[js_authorizer_reference,
|
|
@@ -1346,12 +1268,11 @@ py::object make_py_authorizer(NapiSafeObjectReference js_authorizer) {
|
|
|
1346
1268
|
py::is_method(py::none()));
|
|
1347
1269
|
|
|
1348
1270
|
// Now define our subclass.
|
|
1349
|
-
py::object py_parent_class =
|
|
1350
|
-
|
|
1351
|
-
.attr("NodeAdaptorAuthorizer");
|
|
1271
|
+
py::object py_parent_class = py::module::import("rebootdev.nodejs.python")
|
|
1272
|
+
.attr("NodeAdaptorAuthorizer");
|
|
1352
1273
|
|
|
1353
|
-
py::object py_parent_metaclass =
|
|
1354
|
-
(PyObject*) &PyType_Type);
|
|
1274
|
+
py::object py_parent_metaclass =
|
|
1275
|
+
py::reinterpret_borrow<py::object>((PyObject*) &PyType_Type);
|
|
1355
1276
|
|
|
1356
1277
|
py::object py_class = py_parent_metaclass(
|
|
1357
1278
|
"_NodeAdaptorAuthorizer",
|
|
@@ -1389,20 +1310,14 @@ std::vector<std::shared_ptr<ServicerDetails>> make_servicer_details(
|
|
|
1389
1310
|
Napi::Function js_servicer_constructor = value.As<Napi::Function>();
|
|
1390
1311
|
|
|
1391
1312
|
std::string name =
|
|
1392
|
-
js_servicer_constructor
|
|
1393
|
-
.Get("name")
|
|
1394
|
-
.As<Napi::String>()
|
|
1395
|
-
.Utf8Value();
|
|
1313
|
+
js_servicer_constructor.Get("name").As<Napi::String>().Utf8Value();
|
|
1396
1314
|
|
|
1397
|
-
std::string rbt_module =
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
.As<Napi::String>()
|
|
1401
|
-
.Utf8Value();
|
|
1315
|
+
std::string rbt_module = js_servicer_constructor.Get("__rbtModule__")
|
|
1316
|
+
.As<Napi::String>()
|
|
1317
|
+
.Utf8Value();
|
|
1402
1318
|
|
|
1403
1319
|
std::string servicer_node_adaptor =
|
|
1404
|
-
js_servicer_constructor
|
|
1405
|
-
.Get("__servicerNodeAdaptor__")
|
|
1320
|
+
js_servicer_constructor.Get("__servicerNodeAdaptor__")
|
|
1406
1321
|
.As<Napi::String>()
|
|
1407
1322
|
.Utf8Value();
|
|
1408
1323
|
|
|
@@ -1418,23 +1333,17 @@ std::vector<std::shared_ptr<ServicerDetails>> make_servicer_details(
|
|
|
1418
1333
|
Napi::Persistent(js_servicer_constructor))}));
|
|
1419
1334
|
} else if (
|
|
1420
1335
|
value.IsObject()
|
|
1421
|
-
&& !value
|
|
1422
|
-
.As<Napi::Object>()
|
|
1336
|
+
&& !value.As<Napi::Object>()
|
|
1423
1337
|
.Get("nativeServicerModule")
|
|
1424
1338
|
.IsUndefined()) {
|
|
1425
|
-
std::string module =
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
.As<Napi::String>()
|
|
1430
|
-
.Utf8Value();
|
|
1339
|
+
std::string module = value.As<Napi::Object>()
|
|
1340
|
+
.Get("nativeServicerModule")
|
|
1341
|
+
.As<Napi::String>()
|
|
1342
|
+
.Utf8Value();
|
|
1431
1343
|
servicer_details.push_back(
|
|
1432
|
-
std::make_shared<ServicerDetails>(NativeServicerDetails{
|
|
1433
|
-
module}));
|
|
1344
|
+
std::make_shared<ServicerDetails>(NativeServicerDetails{module}));
|
|
1434
1345
|
} else {
|
|
1435
|
-
Napi::Error::New(
|
|
1436
|
-
env,
|
|
1437
|
-
"Unexpected `servicer` type.")
|
|
1346
|
+
Napi::Error::New(env, "Unexpected `servicer` type.")
|
|
1438
1347
|
.ThrowAsJavaScriptException();
|
|
1439
1348
|
}
|
|
1440
1349
|
}
|
|
@@ -1484,8 +1393,7 @@ py::object make_py_user_servicer(
|
|
|
1484
1393
|
Napi::External<py::object> js_external_self =
|
|
1485
1394
|
make_napi_external(env, py_self);
|
|
1486
1395
|
|
|
1487
|
-
js_servicer
|
|
1488
|
-
.Get("__storeExternal")
|
|
1396
|
+
js_servicer.Get("__storeExternal")
|
|
1489
1397
|
.As<Napi::Function>()
|
|
1490
1398
|
.Call(js_servicer, {js_external_self});
|
|
1491
1399
|
|
|
@@ -1505,11 +1413,11 @@ py::object make_py_user_servicer(
|
|
|
1505
1413
|
|
|
1506
1414
|
// Trampolines us from Python through C++ into Node for Servicer method
|
|
1507
1415
|
// calls.
|
|
1508
|
-
attributes["_trampoline"] =
|
|
1509
|
-
[](NapiSafeObjectReference& js_servicer_reference,
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1416
|
+
attributes["_trampoline"] =
|
|
1417
|
+
py::cpp_function([](NapiSafeObjectReference& js_servicer_reference,
|
|
1418
|
+
py::object py_context,
|
|
1419
|
+
py::object py_cancelled,
|
|
1420
|
+
std::string bytes_call) {
|
|
1513
1421
|
return PythonFutureFromNodePromise(
|
|
1514
1422
|
[&js_servicer_reference,
|
|
1515
1423
|
py_context = new py::object(py_context),
|
|
@@ -1528,11 +1436,9 @@ py::object make_py_user_servicer(
|
|
|
1528
1436
|
|
|
1529
1437
|
js_args.push_back(str_to_uint8array(env, bytes_call));
|
|
1530
1438
|
|
|
1531
|
-
Napi::Object js_servicer =
|
|
1532
|
-
js_servicer_reference.Value(env);
|
|
1439
|
+
Napi::Object js_servicer = js_servicer_reference.Value(env);
|
|
1533
1440
|
|
|
1534
|
-
return js_servicer
|
|
1535
|
-
.Get("__dispatch")
|
|
1441
|
+
return js_servicer.Get("__dispatch")
|
|
1536
1442
|
.As<Napi::Function>()
|
|
1537
1443
|
.Call(js_servicer, js_args)
|
|
1538
1444
|
.As<Napi::Object>();
|
|
@@ -1551,13 +1457,12 @@ py::object make_py_user_servicer(
|
|
|
1551
1457
|
std::optional<NapiSafeObjectReference> js_authorizer;
|
|
1552
1458
|
try {
|
|
1553
1459
|
js_authorizer = RunCallbackOnNodeEventLoop(
|
|
1554
|
-
[&js_servicer_reference](
|
|
1555
|
-
-> std::optional<NapiSafeObjectReference> {
|
|
1460
|
+
[&js_servicer_reference](
|
|
1461
|
+
Napi::Env env) -> std::optional<NapiSafeObjectReference> {
|
|
1556
1462
|
Napi::Object js_servicer = js_servicer_reference.Value(env);
|
|
1557
|
-
Napi::Value js_authorizer =
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
.Call(js_servicer, {});
|
|
1463
|
+
Napi::Value js_authorizer = js_servicer.Get("_authorizer")
|
|
1464
|
+
.As<Napi::Function>()
|
|
1465
|
+
.Call(js_servicer, {});
|
|
1561
1466
|
if (!js_authorizer.IsNull()) {
|
|
1562
1467
|
return NapiSafeObjectReference(
|
|
1563
1468
|
js_authorizer.As<Napi::Object>());
|
|
@@ -1587,8 +1492,8 @@ py::object make_py_user_servicer(
|
|
|
1587
1492
|
py::module::import(details.rbt_module.c_str())
|
|
1588
1493
|
.attr(details.servicer_node_adaptor.c_str());
|
|
1589
1494
|
|
|
1590
|
-
py::object py_metaclass =
|
|
1591
|
-
(PyObject*) &PyType_Type);
|
|
1495
|
+
py::object py_metaclass =
|
|
1496
|
+
py::reinterpret_borrow<py::object>((PyObject*) &PyType_Type);
|
|
1592
1497
|
|
|
1593
1498
|
// Our subclass will be in the `reboot_native` module with
|
|
1594
1499
|
// the same name as what is used in JS/TS, e.g.,
|
|
@@ -1606,8 +1511,7 @@ py::object make_py_user_servicer(
|
|
|
1606
1511
|
|
|
1607
1512
|
// NOTE: must be called from within _Python_.
|
|
1608
1513
|
py::list make_py_servicers(
|
|
1609
|
-
const std::vector<
|
|
1610
|
-
std::shared_ptr<ServicerDetails>>& servicer_details) {
|
|
1514
|
+
const std::vector<std::shared_ptr<ServicerDetails>>& servicer_details) {
|
|
1611
1515
|
py::module_ module = py::module::import("reboot_native");
|
|
1612
1516
|
|
|
1613
1517
|
py::list py_servicers;
|
|
@@ -1619,8 +1523,7 @@ py::list make_py_servicers(
|
|
|
1619
1523
|
auto native_details =
|
|
1620
1524
|
std::get_if<NativeServicerDetails>(details.get())) {
|
|
1621
1525
|
py_servicers.attr("extend")(
|
|
1622
|
-
py::module::import(
|
|
1623
|
-
native_details->py_servicers_module.c_str())
|
|
1526
|
+
py::module::import(native_details->py_servicers_module.c_str())
|
|
1624
1527
|
.attr("servicers")());
|
|
1625
1528
|
}
|
|
1626
1529
|
// TODO: Can I get exhaustiveness checking for the std::variant?
|
|
@@ -1659,8 +1562,7 @@ py::object make_py_token_verifier(NapiSafeObjectReference js_token_verifier) {
|
|
|
1659
1562
|
py::object py_cancelled,
|
|
1660
1563
|
std::string bytes_call) {
|
|
1661
1564
|
NapiSafeObjectReference* js_token_verifier_reference =
|
|
1662
|
-
self.attr("_js_token_verifier")
|
|
1663
|
-
.cast<NapiSafeObjectReference*>();
|
|
1565
|
+
self.attr("_js_token_verifier").cast<NapiSafeObjectReference*>();
|
|
1664
1566
|
|
|
1665
1567
|
return PythonFutureFromNodePromise(
|
|
1666
1568
|
[js_token_verifier_reference,
|
|
@@ -1687,8 +1589,7 @@ py::object make_py_token_verifier(NapiSafeObjectReference js_token_verifier) {
|
|
|
1687
1589
|
Napi::Object js_token_verifier =
|
|
1688
1590
|
js_token_verifier_reference->Value(env);
|
|
1689
1591
|
|
|
1690
|
-
return js_token_verifier
|
|
1691
|
-
.Get("_verifyToken")
|
|
1592
|
+
return js_token_verifier.Get("_verifyToken")
|
|
1692
1593
|
.As<Napi::Function>()
|
|
1693
1594
|
.Call(js_token_verifier, {js_args})
|
|
1694
1595
|
.As<Napi::Object>();
|
|
@@ -1714,12 +1615,11 @@ py::object make_py_token_verifier(NapiSafeObjectReference js_token_verifier) {
|
|
|
1714
1615
|
py::arg("bytes_call"),
|
|
1715
1616
|
py::is_method(py::none()));
|
|
1716
1617
|
|
|
1717
|
-
py::object py_parent_class =
|
|
1718
|
-
|
|
1719
|
-
.attr("NodeAdaptorTokenVerifier");
|
|
1618
|
+
py::object py_parent_class = py::module::import("rebootdev.nodejs.python")
|
|
1619
|
+
.attr("NodeAdaptorTokenVerifier");
|
|
1720
1620
|
|
|
1721
|
-
py::object py_parent_metaclass =
|
|
1722
|
-
(PyObject*) &PyType_Type);
|
|
1621
|
+
py::object py_parent_metaclass =
|
|
1622
|
+
py::reinterpret_borrow<py::object>((PyObject*) &PyType_Type);
|
|
1723
1623
|
|
|
1724
1624
|
py::object py_token_verifier = py_parent_metaclass(
|
|
1725
1625
|
"_NodeAdaptorTokenVerifier",
|
|
@@ -1734,19 +1634,19 @@ Napi::Value Reboot_up(const Napi::CallbackInfo& info) {
|
|
|
1734
1634
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1735
1635
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1736
1636
|
// get out of it will remain valid.
|
|
1737
|
-
auto js_external_reboot =
|
|
1738
|
-
info[0].As<Napi::External<py::object>>());
|
|
1637
|
+
auto js_external_reboot =
|
|
1638
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1739
1639
|
|
|
1740
1640
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1741
1641
|
|
|
1742
1642
|
py::object* py_reboot = js_external_reboot.Value(info.Env()).Data();
|
|
1743
1643
|
|
|
1744
|
-
auto js_external_application =
|
|
1745
|
-
info[1].As<Napi::External<py::object>>());
|
|
1644
|
+
auto js_external_application =
|
|
1645
|
+
NapiSafeReference(info[1].As<Napi::External<py::object>>());
|
|
1746
1646
|
|
|
1747
1647
|
py::object* py_application = js_external_application.Value(info.Env()).Data();
|
|
1748
1648
|
|
|
1749
|
-
bool local_envoy
|
|
1649
|
+
std::optional<bool> local_envoy;
|
|
1750
1650
|
if (!info[2].IsUndefined()) {
|
|
1751
1651
|
local_envoy = info[2].As<Napi::Boolean>();
|
|
1752
1652
|
}
|
|
@@ -1760,12 +1660,16 @@ Napi::Value Reboot_up(const Napi::CallbackInfo& info) {
|
|
|
1760
1660
|
info.Env(),
|
|
1761
1661
|
"Reboot.up(...) in nodejs",
|
|
1762
1662
|
{"asyncio", "create_task"},
|
|
1763
|
-
[js_external_reboot,
|
|
1663
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1764
1664
|
py_reboot,
|
|
1765
|
-
js_external_application,
|
|
1665
|
+
js_external_application, // Ensures `py_application` remains valid.
|
|
1766
1666
|
py_application,
|
|
1767
1667
|
local_envoy,
|
|
1768
1668
|
local_envoy_port]() {
|
|
1669
|
+
py::object py_local_envoy = py::none();
|
|
1670
|
+
if (local_envoy.has_value()) {
|
|
1671
|
+
py_local_envoy = py::bool_(*local_envoy);
|
|
1672
|
+
}
|
|
1769
1673
|
return py_reboot->attr("up")(
|
|
1770
1674
|
py_application,
|
|
1771
1675
|
// NOTE: while we support subprocess servers
|
|
@@ -1774,7 +1678,7 @@ Napi::Value Reboot_up(const Napi::CallbackInfo& info) {
|
|
|
1774
1678
|
// clone a process like we do with multiprocessing
|
|
1775
1679
|
// in Python.
|
|
1776
1680
|
"in_process"_a = true,
|
|
1777
|
-
"local_envoy"_a =
|
|
1681
|
+
"local_envoy"_a = py_local_envoy,
|
|
1778
1682
|
"local_envoy_port"_a = local_envoy_port);
|
|
1779
1683
|
},
|
|
1780
1684
|
[](py::object py_revision) {
|
|
@@ -1790,8 +1694,8 @@ Napi::Value Reboot_up(const Napi::CallbackInfo& info) {
|
|
|
1790
1694
|
}
|
|
1791
1695
|
|
|
1792
1696
|
Napi::Value Reboot_down(const Napi::CallbackInfo& info) {
|
|
1793
|
-
auto js_external_reboot =
|
|
1794
|
-
info[0].As<Napi::External<py::object>>());
|
|
1697
|
+
auto js_external_reboot =
|
|
1698
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1795
1699
|
|
|
1796
1700
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1797
1701
|
|
|
@@ -1801,18 +1705,16 @@ Napi::Value Reboot_down(const Napi::CallbackInfo& info) {
|
|
|
1801
1705
|
info.Env(),
|
|
1802
1706
|
"Reboot.down() in nodejs",
|
|
1803
1707
|
{"asyncio", "create_task"},
|
|
1804
|
-
[js_external_reboot,
|
|
1805
|
-
py_reboot]() {
|
|
1806
|
-
return py_reboot->attr("down")();
|
|
1807
|
-
});
|
|
1708
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1709
|
+
py_reboot]() { return py_reboot->attr("down")(); });
|
|
1808
1710
|
}
|
|
1809
1711
|
|
|
1810
1712
|
Napi::Value Reboot_start(const Napi::CallbackInfo& info) {
|
|
1811
1713
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1812
1714
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1813
1715
|
// get out of it will remain valid.
|
|
1814
|
-
auto js_external_reboot =
|
|
1815
|
-
info[0].As<Napi::External<py::object>>());
|
|
1716
|
+
auto js_external_reboot =
|
|
1717
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1816
1718
|
|
|
1817
1719
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1818
1720
|
|
|
@@ -1826,18 +1728,16 @@ Napi::Value Reboot_start(const Napi::CallbackInfo& info) {
|
|
|
1826
1728
|
info.Env(),
|
|
1827
1729
|
"Reboot.start() in nodejs",
|
|
1828
1730
|
{"asyncio", "create_task"},
|
|
1829
|
-
[js_external_reboot,
|
|
1830
|
-
py_reboot]() {
|
|
1831
|
-
return py_reboot->attr("start")();
|
|
1832
|
-
});
|
|
1731
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1732
|
+
py_reboot]() { return py_reboot->attr("start")(); });
|
|
1833
1733
|
}
|
|
1834
1734
|
|
|
1835
1735
|
Napi::Value Reboot_stop(const Napi::CallbackInfo& info) {
|
|
1836
1736
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1837
1737
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1838
1738
|
// get out of it will remain valid.
|
|
1839
|
-
auto js_external_reboot =
|
|
1840
|
-
info[0].As<Napi::External<py::object>>());
|
|
1739
|
+
auto js_external_reboot =
|
|
1740
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1841
1741
|
|
|
1842
1742
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1843
1743
|
|
|
@@ -1847,22 +1747,18 @@ Napi::Value Reboot_stop(const Napi::CallbackInfo& info) {
|
|
|
1847
1747
|
info.Env(),
|
|
1848
1748
|
"Reboot.stop() in nodejs",
|
|
1849
1749
|
{"asyncio", "create_task"},
|
|
1850
|
-
[js_external_reboot,
|
|
1851
|
-
py_reboot]() {
|
|
1852
|
-
return py_reboot->attr("stop")();
|
|
1853
|
-
});
|
|
1750
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1751
|
+
py_reboot]() { return py_reboot->attr("stop")(); });
|
|
1854
1752
|
|
|
1855
1753
|
// Allow Node to exit after we've resolved or rejected the promise.
|
|
1856
|
-
auto js_resolve_reject =
|
|
1857
|
-
info.Env(),
|
|
1858
|
-
[](const Napi::CallbackInfo& info) {
|
|
1754
|
+
auto js_resolve_reject =
|
|
1755
|
+
Napi::Function::New(info.Env(), [](const Napi::CallbackInfo& info) {
|
|
1859
1756
|
adaptor->AllowNodeToExit(info.Env());
|
|
1860
1757
|
});
|
|
1861
1758
|
|
|
1862
|
-
js_promise
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
.Call(js_promise, {js_resolve_reject, js_resolve_reject});
|
|
1759
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
1760
|
+
js_promise,
|
|
1761
|
+
{js_resolve_reject, js_resolve_reject});
|
|
1866
1762
|
|
|
1867
1763
|
return js_promise;
|
|
1868
1764
|
}
|
|
@@ -1873,18 +1769,17 @@ Napi::Value Reboot_url(const Napi::CallbackInfo& info) {
|
|
|
1873
1769
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1874
1770
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1875
1771
|
// get out of it will remain valid.
|
|
1876
|
-
auto js_external_reboot =
|
|
1877
|
-
info[0].As<Napi::External<py::object>>());
|
|
1772
|
+
auto js_external_reboot =
|
|
1773
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1878
1774
|
|
|
1879
1775
|
// CHECK(...CheckTypeTag(...));
|
|
1880
1776
|
|
|
1881
1777
|
py::object* py_reboot = js_external_reboot.Value(info.Env()).Data();
|
|
1882
1778
|
|
|
1883
|
-
std::string url = RunCallbackOnPythonEventLoop(
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
});
|
|
1779
|
+
std::string url = RunCallbackOnPythonEventLoop([py_reboot]() {
|
|
1780
|
+
py::str url = py_reboot->attr("url")();
|
|
1781
|
+
return std::string(url);
|
|
1782
|
+
});
|
|
1888
1783
|
|
|
1889
1784
|
return Napi::String::New(info.Env(), url);
|
|
1890
1785
|
}
|
|
@@ -1900,13 +1795,11 @@ Napi::Value Service_constructor(const Napi::CallbackInfo& info) {
|
|
|
1900
1795
|
|
|
1901
1796
|
std::string id = js_args.Get("id").As<Napi::String>().Utf8Value();
|
|
1902
1797
|
|
|
1903
|
-
py::object* py_service =
|
|
1904
|
-
[&rbt_module, &node_adaptor, &id]() {
|
|
1798
|
+
py::object* py_service =
|
|
1799
|
+
RunCallbackOnPythonEventLoop([&rbt_module, &node_adaptor, &id]() {
|
|
1905
1800
|
py::object py_module = py::module::import(rbt_module.c_str());
|
|
1906
1801
|
py::object py_schedule_type =
|
|
1907
|
-
py_module
|
|
1908
|
-
.attr(node_adaptor.c_str())
|
|
1909
|
-
.attr("_Schedule");
|
|
1802
|
+
py_module.attr(node_adaptor.c_str()).attr("_Schedule");
|
|
1910
1803
|
return new py::object(py_module.attr(node_adaptor.c_str())(
|
|
1911
1804
|
// The call will stay within the same application.
|
|
1912
1805
|
"application_id"_a = py::none(),
|
|
@@ -1950,8 +1843,7 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1950
1843
|
|
|
1951
1844
|
// CHECK(...CheckTypeTag(...));
|
|
1952
1845
|
|
|
1953
|
-
py::object* py_context =
|
|
1954
|
-
js_external_context.Value(info.Env()).Data();
|
|
1846
|
+
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
1955
1847
|
|
|
1956
1848
|
std::string json_request = js_args.Get("jsonRequest").As<Napi::String>();
|
|
1957
1849
|
|
|
@@ -1961,13 +1853,13 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1961
1853
|
info.Env(),
|
|
1962
1854
|
"servicer._" + kind + "(\"" + method + "\", ...) in nodejs",
|
|
1963
1855
|
js_external_context,
|
|
1964
|
-
[js_external_service,
|
|
1856
|
+
[js_external_service, // Ensures `py_service` remains valid.
|
|
1965
1857
|
py_service,
|
|
1966
1858
|
kind,
|
|
1967
1859
|
method,
|
|
1968
1860
|
request_module,
|
|
1969
1861
|
request_type,
|
|
1970
|
-
js_external_context,
|
|
1862
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
1971
1863
|
py_context,
|
|
1972
1864
|
json_request,
|
|
1973
1865
|
json_options]() {
|
|
@@ -1994,9 +1886,7 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1994
1886
|
json_request,
|
|
1995
1887
|
json_options);
|
|
1996
1888
|
},
|
|
1997
|
-
[](py::object py_json) {
|
|
1998
|
-
return py_json.cast<std::string>();
|
|
1999
|
-
},
|
|
1889
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2000
1890
|
[](Napi::Env env, std::string&& json) {
|
|
2001
1891
|
return Napi::String::New(env, json);
|
|
2002
1892
|
});
|
|
@@ -2014,8 +1904,7 @@ Napi::Value Task_await(const Napi::CallbackInfo& info) {
|
|
|
2014
1904
|
|
|
2015
1905
|
// CHECK(...CheckTypeTag(...));
|
|
2016
1906
|
|
|
2017
|
-
py::object* py_context =
|
|
2018
|
-
js_external_context.Value(info.Env()).Data();
|
|
1907
|
+
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2019
1908
|
|
|
2020
1909
|
std::string rbt_module = js_args.Get("rbtModule").As<Napi::String>();
|
|
2021
1910
|
|
|
@@ -2027,27 +1916,23 @@ Napi::Value Task_await(const Napi::CallbackInfo& info) {
|
|
|
2027
1916
|
|
|
2028
1917
|
return NodePromiseFromPythonTaskWithContext(
|
|
2029
1918
|
info.Env(),
|
|
2030
|
-
"rebootdev.nodejs.python.task_await(\""
|
|
2031
|
-
+
|
|
2032
|
-
+ method + "\", ...) in nodejs",
|
|
1919
|
+
"rebootdev.nodejs.python.task_await(\"" + state_name + "\", \"" + method
|
|
1920
|
+
+ "\", ...) in nodejs",
|
|
2033
1921
|
js_external_context,
|
|
2034
1922
|
[rbt_module = std::move(rbt_module),
|
|
2035
1923
|
state_name = std::move(state_name),
|
|
2036
1924
|
method = std::move(method),
|
|
2037
|
-
js_external_context,
|
|
1925
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2038
1926
|
py_context,
|
|
2039
1927
|
json_task_id]() {
|
|
2040
1928
|
return py::module::import("rebootdev.nodejs.python")
|
|
2041
1929
|
.attr("task_await")(
|
|
2042
1930
|
py_context,
|
|
2043
|
-
py::module::import(rbt_module.c_str())
|
|
2044
|
-
.attr(state_name.c_str()),
|
|
1931
|
+
py::module::import(rbt_module.c_str()).attr(state_name.c_str()),
|
|
2045
1932
|
method,
|
|
2046
1933
|
json_task_id);
|
|
2047
1934
|
},
|
|
2048
|
-
[](py::object py_json) {
|
|
2049
|
-
return py_json.cast<std::string>();
|
|
2050
|
-
},
|
|
1935
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2051
1936
|
[](Napi::Env env, std::string&& json) {
|
|
2052
1937
|
return Napi::String::New(env, json);
|
|
2053
1938
|
});
|
|
@@ -2078,21 +1963,17 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2078
1963
|
|
|
2079
1964
|
std::optional<std::string> idempotency_required_reason;
|
|
2080
1965
|
if (!info[6].IsUndefined()) {
|
|
2081
|
-
idempotency_required_reason =
|
|
2082
|
-
info[6]
|
|
2083
|
-
.As<Napi::String>()
|
|
2084
|
-
.Utf8Value();
|
|
1966
|
+
idempotency_required_reason = info[6].As<Napi::String>().Utf8Value();
|
|
2085
1967
|
}
|
|
2086
1968
|
|
|
2087
|
-
py::object* py_external_context =
|
|
2088
|
-
[&name,
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
py::object py_external = py::module::import(
|
|
2095
|
-
"rebootdev.aio.external");
|
|
1969
|
+
py::object* py_external_context =
|
|
1970
|
+
RunCallbackOnPythonEventLoop([&name,
|
|
1971
|
+
&url,
|
|
1972
|
+
&bearer_token,
|
|
1973
|
+
&idempotency_seed,
|
|
1974
|
+
&idempotency_required,
|
|
1975
|
+
&idempotency_required_reason]() {
|
|
1976
|
+
py::object py_external = py::module::import("rebootdev.aio.external");
|
|
2096
1977
|
|
|
2097
1978
|
auto convert_str =
|
|
2098
1979
|
[](const std::optional<std::string>& optional) -> py::object {
|
|
@@ -2109,8 +1990,8 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2109
1990
|
"bearer_token"_a = convert_str(bearer_token),
|
|
2110
1991
|
"idempotency_seed"_a = convert_str(idempotency_seed),
|
|
2111
1992
|
"idempotency_required"_a = py::bool_(idempotency_required),
|
|
2112
|
-
"idempotency_required_reason"_a =
|
|
2113
|
-
idempotency_required_reason)));
|
|
1993
|
+
"idempotency_required_reason"_a =
|
|
1994
|
+
convert_str(idempotency_required_reason)));
|
|
2114
1995
|
});
|
|
2115
1996
|
|
|
2116
1997
|
Napi::External<py::object> js_external_context = make_napi_external(
|
|
@@ -2122,8 +2003,8 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2122
2003
|
}
|
|
2123
2004
|
|
|
2124
2005
|
Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
2125
|
-
auto js_from_native_external =
|
|
2126
|
-
info[0].As<Napi::Function>());
|
|
2006
|
+
auto js_from_native_external =
|
|
2007
|
+
NapiSafeFunctionReference(info[0].As<Napi::Function>());
|
|
2127
2008
|
|
|
2128
2009
|
Napi::Array js_servicers = info[1].As<Napi::Array>();
|
|
2129
2010
|
|
|
@@ -2137,8 +2018,7 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2137
2018
|
|
|
2138
2019
|
auto servicer_details = make_servicer_details(info.Env(), js_servicers);
|
|
2139
2020
|
|
|
2140
|
-
auto js_initialize = NapiSafeFunctionReference(
|
|
2141
|
-
info[3].As<Napi::Function>());
|
|
2021
|
+
auto js_initialize = NapiSafeFunctionReference(info[3].As<Napi::Function>());
|
|
2142
2022
|
|
|
2143
2023
|
std::optional<std::string> initialize_bearer_token;
|
|
2144
2024
|
if (!info[4].IsUndefined()) {
|
|
@@ -2184,31 +2064,27 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2184
2064
|
Napi::Function js_create_external_context =
|
|
2185
2065
|
Napi::Function::New(
|
|
2186
2066
|
env,
|
|
2187
|
-
[js_from_native_external =
|
|
2188
|
-
js_from_native_external),
|
|
2067
|
+
[js_from_native_external =
|
|
2068
|
+
std::move(js_from_native_external),
|
|
2189
2069
|
// Ensures `py_channel_manager` remains valid.
|
|
2190
2070
|
js_external_channel_manager = NapiSafeReference(
|
|
2191
2071
|
js_external_channel_manager)](
|
|
2192
2072
|
const Napi::CallbackInfo& info) mutable {
|
|
2193
2073
|
Napi::Object js_args = info[0].As<Napi::Object>();
|
|
2194
2074
|
|
|
2195
|
-
std::string name =
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
.As<Napi::String>()
|
|
2199
|
-
.Utf8Value();
|
|
2075
|
+
std::string name = js_args.Get("name")
|
|
2076
|
+
.As<Napi::String>()
|
|
2077
|
+
.Utf8Value();
|
|
2200
2078
|
|
|
2201
2079
|
std::optional<std::string> bearer_token;
|
|
2202
2080
|
if (!js_args.Get("bearerToken").IsUndefined()) {
|
|
2203
|
-
bearer_token =
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
.Utf8Value();
|
|
2081
|
+
bearer_token = js_args.Get("bearerToken")
|
|
2082
|
+
.As<Napi::String>()
|
|
2083
|
+
.Utf8Value();
|
|
2207
2084
|
}
|
|
2208
2085
|
|
|
2209
2086
|
py::object* py_channel_manager =
|
|
2210
|
-
js_external_channel_manager
|
|
2211
|
-
.Value(info.Env())
|
|
2087
|
+
js_external_channel_manager.Value(info.Env())
|
|
2212
2088
|
.Data();
|
|
2213
2089
|
|
|
2214
2090
|
return NodePromiseFromPythonCallback(
|
|
@@ -2246,32 +2122,30 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2246
2122
|
js_from_native_external](
|
|
2247
2123
|
Napi::Env env,
|
|
2248
2124
|
py::object* py_context) {
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
make_napi_external(
|
|
2125
|
+
Napi::External<py::object>
|
|
2126
|
+
// (check_line_length skip)
|
|
2127
|
+
js_external_context = make_napi_external(
|
|
2252
2128
|
env,
|
|
2253
2129
|
py_context,
|
|
2254
2130
|
// (check_line_length skip)
|
|
2255
2131
|
&reboot_aio_external_ExternalContext);
|
|
2256
2132
|
|
|
2257
|
-
return js_from_native_external
|
|
2258
|
-
.Value(env)
|
|
2133
|
+
return js_from_native_external.Value(env)
|
|
2259
2134
|
.Call(
|
|
2260
2135
|
env.Global(),
|
|
2261
2136
|
{js_external_context,
|
|
2262
|
-
|
|
2263
|
-
|
|
2137
|
+
Napi::String::New(
|
|
2138
|
+
env,
|
|
2139
|
+
"external")});
|
|
2264
2140
|
});
|
|
2265
2141
|
});
|
|
2266
2142
|
|
|
2267
|
-
return js_web_framework_start
|
|
2268
|
-
.Value(env)
|
|
2143
|
+
return js_web_framework_start.Value(env)
|
|
2269
2144
|
.Call(
|
|
2270
2145
|
env.Global(),
|
|
2271
2146
|
{Napi::String::New(env, server_id),
|
|
2272
|
-
port.has_value()
|
|
2273
|
-
|
|
2274
|
-
: env.Null(),
|
|
2147
|
+
port.has_value() ? Napi::Number::New(env, *port)
|
|
2148
|
+
: env.Null(),
|
|
2275
2149
|
js_create_external_context})
|
|
2276
2150
|
.As<Napi::Object>();
|
|
2277
2151
|
},
|
|
@@ -2282,17 +2156,13 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2282
2156
|
});
|
|
2283
2157
|
|
|
2284
2158
|
py::object py_web_framework_stop = py::cpp_function(
|
|
2285
|
-
[js_web_framework_stop =
|
|
2286
|
-
|
|
2159
|
+
[js_web_framework_stop =
|
|
2160
|
+
std::move(js_web_framework_stop)](std::string server_id) {
|
|
2287
2161
|
return PythonFutureFromNodePromise(
|
|
2288
2162
|
[js_web_framework_stop = std::move(js_web_framework_stop),
|
|
2289
|
-
server_id = std::move(server_id)](
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
.Value(env)
|
|
2293
|
-
.Call(
|
|
2294
|
-
env.Global(),
|
|
2295
|
-
{Napi::String::New(env, server_id)})
|
|
2163
|
+
server_id = std::move(server_id)](Napi::Env env) mutable {
|
|
2164
|
+
return js_web_framework_stop.Value(env)
|
|
2165
|
+
.Call(env.Global(), {Napi::String::New(env, server_id)})
|
|
2296
2166
|
.As<Napi::Object>();
|
|
2297
2167
|
});
|
|
2298
2168
|
});
|
|
@@ -2303,15 +2173,15 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2303
2173
|
py::object py_context) mutable {
|
|
2304
2174
|
return PythonFutureFromNodePromise(
|
|
2305
2175
|
[js_initialize,
|
|
2306
|
-
js_from_native_external,
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
py_context =
|
|
2314
|
-
|
|
2176
|
+
js_from_native_external, // NOTE: need a _copy_ of
|
|
2177
|
+
// both `js_initialize`
|
|
2178
|
+
// and
|
|
2179
|
+
// `js_from_native_external`
|
|
2180
|
+
// here since
|
|
2181
|
+
// `py_initialize` may be
|
|
2182
|
+
// called more than once!
|
|
2183
|
+
py_context =
|
|
2184
|
+
new py::object(py_context)](Napi::Env env) mutable {
|
|
2315
2185
|
Napi::External<py::object> js_external_context =
|
|
2316
2186
|
make_napi_external(
|
|
2317
2187
|
env,
|
|
@@ -2319,16 +2189,14 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2319
2189
|
&reboot_aio_external_ExternalContext);
|
|
2320
2190
|
|
|
2321
2191
|
Napi::Object js_context =
|
|
2322
|
-
js_from_native_external
|
|
2323
|
-
.Value(env)
|
|
2192
|
+
js_from_native_external.Value(env)
|
|
2324
2193
|
.Call(
|
|
2325
2194
|
env.Global(),
|
|
2326
2195
|
{js_external_context,
|
|
2327
2196
|
Napi::String::New(env, "initialize")})
|
|
2328
2197
|
.As<Napi::Object>();
|
|
2329
2198
|
|
|
2330
|
-
return js_initialize
|
|
2331
|
-
.Value(env)
|
|
2199
|
+
return js_initialize.Value(env)
|
|
2332
2200
|
.Call(env.Global(), {js_context})
|
|
2333
2201
|
.As<Napi::Object>();
|
|
2334
2202
|
});
|
|
@@ -2351,8 +2219,7 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2351
2219
|
"web_framework_start"_a = py_web_framework_start,
|
|
2352
2220
|
"web_framework_stop"_a = py_web_framework_stop,
|
|
2353
2221
|
"initialize"_a = py_initialize,
|
|
2354
|
-
"initialize_bearer_token"_a =
|
|
2355
|
-
py_initialize_bearer_token,
|
|
2222
|
+
"initialize_bearer_token"_a = py_initialize_bearer_token,
|
|
2356
2223
|
"token_verifier"_a = py_token_verifier));
|
|
2357
2224
|
});
|
|
2358
2225
|
|
|
@@ -2370,47 +2237,37 @@ Napi::Value Application_run(const Napi::CallbackInfo& info) {
|
|
|
2370
2237
|
// that we can get calls from Python.
|
|
2371
2238
|
adaptor->KeepNodeFromExiting(info.Env());
|
|
2372
2239
|
|
|
2373
|
-
auto js_external_application =
|
|
2374
|
-
info[0].As<Napi::External<py::object>>());
|
|
2240
|
+
auto js_external_application =
|
|
2241
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2375
2242
|
|
|
2376
|
-
py::object* py_application =
|
|
2377
|
-
js_external_application.Value(info.Env()).Data();
|
|
2243
|
+
py::object* py_application = js_external_application.Value(info.Env()).Data();
|
|
2378
2244
|
|
|
2379
2245
|
Napi::Promise js_promise = NodePromiseFromPythonTask(
|
|
2380
2246
|
info.Env(),
|
|
2381
2247
|
"Application.run() in nodejs",
|
|
2382
2248
|
{"rebootdev.nodejs.python", "create_task"},
|
|
2383
|
-
[js_external_application,
|
|
2384
|
-
py_application]() {
|
|
2385
|
-
return py_application->attr("run")();
|
|
2386
|
-
});
|
|
2249
|
+
[js_external_application, // Ensures `py_application` remains valid.
|
|
2250
|
+
py_application]() { return py_application->attr("run")(); });
|
|
2387
2251
|
|
|
2388
2252
|
// More to do if `Application.run` returns ...
|
|
2389
|
-
js_promise
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
.Get("process")
|
|
2408
|
-
.As<Napi::Object>()
|
|
2409
|
-
.Set("exitCode", 1);
|
|
2410
|
-
|
|
2411
|
-
// Allow Node to exit after `Application.run` returns.
|
|
2412
|
-
adaptor->AllowNodeToExit(info.Env());
|
|
2413
|
-
})});
|
|
2253
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
2254
|
+
js_promise,
|
|
2255
|
+
{Napi::Function::New(
|
|
2256
|
+
info.Env(),
|
|
2257
|
+
[](const Napi::CallbackInfo& info) {
|
|
2258
|
+
// Allow Node to exit after `Application.run` returns.
|
|
2259
|
+
adaptor->AllowNodeToExit(info.Env());
|
|
2260
|
+
}),
|
|
2261
|
+
Napi::Function::New(info.Env(), [](const Napi::CallbackInfo& info) {
|
|
2262
|
+
// There was an error, let's also set the
|
|
2263
|
+
// `process.exitCode` to reflect this.
|
|
2264
|
+
info.Env().Global().Get("process").As<Napi::Object>().Set(
|
|
2265
|
+
"exitCode",
|
|
2266
|
+
1);
|
|
2267
|
+
|
|
2268
|
+
// Allow Node to exit after `Application.run` returns.
|
|
2269
|
+
adaptor->AllowNodeToExit(info.Env());
|
|
2270
|
+
})});
|
|
2414
2271
|
|
|
2415
2272
|
return js_promise;
|
|
2416
2273
|
}
|
|
@@ -2420,22 +2277,18 @@ Napi::Value Context_generateIdempotentStateId(const Napi::CallbackInfo& info) {
|
|
|
2420
2277
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
2421
2278
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
2422
2279
|
// get out of it will remain valid.
|
|
2423
|
-
auto js_external_context =
|
|
2424
|
-
info[0].As<Napi::External<py::object>>());
|
|
2280
|
+
auto js_external_context =
|
|
2281
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2425
2282
|
|
|
2426
2283
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2427
2284
|
|
|
2428
|
-
std::string state_type =
|
|
2429
|
-
info[1].As<Napi::String>().Utf8Value();
|
|
2285
|
+
std::string state_type = info[1].As<Napi::String>().Utf8Value();
|
|
2430
2286
|
|
|
2431
|
-
std::string service_name =
|
|
2432
|
-
info[2].As<Napi::String>().Utf8Value();
|
|
2287
|
+
std::string service_name = info[2].As<Napi::String>().Utf8Value();
|
|
2433
2288
|
|
|
2434
|
-
std::string method =
|
|
2435
|
-
info[3].As<Napi::String>().Utf8Value();
|
|
2289
|
+
std::string method = info[3].As<Napi::String>().Utf8Value();
|
|
2436
2290
|
|
|
2437
|
-
Napi::Object idempotency_options =
|
|
2438
|
-
info[4].As<Napi::Object>();
|
|
2291
|
+
Napi::Object idempotency_options = info[4].As<Napi::Object>();
|
|
2439
2292
|
auto js_key = idempotency_options.Get("key");
|
|
2440
2293
|
std::optional<std::string> key;
|
|
2441
2294
|
if (js_key.IsString()) {
|
|
@@ -2454,7 +2307,7 @@ Napi::Value Context_generateIdempotentStateId(const Napi::CallbackInfo& info) {
|
|
|
2454
2307
|
|
|
2455
2308
|
return NodePromiseFromPythonCallback(
|
|
2456
2309
|
info.Env(),
|
|
2457
|
-
[js_external_context,
|
|
2310
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2458
2311
|
py_context,
|
|
2459
2312
|
state_type = std::move(state_type),
|
|
2460
2313
|
service_name = std::move(service_name),
|
|
@@ -2510,25 +2363,23 @@ Napi::Value WriterContext_set_sync(const Napi::CallbackInfo& info) {
|
|
|
2510
2363
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
2511
2364
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
2512
2365
|
// get out of it will remain valid.
|
|
2513
|
-
auto js_external_context =
|
|
2514
|
-
info[0].As<Napi::External<py::object>>());
|
|
2366
|
+
auto js_external_context =
|
|
2367
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2515
2368
|
|
|
2516
2369
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2517
2370
|
|
|
2518
2371
|
bool sync = info[1].As<Napi::Boolean>();
|
|
2519
2372
|
|
|
2520
2373
|
RunCallbackOnPythonEventLoop(
|
|
2521
|
-
[&py_context, sync]() {
|
|
2522
|
-
py_context->attr("sync") = sync;
|
|
2523
|
-
});
|
|
2374
|
+
[&py_context, sync]() { py_context->attr("sync") = sync; });
|
|
2524
2375
|
|
|
2525
2376
|
return info.Env().Undefined();
|
|
2526
2377
|
}
|
|
2527
2378
|
|
|
2528
2379
|
|
|
2529
2380
|
Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
2530
|
-
auto js_external_context =
|
|
2531
|
-
info[0].As<Napi::External<py::object>>());
|
|
2381
|
+
auto js_external_context =
|
|
2382
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2532
2383
|
|
|
2533
2384
|
// CHECK(...CheckTypeTag(...));
|
|
2534
2385
|
|
|
@@ -2540,51 +2391,47 @@ Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
|
2540
2391
|
info.Env(),
|
|
2541
2392
|
"context.loop(...) in nodejs",
|
|
2542
2393
|
js_external_context,
|
|
2543
|
-
[js_external_context,
|
|
2394
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2544
2395
|
py_context,
|
|
2545
2396
|
alias = std::move(alias)]() {
|
|
2546
2397
|
return py::module::import("rebootdev.nodejs.python")
|
|
2547
2398
|
.attr("loop")(py_context, alias);
|
|
2548
2399
|
},
|
|
2549
|
-
[](py::object py_iterate) {
|
|
2550
|
-
return new py::object(py_iterate);
|
|
2551
|
-
},
|
|
2400
|
+
[](py::object py_iterate) { return new py::object(py_iterate); },
|
|
2552
2401
|
[js_external_context](Napi::Env env, py::object* py_iterate) mutable {
|
|
2553
2402
|
Napi::External<py::object> js_iterate_external =
|
|
2554
2403
|
make_napi_external(env, py_iterate);
|
|
2555
2404
|
|
|
2556
|
-
Napi::Function js_iterate =
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
});
|
|
2587
|
-
});
|
|
2405
|
+
Napi::Function js_iterate = Napi::Function::New(
|
|
2406
|
+
env,
|
|
2407
|
+
[js_external_context,
|
|
2408
|
+
js_iterate_external = // Ensures `py_iterate` remains valid.
|
|
2409
|
+
NapiSafeReference(js_iterate_external),
|
|
2410
|
+
py_iterate](const Napi::CallbackInfo& info) mutable {
|
|
2411
|
+
bool more = info[0].As<Napi::Boolean>();
|
|
2412
|
+
return NodePromiseFromPythonTaskWithContext(
|
|
2413
|
+
info.Env(),
|
|
2414
|
+
"iterate(...) in nodejs",
|
|
2415
|
+
js_external_context,
|
|
2416
|
+
[js_iterate_external, py_iterate, more]() {
|
|
2417
|
+
return (*py_iterate)(more);
|
|
2418
|
+
},
|
|
2419
|
+
[](py::object py_iteration) -> std::optional<int> {
|
|
2420
|
+
if (!py_iteration.is_none()) {
|
|
2421
|
+
return py_iteration.cast<int>();
|
|
2422
|
+
} else {
|
|
2423
|
+
return std::nullopt;
|
|
2424
|
+
}
|
|
2425
|
+
},
|
|
2426
|
+
[](Napi::Env env,
|
|
2427
|
+
std::optional<int>&& iteration) -> Napi::Value {
|
|
2428
|
+
if (iteration.has_value()) {
|
|
2429
|
+
return Napi::Number::New(env, *iteration);
|
|
2430
|
+
} else {
|
|
2431
|
+
return env.Null();
|
|
2432
|
+
}
|
|
2433
|
+
});
|
|
2434
|
+
});
|
|
2588
2435
|
|
|
2589
2436
|
return js_iterate;
|
|
2590
2437
|
});
|
|
@@ -2592,21 +2439,20 @@ Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
|
2592
2439
|
|
|
2593
2440
|
|
|
2594
2441
|
Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
2595
|
-
auto js_external_context =
|
|
2596
|
-
info[0].As<Napi::External<py::object>>());
|
|
2442
|
+
auto js_external_context =
|
|
2443
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2597
2444
|
|
|
2598
2445
|
// CHECK(...CheckTypeTag(...));
|
|
2599
2446
|
|
|
2600
2447
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2601
2448
|
|
|
2602
|
-
auto js_condition = NapiSafeFunctionReference(
|
|
2603
|
-
info[1].As<Napi::Function>());
|
|
2449
|
+
auto js_condition = NapiSafeFunctionReference(info[1].As<Napi::Function>());
|
|
2604
2450
|
|
|
2605
2451
|
return NodePromiseFromPythonTaskWithContext(
|
|
2606
2452
|
info.Env(),
|
|
2607
2453
|
"retry_reactively_until(...) in nodejs",
|
|
2608
2454
|
js_external_context,
|
|
2609
|
-
[js_external_context,
|
|
2455
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2610
2456
|
py_context,
|
|
2611
2457
|
js_condition = std::move(js_condition)]() {
|
|
2612
2458
|
py::object py_condition = py::cpp_function(
|
|
@@ -2617,8 +2463,7 @@ Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
|
2617
2463
|
// `py_condition` may be called more
|
|
2618
2464
|
// than once!
|
|
2619
2465
|
[js_condition](Napi::Env env) mutable {
|
|
2620
|
-
return js_condition
|
|
2621
|
-
.Value(env)
|
|
2466
|
+
return js_condition.Value(env)
|
|
2622
2467
|
.Call(env.Global(), {})
|
|
2623
2468
|
.As<Napi::Object>();
|
|
2624
2469
|
},
|
|
@@ -2634,8 +2479,8 @@ Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
|
2634
2479
|
|
|
2635
2480
|
|
|
2636
2481
|
Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
2637
|
-
auto js_external_context =
|
|
2638
|
-
info[0].As<Napi::External<py::object>>());
|
|
2482
|
+
auto js_external_context =
|
|
2483
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2639
2484
|
|
|
2640
2485
|
// CHECK(...CheckTypeTag(...));
|
|
2641
2486
|
|
|
@@ -2647,8 +2492,7 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2647
2492
|
auto js_how = idempotency_tuple.Get((uint32_t) 1);
|
|
2648
2493
|
std::string how = js_how.As<Napi::String>().Utf8Value();
|
|
2649
2494
|
|
|
2650
|
-
auto js_callable = NapiSafeFunctionReference(
|
|
2651
|
-
info[2].As<Napi::Function>());
|
|
2495
|
+
auto js_callable = NapiSafeFunctionReference(info[2].As<Napi::Function>());
|
|
2652
2496
|
|
|
2653
2497
|
bool at_most_once = info[3].As<Napi::Boolean>();
|
|
2654
2498
|
|
|
@@ -2658,21 +2502,20 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2658
2502
|
info.Env(),
|
|
2659
2503
|
"memoize(...) in nodejs",
|
|
2660
2504
|
js_external_context,
|
|
2661
|
-
[js_external_context,
|
|
2505
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2662
2506
|
py_context,
|
|
2663
2507
|
alias = std::move(alias),
|
|
2664
2508
|
how = std::move(how),
|
|
2665
2509
|
js_callable = std::move(js_callable),
|
|
2666
2510
|
at_most_once,
|
|
2667
2511
|
until]() {
|
|
2668
|
-
py::object py_callable =
|
|
2669
|
-
[js_callable = std::move(js_callable)]() mutable {
|
|
2512
|
+
py::object py_callable =
|
|
2513
|
+
py::cpp_function([js_callable = std::move(js_callable)]() mutable {
|
|
2670
2514
|
return PythonFutureFromNodePromise(
|
|
2671
2515
|
// NOTE: need a _copy_ of `js_callable` here since
|
|
2672
2516
|
// `py_callable` may be called more than once!
|
|
2673
2517
|
[js_callable](Napi::Env env) mutable {
|
|
2674
|
-
return js_callable
|
|
2675
|
-
.Value(env)
|
|
2518
|
+
return js_callable.Value(env)
|
|
2676
2519
|
.Call(env.Global(), {})
|
|
2677
2520
|
.As<Napi::Object>();
|
|
2678
2521
|
},
|
|
@@ -2690,9 +2533,7 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2690
2533
|
"at_most_once"_a = at_most_once,
|
|
2691
2534
|
"until"_a = until);
|
|
2692
2535
|
},
|
|
2693
|
-
[](py::object py_json) {
|
|
2694
|
-
return py_json.cast<std::string>();
|
|
2695
|
-
},
|
|
2536
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2696
2537
|
[](Napi::Env env, std::string&& json) {
|
|
2697
2538
|
return Napi::String::New(env, json);
|
|
2698
2539
|
});
|
|
@@ -2700,15 +2541,15 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2700
2541
|
|
|
2701
2542
|
|
|
2702
2543
|
Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
2703
|
-
auto js_external_servicer =
|
|
2704
|
-
info[0].As<Napi::External<py::object>>());
|
|
2544
|
+
auto js_external_servicer =
|
|
2545
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2705
2546
|
|
|
2706
2547
|
// CHECK(...CheckTypeTag(...));
|
|
2707
2548
|
|
|
2708
2549
|
py::object* py_servicer = js_external_servicer.Value(info.Env()).Data();
|
|
2709
2550
|
|
|
2710
|
-
auto js_external_context =
|
|
2711
|
-
info[1].As<Napi::External<py::object>>());
|
|
2551
|
+
auto js_external_context =
|
|
2552
|
+
NapiSafeReference(info[1].As<Napi::External<py::object>>());
|
|
2712
2553
|
|
|
2713
2554
|
// CHECK(...CheckTypeTag(...));
|
|
2714
2555
|
|
|
@@ -2720,16 +2561,14 @@ Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
|
2720
2561
|
info.Env(),
|
|
2721
2562
|
"servicer._read(...) in nodejs",
|
|
2722
2563
|
js_external_context,
|
|
2723
|
-
[js_external_servicer,
|
|
2564
|
+
[js_external_servicer, // Ensures `py_servicer` remains valid.
|
|
2724
2565
|
py_servicer,
|
|
2725
|
-
js_external_context,
|
|
2566
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2726
2567
|
py_context,
|
|
2727
2568
|
json_options = std::move(json_options)]() {
|
|
2728
2569
|
return py_servicer->attr("_read")(py_context, json_options);
|
|
2729
2570
|
},
|
|
2730
|
-
[](py::object py_json) {
|
|
2731
|
-
return py_json.cast<std::string>();
|
|
2732
|
-
},
|
|
2571
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2733
2572
|
[](Napi::Env env, std::string&& json) {
|
|
2734
2573
|
return Napi::String::New(env, json);
|
|
2735
2574
|
});
|
|
@@ -2737,22 +2576,21 @@ Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
|
2737
2576
|
|
|
2738
2577
|
|
|
2739
2578
|
Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
2740
|
-
auto js_external_servicer =
|
|
2741
|
-
info[0].As<Napi::External<py::object>>());
|
|
2579
|
+
auto js_external_servicer =
|
|
2580
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2742
2581
|
|
|
2743
2582
|
// CHECK(...CheckTypeTag(...));
|
|
2744
2583
|
|
|
2745
2584
|
py::object* py_servicer = js_external_servicer.Value(info.Env()).Data();
|
|
2746
2585
|
|
|
2747
|
-
auto js_external_context =
|
|
2748
|
-
info[1].As<Napi::External<py::object>>());
|
|
2586
|
+
auto js_external_context =
|
|
2587
|
+
NapiSafeReference(info[1].As<Napi::External<py::object>>());
|
|
2749
2588
|
|
|
2750
2589
|
// CHECK(...CheckTypeTag(...));
|
|
2751
2590
|
|
|
2752
2591
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2753
2592
|
|
|
2754
|
-
auto js_writer = NapiSafeFunctionReference(
|
|
2755
|
-
info[2].As<Napi::Function>());
|
|
2593
|
+
auto js_writer = NapiSafeFunctionReference(info[2].As<Napi::Function>());
|
|
2756
2594
|
|
|
2757
2595
|
std::string json_options = info[3].As<Napi::String>().Utf8Value();
|
|
2758
2596
|
|
|
@@ -2760,23 +2598,21 @@ Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
|
2760
2598
|
info.Env(),
|
|
2761
2599
|
"servicer._write(...) in nodejs",
|
|
2762
2600
|
js_external_context,
|
|
2763
|
-
[js_external_servicer,
|
|
2601
|
+
[js_external_servicer, // Ensures `py_servicer` remains valid.
|
|
2764
2602
|
py_servicer,
|
|
2765
|
-
js_external_context,
|
|
2603
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2766
2604
|
py_context,
|
|
2767
2605
|
js_writer = std::move(js_writer),
|
|
2768
2606
|
json_options = std::move(json_options)]() {
|
|
2769
2607
|
py::object py_writer = py::cpp_function(
|
|
2770
|
-
[js_writer = std::move(js_writer)](
|
|
2771
|
-
std::string state_json) mutable {
|
|
2608
|
+
[js_writer = std::move(js_writer)](std::string state_json) mutable {
|
|
2772
2609
|
return PythonFutureFromNodePromise(
|
|
2773
|
-
[js_writer,
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2610
|
+
[js_writer, // NOTE: need a _copy_ of
|
|
2611
|
+
// `js_writer` here since
|
|
2612
|
+
// `py_writer` may be called more
|
|
2613
|
+
// than once!
|
|
2777
2614
|
state_json](Napi::Env env) mutable {
|
|
2778
|
-
return js_writer
|
|
2779
|
-
.Value(env)
|
|
2615
|
+
return js_writer.Value(env)
|
|
2780
2616
|
.Call(
|
|
2781
2617
|
env.Global(),
|
|
2782
2618
|
{Napi::String::New(env, state_json)})
|
|
@@ -2787,14 +2623,9 @@ Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
|
2787
2623
|
});
|
|
2788
2624
|
});
|
|
2789
2625
|
|
|
2790
|
-
return py_servicer->attr("_write")(
|
|
2791
|
-
py_context,
|
|
2792
|
-
py_writer,
|
|
2793
|
-
json_options);
|
|
2794
|
-
},
|
|
2795
|
-
[](py::object py_result) {
|
|
2796
|
-
return py_result.cast<std::string>();
|
|
2626
|
+
return py_servicer->attr("_write")(py_context, py_writer, json_options);
|
|
2797
2627
|
},
|
|
2628
|
+
[](py::object py_result) { return py_result.cast<std::string>(); },
|
|
2798
2629
|
[](Napi::Env env, std::string&& result) {
|
|
2799
2630
|
return Napi::String::New(env, result);
|
|
2800
2631
|
});
|