@technoculture/data-bridge 0.1.1 → 0.1.2
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/CMakeLists.txt +10 -2
- package/deps/include/data_bridge/config.hpp +69 -0
- package/deps/include/data_bridge/protocol/crc16.hpp +8 -0
- package/deps/include/data_bridge/protocol/crc32.hpp +19 -0
- package/deps/include/data_bridge/protocol/packet.hpp +175 -0
- package/deps/include/data_bridge/protocol/reassembler.hpp +80 -0
- package/deps/include/data_bridge/transport/factory.hpp +0 -0
- package/deps/include/data_bridge/transport/iserial_port.hpp +15 -0
- package/deps/include/data_bridge/transport/serial_port.hpp +28 -0
- package/deps/src/CMakeLists.txt +18 -0
- package/deps/src/protocol/crc16.cpp +19 -0
- package/deps/src/protocol/packet.cpp +1 -0
- package/deps/src/transport/platform/linux/linux_serial.cpp +53 -0
- package/deps/src/transport/platform/windows/windows_serial.cpp +51 -0
- package/dist/index.d.mts +41 -72
- package/dist/index.d.ts +41 -72
- package/dist/index.js +196 -102
- package/dist/index.mjs +194 -103
- package/lib/index.ts +12 -160
- package/lib/native.ts +71 -0
- package/lib/reliable.ts +234 -0
- package/lib/resilient.ts +30 -6
- package/package.json +6 -4
- package/prebuilds/darwin-arm64/Release/data_bridge_node.node +0 -0
- package/src/addon.cpp +248 -137
- package/prebuilds/darwin-arm64/.ninja_deps +0 -0
- package/prebuilds/darwin-arm64/.ninja_log +0 -6
- package/prebuilds/darwin-arm64/CMakeCache.txt +0 -398
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeCCompiler.cmake +0 -84
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeCXXCompiler.cmake +0 -104
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeDetermineCompilerABI_C.bin +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeDetermineCompilerABI_CXX.bin +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CMakeSystem.cmake +0 -15
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/CMakeCCompilerId.c +0 -905
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/a.out +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdC/apple-sdk.c +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/CMakeCXXCompilerId.cpp +0 -920
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/a.out +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/4.0.3/CompilerIdCXX/apple-sdk.cpp +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/CMakeConfigureLog.yaml +0 -531
- package/prebuilds/darwin-arm64/CMakeFiles/InstallScripts.json +0 -7
- package/prebuilds/darwin-arm64/CMakeFiles/TargetDirectories.txt +0 -3
- package/prebuilds/darwin-arm64/CMakeFiles/cmake.check_cache +0 -1
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/protocol/crc16.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/transport/platform/linux/linux_serial.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/src/addon.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/data_bridge_node.dir/src/serial_wrapper.cpp.o +0 -0
- package/prebuilds/darwin-arm64/CMakeFiles/rules.ninja +0 -64
- package/prebuilds/darwin-arm64/build.ninja +0 -192
- package/prebuilds/darwin-arm64/cmake_install.cmake +0 -61
package/src/addon.cpp
CHANGED
|
@@ -2,7 +2,10 @@
|
|
|
2
2
|
* Data Bridge Node.js Native Addon
|
|
3
3
|
*
|
|
4
4
|
* Exposes the C++ Data Bridge library to JavaScript via Node-API.
|
|
5
|
-
*
|
|
5
|
+
* Aligned with Python _core:
|
|
6
|
+
* - SerialPort: Raw async serial I/O
|
|
7
|
+
* - Packet: Serialization/Deserialization helpers
|
|
8
|
+
* - Reassembler: Fragmentation handling
|
|
6
9
|
*/
|
|
7
10
|
|
|
8
11
|
#include <napi.h>
|
|
@@ -12,208 +15,316 @@
|
|
|
12
15
|
#include <memory>
|
|
13
16
|
#include <thread>
|
|
14
17
|
#include <atomic>
|
|
15
|
-
#include <
|
|
16
|
-
#include <mutex>
|
|
17
|
-
#include <condition_variable>
|
|
18
|
+
#include <vector>
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
// --- SerialPort Wrapper ---
|
|
21
|
+
class SerialPortWrapper : public Napi::ObjectWrap<SerialPortWrapper> {
|
|
20
22
|
public:
|
|
21
23
|
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
22
|
-
|
|
23
|
-
~
|
|
24
|
+
SerialPortWrapper(const Napi::CallbackInfo& info);
|
|
25
|
+
~SerialPortWrapper();
|
|
24
26
|
|
|
25
27
|
private:
|
|
26
|
-
// JavaScript methods
|
|
27
28
|
Napi::Value Open(const Napi::CallbackInfo& info);
|
|
28
|
-
Napi::Value Send(const Napi::CallbackInfo& info);
|
|
29
29
|
Napi::Value Close(const Napi::CallbackInfo& info);
|
|
30
|
+
Napi::Value Write(const Napi::CallbackInfo& info);
|
|
30
31
|
Napi::Value IsOpen(const Napi::CallbackInfo& info);
|
|
31
|
-
|
|
32
|
-
// Internal state
|
|
32
|
+
|
|
33
33
|
std::unique_ptr<SerialPort> serial_;
|
|
34
34
|
std::atomic<bool> is_open_{false};
|
|
35
35
|
std::atomic<bool> should_stop_{false};
|
|
36
36
|
std::thread receive_thread_;
|
|
37
|
-
uint8_t seq_id_ = 0; // Per-instance sequence ID
|
|
38
|
-
|
|
39
|
-
// Thread-safe receive callback
|
|
40
37
|
Napi::ThreadSafeFunction tsfn_;
|
|
41
|
-
|
|
38
|
+
|
|
42
39
|
void ReceiveLoop();
|
|
43
40
|
void StopReceiveLoop();
|
|
44
41
|
};
|
|
45
42
|
|
|
46
|
-
Napi::Object
|
|
47
|
-
Napi::Function func = DefineClass(env, "
|
|
48
|
-
InstanceMethod("open", &
|
|
49
|
-
InstanceMethod("
|
|
50
|
-
InstanceMethod("
|
|
51
|
-
InstanceMethod("isOpen", &
|
|
43
|
+
Napi::Object SerialPortWrapper::Init(Napi::Env env, Napi::Object exports) {
|
|
44
|
+
Napi::Function func = DefineClass(env, "SerialPort", {
|
|
45
|
+
InstanceMethod("open", &SerialPortWrapper::Open),
|
|
46
|
+
InstanceMethod("close", &SerialPortWrapper::Close),
|
|
47
|
+
InstanceMethod("write", &SerialPortWrapper::Write),
|
|
48
|
+
InstanceMethod("isOpen", &SerialPortWrapper::IsOpen),
|
|
52
49
|
});
|
|
53
|
-
|
|
54
|
-
exports.Set("DataBridge", func);
|
|
50
|
+
exports.Set("SerialPort", func);
|
|
55
51
|
return exports;
|
|
56
52
|
}
|
|
57
53
|
|
|
58
|
-
|
|
59
|
-
: Napi::ObjectWrap<
|
|
54
|
+
SerialPortWrapper::SerialPortWrapper(const Napi::CallbackInfo& info)
|
|
55
|
+
: Napi::ObjectWrap<SerialPortWrapper>(info) {
|
|
60
56
|
serial_ = std::make_unique<SerialPort>();
|
|
61
57
|
}
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
SerialPortWrapper::~SerialPortWrapper() {
|
|
64
60
|
StopReceiveLoop();
|
|
65
61
|
}
|
|
66
62
|
|
|
67
|
-
Napi::Value
|
|
63
|
+
Napi::Value SerialPortWrapper::Open(const Napi::CallbackInfo& info) {
|
|
68
64
|
Napi::Env env = info.Env();
|
|
69
|
-
|
|
70
65
|
if (info.Length() < 1 || !info[0].IsString()) {
|
|
71
66
|
Napi::TypeError::New(env, "Port path required").ThrowAsJavaScriptException();
|
|
72
67
|
return env.Undefined();
|
|
73
68
|
}
|
|
74
|
-
|
|
69
|
+
|
|
75
70
|
std::string port = info[0].As<Napi::String>().Utf8Value();
|
|
76
71
|
int baud = 115200;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
72
|
+
if (info.Length() >= 2 && info[1].IsNumber()) baud = info[1].As<Napi::Number>().Int32Value();
|
|
73
|
+
|
|
74
|
+
// Callback is mandatory for raw serial port to receive data
|
|
75
|
+
if (info.Length() < 3 || !info[2].IsFunction()) {
|
|
76
|
+
Napi::TypeError::New(env, "Callback required").ThrowAsJavaScriptException();
|
|
77
|
+
return env.Undefined();
|
|
80
78
|
}
|
|
81
|
-
|
|
82
|
-
// Create a deferred promise
|
|
83
|
-
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
|
|
84
|
-
|
|
79
|
+
|
|
85
80
|
if (serial_->open(port, baud)) {
|
|
86
81
|
is_open_ = true;
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
0, 1
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
should_stop_ = false;
|
|
98
|
-
receive_thread_ = std::thread(&DataBridgeWrapper::ReceiveLoop, this);
|
|
99
|
-
}
|
|
83
|
+
tsfn_ = Napi::ThreadSafeFunction::New(
|
|
84
|
+
env,
|
|
85
|
+
info[2].As<Napi::Function>(),
|
|
86
|
+
"SerialPort Receive Callback",
|
|
87
|
+
0, 1
|
|
88
|
+
);
|
|
100
89
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
90
|
+
should_stop_ = false;
|
|
91
|
+
receive_thread_ = std::thread(&SerialPortWrapper::ReceiveLoop, this);
|
|
92
|
+
|
|
93
|
+
return Napi::Boolean::New(env, true);
|
|
104
94
|
}
|
|
105
95
|
|
|
106
|
-
return
|
|
96
|
+
return Napi::Boolean::New(env, false);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
Napi::Value SerialPortWrapper::Close(const Napi::CallbackInfo& info) {
|
|
100
|
+
StopReceiveLoop();
|
|
101
|
+
serial_->close();
|
|
102
|
+
is_open_ = false;
|
|
103
|
+
return Napi::Boolean::New(info.Env(), true);
|
|
107
104
|
}
|
|
108
105
|
|
|
109
|
-
Napi::Value
|
|
106
|
+
Napi::Value SerialPortWrapper::Write(const Napi::CallbackInfo& info) {
|
|
110
107
|
Napi::Env env = info.Env();
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
Napi::Error::New(env, "Port not open").ThrowAsJavaScriptException();
|
|
108
|
+
if (info.Length() < 1 || !info[0].IsBuffer()) {
|
|
109
|
+
Napi::TypeError::New(env, "Buffer required").ThrowAsJavaScriptException();
|
|
114
110
|
return env.Undefined();
|
|
115
111
|
}
|
|
116
|
-
|
|
117
|
-
if (info.Length() < 1) {
|
|
118
|
-
Napi::TypeError::New(env, "Data required").ThrowAsJavaScriptException();
|
|
119
|
-
return env.Undefined();
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
std::string payload;
|
|
123
|
-
if (info[0].IsBuffer()) {
|
|
124
|
-
Napi::Buffer<char> buf = info[0].As<Napi::Buffer<char>>();
|
|
125
|
-
payload = std::string(buf.Data(), buf.Length());
|
|
126
|
-
} else if (info[0].IsString()) {
|
|
127
|
-
payload = info[0].As<Napi::String>().Utf8Value();
|
|
128
|
-
} else {
|
|
129
|
-
Napi::TypeError::New(env, "Data must be Buffer or string").ThrowAsJavaScriptException();
|
|
130
|
-
return env.Undefined();
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Serialize and send with fragmentation
|
|
134
|
-
// Sequence ID is managed per-instance
|
|
135
|
-
auto packet = Packet::serialize(Packet::TYPE_DATA, seq_id_++, payload);
|
|
136
|
-
|
|
137
|
-
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
|
|
138
|
-
|
|
139
|
-
// TODO: Implement proper async send with ACK waiting
|
|
140
|
-
// For now, synchronous send
|
|
141
|
-
int written = serial_->write(packet);
|
|
142
|
-
|
|
143
|
-
if (written > 0) {
|
|
144
|
-
deferred.Resolve(Napi::Number::New(env, written));
|
|
145
|
-
} else {
|
|
146
|
-
deferred.Reject(Napi::Error::New(env, "Write failed").Value());
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
return deferred.Promise();
|
|
150
|
-
}
|
|
151
112
|
|
|
152
|
-
Napi::
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
return Napi::
|
|
113
|
+
Napi::Buffer<uint8_t> buf = info[0].As<Napi::Buffer<uint8_t>>();
|
|
114
|
+
std::vector<uint8_t> data(buf.Data(), buf.Data() + buf.Length());
|
|
115
|
+
|
|
116
|
+
// Write is synchronous in C++ implementation usually, or we can make it async if needed.
|
|
117
|
+
// For now, keeping it synchronous/blocking for simplicity as per Python binding.
|
|
118
|
+
// (Node.js event loop might block briefly, but serial write is fast or buffered)
|
|
119
|
+
int written = serial_->write(data);
|
|
120
|
+
return Napi::Number::New(env, written);
|
|
160
121
|
}
|
|
161
122
|
|
|
162
|
-
Napi::Value
|
|
123
|
+
Napi::Value SerialPortWrapper::IsOpen(const Napi::CallbackInfo& info) {
|
|
163
124
|
return Napi::Boolean::New(info.Env(), is_open_.load());
|
|
164
125
|
}
|
|
165
126
|
|
|
166
|
-
void
|
|
167
|
-
uint8_t buffer[
|
|
168
|
-
std::vector<uint8_t> rx_pool;
|
|
169
|
-
Reassembler reassembler;
|
|
170
|
-
|
|
127
|
+
void SerialPortWrapper::ReceiveLoop() {
|
|
128
|
+
uint8_t buffer[4096];
|
|
171
129
|
while (!should_stop_) {
|
|
130
|
+
// Read raw bytes
|
|
172
131
|
int n = serial_->read(buffer, sizeof(buffer));
|
|
173
132
|
if (n > 0) {
|
|
174
|
-
|
|
133
|
+
// Copy data for the callback
|
|
134
|
+
std::vector<uint8_t> data(buffer, buffer + n);
|
|
135
|
+
|
|
136
|
+
auto status = tsfn_.BlockingCall([data](Napi::Env env, Napi::Function callback) {
|
|
137
|
+
callback.Call({
|
|
138
|
+
Napi::Buffer<uint8_t>::Copy(env, data.data(), data.size())
|
|
139
|
+
});
|
|
140
|
+
});
|
|
175
141
|
|
|
176
|
-
|
|
177
|
-
auto frame = Packet::deserialize(rx_pool);
|
|
178
|
-
if (!frame.valid) break;
|
|
179
|
-
|
|
180
|
-
if (frame.header.type == Packet::TYPE_DATA) {
|
|
181
|
-
if (reassembler.process_fragment(frame)) {
|
|
182
|
-
if (reassembler.is_complete(frame)) {
|
|
183
|
-
// Emit to JavaScript via ThreadSafeFunction
|
|
184
|
-
auto data = reassembler.get_data();
|
|
185
|
-
|
|
186
|
-
tsfn_.BlockingCall([data](Napi::Env env, Napi::Function callback) {
|
|
187
|
-
callback.Call({
|
|
188
|
-
Napi::Buffer<char>::Copy(env,
|
|
189
|
-
reinterpret_cast<const char*>(data.data()),
|
|
190
|
-
data.size())
|
|
191
|
-
});
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
// Send ACK
|
|
196
|
-
serial_->write(Packet::serialize(Packet::TYPE_ACK, frame.header.seq_id, ""));
|
|
197
|
-
}
|
|
198
|
-
}
|
|
142
|
+
if (status != napi_ok) break;
|
|
199
143
|
}
|
|
144
|
+
// Small sleep to prevent tight loop if read is non-blocking and returns 0 often
|
|
145
|
+
// But read should be blocking with timeout.
|
|
146
|
+
// Assuming implementation of serial_->read handles timeout or blocking.
|
|
147
|
+
// The previous implementation had a sleep, so we surely need one if non-blocking.
|
|
200
148
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
|
201
149
|
}
|
|
202
150
|
}
|
|
203
151
|
|
|
204
|
-
void
|
|
152
|
+
void SerialPortWrapper::StopReceiveLoop() {
|
|
205
153
|
should_stop_ = true;
|
|
206
|
-
if (receive_thread_.joinable())
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
154
|
+
if (receive_thread_.joinable()) receive_thread_.join();
|
|
155
|
+
if (tsfn_) tsfn_.Release();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// --- Packet Wrapper ---
|
|
159
|
+
class PacketWrapper : public Napi::ObjectWrap<PacketWrapper> {
|
|
160
|
+
public:
|
|
161
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
162
|
+
PacketWrapper(const Napi::CallbackInfo& info);
|
|
163
|
+
|
|
164
|
+
private:
|
|
165
|
+
static Napi::Value Serialize(const Napi::CallbackInfo& info);
|
|
166
|
+
static Napi::Value Deserialize(const Napi::CallbackInfo& info);
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
Napi::Object PacketWrapper::Init(Napi::Env env, Napi::Object exports) {
|
|
170
|
+
Napi::Function func = DefineClass(env, "Packet", {
|
|
171
|
+
StaticMethod("serialize", &PacketWrapper::Serialize),
|
|
172
|
+
StaticMethod("deserialize", &PacketWrapper::Deserialize),
|
|
173
|
+
StaticValue("TYPE_DATA", Napi::Number::New(env, Packet::TYPE_DATA)),
|
|
174
|
+
StaticValue("TYPE_ACK", Napi::Number::New(env, Packet::TYPE_ACK)),
|
|
175
|
+
StaticValue("TYPE_NACK", Napi::Number::New(env, Packet::TYPE_NACK)),
|
|
176
|
+
StaticValue("TYPE_SYN", Napi::Number::New(env, Packet::TYPE_SYN)),
|
|
177
|
+
});
|
|
178
|
+
exports.Set("Packet", func);
|
|
179
|
+
return exports;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
PacketWrapper::PacketWrapper(const Napi::CallbackInfo& info) : Napi::ObjectWrap<PacketWrapper>(info) {}
|
|
183
|
+
|
|
184
|
+
Napi::Value PacketWrapper::Serialize(const Napi::CallbackInfo& info) {
|
|
185
|
+
Napi::Env env = info.Env();
|
|
186
|
+
// Args: type, seq, payload, frag_id (opt), total_frags (opt)
|
|
187
|
+
|
|
188
|
+
if (info.Length() < 3) throw Napi::Error::New(env, "Args: type, seq, payload");
|
|
189
|
+
|
|
190
|
+
uint8_t type = info[0].As<Napi::Number>().Uint32Value();
|
|
191
|
+
uint8_t seq = info[1].As<Napi::Number>().Uint32Value();
|
|
192
|
+
std::string payload;
|
|
193
|
+
|
|
194
|
+
if (info[2].IsBuffer()) {
|
|
195
|
+
Napi::Buffer<char> buf = info[2].As<Napi::Buffer<char>>();
|
|
196
|
+
payload.assign(buf.Data(), buf.Length());
|
|
197
|
+
} else {
|
|
198
|
+
payload = info[2].ToString().Utf8Value();
|
|
211
199
|
}
|
|
200
|
+
|
|
201
|
+
uint16_t frag_id = 0;
|
|
202
|
+
uint16_t total_frags = 1;
|
|
203
|
+
if (info.Length() > 3) frag_id = info[3].As<Napi::Number>().Uint32Value();
|
|
204
|
+
if (info.Length() > 4) total_frags = info[4].As<Napi::Number>().Uint32Value();
|
|
205
|
+
|
|
206
|
+
auto vec = Packet::serialize(type, seq, payload, frag_id, total_frags);
|
|
207
|
+
return Napi::Buffer<uint8_t>::Copy(env, vec.data(), vec.size());
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
Napi::Value PacketWrapper::Deserialize(const Napi::CallbackInfo& info) {
|
|
211
|
+
Napi::Env env = info.Env();
|
|
212
|
+
if (info.Length() < 1 || !info[0].IsBuffer()) throw Napi::Error::New(env, "Buffer required");
|
|
213
|
+
|
|
214
|
+
Napi::Buffer<uint8_t> buf = info[0].As<Napi::Buffer<uint8_t>>();
|
|
215
|
+
std::vector<uint8_t> data(buf.Data(), buf.Data() + buf.Length());
|
|
216
|
+
|
|
217
|
+
// Packet::deserialize modifies the vector (consumes bytes)
|
|
218
|
+
Packet::Frame frame = Packet::deserialize(data);
|
|
219
|
+
|
|
220
|
+
Napi::Object result = Napi::Object::New(env);
|
|
221
|
+
|
|
222
|
+
// Frame object
|
|
223
|
+
Napi::Object frameObj = Napi::Object::New(env);
|
|
224
|
+
frameObj.Set("valid", frame.valid);
|
|
225
|
+
|
|
226
|
+
// Header
|
|
227
|
+
Napi::Object header = Napi::Object::New(env);
|
|
228
|
+
header.Set("type", frame.header.type);
|
|
229
|
+
header.Set("seq_id", frame.header.seq_id);
|
|
230
|
+
header.Set("fragment_id", frame.header.fragment_id);
|
|
231
|
+
header.Set("total_frags", frame.header.total_frags);
|
|
232
|
+
header.Set("payload_len", frame.header.payload_len);
|
|
233
|
+
header.Set("crc32", frame.header.crc32);
|
|
234
|
+
frameObj.Set("header", header);
|
|
235
|
+
|
|
236
|
+
// Payload
|
|
237
|
+
frameObj.Set("payload", Napi::Buffer<uint8_t>::Copy(env, frame.payload.data(), frame.payload.size()));
|
|
238
|
+
|
|
239
|
+
result.Set("frame", frameObj);
|
|
240
|
+
result.Set("remaining", Napi::Buffer<uint8_t>::Copy(env, data.data(), data.size()));
|
|
241
|
+
|
|
242
|
+
return result;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// --- Reassembler Wrapper ---
|
|
246
|
+
class ReassemblerWrapper : public Napi::ObjectWrap<ReassemblerWrapper> {
|
|
247
|
+
public:
|
|
248
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
249
|
+
ReassemblerWrapper(const Napi::CallbackInfo& info);
|
|
250
|
+
|
|
251
|
+
private:
|
|
252
|
+
std::unique_ptr<Reassembler> reassembler_;
|
|
253
|
+
|
|
254
|
+
Napi::Value ProcessFragment(const Napi::CallbackInfo& info);
|
|
255
|
+
Napi::Value IsComplete(const Napi::CallbackInfo& info);
|
|
256
|
+
Napi::Value GetData(const Napi::CallbackInfo& info);
|
|
257
|
+
Napi::Value IsDuplicate(const Napi::CallbackInfo& info);
|
|
258
|
+
Napi::Value GetBufferedSize(const Napi::CallbackInfo& info);
|
|
259
|
+
};
|
|
260
|
+
|
|
261
|
+
Napi::Object ReassemblerWrapper::Init(Napi::Env env, Napi::Object exports) {
|
|
262
|
+
Napi::Function func = DefineClass(env, "Reassembler", {
|
|
263
|
+
InstanceMethod("processFragment", &ReassemblerWrapper::ProcessFragment),
|
|
264
|
+
InstanceMethod("isComplete", &ReassemblerWrapper::IsComplete),
|
|
265
|
+
InstanceMethod("getData", &ReassemblerWrapper::GetData),
|
|
266
|
+
InstanceMethod("isDuplicate", &ReassemblerWrapper::IsDuplicate),
|
|
267
|
+
InstanceMethod("getBufferedSize", &ReassemblerWrapper::GetBufferedSize),
|
|
268
|
+
});
|
|
269
|
+
exports.Set("Reassembler", func);
|
|
270
|
+
return exports;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
ReassemblerWrapper::ReassemblerWrapper(const Napi::CallbackInfo& info) : Napi::ObjectWrap<ReassemblerWrapper>(info) {
|
|
274
|
+
reassembler_ = std::make_unique<Reassembler>();
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// Helper to extract C++ Frame from JS Frame object
|
|
278
|
+
Packet::Frame JsToFrame(Napi::Object jsFrame) {
|
|
279
|
+
Packet::Frame frame;
|
|
280
|
+
frame.valid = jsFrame.Get("valid").As<Napi::Boolean>().Value();
|
|
281
|
+
Napi::Object header = jsFrame.Get("header").As<Napi::Object>();
|
|
282
|
+
frame.header.type = header.Get("type").As<Napi::Number>().Uint32Value();
|
|
283
|
+
frame.header.seq_id = header.Get("seq_id").As<Napi::Number>().Uint32Value();
|
|
284
|
+
frame.header.fragment_id = header.Get("fragment_id").As<Napi::Number>().Uint32Value();
|
|
285
|
+
frame.header.total_frags = header.Get("total_frags").As<Napi::Number>().Uint32Value();
|
|
286
|
+
|
|
287
|
+
Napi::Buffer<uint8_t> pl = jsFrame.Get("payload").As<Napi::Buffer<uint8_t>>();
|
|
288
|
+
frame.payload.assign(pl.Data(), pl.Data() + pl.Length());
|
|
289
|
+
return frame;
|
|
212
290
|
}
|
|
213
291
|
|
|
214
|
-
|
|
292
|
+
Napi::Value ReassemblerWrapper::ProcessFragment(const Napi::CallbackInfo& info) {
|
|
293
|
+
if (info.Length() < 1 || !info[0].IsObject()) throw Napi::Error::New(info.Env(), "Frame object required");
|
|
294
|
+
Packet::Frame frame = JsToFrame(info[0].As<Napi::Object>());
|
|
295
|
+
return Napi::Boolean::New(info.Env(), reassembler_->process_fragment(frame));
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
Napi::Value ReassemblerWrapper::IsComplete(const Napi::CallbackInfo& info) {
|
|
299
|
+
if (info.Length() < 1 || !info[0].IsObject()) throw Napi::Error::New(info.Env(), "Frame object required");
|
|
300
|
+
Packet::Frame frame = JsToFrame(info[0].As<Napi::Object>());
|
|
301
|
+
return Napi::Boolean::New(info.Env(), reassembler_->is_complete(frame));
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
Napi::Value ReassemblerWrapper::GetData(const Napi::CallbackInfo& info) {
|
|
305
|
+
auto data = reassembler_->get_data();
|
|
306
|
+
return Napi::Buffer<uint8_t>::Copy(info.Env(), data.data(), data.size());
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
Napi::Value ReassemblerWrapper::IsDuplicate(const Napi::CallbackInfo& info) {
|
|
310
|
+
if (info.Length() < 1 || !info[0].IsObject()) throw Napi::Error::New(info.Env(), "Frame object required");
|
|
311
|
+
Packet::Frame frame = JsToFrame(info[0].As<Napi::Object>());
|
|
312
|
+
return Napi::Boolean::New(info.Env(), reassembler_->is_duplicate(frame));
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
Napi::Value ReassemblerWrapper::GetBufferedSize(const Napi::CallbackInfo& info) {
|
|
316
|
+
return Napi::Number::New(info.Env(), reassembler_->get_buffered_size());
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
|
|
320
|
+
// --- Init ---
|
|
321
|
+
|
|
215
322
|
Napi::Object InitAll(Napi::Env env, Napi::Object exports) {
|
|
216
|
-
|
|
323
|
+
SerialPortWrapper::Init(env, exports);
|
|
324
|
+
PacketWrapper::Init(env, exports);
|
|
325
|
+
ReassemblerWrapper::Init(env, exports);
|
|
326
|
+
return exports;
|
|
217
327
|
}
|
|
218
328
|
|
|
219
329
|
NODE_API_MODULE(data_bridge_node, InitAll)
|
|
330
|
+
|
|
Binary file
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
# ninja log v6
|
|
2
|
-
1 42 1767813639052166764 CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/protocol/crc16.cpp.o 44a8848073165fd4
|
|
3
|
-
1 286 1767813639052016345 CMakeFiles/data_bridge_node.dir/src/serial_wrapper.cpp.o 9b7a8f38fa1f98b2
|
|
4
|
-
1 301 1767813639052311933 CMakeFiles/data_bridge_node.dir/Users/satyamtiwary/Documents/Python-Things/data-bridge/src/transport/platform/linux/linux_serial.cpp.o 1a4595fea1e208f8
|
|
5
|
-
1 698 1767813639051708840 CMakeFiles/data_bridge_node.dir/src/addon.cpp.o 7d74cb8705ae44b7
|
|
6
|
-
698 745 1767813639749307606 Release/data_bridge_node.node 1305e389db74efac
|