Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
async_op.hpp
Go to the documentation of this file.
1#pragma once
2
4#include <memory>
5#include <napi.h>
6#include <thread>
7#include <utility>
8
9namespace bb::nodejs {
10
11using async_fn = std::function<void(msgpack::sbuffer&)>;
12
28class AsyncOperation : public Napi::AsyncWorker {
29 public:
30 AsyncOperation(Napi::Env env, std::shared_ptr<Napi::Promise::Deferred> deferred, async_fn fn)
31 : Napi::AsyncWorker(env)
32 , _fn(std::move(fn))
33 , _deferred(std::move(deferred))
34 {}
35
40
41 ~AsyncOperation() override = default;
42
43 void Execute() override
44 {
45 try {
46 _fn(_result);
47 } catch (const std::exception& e) {
48 SetError(e.what());
49 } catch (...) {
50 // Catch any other exception type that's not derived from std::exception
51 // This ensures the promise is always rejected rather than leaving it hanging
52 SetError("Unknown exception occurred during async operation");
53 }
54 }
55
56 void OnOK() override
57 {
58 auto buf = Napi::Buffer<char>::Copy(Env(), _result.data(), _result.size());
59 _deferred->Resolve(buf);
60 }
61 void OnError(const Napi::Error& e) override { _deferred->Reject(e.Value()); }
62
63 private:
65 std::shared_ptr<Napi::Promise::Deferred> _deferred;
66 msgpack::sbuffer _result;
67};
68
88class ThreadedAsyncOperation : public std::enable_shared_from_this<ThreadedAsyncOperation> {
89 public:
90 ThreadedAsyncOperation(Napi::Env env, std::shared_ptr<Napi::Promise::Deferred> deferred, async_fn fn)
91 : _fn(std::move(fn))
92 , _deferred(std::move(deferred))
93 {
94 auto dummy = Napi::Function::New(env, [](const Napi::CallbackInfo&) {});
95 _completion_tsfn = Napi::ThreadSafeFunction::New(env, dummy, "ThreadedAsyncOpComplete", 0, 1);
96 }
97
102
104
105 static void Run(Napi::Env env, std::shared_ptr<Napi::Promise::Deferred> deferred, async_fn fn)
106 {
107 auto op = std::make_shared<ThreadedAsyncOperation>(env, std::move(deferred), std::move(fn));
108 op->Queue();
109 }
110
111 private:
112 void Queue()
113 {
114 auto self = shared_from_this();
115 std::thread([self]() {
116 try {
117 self->_fn(self->_result);
118 self->_success = true;
119 } catch (const std::exception& e) {
120 self->_error = e.what();
121 self->_success = false;
122 } catch (...) {
123 self->_error = "Unknown exception occurred during threaded async operation";
124 self->_success = false;
125 }
126
127 // Post completion to the JS main thread. The callback captures `self`
128 // (shared_ptr) so the object stays alive until the callback runs.
129 // napi_tsfn_blocking only blocks on queue insertion, not on callback
130 // completion, so we cannot use raw pointers here.
131 self->_completion_tsfn.BlockingCall([self](Napi::Env env, Napi::Function /*js_callback*/) {
132 if (self->_success) {
133 auto buf = Napi::Buffer<char>::Copy(env, self->_result.data(), self->_result.size());
134 self->_deferred->Resolve(buf);
135 } else {
136 auto error = Napi::Error::New(env, self->_error);
137 self->_deferred->Reject(error.Value());
138 }
139 self->_completion_tsfn.Release();
140 });
141 }).detach();
142 }
143
145 std::shared_ptr<Napi::Promise::Deferred> _deferred;
146 Napi::ThreadSafeFunction _completion_tsfn;
147 msgpack::sbuffer _result;
148 bool _success = false;
149 std::string _error;
150};
151
152} // namespace bb::nodejs
Encapsulatest some work that can be done off the JavaScript main thread.
Definition async_op.hpp:28
AsyncOperation & operator=(AsyncOperation &&)=delete
void Execute() override
Definition async_op.hpp:43
AsyncOperation(AsyncOperation &&)=delete
AsyncOperation & operator=(const AsyncOperation &)=delete
AsyncOperation(const AsyncOperation &)=delete
~AsyncOperation() override=default
AsyncOperation(Napi::Env env, std::shared_ptr< Napi::Promise::Deferred > deferred, async_fn fn)
Definition async_op.hpp:30
void OnError(const Napi::Error &e) override
Definition async_op.hpp:61
std::shared_ptr< Napi::Promise::Deferred > _deferred
Definition async_op.hpp:65
msgpack::sbuffer _result
Definition async_op.hpp:66
Runs work on a dedicated std::thread instead of the libuv thread pool.
Definition async_op.hpp:88
ThreadedAsyncOperation & operator=(const ThreadedAsyncOperation &)=delete
ThreadedAsyncOperation(Napi::Env env, std::shared_ptr< Napi::Promise::Deferred > deferred, async_fn fn)
Definition async_op.hpp:90
ThreadedAsyncOperation(const ThreadedAsyncOperation &)=delete
std::shared_ptr< Napi::Promise::Deferred > _deferred
Definition async_op.hpp:145
static void Run(Napi::Env env, std::shared_ptr< Napi::Promise::Deferred > deferred, async_fn fn)
Definition async_op.hpp:105
ThreadedAsyncOperation & operator=(ThreadedAsyncOperation &&)=delete
Napi::ThreadSafeFunction _completion_tsfn
Definition async_op.hpp:146
ThreadedAsyncOperation(ThreadedAsyncOperation &&)=delete
std::function< void(msgpack::sbuffer &)> async_fn
Definition async_op.hpp:11
STL namespace.
constexpr decltype(auto) get(::tuplet::tuple< T... > &&t) noexcept
Definition tuple.hpp:13