@homaiohq/napi-quickfix 0.0.0-stage → 0.2.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/CMakeLists.txt +135 -0
- package/LICENSE +21 -0
- package/README.md +638 -2
- package/THIRD_PARTY_LICENSES +48 -0
- package/cpp/acceptor_wrap.cpp +468 -0
- package/cpp/acceptor_wrap.h +116 -0
- package/cpp/addon.cpp +87 -0
- package/cpp/application_bridge.cpp +466 -0
- package/cpp/application_bridge.h +204 -0
- package/cpp/data_dictionary_wrap.cpp +165 -0
- package/cpp/data_dictionary_wrap.h +59 -0
- package/cpp/engine_common.cpp +5 -0
- package/cpp/engine_common.h +127 -0
- package/cpp/engine_workers.h +167 -0
- package/cpp/errors.h +142 -0
- package/cpp/field_map_ops.h +492 -0
- package/cpp/group_wrap.cpp +221 -0
- package/cpp/group_wrap.h +76 -0
- package/cpp/initiator_wrap.cpp +492 -0
- package/cpp/initiator_wrap.h +104 -0
- package/cpp/message_wrap.cpp +288 -0
- package/cpp/message_wrap.h +95 -0
- package/cpp/session_id_wrap.cpp +91 -0
- package/cpp/session_id_wrap.h +46 -0
- package/cpp/session_op_gate.h +201 -0
- package/cpp/session_settings_wrap.cpp +98 -0
- package/cpp/session_settings_wrap.h +40 -0
- package/cpp/session_static.cpp +220 -0
- package/cpp/session_wrap.cpp +438 -0
- package/cpp/session_wrap.h +144 -0
- package/dist/cjs/acceptor.d.ts +29 -0
- package/dist/cjs/acceptor.js +38 -0
- package/dist/cjs/application.d.ts +115 -0
- package/dist/cjs/application.js +62 -0
- package/dist/cjs/data-dictionary.d.ts +67 -0
- package/dist/cjs/data-dictionary.js +105 -0
- package/dist/cjs/engine.d.ts +152 -0
- package/dist/cjs/engine.js +183 -0
- package/dist/cjs/enums.d.ts +56 -0
- package/dist/cjs/enums.js +44 -0
- package/dist/cjs/field-value.d.ts +12 -0
- package/dist/cjs/field-value.js +40 -0
- package/dist/cjs/generated/fields.d.ts +6122 -0
- package/dist/cjs/generated/fields.js +6127 -0
- package/dist/cjs/generated/values.d.ts +8548 -0
- package/dist/cjs/generated/values.js +8580 -0
- package/dist/cjs/group.d.ts +126 -0
- package/dist/cjs/group.js +185 -0
- package/dist/cjs/index.d.ts +68 -0
- package/dist/cjs/index.js +73 -0
- package/dist/cjs/initiator.d.ts +29 -0
- package/dist/cjs/initiator.js +38 -0
- package/dist/cjs/load-native.cjs +5 -0
- package/dist/cjs/message.d.ts +238 -0
- package/dist/cjs/message.js +299 -0
- package/dist/cjs/native.d.ts +325 -0
- package/dist/cjs/native.js +22 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/session-id.d.ts +51 -0
- package/dist/cjs/session-id.js +87 -0
- package/dist/cjs/session-settings.d.ts +46 -0
- package/dist/cjs/session-settings.js +75 -0
- package/dist/cjs/session.d.ts +213 -0
- package/dist/cjs/session.js +337 -0
- package/dist/esm/acceptor.d.ts +29 -0
- package/dist/esm/acceptor.js +34 -0
- package/dist/esm/application.d.ts +115 -0
- package/dist/esm/application.js +57 -0
- package/dist/esm/data-dictionary.d.ts +67 -0
- package/dist/esm/data-dictionary.js +101 -0
- package/dist/esm/engine.d.ts +152 -0
- package/dist/esm/engine.js +179 -0
- package/dist/esm/enums.d.ts +56 -0
- package/dist/esm/enums.js +35 -0
- package/dist/esm/field-value.d.ts +12 -0
- package/dist/esm/field-value.js +37 -0
- package/dist/esm/generated/fields.d.ts +6122 -0
- package/dist/esm/generated/fields.js +6124 -0
- package/dist/esm/generated/values.d.ts +8548 -0
- package/dist/esm/generated/values.js +8564 -0
- package/dist/esm/group.d.ts +126 -0
- package/dist/esm/group.js +181 -0
- package/dist/esm/index.d.ts +68 -0
- package/dist/esm/index.js +43 -0
- package/dist/esm/initiator.d.ts +29 -0
- package/dist/esm/initiator.js +34 -0
- package/dist/esm/load-native.cjs +5 -0
- package/dist/esm/message.d.ts +238 -0
- package/dist/esm/message.js +293 -0
- package/dist/esm/native.d.ts +325 -0
- package/dist/esm/native.js +16 -0
- package/dist/esm/session-id.d.ts +51 -0
- package/dist/esm/session-id.js +82 -0
- package/dist/esm/session-settings.d.ts +46 -0
- package/dist/esm/session-settings.js +71 -0
- package/dist/esm/session.d.ts +213 -0
- package/dist/esm/session.js +329 -0
- package/package.json +95 -4
- package/prebuilds/darwin-arm64/node.napi.node +0 -0
- package/prebuilds/darwin-x64/node.napi.node +0 -0
- package/prebuilds/linux-x64/node.napi.glibc.node +0 -0
- package/prebuilds/linux-x64/node.napi.musl.node +0 -0
- package/prebuilds/win32-x64/node.napi.node +0 -0
- package/src/load-native.cjs +5 -0
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
#include "session_wrap.h"
|
|
2
|
+
|
|
3
|
+
#include <cmath>
|
|
4
|
+
#include <ctime>
|
|
5
|
+
#include <limits>
|
|
6
|
+
#include <memory>
|
|
7
|
+
#include <string>
|
|
8
|
+
#include <utility>
|
|
9
|
+
|
|
10
|
+
#include "errors.h"
|
|
11
|
+
#include "quickfix/Exceptions.h"
|
|
12
|
+
#include "quickfix/FieldTypes.h"
|
|
13
|
+
#include "session_id_wrap.h"
|
|
14
|
+
|
|
15
|
+
namespace napi_quickfix {
|
|
16
|
+
|
|
17
|
+
Napi::FunctionReference SessionWrap::constructor_;
|
|
18
|
+
|
|
19
|
+
Napi::Object SessionWrap::Init(Napi::Env env, Napi::Object exports) {
|
|
20
|
+
Napi::Function func = DefineClass(
|
|
21
|
+
env, "Session",
|
|
22
|
+
{
|
|
23
|
+
InstanceMethod("getSessionID", &SessionWrap::GetSessionID),
|
|
24
|
+
|
|
25
|
+
InstanceMethod("isLoggedOn", &SessionWrap::IsLoggedOn),
|
|
26
|
+
InstanceMethod("isEnabled", &SessionWrap::IsEnabled),
|
|
27
|
+
InstanceMethod("sentLogon", &SessionWrap::SentLogon),
|
|
28
|
+
InstanceMethod("sentLogout", &SessionWrap::SentLogout),
|
|
29
|
+
InstanceMethod("receivedLogon", &SessionWrap::ReceivedLogon),
|
|
30
|
+
InstanceMethod("isInitiator", &SessionWrap::IsInitiator),
|
|
31
|
+
InstanceMethod("isAcceptor", &SessionWrap::IsAcceptor),
|
|
32
|
+
InstanceMethod("isSessionTime", &SessionWrap::IsSessionTime),
|
|
33
|
+
InstanceMethod("isLogonTime", &SessionWrap::IsLogonTime),
|
|
34
|
+
|
|
35
|
+
InstanceMethod("getExpectedSenderNum",
|
|
36
|
+
&SessionWrap::GetExpectedSenderNum),
|
|
37
|
+
InstanceMethod("getExpectedTargetNum",
|
|
38
|
+
&SessionWrap::GetExpectedTargetNum),
|
|
39
|
+
InstanceMethod("setNextSenderMsgSeqNum",
|
|
40
|
+
&SessionWrap::SetNextSenderMsgSeqNum),
|
|
41
|
+
InstanceMethod("setNextTargetMsgSeqNum",
|
|
42
|
+
&SessionWrap::SetNextTargetMsgSeqNum),
|
|
43
|
+
|
|
44
|
+
InstanceMethod("getResetOnLogon", &SessionWrap::GetResetOnLogon),
|
|
45
|
+
InstanceMethod("setResetOnLogon", &SessionWrap::SetResetOnLogon),
|
|
46
|
+
InstanceMethod("getResetOnLogout", &SessionWrap::GetResetOnLogout),
|
|
47
|
+
InstanceMethod("setResetOnLogout", &SessionWrap::SetResetOnLogout),
|
|
48
|
+
InstanceMethod("getResetOnDisconnect",
|
|
49
|
+
&SessionWrap::GetResetOnDisconnect),
|
|
50
|
+
InstanceMethod("setResetOnDisconnect",
|
|
51
|
+
&SessionWrap::SetResetOnDisconnect),
|
|
52
|
+
InstanceMethod("getRefreshOnLogon", &SessionWrap::GetRefreshOnLogon),
|
|
53
|
+
InstanceMethod("setRefreshOnLogon", &SessionWrap::SetRefreshOnLogon),
|
|
54
|
+
InstanceMethod("getCheckCompId", &SessionWrap::GetCheckCompId),
|
|
55
|
+
InstanceMethod("setCheckCompId", &SessionWrap::SetCheckCompId),
|
|
56
|
+
InstanceMethod("getCheckLatency", &SessionWrap::GetCheckLatency),
|
|
57
|
+
InstanceMethod("setCheckLatency", &SessionWrap::SetCheckLatency),
|
|
58
|
+
InstanceMethod("getPersistMessages",
|
|
59
|
+
&SessionWrap::GetPersistMessages),
|
|
60
|
+
InstanceMethod("setPersistMessages",
|
|
61
|
+
&SessionWrap::SetPersistMessages),
|
|
62
|
+
InstanceMethod("getSendRedundantResendRequests",
|
|
63
|
+
&SessionWrap::GetSendRedundantResendRequests),
|
|
64
|
+
InstanceMethod("setSendRedundantResendRequests",
|
|
65
|
+
&SessionWrap::SetSendRedundantResendRequests),
|
|
66
|
+
InstanceMethod("getValidateLengthAndChecksum",
|
|
67
|
+
&SessionWrap::GetValidateLengthAndChecksum),
|
|
68
|
+
InstanceMethod("setValidateLengthAndChecksum",
|
|
69
|
+
&SessionWrap::SetValidateLengthAndChecksum),
|
|
70
|
+
InstanceMethod("getSendNextExpectedMsgSeqNum",
|
|
71
|
+
&SessionWrap::GetSendNextExpectedMsgSeqNum),
|
|
72
|
+
InstanceMethod("setSendNextExpectedMsgSeqNum",
|
|
73
|
+
&SessionWrap::SetSendNextExpectedMsgSeqNum),
|
|
74
|
+
InstanceMethod("getIsNonStopSession",
|
|
75
|
+
&SessionWrap::GetIsNonStopSession),
|
|
76
|
+
InstanceMethod("setIsNonStopSession",
|
|
77
|
+
&SessionWrap::SetIsNonStopSession),
|
|
78
|
+
InstanceMethod("getLogonTimeout", &SessionWrap::GetLogonTimeout),
|
|
79
|
+
InstanceMethod("setLogonTimeout", &SessionWrap::SetLogonTimeout),
|
|
80
|
+
InstanceMethod("getLogoutTimeout", &SessionWrap::GetLogoutTimeout),
|
|
81
|
+
InstanceMethod("setLogoutTimeout", &SessionWrap::SetLogoutTimeout),
|
|
82
|
+
InstanceMethod("getMaxLatency", &SessionWrap::GetMaxLatency),
|
|
83
|
+
InstanceMethod("setMaxLatency", &SessionWrap::SetMaxLatency),
|
|
84
|
+
InstanceMethod("getTimestampPrecision",
|
|
85
|
+
&SessionWrap::GetTimestampPrecision),
|
|
86
|
+
InstanceMethod("setTimestampPrecision",
|
|
87
|
+
&SessionWrap::SetTimestampPrecision),
|
|
88
|
+
|
|
89
|
+
InstanceMethod("logon", &SessionWrap::Logon),
|
|
90
|
+
InstanceMethod("logout", &SessionWrap::Logout),
|
|
91
|
+
InstanceMethod("refresh", &SessionWrap::Refresh),
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
constructor_ = Napi::Persistent(func);
|
|
95
|
+
constructor_.SuppressDestruct();
|
|
96
|
+
|
|
97
|
+
exports.Set("SessionWrap", func);
|
|
98
|
+
return exports;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
Napi::Object SessionWrap::NewInstance(Napi::Env env, const FIX::SessionID& id,
|
|
102
|
+
std::shared_ptr<SessionOpGate> gate) {
|
|
103
|
+
Napi::Object obj = constructor_.New({SessionIDWrap::NewInstance(env, id)});
|
|
104
|
+
Unwrap(obj)->gate_ = std::move(gate);
|
|
105
|
+
return obj;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
SessionWrap::SessionWrap(const Napi::CallbackInfo& info)
|
|
109
|
+
: Napi::ObjectWrap<SessionWrap>(info) {
|
|
110
|
+
Napi::Env env = info.Env();
|
|
111
|
+
if (info.Length() < 1) {
|
|
112
|
+
throw Napi::TypeError::New(
|
|
113
|
+
env,
|
|
114
|
+
"Session cannot be constructed directly; use lookupSession() or "
|
|
115
|
+
"engine.getSession()");
|
|
116
|
+
}
|
|
117
|
+
// Copy by value: the wrap must outlive any SessionID JS object.
|
|
118
|
+
id_ = SessionIDWrap::UnwrapArg(env, info[0], "sessionID")->SessionID();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Engines are created and destroyed on the JS thread only, and so is this
|
|
122
|
+
// call, so the owner check and the lookup cannot interleave with an engine
|
|
123
|
+
// stop. During a graceful stop() the gate stays registered until the engine is
|
|
124
|
+
// destroyed (Freeze() -> Unregister() -> delete, all before stop() settles), so
|
|
125
|
+
// a 'logout' listener fired by the stop still resolves the session.
|
|
126
|
+
FIX::Session& SessionWrap::Resolve() {
|
|
127
|
+
if (!gate_ || SessionOpGate::Lookup(id_) != gate_) {
|
|
128
|
+
throw FIX::SessionNotFound(id_.toString());
|
|
129
|
+
}
|
|
130
|
+
FIX::Session* session = FIX::Session::lookupSession(id_);
|
|
131
|
+
if (session == nullptr) {
|
|
132
|
+
throw FIX::SessionNotFound(id_.toString());
|
|
133
|
+
}
|
|
134
|
+
return *session;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
Napi::Value SessionWrap::GetSessionID(const Napi::CallbackInfo& info) {
|
|
138
|
+
return SessionIDWrap::NewInstance(info.Env(), id_);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// --- generic helpers ---------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
template <typename Fn>
|
|
144
|
+
Napi::Value SessionWrap::BoolGet(const Napi::CallbackInfo& info, Fn fn) {
|
|
145
|
+
Napi::Env env = info.Env();
|
|
146
|
+
NQ_TRY(env) {
|
|
147
|
+
return Napi::Boolean::New(env, (Resolve().*fn)());
|
|
148
|
+
} NQ_CATCH(env)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
template <typename Fn>
|
|
152
|
+
Napi::Value SessionWrap::IntGet(const Napi::CallbackInfo& info, Fn fn) {
|
|
153
|
+
Napi::Env env = info.Env();
|
|
154
|
+
NQ_TRY(env) {
|
|
155
|
+
return Napi::Number::New(env, static_cast<double>((Resolve().*fn)()));
|
|
156
|
+
} NQ_CATCH(env)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
template <typename Fn>
|
|
160
|
+
Napi::Value SessionWrap::BoolSet(const Napi::CallbackInfo& info, Fn fn,
|
|
161
|
+
const char* name) {
|
|
162
|
+
Napi::Env env = info.Env();
|
|
163
|
+
if (info.Length() < 1 || !info[0].IsBoolean()) {
|
|
164
|
+
throw Napi::TypeError::New(env, std::string(name) + "(value: boolean)");
|
|
165
|
+
}
|
|
166
|
+
const bool value = info[0].As<Napi::Boolean>().Value();
|
|
167
|
+
NQ_TRY(env) {
|
|
168
|
+
(Resolve().*fn)(value);
|
|
169
|
+
return env.Undefined();
|
|
170
|
+
} NQ_CATCH(env)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// The FIX::Session setters take a plain `int`; a double outside its range is
|
|
174
|
+
// undefined behaviour to cast (and on x86-64 lands on INT_MIN, which would e.g.
|
|
175
|
+
// make a MaxLatency reject every inbound message). Bound it here and report
|
|
176
|
+
// a RangeError, matching SeqNumSet / SetTimestampPrecision.
|
|
177
|
+
template <typename Fn>
|
|
178
|
+
Napi::Value SessionWrap::IntSet(const Napi::CallbackInfo& info, Fn fn,
|
|
179
|
+
const char* name) {
|
|
180
|
+
Napi::Env env = info.Env();
|
|
181
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
182
|
+
throw Napi::TypeError::New(env, std::string(name) + "(value: number)");
|
|
183
|
+
}
|
|
184
|
+
const double raw = info[0].As<Napi::Number>().DoubleValue();
|
|
185
|
+
constexpr double kIntMin = static_cast<double>(std::numeric_limits<int>::min());
|
|
186
|
+
constexpr double kIntMax = static_cast<double>(std::numeric_limits<int>::max());
|
|
187
|
+
if (!std::isfinite(raw) || std::floor(raw) != raw || raw < kIntMin ||
|
|
188
|
+
raw > kIntMax) {
|
|
189
|
+
throw Napi::RangeError::New(
|
|
190
|
+
env, std::string(name) + ": value must be an integer in the int32 range");
|
|
191
|
+
}
|
|
192
|
+
NQ_TRY(env) {
|
|
193
|
+
(Resolve().*fn)(static_cast<int>(raw));
|
|
194
|
+
return env.Undefined();
|
|
195
|
+
} NQ_CATCH(env)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// isSessionTime(nowMs?) / isLogonTime(nowMs?): `nowMs` is an epoch-millisecond
|
|
199
|
+
// number (Date.getTime()); omitted => the engine's current UTC clock.
|
|
200
|
+
Napi::Value SessionWrap::TimeCheck(const Napi::CallbackInfo& info,
|
|
201
|
+
bool logonTime) {
|
|
202
|
+
Napi::Env env = info.Env();
|
|
203
|
+
bool hasNow = info.Length() >= 1 && !info[0].IsUndefined();
|
|
204
|
+
double nowMs = 0;
|
|
205
|
+
if (hasNow) {
|
|
206
|
+
if (!info[0].IsNumber()) {
|
|
207
|
+
throw Napi::TypeError::New(
|
|
208
|
+
env, logonTime ? "isLogonTime(nowMs?: number)"
|
|
209
|
+
: "isSessionTime(nowMs?: number)");
|
|
210
|
+
}
|
|
211
|
+
nowMs = info[0].As<Napi::Number>().DoubleValue();
|
|
212
|
+
// Bound to the range a JS Date can hold (+/- 100M days around the epoch)
|
|
213
|
+
// before the floating-to-integer cast below: converting a finite double
|
|
214
|
+
// that does not fit in time_t is undefined behaviour, not a saturation.
|
|
215
|
+
constexpr double kMaxDateMs = 8.64e15;
|
|
216
|
+
if (!std::isfinite(nowMs) || std::fabs(nowMs) > kMaxDateMs) {
|
|
217
|
+
throw Napi::RangeError::New(
|
|
218
|
+
env, "nowMs must be an epoch-millisecond number in the Date range");
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
NQ_TRY(env) {
|
|
222
|
+
FIX::Session& session = Resolve();
|
|
223
|
+
FIX::UtcTimeStamp now = FIX::UtcTimeStamp::now();
|
|
224
|
+
if (hasNow) {
|
|
225
|
+
const double secs = std::floor(nowMs / 1000.0);
|
|
226
|
+
const int millis = static_cast<int>(nowMs - secs * 1000.0);
|
|
227
|
+
now = FIX::UtcTimeStamp(static_cast<time_t>(secs), millis);
|
|
228
|
+
}
|
|
229
|
+
return Napi::Boolean::New(env, logonTime ? session.isLogonTime(now)
|
|
230
|
+
: session.isSessionTime(now));
|
|
231
|
+
} NQ_CATCH(env)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
// Sequence numbers are FIX::SEQNUM (uint64_t). JS numbers are exact up to
|
|
235
|
+
// 2^53, which is far beyond any practical MsgSeqNum; reject anything that is
|
|
236
|
+
// not a positive safe integer. MsgSeqNum (tag 34) is 1-based: QuickFIX's own
|
|
237
|
+
// SessionState::reset() and MemoryStore start at 1, and a peer answers 34=0
|
|
238
|
+
// with a Logout ("MsgSeqNum too low").
|
|
239
|
+
Napi::Value SessionWrap::SeqNumSet(const Napi::CallbackInfo& info, bool sender,
|
|
240
|
+
const char* name) {
|
|
241
|
+
Napi::Env env = info.Env();
|
|
242
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
243
|
+
throw Napi::TypeError::New(env, std::string(name) + "(seqNum: number)");
|
|
244
|
+
}
|
|
245
|
+
const double raw = info[0].As<Napi::Number>().DoubleValue();
|
|
246
|
+
constexpr double kMaxSafe = 9007199254740991.0; // Number.MAX_SAFE_INTEGER
|
|
247
|
+
if (!std::isfinite(raw) || std::floor(raw) != raw || raw < 1 ||
|
|
248
|
+
raw > kMaxSafe) {
|
|
249
|
+
throw Napi::RangeError::New(
|
|
250
|
+
env, std::string(name) + ": seqNum must be a positive safe integer");
|
|
251
|
+
}
|
|
252
|
+
const FIX::SEQNUM num = static_cast<FIX::SEQNUM>(raw);
|
|
253
|
+
NQ_TRY(env) {
|
|
254
|
+
// These touch the MessageStore (may throw IOException) but take only the
|
|
255
|
+
// SessionState mutex, which QuickFIX never holds across a callback -- that
|
|
256
|
+
// is what makes them safe to run here. It also means they are NOT
|
|
257
|
+
// serialised against the engine: Session::sendRaw holds m_mutex across
|
|
258
|
+
// fill() (reads the next sender num into the header), toApp/toAdmin and
|
|
259
|
+
// persist() (incrNextSenderMsgSeqNum from the store), and Session::next()
|
|
260
|
+
// likewise across the target-num verification, fromApp/fromAdmin and
|
|
261
|
+
// incrNextTargetMsgSeqNum. A setter landing inside that window -- from a
|
|
262
|
+
// handler, or while a sendToTarget() / heartbeat is in flight on this
|
|
263
|
+
// session -- is overwritten by the increment that follows, and the wire
|
|
264
|
+
// is left one off from the peer. The setters are meant for a quiescent
|
|
265
|
+
// session (before start(), from a 'logout' event, or when the caller
|
|
266
|
+
// knows nothing is in flight); documented on the JS API, not fixable here
|
|
267
|
+
// (m_mutex is private and must not be taken from the JS thread anyway).
|
|
268
|
+
if (sender) {
|
|
269
|
+
Resolve().setNextSenderMsgSeqNum(num);
|
|
270
|
+
} else {
|
|
271
|
+
Resolve().setNextTargetMsgSeqNum(num);
|
|
272
|
+
}
|
|
273
|
+
return env.Undefined();
|
|
274
|
+
} NQ_CATCH(env)
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// --- state getters -----------------------------------------------------------
|
|
278
|
+
|
|
279
|
+
Napi::Value SessionWrap::IsLoggedOn(const Napi::CallbackInfo& info) {
|
|
280
|
+
return BoolGet(info, &FIX::Session::isLoggedOn);
|
|
281
|
+
}
|
|
282
|
+
Napi::Value SessionWrap::IsEnabled(const Napi::CallbackInfo& info) {
|
|
283
|
+
return BoolGet(info, &FIX::Session::isEnabled);
|
|
284
|
+
}
|
|
285
|
+
Napi::Value SessionWrap::SentLogon(const Napi::CallbackInfo& info) {
|
|
286
|
+
return BoolGet(info, &FIX::Session::sentLogon);
|
|
287
|
+
}
|
|
288
|
+
Napi::Value SessionWrap::SentLogout(const Napi::CallbackInfo& info) {
|
|
289
|
+
return BoolGet(info, &FIX::Session::sentLogout);
|
|
290
|
+
}
|
|
291
|
+
Napi::Value SessionWrap::ReceivedLogon(const Napi::CallbackInfo& info) {
|
|
292
|
+
return BoolGet(info, &FIX::Session::receivedLogon);
|
|
293
|
+
}
|
|
294
|
+
Napi::Value SessionWrap::IsInitiator(const Napi::CallbackInfo& info) {
|
|
295
|
+
return BoolGet(info, &FIX::Session::isInitiator);
|
|
296
|
+
}
|
|
297
|
+
Napi::Value SessionWrap::IsAcceptor(const Napi::CallbackInfo& info) {
|
|
298
|
+
return BoolGet(info, &FIX::Session::isAcceptor);
|
|
299
|
+
}
|
|
300
|
+
Napi::Value SessionWrap::IsSessionTime(const Napi::CallbackInfo& info) {
|
|
301
|
+
return TimeCheck(info, /*logonTime=*/false);
|
|
302
|
+
}
|
|
303
|
+
Napi::Value SessionWrap::IsLogonTime(const Napi::CallbackInfo& info) {
|
|
304
|
+
return TimeCheck(info, /*logonTime=*/true);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// --- sequence numbers --------------------------------------------------------
|
|
308
|
+
|
|
309
|
+
Napi::Value SessionWrap::GetExpectedSenderNum(const Napi::CallbackInfo& info) {
|
|
310
|
+
return IntGet(info, &FIX::Session::getExpectedSenderNum);
|
|
311
|
+
}
|
|
312
|
+
Napi::Value SessionWrap::GetExpectedTargetNum(const Napi::CallbackInfo& info) {
|
|
313
|
+
return IntGet(info, &FIX::Session::getExpectedTargetNum);
|
|
314
|
+
}
|
|
315
|
+
Napi::Value SessionWrap::SetNextSenderMsgSeqNum(
|
|
316
|
+
const Napi::CallbackInfo& info) {
|
|
317
|
+
return SeqNumSet(info, /*sender=*/true, "setNextSenderMsgSeqNum");
|
|
318
|
+
}
|
|
319
|
+
Napi::Value SessionWrap::SetNextTargetMsgSeqNum(
|
|
320
|
+
const Napi::CallbackInfo& info) {
|
|
321
|
+
return SeqNumSet(info, /*sender=*/false, "setNextTargetMsgSeqNum");
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// --- runtime options ---------------------------------------------------------
|
|
325
|
+
|
|
326
|
+
#define NQ_BOOL_OPTION(Name) \
|
|
327
|
+
Napi::Value SessionWrap::Get##Name(const Napi::CallbackInfo& info) { \
|
|
328
|
+
return BoolGet(info, &FIX::Session::get##Name); \
|
|
329
|
+
} \
|
|
330
|
+
Napi::Value SessionWrap::Set##Name(const Napi::CallbackInfo& info) { \
|
|
331
|
+
return BoolSet(info, &FIX::Session::set##Name, "set" #Name); \
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
#define NQ_INT_OPTION(Name) \
|
|
335
|
+
Napi::Value SessionWrap::Get##Name(const Napi::CallbackInfo& info) { \
|
|
336
|
+
return IntGet(info, &FIX::Session::get##Name); \
|
|
337
|
+
} \
|
|
338
|
+
Napi::Value SessionWrap::Set##Name(const Napi::CallbackInfo& info) { \
|
|
339
|
+
return IntSet(info, &FIX::Session::set##Name, "set" #Name); \
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
NQ_BOOL_OPTION(ResetOnLogon)
|
|
343
|
+
NQ_BOOL_OPTION(ResetOnLogout)
|
|
344
|
+
NQ_BOOL_OPTION(ResetOnDisconnect)
|
|
345
|
+
NQ_BOOL_OPTION(RefreshOnLogon)
|
|
346
|
+
NQ_BOOL_OPTION(CheckCompId)
|
|
347
|
+
NQ_BOOL_OPTION(CheckLatency)
|
|
348
|
+
NQ_BOOL_OPTION(PersistMessages)
|
|
349
|
+
NQ_BOOL_OPTION(SendRedundantResendRequests)
|
|
350
|
+
NQ_BOOL_OPTION(ValidateLengthAndChecksum)
|
|
351
|
+
NQ_BOOL_OPTION(SendNextExpectedMsgSeqNum)
|
|
352
|
+
NQ_BOOL_OPTION(IsNonStopSession)
|
|
353
|
+
NQ_INT_OPTION(LogonTimeout)
|
|
354
|
+
NQ_INT_OPTION(LogoutTimeout)
|
|
355
|
+
NQ_INT_OPTION(MaxLatency)
|
|
356
|
+
|
|
357
|
+
#undef NQ_BOOL_OPTION
|
|
358
|
+
#undef NQ_INT_OPTION
|
|
359
|
+
|
|
360
|
+
Napi::Value SessionWrap::GetTimestampPrecision(const Napi::CallbackInfo& info) {
|
|
361
|
+
return IntGet(info, &FIX::Session::getTimestampPrecision);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// FIX::Session::setTimestampPrecision silently ignores values outside 0..9;
|
|
365
|
+
// surface that as a RangeError instead of a no-op.
|
|
366
|
+
Napi::Value SessionWrap::SetTimestampPrecision(const Napi::CallbackInfo& info) {
|
|
367
|
+
Napi::Env env = info.Env();
|
|
368
|
+
if (info.Length() < 1 || !info[0].IsNumber()) {
|
|
369
|
+
throw Napi::TypeError::New(env, "setTimestampPrecision(precision: number)");
|
|
370
|
+
}
|
|
371
|
+
const double raw = info[0].As<Napi::Number>().DoubleValue();
|
|
372
|
+
if (!std::isfinite(raw) || std::floor(raw) != raw || raw < 0 || raw > 9) {
|
|
373
|
+
throw Napi::RangeError::New(
|
|
374
|
+
env, "setTimestampPrecision: precision must be an integer in 0..9");
|
|
375
|
+
}
|
|
376
|
+
NQ_TRY(env) {
|
|
377
|
+
Resolve().setTimestampPrecision(static_cast<int>(raw));
|
|
378
|
+
return env.Undefined();
|
|
379
|
+
} NQ_CATCH(env)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
// --- control ------------------------------------------------------------------
|
|
383
|
+
// FIX::Session::logon()/logout() only flip SessionState's `enabled` flag and
|
|
384
|
+
// `logoutReason` (the latter under SessionState's own mutex), and refresh()
|
|
385
|
+
// re-reads the store under that same mutex; none of them take
|
|
386
|
+
// FIX::Session::m_mutex or fire a callback, so they cannot deadlock the JS
|
|
387
|
+
// thread against a QuickFIX thread blocked in a handler. That is the property
|
|
388
|
+
// that lets them run here. What they are NOT is race-free: `enabled` is a
|
|
389
|
+
// plain bool that SessionState::enabled(bool) stores with no lock and that
|
|
390
|
+
// the engine's network thread reads in Session::next() under Session::m_mutex
|
|
391
|
+
// -- formally a data race (ThreadSanitizer reports it), the same one
|
|
392
|
+
// FIX::Initiator::stop() makes when it calls logout()/logon() on every session
|
|
393
|
+
// from the stopping thread. In practice the network thread observes the flag
|
|
394
|
+
// on its next pass; this binding does not patch QuickFIX to make it atomic.
|
|
395
|
+
// Keeping them synchronous also keeps them ORDERED: as AsyncWorkers,
|
|
396
|
+
// `logout(); logon();` could have run on two pool threads in either order.
|
|
397
|
+
//
|
|
398
|
+
// FIX::Session::disconnect() and reset() are deliberately NOT exposed. Through
|
|
399
|
+
// the session's responder they reach FIX::SocketMonitor::drop(), which mutates
|
|
400
|
+
// the monitor's socket sets with no lock while the engine's network thread
|
|
401
|
+
// iterates them in SocketMonitor::block(); QuickFIX only ever calls them from
|
|
402
|
+
// that thread itself (upstream issue #346, closed "not planned"). Any thread
|
|
403
|
+
// this binding could run them on -- JS or libuv -- races it. logout() is the
|
|
404
|
+
// supported way to bring a session down from the application.
|
|
405
|
+
|
|
406
|
+
Napi::Value SessionWrap::Logon(const Napi::CallbackInfo& info) {
|
|
407
|
+
Napi::Env env = info.Env();
|
|
408
|
+
NQ_TRY(env) {
|
|
409
|
+
Resolve().logon();
|
|
410
|
+
return env.Undefined();
|
|
411
|
+
} NQ_CATCH(env)
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
Napi::Value SessionWrap::Logout(const Napi::CallbackInfo& info) {
|
|
415
|
+
Napi::Env env = info.Env();
|
|
416
|
+
std::string reason;
|
|
417
|
+
if (info.Length() >= 1 && !info[0].IsUndefined()) {
|
|
418
|
+
if (!info[0].IsString()) {
|
|
419
|
+
throw Napi::TypeError::New(env, "logout(reason?: string)");
|
|
420
|
+
}
|
|
421
|
+
reason = info[0].As<Napi::String>().Utf8Value();
|
|
422
|
+
}
|
|
423
|
+
NQ_TRY(env) {
|
|
424
|
+
Resolve().logout(reason);
|
|
425
|
+
return env.Undefined();
|
|
426
|
+
} NQ_CATCH(env)
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// May throw IOException from the message store (mapped to QuickFixError).
|
|
430
|
+
Napi::Value SessionWrap::Refresh(const Napi::CallbackInfo& info) {
|
|
431
|
+
Napi::Env env = info.Env();
|
|
432
|
+
NQ_TRY(env) {
|
|
433
|
+
Resolve().refresh();
|
|
434
|
+
return env.Undefined();
|
|
435
|
+
} NQ_CATCH(env)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
} // namespace napi_quickfix
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
#ifndef NAPI_QUICKFIX_SESSION_WRAP_H
|
|
2
|
+
#define NAPI_QUICKFIX_SESSION_WRAP_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
#include "quickfix/Session.h"
|
|
9
|
+
#include "quickfix/SessionID.h"
|
|
10
|
+
#include "session_op_gate.h"
|
|
11
|
+
|
|
12
|
+
namespace napi_quickfix {
|
|
13
|
+
|
|
14
|
+
// Napi::ObjectWrap giving JS a handle on a live FIX::Session.
|
|
15
|
+
//
|
|
16
|
+
// Lifetime: FIX::Session objects are OWNED BY THE ENGINE (Initiator/Acceptor)
|
|
17
|
+
// and FIX::Session::lookupSession returns a raw, non-owning pointer. This wrap
|
|
18
|
+
// therefore never caches that pointer: it stores the FIX::SessionID by value
|
|
19
|
+
// plus the SessionOpGate of the engine that owned the session when the handle
|
|
20
|
+
// was created, and re-resolves on EVERY call, throwing a QuickFixError with
|
|
21
|
+
// fixErrorName 'SessionNotFound' once the engine has been stopped (which
|
|
22
|
+
// destroys its sessions). The gate is what ties the handle to ONE engine: the
|
|
23
|
+
// process-wide registry lookupSession() reads is keyed by SessionID alone, so
|
|
24
|
+
// after the owner is stopped a new engine may register the same id, and a
|
|
25
|
+
// handle that only re-resolved the id would silently operate on the new
|
|
26
|
+
// engine's session. Resolve() therefore also requires the registered owner of
|
|
27
|
+
// the id (SessionOpGate::Lookup) to still be the gate captured at creation.
|
|
28
|
+
//
|
|
29
|
+
// new SessionWrap(sessionID: SessionIDWrap) -- internal; JS reaches a
|
|
30
|
+
// Session through lookupSession() / engine.getSession(), which bind the
|
|
31
|
+
// gate via NewInstance(). A handle built any other way has no gate and
|
|
32
|
+
// always throws SessionNotFound.
|
|
33
|
+
//
|
|
34
|
+
// Every member is synchronous and safe on the JS thread: none takes
|
|
35
|
+
// FIX::Session::m_mutex, which QuickFIX holds across application callbacks.
|
|
36
|
+
// getSessionID, isLoggedOn, isEnabled, sentLogon, sentLogout, receivedLogon,
|
|
37
|
+
// isInitiator, isAcceptor, isSessionTime(nowMs?), isLogonTime(nowMs?),
|
|
38
|
+
// getExpectedSenderNum, getExpectedTargetNum, setNextSenderMsgSeqNum,
|
|
39
|
+
// setNextTargetMsgSeqNum, logon, logout(reason?), refresh, and the runtime
|
|
40
|
+
// option getters/setters.
|
|
41
|
+
// FIX::Session::disconnect()/reset() are not exposed: they are only safe on
|
|
42
|
+
// the engine's own network thread (see session_wrap.cpp).
|
|
43
|
+
class SessionWrap : public Napi::ObjectWrap<SessionWrap> {
|
|
44
|
+
public:
|
|
45
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
46
|
+
|
|
47
|
+
// Build a JS Session bound to a copy of `id` and to `gate`, the
|
|
48
|
+
// SessionOpGate of the engine owning the session (SessionOpGate::Lookup(id)
|
|
49
|
+
// or the engine wrap's own gate_). Does NOT check that the session exists;
|
|
50
|
+
// callers (lookupSession / engine.getSession) do.
|
|
51
|
+
static Napi::Object NewInstance(Napi::Env env, const FIX::SessionID& id,
|
|
52
|
+
std::shared_ptr<SessionOpGate> gate);
|
|
53
|
+
|
|
54
|
+
explicit SessionWrap(const Napi::CallbackInfo& info);
|
|
55
|
+
|
|
56
|
+
const FIX::SessionID& SessionID() const { return id_; }
|
|
57
|
+
|
|
58
|
+
private:
|
|
59
|
+
static Napi::FunctionReference constructor_;
|
|
60
|
+
|
|
61
|
+
// Resolve the live FIX::Session of the engine this handle was created for,
|
|
62
|
+
// or throw FIX::SessionNotFound (session gone, or the id now belongs to a
|
|
63
|
+
// different engine). Must be called inside NQ_TRY so the exception maps to a
|
|
64
|
+
// QuickFixError.
|
|
65
|
+
FIX::Session& Resolve();
|
|
66
|
+
|
|
67
|
+
Napi::Value GetSessionID(const Napi::CallbackInfo& info);
|
|
68
|
+
|
|
69
|
+
Napi::Value IsLoggedOn(const Napi::CallbackInfo& info);
|
|
70
|
+
Napi::Value IsEnabled(const Napi::CallbackInfo& info);
|
|
71
|
+
Napi::Value SentLogon(const Napi::CallbackInfo& info);
|
|
72
|
+
Napi::Value SentLogout(const Napi::CallbackInfo& info);
|
|
73
|
+
Napi::Value ReceivedLogon(const Napi::CallbackInfo& info);
|
|
74
|
+
Napi::Value IsInitiator(const Napi::CallbackInfo& info);
|
|
75
|
+
Napi::Value IsAcceptor(const Napi::CallbackInfo& info);
|
|
76
|
+
Napi::Value IsSessionTime(const Napi::CallbackInfo& info);
|
|
77
|
+
Napi::Value IsLogonTime(const Napi::CallbackInfo& info);
|
|
78
|
+
|
|
79
|
+
Napi::Value GetExpectedSenderNum(const Napi::CallbackInfo& info);
|
|
80
|
+
Napi::Value GetExpectedTargetNum(const Napi::CallbackInfo& info);
|
|
81
|
+
Napi::Value SetNextSenderMsgSeqNum(const Napi::CallbackInfo& info);
|
|
82
|
+
Napi::Value SetNextTargetMsgSeqNum(const Napi::CallbackInfo& info);
|
|
83
|
+
|
|
84
|
+
// Runtime options (plain members on FIX::Session; no locking, no callbacks).
|
|
85
|
+
Napi::Value GetResetOnLogon(const Napi::CallbackInfo& info);
|
|
86
|
+
Napi::Value SetResetOnLogon(const Napi::CallbackInfo& info);
|
|
87
|
+
Napi::Value GetResetOnLogout(const Napi::CallbackInfo& info);
|
|
88
|
+
Napi::Value SetResetOnLogout(const Napi::CallbackInfo& info);
|
|
89
|
+
Napi::Value GetResetOnDisconnect(const Napi::CallbackInfo& info);
|
|
90
|
+
Napi::Value SetResetOnDisconnect(const Napi::CallbackInfo& info);
|
|
91
|
+
Napi::Value GetRefreshOnLogon(const Napi::CallbackInfo& info);
|
|
92
|
+
Napi::Value SetRefreshOnLogon(const Napi::CallbackInfo& info);
|
|
93
|
+
Napi::Value GetCheckCompId(const Napi::CallbackInfo& info);
|
|
94
|
+
Napi::Value SetCheckCompId(const Napi::CallbackInfo& info);
|
|
95
|
+
Napi::Value GetCheckLatency(const Napi::CallbackInfo& info);
|
|
96
|
+
Napi::Value SetCheckLatency(const Napi::CallbackInfo& info);
|
|
97
|
+
Napi::Value GetPersistMessages(const Napi::CallbackInfo& info);
|
|
98
|
+
Napi::Value SetPersistMessages(const Napi::CallbackInfo& info);
|
|
99
|
+
Napi::Value GetSendRedundantResendRequests(const Napi::CallbackInfo& info);
|
|
100
|
+
Napi::Value SetSendRedundantResendRequests(const Napi::CallbackInfo& info);
|
|
101
|
+
Napi::Value GetValidateLengthAndChecksum(const Napi::CallbackInfo& info);
|
|
102
|
+
Napi::Value SetValidateLengthAndChecksum(const Napi::CallbackInfo& info);
|
|
103
|
+
Napi::Value GetSendNextExpectedMsgSeqNum(const Napi::CallbackInfo& info);
|
|
104
|
+
Napi::Value SetSendNextExpectedMsgSeqNum(const Napi::CallbackInfo& info);
|
|
105
|
+
Napi::Value GetIsNonStopSession(const Napi::CallbackInfo& info);
|
|
106
|
+
Napi::Value SetIsNonStopSession(const Napi::CallbackInfo& info);
|
|
107
|
+
Napi::Value GetLogonTimeout(const Napi::CallbackInfo& info);
|
|
108
|
+
Napi::Value SetLogonTimeout(const Napi::CallbackInfo& info);
|
|
109
|
+
Napi::Value GetLogoutTimeout(const Napi::CallbackInfo& info);
|
|
110
|
+
Napi::Value SetLogoutTimeout(const Napi::CallbackInfo& info);
|
|
111
|
+
Napi::Value GetMaxLatency(const Napi::CallbackInfo& info);
|
|
112
|
+
Napi::Value SetMaxLatency(const Napi::CallbackInfo& info);
|
|
113
|
+
Napi::Value GetTimestampPrecision(const Napi::CallbackInfo& info);
|
|
114
|
+
Napi::Value SetTimestampPrecision(const Napi::CallbackInfo& info);
|
|
115
|
+
|
|
116
|
+
// Control. All sync: they only touch SessionState under its own mutex,
|
|
117
|
+
// which QuickFIX never holds across a callback.
|
|
118
|
+
Napi::Value Logon(const Napi::CallbackInfo& info);
|
|
119
|
+
Napi::Value Logout(const Napi::CallbackInfo& info);
|
|
120
|
+
Napi::Value Refresh(const Napi::CallbackInfo& info);
|
|
121
|
+
|
|
122
|
+
// Shared helpers for the one-liner getters/setters above.
|
|
123
|
+
template <typename Fn>
|
|
124
|
+
Napi::Value BoolGet(const Napi::CallbackInfo& info, Fn fn);
|
|
125
|
+
template <typename Fn>
|
|
126
|
+
Napi::Value IntGet(const Napi::CallbackInfo& info, Fn fn);
|
|
127
|
+
template <typename Fn>
|
|
128
|
+
Napi::Value BoolSet(const Napi::CallbackInfo& info, Fn fn, const char* name);
|
|
129
|
+
template <typename Fn>
|
|
130
|
+
Napi::Value IntSet(const Napi::CallbackInfo& info, Fn fn, const char* name);
|
|
131
|
+
Napi::Value TimeCheck(const Napi::CallbackInfo& info, bool logonTime);
|
|
132
|
+
Napi::Value SeqNumSet(const Napi::CallbackInfo& info, bool sender,
|
|
133
|
+
const char* name);
|
|
134
|
+
|
|
135
|
+
FIX::SessionID id_;
|
|
136
|
+
// The owning engine's gate at creation; held by shared_ptr so the object
|
|
137
|
+
// stays alive (and its address unique) as long as the handle does. nullptr
|
|
138
|
+
// for a handle not created through NewInstance().
|
|
139
|
+
std::shared_ptr<SessionOpGate> gate_;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
} // namespace napi_quickfix
|
|
143
|
+
|
|
144
|
+
#endif // NAPI_QUICKFIX_SESSION_WRAP_H
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Engine, type EngineOptions } from './engine.js';
|
|
2
|
+
export type { EngineOptions } from './engine.js';
|
|
3
|
+
/**
|
|
4
|
+
* A FIX session acceptor (wraps `FIX::SocketAcceptor`). Acceptors listen for
|
|
5
|
+
* inbound connections from initiators as configured in
|
|
6
|
+
* {@link EngineOptions.settings}.
|
|
7
|
+
*
|
|
8
|
+
* Extends {@link Engine} (an {@link import('node:events').EventEmitter}), so you
|
|
9
|
+
* can observe lifecycle/message events in addition to supplying `handlers`.
|
|
10
|
+
* Remember: only `handlers` may mutate outbound messages or reject inbound ones;
|
|
11
|
+
* events are observe-only.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const acceptor = new Acceptor({
|
|
16
|
+
* settings: SessionSettings.fromString(cfg),
|
|
17
|
+
* handlers: {
|
|
18
|
+
* fromApp: (msg, id) => { void sendToTarget(makeReply(msg), id); },
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
* await acceptor.start();
|
|
22
|
+
* // ... later
|
|
23
|
+
* await acceptor.stop();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare class Acceptor extends Engine {
|
|
27
|
+
/** @param options Engine options. */
|
|
28
|
+
constructor(options: EngineOptions);
|
|
29
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Acceptor = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* FIX session acceptor (server side — listens for initiators).
|
|
6
|
+
*/
|
|
7
|
+
const native_js_1 = require("./native.js");
|
|
8
|
+
const engine_js_1 = require("./engine.js");
|
|
9
|
+
/**
|
|
10
|
+
* A FIX session acceptor (wraps `FIX::SocketAcceptor`). Acceptors listen for
|
|
11
|
+
* inbound connections from initiators as configured in
|
|
12
|
+
* {@link EngineOptions.settings}.
|
|
13
|
+
*
|
|
14
|
+
* Extends {@link Engine} (an {@link import('node:events').EventEmitter}), so you
|
|
15
|
+
* can observe lifecycle/message events in addition to supplying `handlers`.
|
|
16
|
+
* Remember: only `handlers` may mutate outbound messages or reject inbound ones;
|
|
17
|
+
* events are observe-only.
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```ts
|
|
21
|
+
* const acceptor = new Acceptor({
|
|
22
|
+
* settings: SessionSettings.fromString(cfg),
|
|
23
|
+
* handlers: {
|
|
24
|
+
* fromApp: (msg, id) => { void sendToTarget(makeReply(msg), id); },
|
|
25
|
+
* },
|
|
26
|
+
* });
|
|
27
|
+
* await acceptor.start();
|
|
28
|
+
* // ... later
|
|
29
|
+
* await acceptor.stop();
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
class Acceptor extends engine_js_1.Engine {
|
|
33
|
+
/** @param options Engine options. */
|
|
34
|
+
constructor(options) {
|
|
35
|
+
super(native_js_1.native.AcceptorWrap, options);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.Acceptor = Acceptor;
|