diff --git a/deps/node/src/env.cc b/deps/node/src/env.cc index ec3062a700..03475b33ba 100644 --- a/deps/node/src/env.cc +++ b/deps/node/src/env.cc @@ -311,6 +311,16 @@ std::string GetExecPath(const std::vector& argv) { return exec_path; } +std::unique_ptr ChannelHolder::instance; + +void ChannelHolder::Init() { + channel_ = Channel::New(uv_promise_.get_future(), "embedder"); +} + +std::shared_ptr ChannelHolder::GetPort() { + return channel_.port1; +} + Environment::Environment(IsolateData* isolate_data, Local context, const std::vector& args, @@ -359,7 +369,15 @@ Environment::Environment(IsolateData* isolate_data, } #if defined(LWNODE) - channel_ = Channel::New(uv_promise_.get_future(), "embedder"); + if (ChannelHolder::instance != nullptr) { + // channel.port1 is already being used. + channel_ = ChannelHolder::instance->channel_; + uv_promise_ = std::move(ChannelHolder::instance->uv_promise_); + ChannelHolder::instance.reset(); + } else { + channel_ = Channel::New(uv_promise_.get_future(), "embedder"); + } + main_message_port_ = new MainMessagePort(channel_.port2, std::move(uv_promise_)); loop_holder_ = new LoopHolderUV(isolate_data->event_loop()); diff --git a/deps/node/src/env.h b/deps/node/src/env.h index 9bb3405672..09572727a9 100644 --- a/deps/node/src/env.h +++ b/deps/node/src/env.h @@ -1419,6 +1419,19 @@ class Environment : public MemoryRetainer { #endif }; +class ChannelHolder { + public: + ChannelHolder() = default; + void Init(); + std::shared_ptr GetPort(); + static std::unique_ptr instance; + + private: + std::promise uv_promise_; + Channel channel_; + friend class Environment; +}; + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/deps/node/src/node_errors.cc b/deps/node/src/node_errors.cc index 6961e748c0..7f78a038a8 100644 --- a/deps/node/src/node_errors.cc +++ b/deps/node/src/node_errors.cc @@ -105,6 +105,10 @@ static std::string GetErrorSource(Isolate* isolate, sourceline.c_str()); CHECK_GT(buf.size(), 0); + // @lwnode + start = std::min(start, (int)sourceline.length()); + end = std::min(end, (int)sourceline.length()); + constexpr int kUnderlineBufsize = 1020; char underline_buf[kUnderlineBufsize + 4]; int off = 0; diff --git a/deps/node/src/node_main_lw_runner-inl.h b/deps/node/src/node_main_lw_runner-inl.h index 806baf4047..1d75703dcc 100644 --- a/deps/node/src/node_main_lw_runner-inl.h +++ b/deps/node/src/node_main_lw_runner-inl.h @@ -103,6 +103,8 @@ class LoopStrategy : public MainLoopStrategy { class LWNodeMainRunner { public: + LWNodeMainRunner() { ChannelHolder::instance.reset(); } + ~LWNodeMainRunner() { LWNODE_DEV_LOG("[LWNodeMainRunner::~LWNodeMainRunner]"); } @@ -233,7 +235,17 @@ class LWNodeMainRunner { } std::shared_ptr GetPort() { - CHECK_NOT_NULL(environment_); + if (environment_ == nullptr) { + if (ChannelHolder::instance == nullptr) { + ChannelHolder::instance = std::make_unique(); + ChannelHolder::instance->Init(); + } + return ChannelHolder::instance->GetPort(); + } else { + if (ChannelHolder::instance) { + ChannelHolder::instance.reset(); + } + } return environment_->GetPort(); } diff --git a/include/lwnode/lwnode-version.h b/include/lwnode/lwnode-version.h index 0d65976da0..15bf3b1fbf 100644 --- a/include/lwnode/lwnode-version.h +++ b/include/lwnode/lwnode-version.h @@ -17,6 +17,6 @@ #pragma once #define LWNODE_VERSION_MAJOR 1 - #define LWNODE_VERSION_MINOR 0 + #define LWNODE_VERSION_MINOR 1 #define LWNODE_VERSION_PATCH 9 - #define LWNODE_VERSION_TAG "v1.0.9" + #define LWNODE_VERSION_TAG "v1.1.9" diff --git a/test/embedding/embedtest.cc b/test/embedding/embedtest.cc index 98a04224eb..f0666bc527 100644 --- a/test/embedding/embedtest.cc +++ b/test/embedding/embedtest.cc @@ -76,6 +76,50 @@ TEST0(Embedtest, MessagePort2_Post_Many_JS_First) { EXPECT_EQ(count1, 10); } +TEST0(Embedtest, MessagePort2_Post_JS_First) { + int count1 = 0; + + auto runtime = std::make_shared(); + + // 1. Set OnMessage before starting the runtime + auto port2 = runtime->GetPort(); + port2->OnMessage([&](const MessageEvent* event) { + count1++; + if (event->data() == "ping") { + auto extra = std::to_string(count1); + std::cout << getTimestamp() << " NS pong " + extra << std::endl; + port2->PostMessage(MessageEvent::New("pong " + extra)); + } else { + std::cout << getTimestamp() << " NS ping" << std::endl; + port2->PostMessage(MessageEvent::New("ping")); + } + }); + + // 2. Start the runtime + std::promise promise; + std::future init_future = promise.get_future(); + const char* script = "test/embedding/test-05-message-port-first.js"; + std::string path = (std::filesystem::current_path() / script).string(); + + const bool post_first = true; + char* args[] = {const_cast(""), + const_cast(path.c_str()), + const_cast(std::to_string(post_first).c_str())}; + + std::thread worker = std::thread( + [&](std::promise&& promise) mutable { + runtime->Start(COUNT_OF(args), args, std::move(promise)); + }, + std::move(promise)); + + // 3. Wait for the entry script to run + init_future.wait(); + + worker.join(); + + EXPECT_EQ(count1, 1); +} + TEST0(Embedtest, Restart) { TEST_SKIP("This is not yet production-ready."); diff --git a/test/embedding/test-05-message-port-first.js b/test/embedding/test-05-message-port-first.js new file mode 100644 index 0000000000..95549c6656 --- /dev/null +++ b/test/embedding/test-05-message-port-first.js @@ -0,0 +1,31 @@ +const lwnode = process.lwnode; +const port = process.lwnode.port; +const post_first = +process.argv[2]; + +lwnode.ref(); + +function getTimestamp() { + const now = new Date(); + return now.toISOString().slice(14, 23); +} + +lwnode.postMessage(`ping`); + +const stop_count = 1; +let count = 0; + +lwnode.onmessage = async (event) => { + if (stop_count <= ++count) { + console.log(`${getTimestamp()} JS stop`); + lwnode.unref(); + return; + } + + if (event.data == "ping") { + console.log(`${getTimestamp()} JS pong`); + lwnode.postMessage(`pong ${count}`); + } else { + console.log(`${getTimestamp()} JS ping`); + lwnode.postMessage(`ping`); + } +};