@reboot-dev/reboot 0.41.0 → 0.43.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 +492 -665
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/zod-to-proto.js +35 -35
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,15 +1634,15 @@ 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
|
|
|
@@ -1760,9 +1660,9 @@ 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]() {
|
|
@@ -1790,8 +1690,8 @@ Napi::Value Reboot_up(const Napi::CallbackInfo& info) {
|
|
|
1790
1690
|
}
|
|
1791
1691
|
|
|
1792
1692
|
Napi::Value Reboot_down(const Napi::CallbackInfo& info) {
|
|
1793
|
-
auto js_external_reboot =
|
|
1794
|
-
info[0].As<Napi::External<py::object>>());
|
|
1693
|
+
auto js_external_reboot =
|
|
1694
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1795
1695
|
|
|
1796
1696
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1797
1697
|
|
|
@@ -1801,18 +1701,16 @@ Napi::Value Reboot_down(const Napi::CallbackInfo& info) {
|
|
|
1801
1701
|
info.Env(),
|
|
1802
1702
|
"Reboot.down() in nodejs",
|
|
1803
1703
|
{"asyncio", "create_task"},
|
|
1804
|
-
[js_external_reboot,
|
|
1805
|
-
py_reboot]() {
|
|
1806
|
-
return py_reboot->attr("down")();
|
|
1807
|
-
});
|
|
1704
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1705
|
+
py_reboot]() { return py_reboot->attr("down")(); });
|
|
1808
1706
|
}
|
|
1809
1707
|
|
|
1810
1708
|
Napi::Value Reboot_start(const Napi::CallbackInfo& info) {
|
|
1811
1709
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1812
1710
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1813
1711
|
// get out of it will remain valid.
|
|
1814
|
-
auto js_external_reboot =
|
|
1815
|
-
info[0].As<Napi::External<py::object>>());
|
|
1712
|
+
auto js_external_reboot =
|
|
1713
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1816
1714
|
|
|
1817
1715
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1818
1716
|
|
|
@@ -1826,18 +1724,16 @@ Napi::Value Reboot_start(const Napi::CallbackInfo& info) {
|
|
|
1826
1724
|
info.Env(),
|
|
1827
1725
|
"Reboot.start() in nodejs",
|
|
1828
1726
|
{"asyncio", "create_task"},
|
|
1829
|
-
[js_external_reboot,
|
|
1830
|
-
py_reboot]() {
|
|
1831
|
-
return py_reboot->attr("start")();
|
|
1832
|
-
});
|
|
1727
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1728
|
+
py_reboot]() { return py_reboot->attr("start")(); });
|
|
1833
1729
|
}
|
|
1834
1730
|
|
|
1835
1731
|
Napi::Value Reboot_stop(const Napi::CallbackInfo& info) {
|
|
1836
1732
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1837
1733
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1838
1734
|
// get out of it will remain valid.
|
|
1839
|
-
auto js_external_reboot =
|
|
1840
|
-
info[0].As<Napi::External<py::object>>());
|
|
1735
|
+
auto js_external_reboot =
|
|
1736
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1841
1737
|
|
|
1842
1738
|
// CHECK(js_external_reboot.CheckTypeTag(&reboot_aio_tests_Reboot));
|
|
1843
1739
|
|
|
@@ -1847,22 +1743,18 @@ Napi::Value Reboot_stop(const Napi::CallbackInfo& info) {
|
|
|
1847
1743
|
info.Env(),
|
|
1848
1744
|
"Reboot.stop() in nodejs",
|
|
1849
1745
|
{"asyncio", "create_task"},
|
|
1850
|
-
[js_external_reboot,
|
|
1851
|
-
py_reboot]() {
|
|
1852
|
-
return py_reboot->attr("stop")();
|
|
1853
|
-
});
|
|
1746
|
+
[js_external_reboot, // Ensures `py_reboot` remains valid.
|
|
1747
|
+
py_reboot]() { return py_reboot->attr("stop")(); });
|
|
1854
1748
|
|
|
1855
1749
|
// 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) {
|
|
1750
|
+
auto js_resolve_reject =
|
|
1751
|
+
Napi::Function::New(info.Env(), [](const Napi::CallbackInfo& info) {
|
|
1859
1752
|
adaptor->AllowNodeToExit(info.Env());
|
|
1860
1753
|
});
|
|
1861
1754
|
|
|
1862
|
-
js_promise
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
.Call(js_promise, {js_resolve_reject, js_resolve_reject});
|
|
1755
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
1756
|
+
js_promise,
|
|
1757
|
+
{js_resolve_reject, js_resolve_reject});
|
|
1866
1758
|
|
|
1867
1759
|
return js_promise;
|
|
1868
1760
|
}
|
|
@@ -1873,18 +1765,17 @@ Napi::Value Reboot_url(const Napi::CallbackInfo& info) {
|
|
|
1873
1765
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
1874
1766
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
1875
1767
|
// get out of it will remain valid.
|
|
1876
|
-
auto js_external_reboot =
|
|
1877
|
-
info[0].As<Napi::External<py::object>>());
|
|
1768
|
+
auto js_external_reboot =
|
|
1769
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
1878
1770
|
|
|
1879
1771
|
// CHECK(...CheckTypeTag(...));
|
|
1880
1772
|
|
|
1881
1773
|
py::object* py_reboot = js_external_reboot.Value(info.Env()).Data();
|
|
1882
1774
|
|
|
1883
|
-
std::string url = RunCallbackOnPythonEventLoop(
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
});
|
|
1775
|
+
std::string url = RunCallbackOnPythonEventLoop([py_reboot]() {
|
|
1776
|
+
py::str url = py_reboot->attr("url")();
|
|
1777
|
+
return std::string(url);
|
|
1778
|
+
});
|
|
1888
1779
|
|
|
1889
1780
|
return Napi::String::New(info.Env(), url);
|
|
1890
1781
|
}
|
|
@@ -1900,13 +1791,11 @@ Napi::Value Service_constructor(const Napi::CallbackInfo& info) {
|
|
|
1900
1791
|
|
|
1901
1792
|
std::string id = js_args.Get("id").As<Napi::String>().Utf8Value();
|
|
1902
1793
|
|
|
1903
|
-
py::object* py_service =
|
|
1904
|
-
[&rbt_module, &node_adaptor, &id]() {
|
|
1794
|
+
py::object* py_service =
|
|
1795
|
+
RunCallbackOnPythonEventLoop([&rbt_module, &node_adaptor, &id]() {
|
|
1905
1796
|
py::object py_module = py::module::import(rbt_module.c_str());
|
|
1906
1797
|
py::object py_schedule_type =
|
|
1907
|
-
py_module
|
|
1908
|
-
.attr(node_adaptor.c_str())
|
|
1909
|
-
.attr("_Schedule");
|
|
1798
|
+
py_module.attr(node_adaptor.c_str()).attr("_Schedule");
|
|
1910
1799
|
return new py::object(py_module.attr(node_adaptor.c_str())(
|
|
1911
1800
|
// The call will stay within the same application.
|
|
1912
1801
|
"application_id"_a = py::none(),
|
|
@@ -1950,8 +1839,7 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1950
1839
|
|
|
1951
1840
|
// CHECK(...CheckTypeTag(...));
|
|
1952
1841
|
|
|
1953
|
-
py::object* py_context =
|
|
1954
|
-
js_external_context.Value(info.Env()).Data();
|
|
1842
|
+
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
1955
1843
|
|
|
1956
1844
|
std::string json_request = js_args.Get("jsonRequest").As<Napi::String>();
|
|
1957
1845
|
|
|
@@ -1961,13 +1849,13 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1961
1849
|
info.Env(),
|
|
1962
1850
|
"servicer._" + kind + "(\"" + method + "\", ...) in nodejs",
|
|
1963
1851
|
js_external_context,
|
|
1964
|
-
[js_external_service,
|
|
1852
|
+
[js_external_service, // Ensures `py_service` remains valid.
|
|
1965
1853
|
py_service,
|
|
1966
1854
|
kind,
|
|
1967
1855
|
method,
|
|
1968
1856
|
request_module,
|
|
1969
1857
|
request_type,
|
|
1970
|
-
js_external_context,
|
|
1858
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
1971
1859
|
py_context,
|
|
1972
1860
|
json_request,
|
|
1973
1861
|
json_options]() {
|
|
@@ -1994,9 +1882,7 @@ Napi::Value Service_call(const Napi::CallbackInfo& info) {
|
|
|
1994
1882
|
json_request,
|
|
1995
1883
|
json_options);
|
|
1996
1884
|
},
|
|
1997
|
-
[](py::object py_json) {
|
|
1998
|
-
return py_json.cast<std::string>();
|
|
1999
|
-
},
|
|
1885
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2000
1886
|
[](Napi::Env env, std::string&& json) {
|
|
2001
1887
|
return Napi::String::New(env, json);
|
|
2002
1888
|
});
|
|
@@ -2014,8 +1900,7 @@ Napi::Value Task_await(const Napi::CallbackInfo& info) {
|
|
|
2014
1900
|
|
|
2015
1901
|
// CHECK(...CheckTypeTag(...));
|
|
2016
1902
|
|
|
2017
|
-
py::object* py_context =
|
|
2018
|
-
js_external_context.Value(info.Env()).Data();
|
|
1903
|
+
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2019
1904
|
|
|
2020
1905
|
std::string rbt_module = js_args.Get("rbtModule").As<Napi::String>();
|
|
2021
1906
|
|
|
@@ -2027,27 +1912,23 @@ Napi::Value Task_await(const Napi::CallbackInfo& info) {
|
|
|
2027
1912
|
|
|
2028
1913
|
return NodePromiseFromPythonTaskWithContext(
|
|
2029
1914
|
info.Env(),
|
|
2030
|
-
"rebootdev.nodejs.python.task_await(\""
|
|
2031
|
-
+
|
|
2032
|
-
+ method + "\", ...) in nodejs",
|
|
1915
|
+
"rebootdev.nodejs.python.task_await(\"" + state_name + "\", \"" + method
|
|
1916
|
+
+ "\", ...) in nodejs",
|
|
2033
1917
|
js_external_context,
|
|
2034
1918
|
[rbt_module = std::move(rbt_module),
|
|
2035
1919
|
state_name = std::move(state_name),
|
|
2036
1920
|
method = std::move(method),
|
|
2037
|
-
js_external_context,
|
|
1921
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2038
1922
|
py_context,
|
|
2039
1923
|
json_task_id]() {
|
|
2040
1924
|
return py::module::import("rebootdev.nodejs.python")
|
|
2041
1925
|
.attr("task_await")(
|
|
2042
1926
|
py_context,
|
|
2043
|
-
py::module::import(rbt_module.c_str())
|
|
2044
|
-
.attr(state_name.c_str()),
|
|
1927
|
+
py::module::import(rbt_module.c_str()).attr(state_name.c_str()),
|
|
2045
1928
|
method,
|
|
2046
1929
|
json_task_id);
|
|
2047
1930
|
},
|
|
2048
|
-
[](py::object py_json) {
|
|
2049
|
-
return py_json.cast<std::string>();
|
|
2050
|
-
},
|
|
1931
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2051
1932
|
[](Napi::Env env, std::string&& json) {
|
|
2052
1933
|
return Napi::String::New(env, json);
|
|
2053
1934
|
});
|
|
@@ -2078,21 +1959,17 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2078
1959
|
|
|
2079
1960
|
std::optional<std::string> idempotency_required_reason;
|
|
2080
1961
|
if (!info[6].IsUndefined()) {
|
|
2081
|
-
idempotency_required_reason =
|
|
2082
|
-
info[6]
|
|
2083
|
-
.As<Napi::String>()
|
|
2084
|
-
.Utf8Value();
|
|
1962
|
+
idempotency_required_reason = info[6].As<Napi::String>().Utf8Value();
|
|
2085
1963
|
}
|
|
2086
1964
|
|
|
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");
|
|
1965
|
+
py::object* py_external_context =
|
|
1966
|
+
RunCallbackOnPythonEventLoop([&name,
|
|
1967
|
+
&url,
|
|
1968
|
+
&bearer_token,
|
|
1969
|
+
&idempotency_seed,
|
|
1970
|
+
&idempotency_required,
|
|
1971
|
+
&idempotency_required_reason]() {
|
|
1972
|
+
py::object py_external = py::module::import("rebootdev.aio.external");
|
|
2096
1973
|
|
|
2097
1974
|
auto convert_str =
|
|
2098
1975
|
[](const std::optional<std::string>& optional) -> py::object {
|
|
@@ -2109,8 +1986,8 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2109
1986
|
"bearer_token"_a = convert_str(bearer_token),
|
|
2110
1987
|
"idempotency_seed"_a = convert_str(idempotency_seed),
|
|
2111
1988
|
"idempotency_required"_a = py::bool_(idempotency_required),
|
|
2112
|
-
"idempotency_required_reason"_a =
|
|
2113
|
-
idempotency_required_reason)));
|
|
1989
|
+
"idempotency_required_reason"_a =
|
|
1990
|
+
convert_str(idempotency_required_reason)));
|
|
2114
1991
|
});
|
|
2115
1992
|
|
|
2116
1993
|
Napi::External<py::object> js_external_context = make_napi_external(
|
|
@@ -2122,8 +1999,8 @@ Napi::Value ExternalContext_constructor(const Napi::CallbackInfo& info) {
|
|
|
2122
1999
|
}
|
|
2123
2000
|
|
|
2124
2001
|
Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
2125
|
-
auto js_from_native_external =
|
|
2126
|
-
info[0].As<Napi::Function>());
|
|
2002
|
+
auto js_from_native_external =
|
|
2003
|
+
NapiSafeFunctionReference(info[0].As<Napi::Function>());
|
|
2127
2004
|
|
|
2128
2005
|
Napi::Array js_servicers = info[1].As<Napi::Array>();
|
|
2129
2006
|
|
|
@@ -2137,8 +2014,7 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2137
2014
|
|
|
2138
2015
|
auto servicer_details = make_servicer_details(info.Env(), js_servicers);
|
|
2139
2016
|
|
|
2140
|
-
auto js_initialize = NapiSafeFunctionReference(
|
|
2141
|
-
info[3].As<Napi::Function>());
|
|
2017
|
+
auto js_initialize = NapiSafeFunctionReference(info[3].As<Napi::Function>());
|
|
2142
2018
|
|
|
2143
2019
|
std::optional<std::string> initialize_bearer_token;
|
|
2144
2020
|
if (!info[4].IsUndefined()) {
|
|
@@ -2184,31 +2060,27 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2184
2060
|
Napi::Function js_create_external_context =
|
|
2185
2061
|
Napi::Function::New(
|
|
2186
2062
|
env,
|
|
2187
|
-
[js_from_native_external =
|
|
2188
|
-
js_from_native_external),
|
|
2063
|
+
[js_from_native_external =
|
|
2064
|
+
std::move(js_from_native_external),
|
|
2189
2065
|
// Ensures `py_channel_manager` remains valid.
|
|
2190
2066
|
js_external_channel_manager = NapiSafeReference(
|
|
2191
2067
|
js_external_channel_manager)](
|
|
2192
2068
|
const Napi::CallbackInfo& info) mutable {
|
|
2193
2069
|
Napi::Object js_args = info[0].As<Napi::Object>();
|
|
2194
2070
|
|
|
2195
|
-
std::string name =
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
.As<Napi::String>()
|
|
2199
|
-
.Utf8Value();
|
|
2071
|
+
std::string name = js_args.Get("name")
|
|
2072
|
+
.As<Napi::String>()
|
|
2073
|
+
.Utf8Value();
|
|
2200
2074
|
|
|
2201
2075
|
std::optional<std::string> bearer_token;
|
|
2202
2076
|
if (!js_args.Get("bearerToken").IsUndefined()) {
|
|
2203
|
-
bearer_token =
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
.Utf8Value();
|
|
2077
|
+
bearer_token = js_args.Get("bearerToken")
|
|
2078
|
+
.As<Napi::String>()
|
|
2079
|
+
.Utf8Value();
|
|
2207
2080
|
}
|
|
2208
2081
|
|
|
2209
2082
|
py::object* py_channel_manager =
|
|
2210
|
-
js_external_channel_manager
|
|
2211
|
-
.Value(info.Env())
|
|
2083
|
+
js_external_channel_manager.Value(info.Env())
|
|
2212
2084
|
.Data();
|
|
2213
2085
|
|
|
2214
2086
|
return NodePromiseFromPythonCallback(
|
|
@@ -2246,32 +2118,30 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2246
2118
|
js_from_native_external](
|
|
2247
2119
|
Napi::Env env,
|
|
2248
2120
|
py::object* py_context) {
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
make_napi_external(
|
|
2121
|
+
Napi::External<py::object>
|
|
2122
|
+
// (check_line_length skip)
|
|
2123
|
+
js_external_context = make_napi_external(
|
|
2252
2124
|
env,
|
|
2253
2125
|
py_context,
|
|
2254
2126
|
// (check_line_length skip)
|
|
2255
2127
|
&reboot_aio_external_ExternalContext);
|
|
2256
2128
|
|
|
2257
|
-
return js_from_native_external
|
|
2258
|
-
.Value(env)
|
|
2129
|
+
return js_from_native_external.Value(env)
|
|
2259
2130
|
.Call(
|
|
2260
2131
|
env.Global(),
|
|
2261
2132
|
{js_external_context,
|
|
2262
|
-
|
|
2263
|
-
|
|
2133
|
+
Napi::String::New(
|
|
2134
|
+
env,
|
|
2135
|
+
"external")});
|
|
2264
2136
|
});
|
|
2265
2137
|
});
|
|
2266
2138
|
|
|
2267
|
-
return js_web_framework_start
|
|
2268
|
-
.Value(env)
|
|
2139
|
+
return js_web_framework_start.Value(env)
|
|
2269
2140
|
.Call(
|
|
2270
2141
|
env.Global(),
|
|
2271
2142
|
{Napi::String::New(env, server_id),
|
|
2272
|
-
port.has_value()
|
|
2273
|
-
|
|
2274
|
-
: env.Null(),
|
|
2143
|
+
port.has_value() ? Napi::Number::New(env, *port)
|
|
2144
|
+
: env.Null(),
|
|
2275
2145
|
js_create_external_context})
|
|
2276
2146
|
.As<Napi::Object>();
|
|
2277
2147
|
},
|
|
@@ -2282,17 +2152,13 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2282
2152
|
});
|
|
2283
2153
|
|
|
2284
2154
|
py::object py_web_framework_stop = py::cpp_function(
|
|
2285
|
-
[js_web_framework_stop =
|
|
2286
|
-
|
|
2155
|
+
[js_web_framework_stop =
|
|
2156
|
+
std::move(js_web_framework_stop)](std::string server_id) {
|
|
2287
2157
|
return PythonFutureFromNodePromise(
|
|
2288
2158
|
[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)})
|
|
2159
|
+
server_id = std::move(server_id)](Napi::Env env) mutable {
|
|
2160
|
+
return js_web_framework_stop.Value(env)
|
|
2161
|
+
.Call(env.Global(), {Napi::String::New(env, server_id)})
|
|
2296
2162
|
.As<Napi::Object>();
|
|
2297
2163
|
});
|
|
2298
2164
|
});
|
|
@@ -2303,15 +2169,15 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2303
2169
|
py::object py_context) mutable {
|
|
2304
2170
|
return PythonFutureFromNodePromise(
|
|
2305
2171
|
[js_initialize,
|
|
2306
|
-
js_from_native_external,
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
py_context =
|
|
2314
|
-
|
|
2172
|
+
js_from_native_external, // NOTE: need a _copy_ of
|
|
2173
|
+
// both `js_initialize`
|
|
2174
|
+
// and
|
|
2175
|
+
// `js_from_native_external`
|
|
2176
|
+
// here since
|
|
2177
|
+
// `py_initialize` may be
|
|
2178
|
+
// called more than once!
|
|
2179
|
+
py_context =
|
|
2180
|
+
new py::object(py_context)](Napi::Env env) mutable {
|
|
2315
2181
|
Napi::External<py::object> js_external_context =
|
|
2316
2182
|
make_napi_external(
|
|
2317
2183
|
env,
|
|
@@ -2319,16 +2185,14 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2319
2185
|
&reboot_aio_external_ExternalContext);
|
|
2320
2186
|
|
|
2321
2187
|
Napi::Object js_context =
|
|
2322
|
-
js_from_native_external
|
|
2323
|
-
.Value(env)
|
|
2188
|
+
js_from_native_external.Value(env)
|
|
2324
2189
|
.Call(
|
|
2325
2190
|
env.Global(),
|
|
2326
2191
|
{js_external_context,
|
|
2327
2192
|
Napi::String::New(env, "initialize")})
|
|
2328
2193
|
.As<Napi::Object>();
|
|
2329
2194
|
|
|
2330
|
-
return js_initialize
|
|
2331
|
-
.Value(env)
|
|
2195
|
+
return js_initialize.Value(env)
|
|
2332
2196
|
.Call(env.Global(), {js_context})
|
|
2333
2197
|
.As<Napi::Object>();
|
|
2334
2198
|
});
|
|
@@ -2351,8 +2215,7 @@ Napi::Value Application_constructor(const Napi::CallbackInfo& info) {
|
|
|
2351
2215
|
"web_framework_start"_a = py_web_framework_start,
|
|
2352
2216
|
"web_framework_stop"_a = py_web_framework_stop,
|
|
2353
2217
|
"initialize"_a = py_initialize,
|
|
2354
|
-
"initialize_bearer_token"_a =
|
|
2355
|
-
py_initialize_bearer_token,
|
|
2218
|
+
"initialize_bearer_token"_a = py_initialize_bearer_token,
|
|
2356
2219
|
"token_verifier"_a = py_token_verifier));
|
|
2357
2220
|
});
|
|
2358
2221
|
|
|
@@ -2370,47 +2233,37 @@ Napi::Value Application_run(const Napi::CallbackInfo& info) {
|
|
|
2370
2233
|
// that we can get calls from Python.
|
|
2371
2234
|
adaptor->KeepNodeFromExiting(info.Env());
|
|
2372
2235
|
|
|
2373
|
-
auto js_external_application =
|
|
2374
|
-
info[0].As<Napi::External<py::object>>());
|
|
2236
|
+
auto js_external_application =
|
|
2237
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2375
2238
|
|
|
2376
|
-
py::object* py_application =
|
|
2377
|
-
js_external_application.Value(info.Env()).Data();
|
|
2239
|
+
py::object* py_application = js_external_application.Value(info.Env()).Data();
|
|
2378
2240
|
|
|
2379
2241
|
Napi::Promise js_promise = NodePromiseFromPythonTask(
|
|
2380
2242
|
info.Env(),
|
|
2381
2243
|
"Application.run() in nodejs",
|
|
2382
2244
|
{"rebootdev.nodejs.python", "create_task"},
|
|
2383
|
-
[js_external_application,
|
|
2384
|
-
py_application]() {
|
|
2385
|
-
return py_application->attr("run")();
|
|
2386
|
-
});
|
|
2245
|
+
[js_external_application, // Ensures `py_application` remains valid.
|
|
2246
|
+
py_application]() { return py_application->attr("run")(); });
|
|
2387
2247
|
|
|
2388
2248
|
// 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
|
-
})});
|
|
2249
|
+
js_promise.Get("then").As<Napi::Function>().Call(
|
|
2250
|
+
js_promise,
|
|
2251
|
+
{Napi::Function::New(
|
|
2252
|
+
info.Env(),
|
|
2253
|
+
[](const Napi::CallbackInfo& info) {
|
|
2254
|
+
// Allow Node to exit after `Application.run` returns.
|
|
2255
|
+
adaptor->AllowNodeToExit(info.Env());
|
|
2256
|
+
}),
|
|
2257
|
+
Napi::Function::New(info.Env(), [](const Napi::CallbackInfo& info) {
|
|
2258
|
+
// There was an error, let's also set the
|
|
2259
|
+
// `process.exitCode` to reflect this.
|
|
2260
|
+
info.Env().Global().Get("process").As<Napi::Object>().Set(
|
|
2261
|
+
"exitCode",
|
|
2262
|
+
1);
|
|
2263
|
+
|
|
2264
|
+
// Allow Node to exit after `Application.run` returns.
|
|
2265
|
+
adaptor->AllowNodeToExit(info.Env());
|
|
2266
|
+
})});
|
|
2414
2267
|
|
|
2415
2268
|
return js_promise;
|
|
2416
2269
|
}
|
|
@@ -2420,22 +2273,18 @@ Napi::Value Context_generateIdempotentStateId(const Napi::CallbackInfo& info) {
|
|
|
2420
2273
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
2421
2274
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
2422
2275
|
// get out of it will remain valid.
|
|
2423
|
-
auto js_external_context =
|
|
2424
|
-
info[0].As<Napi::External<py::object>>());
|
|
2276
|
+
auto js_external_context =
|
|
2277
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2425
2278
|
|
|
2426
2279
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2427
2280
|
|
|
2428
|
-
std::string state_type =
|
|
2429
|
-
info[1].As<Napi::String>().Utf8Value();
|
|
2281
|
+
std::string state_type = info[1].As<Napi::String>().Utf8Value();
|
|
2430
2282
|
|
|
2431
|
-
std::string service_name =
|
|
2432
|
-
info[2].As<Napi::String>().Utf8Value();
|
|
2283
|
+
std::string service_name = info[2].As<Napi::String>().Utf8Value();
|
|
2433
2284
|
|
|
2434
|
-
std::string method =
|
|
2435
|
-
info[3].As<Napi::String>().Utf8Value();
|
|
2285
|
+
std::string method = info[3].As<Napi::String>().Utf8Value();
|
|
2436
2286
|
|
|
2437
|
-
Napi::Object idempotency_options =
|
|
2438
|
-
info[4].As<Napi::Object>();
|
|
2287
|
+
Napi::Object idempotency_options = info[4].As<Napi::Object>();
|
|
2439
2288
|
auto js_key = idempotency_options.Get("key");
|
|
2440
2289
|
std::optional<std::string> key;
|
|
2441
2290
|
if (js_key.IsString()) {
|
|
@@ -2454,7 +2303,7 @@ Napi::Value Context_generateIdempotentStateId(const Napi::CallbackInfo& info) {
|
|
|
2454
2303
|
|
|
2455
2304
|
return NodePromiseFromPythonCallback(
|
|
2456
2305
|
info.Env(),
|
|
2457
|
-
[js_external_context,
|
|
2306
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2458
2307
|
py_context,
|
|
2459
2308
|
state_type = std::move(state_type),
|
|
2460
2309
|
service_name = std::move(service_name),
|
|
@@ -2510,25 +2359,23 @@ Napi::Value WriterContext_set_sync(const Napi::CallbackInfo& info) {
|
|
|
2510
2359
|
// NOTE: we immediately get a safe reference to the `Napi::External`
|
|
2511
2360
|
// so that Node will not garbage collect it and the `py::object*` we
|
|
2512
2361
|
// get out of it will remain valid.
|
|
2513
|
-
auto js_external_context =
|
|
2514
|
-
info[0].As<Napi::External<py::object>>());
|
|
2362
|
+
auto js_external_context =
|
|
2363
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2515
2364
|
|
|
2516
2365
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2517
2366
|
|
|
2518
2367
|
bool sync = info[1].As<Napi::Boolean>();
|
|
2519
2368
|
|
|
2520
2369
|
RunCallbackOnPythonEventLoop(
|
|
2521
|
-
[&py_context, sync]() {
|
|
2522
|
-
py_context->attr("sync") = sync;
|
|
2523
|
-
});
|
|
2370
|
+
[&py_context, sync]() { py_context->attr("sync") = sync; });
|
|
2524
2371
|
|
|
2525
2372
|
return info.Env().Undefined();
|
|
2526
2373
|
}
|
|
2527
2374
|
|
|
2528
2375
|
|
|
2529
2376
|
Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
2530
|
-
auto js_external_context =
|
|
2531
|
-
info[0].As<Napi::External<py::object>>());
|
|
2377
|
+
auto js_external_context =
|
|
2378
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2532
2379
|
|
|
2533
2380
|
// CHECK(...CheckTypeTag(...));
|
|
2534
2381
|
|
|
@@ -2540,51 +2387,47 @@ Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
|
2540
2387
|
info.Env(),
|
|
2541
2388
|
"context.loop(...) in nodejs",
|
|
2542
2389
|
js_external_context,
|
|
2543
|
-
[js_external_context,
|
|
2390
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2544
2391
|
py_context,
|
|
2545
2392
|
alias = std::move(alias)]() {
|
|
2546
2393
|
return py::module::import("rebootdev.nodejs.python")
|
|
2547
2394
|
.attr("loop")(py_context, alias);
|
|
2548
2395
|
},
|
|
2549
|
-
[](py::object py_iterate) {
|
|
2550
|
-
return new py::object(py_iterate);
|
|
2551
|
-
},
|
|
2396
|
+
[](py::object py_iterate) { return new py::object(py_iterate); },
|
|
2552
2397
|
[js_external_context](Napi::Env env, py::object* py_iterate) mutable {
|
|
2553
2398
|
Napi::External<py::object> js_iterate_external =
|
|
2554
2399
|
make_napi_external(env, py_iterate);
|
|
2555
2400
|
|
|
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
|
-
});
|
|
2401
|
+
Napi::Function js_iterate = Napi::Function::New(
|
|
2402
|
+
env,
|
|
2403
|
+
[js_external_context,
|
|
2404
|
+
js_iterate_external = // Ensures `py_iterate` remains valid.
|
|
2405
|
+
NapiSafeReference(js_iterate_external),
|
|
2406
|
+
py_iterate](const Napi::CallbackInfo& info) mutable {
|
|
2407
|
+
bool more = info[0].As<Napi::Boolean>();
|
|
2408
|
+
return NodePromiseFromPythonTaskWithContext(
|
|
2409
|
+
info.Env(),
|
|
2410
|
+
"iterate(...) in nodejs",
|
|
2411
|
+
js_external_context,
|
|
2412
|
+
[js_iterate_external, py_iterate, more]() {
|
|
2413
|
+
return (*py_iterate)(more);
|
|
2414
|
+
},
|
|
2415
|
+
[](py::object py_iteration) -> std::optional<int> {
|
|
2416
|
+
if (!py_iteration.is_none()) {
|
|
2417
|
+
return py_iteration.cast<int>();
|
|
2418
|
+
} else {
|
|
2419
|
+
return std::nullopt;
|
|
2420
|
+
}
|
|
2421
|
+
},
|
|
2422
|
+
[](Napi::Env env,
|
|
2423
|
+
std::optional<int>&& iteration) -> Napi::Value {
|
|
2424
|
+
if (iteration.has_value()) {
|
|
2425
|
+
return Napi::Number::New(env, *iteration);
|
|
2426
|
+
} else {
|
|
2427
|
+
return env.Null();
|
|
2428
|
+
}
|
|
2429
|
+
});
|
|
2430
|
+
});
|
|
2588
2431
|
|
|
2589
2432
|
return js_iterate;
|
|
2590
2433
|
});
|
|
@@ -2592,21 +2435,20 @@ Napi::Value WorkflowContext_loop(const Napi::CallbackInfo& info) {
|
|
|
2592
2435
|
|
|
2593
2436
|
|
|
2594
2437
|
Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
2595
|
-
auto js_external_context =
|
|
2596
|
-
info[0].As<Napi::External<py::object>>());
|
|
2438
|
+
auto js_external_context =
|
|
2439
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2597
2440
|
|
|
2598
2441
|
// CHECK(...CheckTypeTag(...));
|
|
2599
2442
|
|
|
2600
2443
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2601
2444
|
|
|
2602
|
-
auto js_condition = NapiSafeFunctionReference(
|
|
2603
|
-
info[1].As<Napi::Function>());
|
|
2445
|
+
auto js_condition = NapiSafeFunctionReference(info[1].As<Napi::Function>());
|
|
2604
2446
|
|
|
2605
2447
|
return NodePromiseFromPythonTaskWithContext(
|
|
2606
2448
|
info.Env(),
|
|
2607
2449
|
"retry_reactively_until(...) in nodejs",
|
|
2608
2450
|
js_external_context,
|
|
2609
|
-
[js_external_context,
|
|
2451
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2610
2452
|
py_context,
|
|
2611
2453
|
js_condition = std::move(js_condition)]() {
|
|
2612
2454
|
py::object py_condition = py::cpp_function(
|
|
@@ -2617,8 +2459,7 @@ Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
|
2617
2459
|
// `py_condition` may be called more
|
|
2618
2460
|
// than once!
|
|
2619
2461
|
[js_condition](Napi::Env env) mutable {
|
|
2620
|
-
return js_condition
|
|
2621
|
-
.Value(env)
|
|
2462
|
+
return js_condition.Value(env)
|
|
2622
2463
|
.Call(env.Global(), {})
|
|
2623
2464
|
.As<Napi::Object>();
|
|
2624
2465
|
},
|
|
@@ -2634,8 +2475,8 @@ Napi::Value retry_reactively_until(const Napi::CallbackInfo& info) {
|
|
|
2634
2475
|
|
|
2635
2476
|
|
|
2636
2477
|
Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
2637
|
-
auto js_external_context =
|
|
2638
|
-
info[0].As<Napi::External<py::object>>());
|
|
2478
|
+
auto js_external_context =
|
|
2479
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2639
2480
|
|
|
2640
2481
|
// CHECK(...CheckTypeTag(...));
|
|
2641
2482
|
|
|
@@ -2647,8 +2488,7 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2647
2488
|
auto js_how = idempotency_tuple.Get((uint32_t) 1);
|
|
2648
2489
|
std::string how = js_how.As<Napi::String>().Utf8Value();
|
|
2649
2490
|
|
|
2650
|
-
auto js_callable = NapiSafeFunctionReference(
|
|
2651
|
-
info[2].As<Napi::Function>());
|
|
2491
|
+
auto js_callable = NapiSafeFunctionReference(info[2].As<Napi::Function>());
|
|
2652
2492
|
|
|
2653
2493
|
bool at_most_once = info[3].As<Napi::Boolean>();
|
|
2654
2494
|
|
|
@@ -2658,21 +2498,20 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2658
2498
|
info.Env(),
|
|
2659
2499
|
"memoize(...) in nodejs",
|
|
2660
2500
|
js_external_context,
|
|
2661
|
-
[js_external_context,
|
|
2501
|
+
[js_external_context, // Ensures `py_context` remains valid.
|
|
2662
2502
|
py_context,
|
|
2663
2503
|
alias = std::move(alias),
|
|
2664
2504
|
how = std::move(how),
|
|
2665
2505
|
js_callable = std::move(js_callable),
|
|
2666
2506
|
at_most_once,
|
|
2667
2507
|
until]() {
|
|
2668
|
-
py::object py_callable =
|
|
2669
|
-
[js_callable = std::move(js_callable)]() mutable {
|
|
2508
|
+
py::object py_callable =
|
|
2509
|
+
py::cpp_function([js_callable = std::move(js_callable)]() mutable {
|
|
2670
2510
|
return PythonFutureFromNodePromise(
|
|
2671
2511
|
// NOTE: need a _copy_ of `js_callable` here since
|
|
2672
2512
|
// `py_callable` may be called more than once!
|
|
2673
2513
|
[js_callable](Napi::Env env) mutable {
|
|
2674
|
-
return js_callable
|
|
2675
|
-
.Value(env)
|
|
2514
|
+
return js_callable.Value(env)
|
|
2676
2515
|
.Call(env.Global(), {})
|
|
2677
2516
|
.As<Napi::Object>();
|
|
2678
2517
|
},
|
|
@@ -2690,9 +2529,7 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2690
2529
|
"at_most_once"_a = at_most_once,
|
|
2691
2530
|
"until"_a = until);
|
|
2692
2531
|
},
|
|
2693
|
-
[](py::object py_json) {
|
|
2694
|
-
return py_json.cast<std::string>();
|
|
2695
|
-
},
|
|
2532
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2696
2533
|
[](Napi::Env env, std::string&& json) {
|
|
2697
2534
|
return Napi::String::New(env, json);
|
|
2698
2535
|
});
|
|
@@ -2700,15 +2537,15 @@ Napi::Value memoize(const Napi::CallbackInfo& info) {
|
|
|
2700
2537
|
|
|
2701
2538
|
|
|
2702
2539
|
Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
2703
|
-
auto js_external_servicer =
|
|
2704
|
-
info[0].As<Napi::External<py::object>>());
|
|
2540
|
+
auto js_external_servicer =
|
|
2541
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2705
2542
|
|
|
2706
2543
|
// CHECK(...CheckTypeTag(...));
|
|
2707
2544
|
|
|
2708
2545
|
py::object* py_servicer = js_external_servicer.Value(info.Env()).Data();
|
|
2709
2546
|
|
|
2710
|
-
auto js_external_context =
|
|
2711
|
-
info[1].As<Napi::External<py::object>>());
|
|
2547
|
+
auto js_external_context =
|
|
2548
|
+
NapiSafeReference(info[1].As<Napi::External<py::object>>());
|
|
2712
2549
|
|
|
2713
2550
|
// CHECK(...CheckTypeTag(...));
|
|
2714
2551
|
|
|
@@ -2720,16 +2557,14 @@ Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
|
2720
2557
|
info.Env(),
|
|
2721
2558
|
"servicer._read(...) in nodejs",
|
|
2722
2559
|
js_external_context,
|
|
2723
|
-
[js_external_servicer,
|
|
2560
|
+
[js_external_servicer, // Ensures `py_servicer` remains valid.
|
|
2724
2561
|
py_servicer,
|
|
2725
|
-
js_external_context,
|
|
2562
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2726
2563
|
py_context,
|
|
2727
2564
|
json_options = std::move(json_options)]() {
|
|
2728
2565
|
return py_servicer->attr("_read")(py_context, json_options);
|
|
2729
2566
|
},
|
|
2730
|
-
[](py::object py_json) {
|
|
2731
|
-
return py_json.cast<std::string>();
|
|
2732
|
-
},
|
|
2567
|
+
[](py::object py_json) { return py_json.cast<std::string>(); },
|
|
2733
2568
|
[](Napi::Env env, std::string&& json) {
|
|
2734
2569
|
return Napi::String::New(env, json);
|
|
2735
2570
|
});
|
|
@@ -2737,22 +2572,21 @@ Napi::Value Servicer_read(const Napi::CallbackInfo& info) {
|
|
|
2737
2572
|
|
|
2738
2573
|
|
|
2739
2574
|
Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
2740
|
-
auto js_external_servicer =
|
|
2741
|
-
info[0].As<Napi::External<py::object>>());
|
|
2575
|
+
auto js_external_servicer =
|
|
2576
|
+
NapiSafeReference(info[0].As<Napi::External<py::object>>());
|
|
2742
2577
|
|
|
2743
2578
|
// CHECK(...CheckTypeTag(...));
|
|
2744
2579
|
|
|
2745
2580
|
py::object* py_servicer = js_external_servicer.Value(info.Env()).Data();
|
|
2746
2581
|
|
|
2747
|
-
auto js_external_context =
|
|
2748
|
-
info[1].As<Napi::External<py::object>>());
|
|
2582
|
+
auto js_external_context =
|
|
2583
|
+
NapiSafeReference(info[1].As<Napi::External<py::object>>());
|
|
2749
2584
|
|
|
2750
2585
|
// CHECK(...CheckTypeTag(...));
|
|
2751
2586
|
|
|
2752
2587
|
py::object* py_context = js_external_context.Value(info.Env()).Data();
|
|
2753
2588
|
|
|
2754
|
-
auto js_writer = NapiSafeFunctionReference(
|
|
2755
|
-
info[2].As<Napi::Function>());
|
|
2589
|
+
auto js_writer = NapiSafeFunctionReference(info[2].As<Napi::Function>());
|
|
2756
2590
|
|
|
2757
2591
|
std::string json_options = info[3].As<Napi::String>().Utf8Value();
|
|
2758
2592
|
|
|
@@ -2760,23 +2594,21 @@ Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
|
2760
2594
|
info.Env(),
|
|
2761
2595
|
"servicer._write(...) in nodejs",
|
|
2762
2596
|
js_external_context,
|
|
2763
|
-
[js_external_servicer,
|
|
2597
|
+
[js_external_servicer, // Ensures `py_servicer` remains valid.
|
|
2764
2598
|
py_servicer,
|
|
2765
|
-
js_external_context,
|
|
2599
|
+
js_external_context, // Ensures `py_context` remains valid.
|
|
2766
2600
|
py_context,
|
|
2767
2601
|
js_writer = std::move(js_writer),
|
|
2768
2602
|
json_options = std::move(json_options)]() {
|
|
2769
2603
|
py::object py_writer = py::cpp_function(
|
|
2770
|
-
[js_writer = std::move(js_writer)](
|
|
2771
|
-
std::string state_json) mutable {
|
|
2604
|
+
[js_writer = std::move(js_writer)](std::string state_json) mutable {
|
|
2772
2605
|
return PythonFutureFromNodePromise(
|
|
2773
|
-
[js_writer,
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2606
|
+
[js_writer, // NOTE: need a _copy_ of
|
|
2607
|
+
// `js_writer` here since
|
|
2608
|
+
// `py_writer` may be called more
|
|
2609
|
+
// than once!
|
|
2777
2610
|
state_json](Napi::Env env) mutable {
|
|
2778
|
-
return js_writer
|
|
2779
|
-
.Value(env)
|
|
2611
|
+
return js_writer.Value(env)
|
|
2780
2612
|
.Call(
|
|
2781
2613
|
env.Global(),
|
|
2782
2614
|
{Napi::String::New(env, state_json)})
|
|
@@ -2787,14 +2619,9 @@ Napi::Value Servicer_write(const Napi::CallbackInfo& info) {
|
|
|
2787
2619
|
});
|
|
2788
2620
|
});
|
|
2789
2621
|
|
|
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>();
|
|
2622
|
+
return py_servicer->attr("_write")(py_context, py_writer, json_options);
|
|
2797
2623
|
},
|
|
2624
|
+
[](py::object py_result) { return py_result.cast<std::string>(); },
|
|
2798
2625
|
[](Napi::Env env, std::string&& result) {
|
|
2799
2626
|
return Napi::String::New(env, result);
|
|
2800
2627
|
});
|