@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,288 @@
|
|
|
1
|
+
#include "message_wrap.h"
|
|
2
|
+
|
|
3
|
+
#include <algorithm>
|
|
4
|
+
#include <string>
|
|
5
|
+
#include <utility>
|
|
6
|
+
|
|
7
|
+
#include "data_dictionary_wrap.h"
|
|
8
|
+
#include "errors.h"
|
|
9
|
+
#include "field_map_ops.h"
|
|
10
|
+
#include "quickfix/FieldNumbers.h"
|
|
11
|
+
|
|
12
|
+
namespace napi_quickfix {
|
|
13
|
+
|
|
14
|
+
Napi::FunctionReference MessageWrap::constructor_;
|
|
15
|
+
|
|
16
|
+
Napi::Object MessageWrap::Init(Napi::Env env, Napi::Object exports) {
|
|
17
|
+
Napi::Function func = DefineClass(
|
|
18
|
+
env, "Message",
|
|
19
|
+
{
|
|
20
|
+
InstanceMethod("getField", &MessageWrap::GetField),
|
|
21
|
+
InstanceMethod("setField", &MessageWrap::SetField),
|
|
22
|
+
InstanceMethod("isSetField", &MessageWrap::IsSetField),
|
|
23
|
+
InstanceMethod("removeField", &MessageWrap::RemoveField),
|
|
24
|
+
InstanceMethod("getFieldIfSet", &MessageWrap::GetFieldIfSet),
|
|
25
|
+
InstanceMethod("getHeaderField", &MessageWrap::GetHeaderField),
|
|
26
|
+
InstanceMethod("setHeaderField", &MessageWrap::SetHeaderField),
|
|
27
|
+
InstanceMethod("getTrailerField", &MessageWrap::GetTrailerField),
|
|
28
|
+
InstanceMethod("setTrailerField", &MessageWrap::SetTrailerField),
|
|
29
|
+
InstanceMethod("isEmpty", &MessageWrap::IsEmpty),
|
|
30
|
+
InstanceMethod("totalFields", &MessageWrap::TotalFields),
|
|
31
|
+
InstanceMethod("clear", &MessageWrap::Clear),
|
|
32
|
+
InstanceMethod("fields", &MessageWrap::Fields),
|
|
33
|
+
InstanceMethod("headerFields", &MessageWrap::HeaderFields),
|
|
34
|
+
InstanceMethod("trailerFields", &MessageWrap::TrailerFields),
|
|
35
|
+
InstanceMethod("addGroup", &MessageWrap::AddGroup),
|
|
36
|
+
InstanceMethod("getGroup", &MessageWrap::GetGroup),
|
|
37
|
+
InstanceMethod("replaceGroup", &MessageWrap::ReplaceGroup),
|
|
38
|
+
InstanceMethod("removeGroup", &MessageWrap::RemoveGroup),
|
|
39
|
+
InstanceMethod("hasGroup", &MessageWrap::HasGroup),
|
|
40
|
+
InstanceMethod("groupCount", &MessageWrap::GroupCount),
|
|
41
|
+
InstanceMethod("toString", &MessageWrap::ToString),
|
|
42
|
+
InstanceMethod("toPretty", &MessageWrap::ToPretty),
|
|
43
|
+
InstanceMethod("getMsgType", &MessageWrap::GetMsgType),
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
constructor_ = Napi::Persistent(func);
|
|
47
|
+
constructor_.SuppressDestruct();
|
|
48
|
+
|
|
49
|
+
exports.Set("MessageWrap", func);
|
|
50
|
+
return exports;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Both construct an empty MessageWrap then fill its (empty) FIX::Message. A
|
|
54
|
+
// move keeps the nested entries typed by itself: FieldMap's move assignment
|
|
55
|
+
// takes the entry pointers over.
|
|
56
|
+
Napi::Object MessageWrap::NewInstance(Napi::Env env, const FIX::Message& msg) {
|
|
57
|
+
Napi::Object obj = constructor_.New({});
|
|
58
|
+
MessageWrap* wrap = Napi::ObjectWrap<MessageWrap>::Unwrap(obj);
|
|
59
|
+
fieldmap::CloneMessage(wrap->message_, msg);
|
|
60
|
+
return obj;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
Napi::Object MessageWrap::NewInstance(
|
|
64
|
+
Napi::Env env, FIX::Message&& msg,
|
|
65
|
+
std::shared_ptr<const FIX::DataDictionary> sessionDictionary) {
|
|
66
|
+
Napi::Object obj = constructor_.New({});
|
|
67
|
+
MessageWrap* wrap = Napi::ObjectWrap<MessageWrap>::Unwrap(obj);
|
|
68
|
+
wrap->message_ = std::move(msg);
|
|
69
|
+
wrap->sessionDictionary_ = std::move(sessionDictionary);
|
|
70
|
+
return obj;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
MessageWrap* MessageWrap::UnwrapArg(Napi::Env env, Napi::Value value,
|
|
74
|
+
const char* argName) {
|
|
75
|
+
if (!value.IsObject() ||
|
|
76
|
+
!value.As<Napi::Object>().InstanceOf(constructor_.Value())) {
|
|
77
|
+
throw Napi::TypeError::New(
|
|
78
|
+
env, std::string(argName) + " must be a Message instance");
|
|
79
|
+
}
|
|
80
|
+
return Napi::ObjectWrap<MessageWrap>::Unwrap(value.As<Napi::Object>());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
MessageWrap::MessageWrap(const Napi::CallbackInfo& info)
|
|
84
|
+
: Napi::ObjectWrap<MessageWrap>(info) {
|
|
85
|
+
Napi::Env env = info.Env();
|
|
86
|
+
if (info.Length() == 0) {
|
|
87
|
+
// Empty message.
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
if (!info[0].IsString()) {
|
|
91
|
+
throw Napi::TypeError::New(
|
|
92
|
+
env,
|
|
93
|
+
"new Message(raw: string, validate?: boolean, "
|
|
94
|
+
"sessionDictionary?: DataDictionary, "
|
|
95
|
+
"applicationDictionary?: DataDictionary)");
|
|
96
|
+
}
|
|
97
|
+
const std::string raw = info[0].As<Napi::String>().Utf8Value();
|
|
98
|
+
bool validate = false;
|
|
99
|
+
if (info.Length() >= 2 && !fieldmap::IsNullish(info[1])) {
|
|
100
|
+
validate = info[1].ToBoolean().Value();
|
|
101
|
+
}
|
|
102
|
+
const FIX::DataDictionary* sessionDD = nullptr;
|
|
103
|
+
const FIX::DataDictionary* appDD = nullptr;
|
|
104
|
+
if (info.Length() >= 3 && !fieldmap::IsNullish(info[2])) {
|
|
105
|
+
sessionDictionary_ =
|
|
106
|
+
DataDictionaryWrap::UnwrapArg(env, info[2], "sessionDictionary")
|
|
107
|
+
->Shared();
|
|
108
|
+
sessionDD = sessionDictionary_.get();
|
|
109
|
+
}
|
|
110
|
+
if (info.Length() >= 4 && !fieldmap::IsNullish(info[3])) {
|
|
111
|
+
appDD = &DataDictionaryWrap::UnwrapArg(env, info[3], "applicationDictionary")
|
|
112
|
+
->Dictionary();
|
|
113
|
+
}
|
|
114
|
+
NQ_TRY(env) {
|
|
115
|
+
if (sessionDD != nullptr || appDD != nullptr) {
|
|
116
|
+
// The dictionaries are read only during this call; the wrapper objects
|
|
117
|
+
// are kept alive by the caller's arguments for its duration.
|
|
118
|
+
message_.setString(raw, validate, sessionDD, appDD);
|
|
119
|
+
} else {
|
|
120
|
+
message_.setString(raw, validate);
|
|
121
|
+
}
|
|
122
|
+
} NQ_CATCH(env)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
namespace {
|
|
126
|
+
|
|
127
|
+
bool Holds(const FIX::FieldMap& map, int tag) {
|
|
128
|
+
return map.isSetField(tag) || map.hasGroup(tag);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
} // namespace
|
|
132
|
+
|
|
133
|
+
// Auto-route standard header/trailer fields (MsgType, SenderCompID, CheckSum,
|
|
134
|
+
// NoHops, ...) and the ones the session dictionary declares to the right
|
|
135
|
+
// section, as the parser does, so callers don't have to know which section a
|
|
136
|
+
// tag belongs to, and a dictionary header field that is removed and set again
|
|
137
|
+
// goes back to the header. Without a dictionary (a message built in JS or
|
|
138
|
+
// parsed without one), any other tag is a body field unless the header or
|
|
139
|
+
// trailer already holds it, so reads find such a field and setField /
|
|
140
|
+
// removeField edit it in place rather than adding a body duplicate. A tag
|
|
141
|
+
// held nowhere stays a body field.
|
|
142
|
+
FIX::FieldMap& MessageWrap::SectionFor(int tag) {
|
|
143
|
+
const FIX::DataDictionary* dd = sessionDictionary_.get();
|
|
144
|
+
if (FIX::Message::isHeaderField(tag, dd)) {
|
|
145
|
+
return message_.getHeader();
|
|
146
|
+
}
|
|
147
|
+
if (FIX::Message::isTrailerField(tag, dd)) {
|
|
148
|
+
return message_.getTrailer();
|
|
149
|
+
}
|
|
150
|
+
if (Holds(message_, tag)) {
|
|
151
|
+
return message_;
|
|
152
|
+
}
|
|
153
|
+
if (Holds(message_.getHeader(), tag)) {
|
|
154
|
+
return message_.getHeader();
|
|
155
|
+
}
|
|
156
|
+
if (Holds(message_.getTrailer(), tag)) {
|
|
157
|
+
return message_.getTrailer();
|
|
158
|
+
}
|
|
159
|
+
return message_;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
#define NQ_ROUTED [this](int tag) -> FIX::FieldMap& { return SectionFor(tag); }
|
|
163
|
+
#define NQ_HEADER [this](int) -> FIX::FieldMap& { return message_.getHeader(); }
|
|
164
|
+
#define NQ_TRAILER [this](int) -> FIX::FieldMap& { return message_.getTrailer(); }
|
|
165
|
+
|
|
166
|
+
Napi::Value MessageWrap::GetField(const Napi::CallbackInfo& info) {
|
|
167
|
+
return fieldmap::GetField(info, NQ_ROUTED);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
Napi::Value MessageWrap::SetField(const Napi::CallbackInfo& info) {
|
|
171
|
+
return fieldmap::SetField(info, NQ_ROUTED);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
Napi::Value MessageWrap::IsSetField(const Napi::CallbackInfo& info) {
|
|
175
|
+
return fieldmap::IsSetField(info, NQ_ROUTED);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Napi::Value MessageWrap::RemoveField(const Napi::CallbackInfo& info) {
|
|
179
|
+
return fieldmap::RemoveField(info, NQ_ROUTED);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
Napi::Value MessageWrap::GetFieldIfSet(const Napi::CallbackInfo& info) {
|
|
183
|
+
return fieldmap::GetFieldIfSet(info, NQ_ROUTED);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
Napi::Value MessageWrap::GetHeaderField(const Napi::CallbackInfo& info) {
|
|
187
|
+
return fieldmap::GetField(info, NQ_HEADER);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
Napi::Value MessageWrap::SetHeaderField(const Napi::CallbackInfo& info) {
|
|
191
|
+
return fieldmap::SetField(info, NQ_HEADER);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
Napi::Value MessageWrap::GetTrailerField(const Napi::CallbackInfo& info) {
|
|
195
|
+
return fieldmap::GetField(info, NQ_TRAILER);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
Napi::Value MessageWrap::SetTrailerField(const Napi::CallbackInfo& info) {
|
|
199
|
+
return fieldmap::SetField(info, NQ_TRAILER);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Header, body and trailer (FIX::Message::isEmpty, not FieldMap's body-only
|
|
203
|
+
// one), like clear().
|
|
204
|
+
Napi::Value MessageWrap::IsEmpty(const Napi::CallbackInfo& info) {
|
|
205
|
+
Napi::Env env = info.Env();
|
|
206
|
+
NQ_TRY(env) {
|
|
207
|
+
return Napi::Boolean::New(env, message_.isEmpty());
|
|
208
|
+
} NQ_CATCH(env)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
Napi::Value MessageWrap::TotalFields(const Napi::CallbackInfo& info) {
|
|
212
|
+
return fieldmap::TotalFields(info.Env(), message_);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Empties header, body and trailer.
|
|
216
|
+
Napi::Value MessageWrap::Clear(const Napi::CallbackInfo& info) {
|
|
217
|
+
Napi::Env env = info.Env();
|
|
218
|
+
NQ_TRY(env) {
|
|
219
|
+
message_.clear();
|
|
220
|
+
} NQ_CATCH(env)
|
|
221
|
+
return env.Undefined();
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
Napi::Value MessageWrap::Fields(const Napi::CallbackInfo& info) {
|
|
225
|
+
return fieldmap::Fields(info.Env(), message_);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
Napi::Value MessageWrap::HeaderFields(const Napi::CallbackInfo& info) {
|
|
229
|
+
return fieldmap::Fields(info.Env(), message_.getHeader());
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
Napi::Value MessageWrap::TrailerFields(const Napi::CallbackInfo& info) {
|
|
233
|
+
return fieldmap::Fields(info.Env(), message_.getTrailer());
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
Napi::Value MessageWrap::AddGroup(const Napi::CallbackInfo& info) {
|
|
237
|
+
return fieldmap::AddGroup(info, NQ_ROUTED);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
Napi::Value MessageWrap::GetGroup(const Napi::CallbackInfo& info) {
|
|
241
|
+
return fieldmap::GetGroup(info, NQ_ROUTED);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
Napi::Value MessageWrap::ReplaceGroup(const Napi::CallbackInfo& info) {
|
|
245
|
+
return fieldmap::ReplaceGroup(info, NQ_ROUTED);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
Napi::Value MessageWrap::RemoveGroup(const Napi::CallbackInfo& info) {
|
|
249
|
+
return fieldmap::RemoveGroup(info, NQ_ROUTED);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
Napi::Value MessageWrap::HasGroup(const Napi::CallbackInfo& info) {
|
|
253
|
+
return fieldmap::HasGroup(info, NQ_ROUTED);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
Napi::Value MessageWrap::GroupCount(const Napi::CallbackInfo& info) {
|
|
257
|
+
return fieldmap::GroupCount(info, NQ_ROUTED);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#undef NQ_ROUTED
|
|
261
|
+
#undef NQ_HEADER
|
|
262
|
+
#undef NQ_TRAILER
|
|
263
|
+
|
|
264
|
+
Napi::Value MessageWrap::ToString(const Napi::CallbackInfo& info) {
|
|
265
|
+
Napi::Env env = info.Env();
|
|
266
|
+
NQ_TRY(env) {
|
|
267
|
+
return Napi::String::New(env, message_.toString());
|
|
268
|
+
} NQ_CATCH(env)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
Napi::Value MessageWrap::ToPretty(const Napi::CallbackInfo& info) {
|
|
272
|
+
Napi::Env env = info.Env();
|
|
273
|
+
NQ_TRY(env) {
|
|
274
|
+
std::string s = message_.toString();
|
|
275
|
+
std::replace(s.begin(), s.end(), '\x01', '|');
|
|
276
|
+
return Napi::String::New(env, s);
|
|
277
|
+
} NQ_CATCH(env)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
Napi::Value MessageWrap::GetMsgType(const Napi::CallbackInfo& info) {
|
|
281
|
+
Napi::Env env = info.Env();
|
|
282
|
+
NQ_TRY(env) {
|
|
283
|
+
const std::string& msgType = message_.getHeader().getField(FIX::FIELD::MsgType);
|
|
284
|
+
return Napi::String::New(env, msgType);
|
|
285
|
+
} NQ_CATCH(env)
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
} // namespace napi_quickfix
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
#ifndef NAPI_QUICKFIX_MESSAGE_WRAP_H
|
|
2
|
+
#define NAPI_QUICKFIX_MESSAGE_WRAP_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include <memory>
|
|
7
|
+
|
|
8
|
+
#include "quickfix/DataDictionary.h"
|
|
9
|
+
#include "quickfix/Message.h"
|
|
10
|
+
|
|
11
|
+
namespace napi_quickfix {
|
|
12
|
+
|
|
13
|
+
// Napi::ObjectWrap over FIX::Message.
|
|
14
|
+
//
|
|
15
|
+
// new MessageWrap()
|
|
16
|
+
// new MessageWrap(raw: string, validate?: boolean = false,
|
|
17
|
+
// sessionDictionary?: DataDictionary,
|
|
18
|
+
// applicationDictionary?: DataDictionary)
|
|
19
|
+
//
|
|
20
|
+
// With a dictionary the raw string is parsed structurally (repeating groups
|
|
21
|
+
// become nested FieldMaps); without one it is parsed flat, as before.
|
|
22
|
+
//
|
|
23
|
+
// Field methods (getField / setField / isSetField / removeField /
|
|
24
|
+
// getFieldIfSet) and group methods (addGroup / getGroup / replaceGroup /
|
|
25
|
+
// removeGroup / hasGroup / groupCount) auto-route standard header/trailer
|
|
26
|
+
// tags to the right section, as well as the header/trailer fields declared by
|
|
27
|
+
// the session dictionary the message was parsed or delivered with. Any other
|
|
28
|
+
// tag goes to the section that already holds it (body first). isEmpty and
|
|
29
|
+
// clear() cover all three sections; totalFields / fields read the body.
|
|
30
|
+
class MessageWrap : public Napi::ObjectWrap<MessageWrap> {
|
|
31
|
+
public:
|
|
32
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
33
|
+
|
|
34
|
+
// Build a JS MessageWrap holding a copy of `msg` (typed down to the last
|
|
35
|
+
// nested group entry, see fieldmap::CloneMessage), or taking `msg` over.
|
|
36
|
+
// The ApplicationBridge trampoline moves its own copy in, with the session
|
|
37
|
+
// dictionary that routes its fields (null: none).
|
|
38
|
+
static Napi::Object NewInstance(Napi::Env env, const FIX::Message& msg);
|
|
39
|
+
static Napi::Object NewInstance(
|
|
40
|
+
Napi::Env env, FIX::Message&& msg,
|
|
41
|
+
std::shared_ptr<const FIX::DataDictionary> sessionDictionary = nullptr);
|
|
42
|
+
|
|
43
|
+
explicit MessageWrap(const Napi::CallbackInfo& info);
|
|
44
|
+
|
|
45
|
+
// Internal accessor for other wrappers (validate, sendToTarget, bridge).
|
|
46
|
+
FIX::Message& Message() { return message_; }
|
|
47
|
+
const FIX::Message& Message() const { return message_; }
|
|
48
|
+
|
|
49
|
+
// Unwrap a JS value that must be a MessageWrap; throws Napi::TypeError if not.
|
|
50
|
+
static MessageWrap* UnwrapArg(Napi::Env env, Napi::Value value,
|
|
51
|
+
const char* argName);
|
|
52
|
+
|
|
53
|
+
private:
|
|
54
|
+
static Napi::FunctionReference constructor_;
|
|
55
|
+
|
|
56
|
+
// The section (header / body / trailer) that owns `tag`.
|
|
57
|
+
FIX::FieldMap& SectionFor(int tag);
|
|
58
|
+
|
|
59
|
+
Napi::Value GetField(const Napi::CallbackInfo& info);
|
|
60
|
+
Napi::Value SetField(const Napi::CallbackInfo& info);
|
|
61
|
+
Napi::Value IsSetField(const Napi::CallbackInfo& info);
|
|
62
|
+
Napi::Value RemoveField(const Napi::CallbackInfo& info);
|
|
63
|
+
Napi::Value GetFieldIfSet(const Napi::CallbackInfo& info);
|
|
64
|
+
Napi::Value GetHeaderField(const Napi::CallbackInfo& info);
|
|
65
|
+
Napi::Value SetHeaderField(const Napi::CallbackInfo& info);
|
|
66
|
+
Napi::Value GetTrailerField(const Napi::CallbackInfo& info);
|
|
67
|
+
Napi::Value SetTrailerField(const Napi::CallbackInfo& info);
|
|
68
|
+
Napi::Value IsEmpty(const Napi::CallbackInfo& info);
|
|
69
|
+
Napi::Value TotalFields(const Napi::CallbackInfo& info);
|
|
70
|
+
Napi::Value Clear(const Napi::CallbackInfo& info);
|
|
71
|
+
Napi::Value Fields(const Napi::CallbackInfo& info);
|
|
72
|
+
Napi::Value HeaderFields(const Napi::CallbackInfo& info);
|
|
73
|
+
Napi::Value TrailerFields(const Napi::CallbackInfo& info);
|
|
74
|
+
|
|
75
|
+
Napi::Value AddGroup(const Napi::CallbackInfo& info);
|
|
76
|
+
Napi::Value GetGroup(const Napi::CallbackInfo& info);
|
|
77
|
+
Napi::Value ReplaceGroup(const Napi::CallbackInfo& info);
|
|
78
|
+
Napi::Value RemoveGroup(const Napi::CallbackInfo& info);
|
|
79
|
+
Napi::Value HasGroup(const Napi::CallbackInfo& info);
|
|
80
|
+
Napi::Value GroupCount(const Napi::CallbackInfo& info);
|
|
81
|
+
|
|
82
|
+
Napi::Value ToString(const Napi::CallbackInfo& info);
|
|
83
|
+
Napi::Value ToPretty(const Napi::CallbackInfo& info);
|
|
84
|
+
Napi::Value GetMsgType(const Napi::CallbackInfo& info);
|
|
85
|
+
|
|
86
|
+
FIX::Message message_;
|
|
87
|
+
// The session dictionary whose header/trailer fields SectionFor routes
|
|
88
|
+
// (null: none). Shared, since the message may outlive the session or the
|
|
89
|
+
// JS DataDictionary it came from.
|
|
90
|
+
std::shared_ptr<const FIX::DataDictionary> sessionDictionary_;
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
} // namespace napi_quickfix
|
|
94
|
+
|
|
95
|
+
#endif // NAPI_QUICKFIX_MESSAGE_WRAP_H
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#include "session_id_wrap.h"
|
|
2
|
+
|
|
3
|
+
#include <string>
|
|
4
|
+
|
|
5
|
+
#include "errors.h"
|
|
6
|
+
|
|
7
|
+
namespace napi_quickfix {
|
|
8
|
+
|
|
9
|
+
Napi::FunctionReference SessionIDWrap::constructor_;
|
|
10
|
+
|
|
11
|
+
Napi::Object SessionIDWrap::Init(Napi::Env env, Napi::Object exports) {
|
|
12
|
+
Napi::Function func = DefineClass(
|
|
13
|
+
env, "SessionID",
|
|
14
|
+
{
|
|
15
|
+
InstanceMethod("getBeginString", &SessionIDWrap::GetBeginString),
|
|
16
|
+
InstanceMethod("getSenderCompID", &SessionIDWrap::GetSenderCompID),
|
|
17
|
+
InstanceMethod("getTargetCompID", &SessionIDWrap::GetTargetCompID),
|
|
18
|
+
InstanceMethod("getSessionQualifier",
|
|
19
|
+
&SessionIDWrap::GetSessionQualifier),
|
|
20
|
+
InstanceMethod("toString", &SessionIDWrap::ToString),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
constructor_ = Napi::Persistent(func);
|
|
24
|
+
constructor_.SuppressDestruct();
|
|
25
|
+
|
|
26
|
+
exports.Set("SessionIDWrap", func);
|
|
27
|
+
return exports;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
Napi::Object SessionIDWrap::NewInstance(Napi::Env env,
|
|
31
|
+
const FIX::SessionID& id) {
|
|
32
|
+
Napi::Object obj = constructor_.New(
|
|
33
|
+
{Napi::String::New(env, id.getBeginString().getValue()),
|
|
34
|
+
Napi::String::New(env, id.getSenderCompID().getValue()),
|
|
35
|
+
Napi::String::New(env, id.getTargetCompID().getValue()),
|
|
36
|
+
Napi::String::New(env, id.getSessionQualifier())});
|
|
37
|
+
return obj;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
SessionIDWrap* SessionIDWrap::UnwrapArg(Napi::Env env, Napi::Value value,
|
|
41
|
+
const char* argName) {
|
|
42
|
+
if (!value.IsObject() ||
|
|
43
|
+
!value.As<Napi::Object>().InstanceOf(constructor_.Value())) {
|
|
44
|
+
throw Napi::TypeError::New(
|
|
45
|
+
env, std::string(argName) + " must be a SessionID instance");
|
|
46
|
+
}
|
|
47
|
+
return Napi::ObjectWrap<SessionIDWrap>::Unwrap(value.As<Napi::Object>());
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
SessionIDWrap::SessionIDWrap(const Napi::CallbackInfo& info)
|
|
51
|
+
: Napi::ObjectWrap<SessionIDWrap>(info) {
|
|
52
|
+
Napi::Env env = info.Env();
|
|
53
|
+
if (info.Length() < 3 || !info[0].IsString() || !info[1].IsString() ||
|
|
54
|
+
!info[2].IsString()) {
|
|
55
|
+
throw Napi::TypeError::New(
|
|
56
|
+
env,
|
|
57
|
+
"new SessionID(beginString, senderCompID, targetCompID, qualifier?)");
|
|
58
|
+
}
|
|
59
|
+
std::string begin = info[0].As<Napi::String>().Utf8Value();
|
|
60
|
+
std::string sender = info[1].As<Napi::String>().Utf8Value();
|
|
61
|
+
std::string target = info[2].As<Napi::String>().Utf8Value();
|
|
62
|
+
std::string qualifier;
|
|
63
|
+
if (info.Length() >= 4 && info[3].IsString()) {
|
|
64
|
+
qualifier = info[3].As<Napi::String>().Utf8Value();
|
|
65
|
+
}
|
|
66
|
+
session_id_ = FIX::SessionID(begin, sender, target, qualifier);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
Napi::Value SessionIDWrap::GetBeginString(const Napi::CallbackInfo& info) {
|
|
70
|
+
return Napi::String::New(info.Env(), session_id_.getBeginString().getValue());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
Napi::Value SessionIDWrap::GetSenderCompID(const Napi::CallbackInfo& info) {
|
|
74
|
+
return Napi::String::New(info.Env(),
|
|
75
|
+
session_id_.getSenderCompID().getValue());
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
Napi::Value SessionIDWrap::GetTargetCompID(const Napi::CallbackInfo& info) {
|
|
79
|
+
return Napi::String::New(info.Env(),
|
|
80
|
+
session_id_.getTargetCompID().getValue());
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
Napi::Value SessionIDWrap::GetSessionQualifier(const Napi::CallbackInfo& info) {
|
|
84
|
+
return Napi::String::New(info.Env(), session_id_.getSessionQualifier());
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
Napi::Value SessionIDWrap::ToString(const Napi::CallbackInfo& info) {
|
|
88
|
+
return Napi::String::New(info.Env(), session_id_.toString());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
} // namespace napi_quickfix
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
#ifndef NAPI_QUICKFIX_SESSION_ID_WRAP_H
|
|
2
|
+
#define NAPI_QUICKFIX_SESSION_ID_WRAP_H
|
|
3
|
+
|
|
4
|
+
#include <napi.h>
|
|
5
|
+
|
|
6
|
+
#include "quickfix/SessionID.h"
|
|
7
|
+
|
|
8
|
+
namespace napi_quickfix {
|
|
9
|
+
|
|
10
|
+
// Napi::ObjectWrap over FIX::SessionID.
|
|
11
|
+
//
|
|
12
|
+
// new SessionID(beginString, senderCompID, targetCompID, qualifier?)
|
|
13
|
+
//
|
|
14
|
+
// Getters: getBeginString / getSenderCompID / getTargetCompID /
|
|
15
|
+
// getSessionQualifier; plus toString.
|
|
16
|
+
class SessionIDWrap : public Napi::ObjectWrap<SessionIDWrap> {
|
|
17
|
+
public:
|
|
18
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports);
|
|
19
|
+
|
|
20
|
+
// Build a JS SessionID wrapping a copy of the given FIX::SessionID.
|
|
21
|
+
static Napi::Object NewInstance(Napi::Env env, const FIX::SessionID& id);
|
|
22
|
+
|
|
23
|
+
explicit SessionIDWrap(const Napi::CallbackInfo& info);
|
|
24
|
+
|
|
25
|
+
FIX::SessionID& SessionID() { return session_id_; }
|
|
26
|
+
const FIX::SessionID& SessionID() const { return session_id_; }
|
|
27
|
+
|
|
28
|
+
// Unwrap a JS value that must be a SessionID; throws Napi::TypeError if not.
|
|
29
|
+
static SessionIDWrap* UnwrapArg(Napi::Env env, Napi::Value value,
|
|
30
|
+
const char* argName);
|
|
31
|
+
|
|
32
|
+
private:
|
|
33
|
+
static Napi::FunctionReference constructor_;
|
|
34
|
+
|
|
35
|
+
Napi::Value GetBeginString(const Napi::CallbackInfo& info);
|
|
36
|
+
Napi::Value GetSenderCompID(const Napi::CallbackInfo& info);
|
|
37
|
+
Napi::Value GetTargetCompID(const Napi::CallbackInfo& info);
|
|
38
|
+
Napi::Value GetSessionQualifier(const Napi::CallbackInfo& info);
|
|
39
|
+
Napi::Value ToString(const Napi::CallbackInfo& info);
|
|
40
|
+
|
|
41
|
+
FIX::SessionID session_id_;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
} // namespace napi_quickfix
|
|
45
|
+
|
|
46
|
+
#endif // NAPI_QUICKFIX_SESSION_ID_WRAP_H
|