Skip to content

Commit a51b267

Browse files
committed
Fix: Detect Electron version at runtime
This way, no separate build for NodeJS and Electron v21(+) is needed. Cache the result once, to not have to look up the value on each incoming message.
1 parent 05556cb commit a51b267

File tree

2 files changed

+72
-25
lines changed

2 files changed

+72
-25
lines changed

src/incoming_msg.cc

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* Copyright (c) 2017-2019 Rolf Timmermans */
22
#include "incoming_msg.h"
33

4+
#include "util/electron_helper.h"
45
#include "util/error.h"
56

67
namespace zmq {
@@ -14,39 +15,37 @@ IncomingMsg::~IncomingMsg() {
1415
}
1516

1617
Napi::Value IncomingMsg::IntoBuffer(const Napi::Env& env) {
17-
#if !(NODE_RUNTIME_ELECTRON && NODE_MODULE_VERSION >= 109) // 109 is Electron v21 and up
18-
if (moved) {
19-
/* If ownership has been transferred, do not attempt to read the buffer
20-
again in any case. This should not happen of course. */
21-
ErrnoException(env, EINVAL).ThrowAsJavaScriptException();
22-
return env.Undefined();
18+
if (!hasElectronMemoryCage(env)) {
19+
if (moved) {
20+
/* If ownership has been transferred, do not attempt to read the buffer
21+
again in any case. This should not happen of course. */
22+
ErrnoException(env, EINVAL).ThrowAsJavaScriptException();
23+
return env.Undefined();
24+
}
2325
}
24-
25-
static auto constexpr zero_copy_threshold = 1 << 7;
26-
#endif
27-
2826
auto data = reinterpret_cast<uint8_t*>(zmq_msg_data(*ref));
2927
auto length = zmq_msg_size(*ref);
3028

31-
#if !(NODE_RUNTIME_ELECTRON && NODE_MODULE_VERSION >= 109) // 109 is Electron v21 and up
32-
if (length > zero_copy_threshold) {
33-
/* Reuse existing buffer for external storage. This avoids copying but
34-
does include an overhead in having to call a finalizer when the
35-
buffer is GC'ed. For very small messages it is faster to copy. */
36-
moved = true;
29+
if (!hasElectronMemoryCage(env)) {
30+
static auto constexpr zero_copy_threshold = 1 << 7;
31+
if (length > zero_copy_threshold) {
32+
/* Reuse existing buffer for external storage. This avoids copying but
33+
does include an overhead in having to call a finalizer when the
34+
buffer is GC'ed. For very small messages it is faster to copy. */
35+
moved = true;
3736

38-
/* Put appropriate GC pressure according to the size of the buffer. */
39-
Napi::MemoryManagement::AdjustExternalMemory(env, length);
37+
/* Put appropriate GC pressure according to the size of the buffer. */
38+
Napi::MemoryManagement::AdjustExternalMemory(env, length);
4039

41-
auto release = [](const Napi::Env& env, uint8_t*, Reference* ref) {
42-
ptrdiff_t length = zmq_msg_size(*ref);
43-
Napi::MemoryManagement::AdjustExternalMemory(env, -length);
44-
delete ref;
45-
};
40+
auto release = [](const Napi::Env& env, uint8_t*, Reference* ref) {
41+
ptrdiff_t length = zmq_msg_size(*ref);
42+
Napi::MemoryManagement::AdjustExternalMemory(env, -length);
43+
delete ref;
44+
};
4645

47-
return Napi::Buffer<uint8_t>::New(env, data, length, release, ref);
46+
return Napi::Buffer<uint8_t>::New(env, data, length, release, ref);
47+
}
4848
}
49-
#endif
5049

5150
if (length > 0) {
5251
return Napi::Buffer<uint8_t>::Copy(env, data, length);

src/util/electron_helper.h

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#pragma once
2+
3+
#include <napi.h>
4+
#include <string>
5+
6+
namespace zmq {
7+
bool hasRun = false;
8+
bool hasElectronMemoryCageCache = false;
9+
10+
static inline std::string first_component(std::string const& value) {
11+
std::string::size_type pos = value.find('.');
12+
return pos == value.npos ? value : value.substr(0, pos);
13+
}
14+
15+
/* Check if runtime is Electron. */
16+
static inline bool IsElectron(const Napi::Env& env) {
17+
auto global = env.Global();
18+
auto isElectron = global.Get("process")
19+
.As<Napi::Object>()
20+
.Get("versions")
21+
.As<Napi::Object>()
22+
.Has("electron");
23+
return isElectron;
24+
}
25+
26+
static inline bool hasElectronMemoryCage(const Napi::Env& env) {
27+
if (!hasRun) {
28+
if (IsElectron(env)) {
29+
auto electronVers = env.Global()
30+
.Get("window")
31+
.ToObject()
32+
.Get("process")
33+
.ToObject()
34+
.Get("versions")
35+
.ToObject()
36+
.Get("electron")
37+
.ToString()
38+
.Utf8Value();
39+
int majorVer = stoi(first_component(electronVers));
40+
if (majorVer >= 21) {
41+
hasElectronMemoryCageCache = true;
42+
}
43+
}
44+
hasRun = true;
45+
}
46+
return hasElectronMemoryCageCache;
47+
}
48+
}

0 commit comments

Comments
 (0)