jspurefix 4.1.2 → 5.1.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/BACKPORT_PLAN.md +214 -0
- package/README.md +1 -2
- package/data/examples/FIX.4.4/fixsim/fix.txt +46 -0
- package/data/session/fixsim-qf44-initiator.json +21 -0
- package/dist/buffer/ascii/ascii-parser-state.js +0 -7
- package/dist/buffer/ascii/ascii-parser-state.js.map +1 -1
- package/dist/buffer/ascii/ascii-parser.d.ts +1 -0
- package/dist/buffer/ascii/ascii-parser.js +8 -2
- package/dist/buffer/ascii/ascii-parser.js.map +1 -1
- package/dist/buffer/ascii/ascii-segment-parser.js +36 -0
- package/dist/buffer/ascii/ascii-segment-parser.js.map +1 -1
- package/dist/buffer/ascii/tag-index.d.ts +20 -0
- package/dist/buffer/ascii/tag-index.js +89 -0
- package/dist/buffer/ascii/tag-index.js.map +1 -0
- package/dist/buffer/msg-view.js +17 -4
- package/dist/buffer/msg-view.js.map +1 -1
- package/dist/buffer/segment/segment-description.d.ts +3 -0
- package/dist/buffer/segment/segment-description.js +8 -0
- package/dist/buffer/segment/segment-description.js.map +1 -1
- package/dist/buffer/segment/segment-view.d.ts +13 -0
- package/dist/buffer/segment/segment-view.js +27 -0
- package/dist/buffer/segment/segment-view.js.map +1 -0
- package/dist/collections/collection.js.map +1 -1
- package/dist/config/js-fix-logger.js.map +1 -1
- package/dist/store/fix-msg-ascii-store-resend.js.map +1 -1
- package/dist/transport/session/fix-session.js +6 -0
- package/dist/transport/session/fix-session.js.map +1 -1
- package/dist/transport/tcp/tcp-initiator-connector.js.map +1 -1
- package/dist/types/FIX.5.0SP2/quickfix/enum/all-enum.js.map +1 -1
- package/dist/types/FIX.5.0SP2/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX.5.0SP2/repo/set/hop_grp.js.map +1 -1
- package/dist/types/FIX4.0/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.1/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.2/quickfix/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.2/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.3/quickfix/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.3/repo/allocation.js.map +1 -1
- package/dist/types/FIX4.3/repo/allocation_ack.js.map +1 -1
- package/dist/types/FIX4.3/repo/cross_order_cancel_replace_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/cross_order_cancel_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/derivative_security_list.js.map +1 -1
- package/dist/types/FIX4.3/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.3/repo/execution_report.js.map +1 -1
- package/dist/types/FIX4.3/repo/mass_quote.js.map +1 -1
- package/dist/types/FIX4.3/repo/mass_quote_acknowledgement.js.map +1 -1
- package/dist/types/FIX4.3/repo/multileg_order_cancel_replace_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/new_order_cross.js.map +1 -1
- package/dist/types/FIX4.3/repo/new_order_list.js.map +1 -1
- package/dist/types/FIX4.3/repo/new_order_multileg.js.map +1 -1
- package/dist/types/FIX4.3/repo/new_order_single.js.map +1 -1
- package/dist/types/FIX4.3/repo/order_cancel_replace_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/order_cancel_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/order_mass_status_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/order_status_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote_cancel.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote_request_reject.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote_status_report.js.map +1 -1
- package/dist/types/FIX4.3/repo/quote_status_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/registration_instructions.js.map +1 -1
- package/dist/types/FIX4.3/repo/registration_instructions_response.js.map +1 -1
- package/dist/types/FIX4.3/repo/security_definition.js.map +1 -1
- package/dist/types/FIX4.3/repo/security_definition_request.js.map +1 -1
- package/dist/types/FIX4.3/repo/security_list.js.map +1 -1
- package/dist/types/FIX4.3/repo/settlement_instructions.js.map +1 -1
- package/dist/types/FIX4.3/repo/trade_capture_report.js.map +1 -1
- package/dist/types/FIX4.3/repo/trade_capture_report_request.js.map +1 -1
- package/dist/types/FIX4.4/quickfix/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.4/repo/enum/all-enum.js.map +1 -1
- package/dist/types/FIX4.4/repo/set/hop.js.map +1 -1
- package/dist/types/FIXML50SP2/adjusted_position_report.js.map +1 -1
- package/dist/types/FIXML50SP2/derivative_security_list.js.map +1 -1
- package/dist/types/FIXML50SP2/derivative_security_list_update_report.js.map +1 -1
- package/dist/types/FIXML50SP2/email.js.map +1 -1
- package/dist/types/FIXML50SP2/enum/all-enum.js.map +1 -1
- package/dist/types/FIXML50SP2/news.js.map +1 -1
- package/dist/types/FIXML50SP2/quote_cancel.js.map +1 -1
- package/dist/types/FIXML50SP2/set/market_segment_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/party_risk_limits_ack_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/party_risk_limits_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/party_risk_limits_update_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/sec_list_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/sec_lst_upd_rel_sym_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/trading_session_rules_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/trd_instrmt_leg_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/set/trd_sess_lst_grp.js.map +1 -1
- package/dist/types/FIXML50SP2/stream_assignment_report.js.map +1 -1
- package/dist/types/FIXML50SP2/stream_assignment_request.js.map +1 -1
- package/eslint.config.mjs +119 -0
- package/jsfix.test_client.txt +66 -66
- package/jsfix.test_server.txt +63 -63
- package/package.json +4 -5
- package/src/buffer/ascii/ascii-parser-state.ts +4 -7
- package/src/buffer/ascii/ascii-parser.ts +14 -3
- package/src/buffer/ascii/ascii-segment-parser.ts +37 -0
- package/src/buffer/ascii/tag-index.ts +101 -0
- package/src/buffer/msg-view.ts +18 -6
- package/src/buffer/segment/segment-description.ts +10 -0
- package/src/buffer/segment/segment-view.ts +28 -0
- package/src/collections/collection.ts +0 -1
- package/src/config/js-fix-logger.ts +0 -1
- package/src/store/fix-msg-ascii-store-resend.ts +1 -1
- package/src/transport/session/fix-session.ts +7 -0
- package/src/transport/tcp/tcp-initiator-connector.ts +1 -1
- package/src/types/FIX.5.0SP2/quickfix/enum/all-enum.ts +0 -1
- package/src/types/FIX.5.0SP2/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX.5.0SP2/repo/set/hop_grp.ts +1 -1
- package/src/types/FIX4.0/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX4.1/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX4.2/quickfix/enum/all-enum.ts +0 -1
- package/src/types/FIX4.2/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX4.3/quickfix/enum/all-enum.ts +0 -1
- package/src/types/FIX4.3/repo/allocation.ts +2 -2
- package/src/types/FIX4.3/repo/allocation_ack.ts +1 -1
- package/src/types/FIX4.3/repo/cross_order_cancel_replace_request.ts +4 -4
- package/src/types/FIX4.3/repo/cross_order_cancel_request.ts +1 -1
- package/src/types/FIX4.3/repo/derivative_security_list.ts +1 -1
- package/src/types/FIX4.3/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX4.3/repo/execution_report.ts +5 -5
- package/src/types/FIX4.3/repo/mass_quote.ts +1 -1
- package/src/types/FIX4.3/repo/mass_quote_acknowledgement.ts +1 -1
- package/src/types/FIX4.3/repo/multileg_order_cancel_replace_request.ts +3 -3
- package/src/types/FIX4.3/repo/new_order_cross.ts +4 -4
- package/src/types/FIX4.3/repo/new_order_list.ts +4 -4
- package/src/types/FIX4.3/repo/new_order_multileg.ts +3 -3
- package/src/types/FIX4.3/repo/new_order_single.ts +4 -4
- package/src/types/FIX4.3/repo/order_cancel_replace_request.ts +3 -3
- package/src/types/FIX4.3/repo/order_cancel_request.ts +1 -1
- package/src/types/FIX4.3/repo/order_mass_status_request.ts +1 -1
- package/src/types/FIX4.3/repo/order_status_request.ts +1 -1
- package/src/types/FIX4.3/repo/quote.ts +1 -1
- package/src/types/FIX4.3/repo/quote_cancel.ts +1 -1
- package/src/types/FIX4.3/repo/quote_request.ts +2 -2
- package/src/types/FIX4.3/repo/quote_request_reject.ts +2 -2
- package/src/types/FIX4.3/repo/quote_status_report.ts +1 -1
- package/src/types/FIX4.3/repo/quote_status_request.ts +1 -1
- package/src/types/FIX4.3/repo/registration_instructions.ts +2 -2
- package/src/types/FIX4.3/repo/registration_instructions_response.ts +1 -1
- package/src/types/FIX4.3/repo/security_definition.ts +1 -1
- package/src/types/FIX4.3/repo/security_definition_request.ts +1 -1
- package/src/types/FIX4.3/repo/security_list.ts +1 -1
- package/src/types/FIX4.3/repo/settlement_instructions.ts +1 -1
- package/src/types/FIX4.3/repo/trade_capture_report.ts +1 -1
- package/src/types/FIX4.3/repo/trade_capture_report_request.ts +1 -1
- package/src/types/FIX4.4/quickfix/enum/all-enum.ts +0 -1
- package/src/types/FIX4.4/repo/enum/all-enum.ts +0 -1
- package/src/types/FIX4.4/repo/set/hop.ts +1 -1
- package/src/types/FIXML50SP2/adjusted_position_report.ts +1 -1
- package/src/types/FIXML50SP2/derivative_security_list.ts +1 -1
- package/src/types/FIXML50SP2/derivative_security_list_update_report.ts +1 -1
- package/src/types/FIXML50SP2/email.ts +1 -1
- package/src/types/FIXML50SP2/enum/all-enum.ts +0 -1
- package/src/types/FIXML50SP2/news.ts +1 -1
- package/src/types/FIXML50SP2/quote_cancel.ts +1 -1
- package/src/types/FIXML50SP2/set/market_segment_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/party_risk_limits_ack_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/party_risk_limits_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/party_risk_limits_update_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/sec_list_grp.ts +2 -2
- package/src/types/FIXML50SP2/set/sec_lst_upd_rel_sym_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/trading_session_rules_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/trd_instrmt_leg_grp.ts +1 -1
- package/src/types/FIXML50SP2/set/trd_sess_lst_grp.ts +1 -1
- package/src/types/FIXML50SP2/stream_assignment_report.ts +1 -1
- package/src/types/FIXML50SP2/stream_assignment_request.ts +1 -1
- package/src/util/unzip.js +0 -1
package/BACKPORT_PLAN.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# Backport Plan: C# cspurefix → TypeScript jspurefix
|
|
2
|
+
|
|
3
|
+
## Background
|
|
4
|
+
|
|
5
|
+
The C# dotnet core port (`~/dev/cs/cspurefix`) has accumulated significant improvements over the TypeScript version which has had no real improvements for some time. The two codebases are structurally very similar, making incremental backporting feasible. The goal is to bring the TS version up to the same quality level through careful, non-disruptive changes.
|
|
6
|
+
|
|
7
|
+
A standalone demo at `~/dev/cs/purefix-standalone-demo` demonstrates the C# store/recovery working end-to-end including restart scenarios and extended soak testing.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Phase 1: Non-Contiguous Tag Parsing (Correctness Fix)
|
|
12
|
+
|
|
13
|
+
**Priority: Highest | Risk: Medium | Scope: Contained to `src/buffer/`**
|
|
14
|
+
|
|
15
|
+
### Problem
|
|
16
|
+
|
|
17
|
+
The TS segment parser assumes component tags appear in a contiguous block within the message body. Some brokers (discovered when using the C# engine) send messages where root-level component tags are scattered. For example, an Instrument component's tags (Symbol=55, SecurityIDSource=22, SecurityID=48) can be interleaved with non-Instrument tags (HandlInst=21, OrderQty=38, OrdType=40, Price=44, Side=54).
|
|
18
|
+
|
|
19
|
+
This is valid FIX — the spec does not require component tags to be contiguous at the root level. The TS parser fails to correctly resolve these messages.
|
|
20
|
+
|
|
21
|
+
### Example (from fixsim-examples.txt NewOrderSingle)
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
8=FIX.4.4|9=193|35=D|34=5|49=FIXSIMDEMO|52=20241013-14:09:45.126|56=sjames8888@gmail_com|
|
|
25
|
+
11=567638644253361428000|15=GBP|21=2|22=5|38=100|40=2|44=100|48=VOD.L|54=1|55=VOD.L|
|
|
26
|
+
59=0|60=20241013-14:09:45.126|388=1|10=091|
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Instrument tags (15, 22, 48, 55) are scattered among order tags (21, 38, 40, 44, 54, 59, 60).
|
|
30
|
+
|
|
31
|
+
### C# Solution
|
|
32
|
+
|
|
33
|
+
| File | Purpose |
|
|
34
|
+
|------|---------|
|
|
35
|
+
| `PureFix.Buffer/Ascii/AsciiSegmentParser.cs` | Stack-based parser with fragment detection |
|
|
36
|
+
| `PureFix.Buffer/Ascii/AsciiSegmentParser.Context.cs` | Parse state with `ExitedDepth1Components` and `FragmentedComponents` tracking |
|
|
37
|
+
| `PureFix.Buffer/Ascii/TagIndex.cs` | Indexes tags for non-contiguous access via `_tagSpans` dictionary |
|
|
38
|
+
| `PureFix.Buffer/Segment/SegmentView.cs` | Transparent access to scattered tags as if contiguous |
|
|
39
|
+
| `PureFix.Buffer/Segment/SegmentDescription.cs` | Segment metadata with position tracking |
|
|
40
|
+
|
|
41
|
+
**Algorithm:**
|
|
42
|
+
|
|
43
|
+
1. **Discovery**: Stack-based recursive descent through tags. When a depth-1 component is popped from the stack, it's added to `ExitedDepth1Components`.
|
|
44
|
+
2. **Fragment Detection**: If a tag belonging to an already-exited depth-1 component is encountered, that component is added to `FragmentedComponents`.
|
|
45
|
+
3. **Optimised Access**: Only fragmented components get expensive `SegmentView` construction via `TagIndex`. Non-fragmented components use simple position ranges (no overhead).
|
|
46
|
+
|
|
47
|
+
### TS Files to Modify
|
|
48
|
+
|
|
49
|
+
| File | Change |
|
|
50
|
+
|------|--------|
|
|
51
|
+
| `src/buffer/ascii/ascii-segment-parser.ts` | Add fragment detection (ExitedDepth1Components, FragmentedComponents tracking) |
|
|
52
|
+
| `src/buffer/segment/segment-description.ts` | May need SegmentView reference for fragmented components |
|
|
53
|
+
| New: `src/buffer/segment/segment-view.ts` | Port SegmentView for non-contiguous tag access |
|
|
54
|
+
| New: `src/buffer/ascii/tag-index.ts` | Port TagIndex for tag span indexing |
|
|
55
|
+
|
|
56
|
+
### Test Data
|
|
57
|
+
|
|
58
|
+
Port from `~/dev/cs/cspurefix/PureFix.Test.ModularTypes/Data/examples/FIX.4.4/fixsim-examples.txt` — 46 real FIX messages including fragmented Instrument components. Write a failing test first to prove the problem, then fix.
|
|
59
|
+
|
|
60
|
+
### C# Test Reference
|
|
61
|
+
|
|
62
|
+
`~/dev/cs/cspurefix/PureFix.Test.ModularTypes/FixSimTest.cs` — parses all 46 messages, verifies type counts, deserialises ExecutionReport to strongly-typed object.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Phase 2: Parser Reset on Disconnect (Quick Win)
|
|
67
|
+
|
|
68
|
+
**Priority: High | Risk: Low | Scope: Small**
|
|
69
|
+
|
|
70
|
+
### Problem
|
|
71
|
+
|
|
72
|
+
When a TCP connection drops mid-message, the ASCII parser retains partial buffer state. On reconnect, the stale buffer can corrupt the next message parse. The C# version explicitly resets the parser during reconnection preparation.
|
|
73
|
+
|
|
74
|
+
### C# Solution
|
|
75
|
+
|
|
76
|
+
In `FixSession.cs` → `PrepareForReconnect()`:
|
|
77
|
+
```csharp
|
|
78
|
+
m_parser.Reset();
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
Also resets transient coordinator state (logon retry count, timeout recovery attempts) while preserving sequence numbers.
|
|
82
|
+
|
|
83
|
+
### TS Files to Modify
|
|
84
|
+
|
|
85
|
+
| File | Change |
|
|
86
|
+
|------|--------|
|
|
87
|
+
| `src/transport/session/fix-session.ts` | Add parser reset in reconnection path |
|
|
88
|
+
| `src/buffer/ascii/ascii-parser.ts` | Ensure `reset()` method clears all partial state |
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Phase 3: SessionSequenceCoordinator (Foundation)
|
|
93
|
+
|
|
94
|
+
**Priority: High | Risk: Medium | Scope: Medium**
|
|
95
|
+
|
|
96
|
+
### Problem
|
|
97
|
+
|
|
98
|
+
The TS version has sequence state scattered across `fix-session-state.ts` and `ascii-session.ts` with no single source of truth. This makes it hard to reason about recovery, reset, and reconnect behaviour. The C# version centralises all of this.
|
|
99
|
+
|
|
100
|
+
### C# Solution
|
|
101
|
+
|
|
102
|
+
| File | Purpose |
|
|
103
|
+
|------|---------|
|
|
104
|
+
| `PureFix.Transport/Session/SessionSequenceCoordinator.cs` | Single source of truth for sender/target sequences |
|
|
105
|
+
|
|
106
|
+
**Key capabilities missing from TS:**
|
|
107
|
+
|
|
108
|
+
- `PrepareForReconnect()` — resets transient state, preserves sequences
|
|
109
|
+
- `HandlePeerReset()` — coordinates ResetSeqNumFlag=Y from peer
|
|
110
|
+
- `ResetAsAcceptor()` — acceptor-initiated reset
|
|
111
|
+
- `PossDupFlag` handling — messages with PossDupFlag=Y bypass normal sequence checks
|
|
112
|
+
- Logon retry with `MaxLogonRetries=100`
|
|
113
|
+
- Timeout recovery with `MaxTimeoutRecoveryAttempts=3` (handles sleep/wake scenarios)
|
|
114
|
+
- `ResendRequestManager` integration — storm protection, pending request tracking
|
|
115
|
+
- Delayed message acceptance — out-of-order messages that fill pending gap ranges
|
|
116
|
+
|
|
117
|
+
### TS Files to Modify
|
|
118
|
+
|
|
119
|
+
| File | Change |
|
|
120
|
+
|------|--------|
|
|
121
|
+
| New: `src/transport/session/session-sequence-coordinator.ts` | Port coordinator |
|
|
122
|
+
| `src/transport/session/fix-session.ts` | Integrate coordinator as sequence authority |
|
|
123
|
+
| `src/transport/ascii/ascii-session.ts` | Replace inline sequence logic with coordinator calls |
|
|
124
|
+
| `src/transport/session/fix-session-state.ts` | May reduce scope — coordinator takes over sequence tracking |
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Phase 4: Persistent Message Store
|
|
129
|
+
|
|
130
|
+
**Priority: Medium-High | Risk: Medium | Scope: Medium**
|
|
131
|
+
|
|
132
|
+
### Problem
|
|
133
|
+
|
|
134
|
+
The TS version only has `FixMsgMemoryStore` — all message history and sequence state is lost on process restart. The C# version has a QuickFix-compatible file store that persists across restarts.
|
|
135
|
+
|
|
136
|
+
### C# Solution
|
|
137
|
+
|
|
138
|
+
| File | Purpose |
|
|
139
|
+
|------|---------|
|
|
140
|
+
| `PureFix.Transport/Store/IFixSessionStore.cs` | Unified persistence interface |
|
|
141
|
+
| `PureFix.Transport/Store/FileSessionStore.cs` | QuickFix-compatible file storage |
|
|
142
|
+
| `PureFix.Transport/Store/MemorySessionStore.cs` | In-memory implementation |
|
|
143
|
+
| `PureFix.Transport/Store/FileSessionStoreFactory.cs` | Factory pattern for store creation |
|
|
144
|
+
| `PureFix.Transport/Store/FixMsgStoreRecord.cs` | Persisted message record |
|
|
145
|
+
|
|
146
|
+
**QuickFix file format:**
|
|
147
|
+
- `.seqnums` — 20-char padded sender:target sequence numbers
|
|
148
|
+
- `.session` — creation timestamp
|
|
149
|
+
- `.header` — seqnum,offset,length index
|
|
150
|
+
- `.body` — raw FIX message bytes
|
|
151
|
+
|
|
152
|
+
### Key Integration Points
|
|
153
|
+
|
|
154
|
+
- `StoreEncodedMessage()` — persist every sent message
|
|
155
|
+
- `InitializeSessionStore()` — load state on startup
|
|
156
|
+
- Store factory in config — deferred creation
|
|
157
|
+
- Store reset on `ResetSeqNumFlag=Y`
|
|
158
|
+
- Resender recreation after reset
|
|
159
|
+
|
|
160
|
+
### TS Files to Modify
|
|
161
|
+
|
|
162
|
+
| File | Change |
|
|
163
|
+
|------|--------|
|
|
164
|
+
| New: `src/store/fix-session-store.ts` | Port IFixSessionStore interface |
|
|
165
|
+
| New: `src/store/file-session-store.ts` | Port FileSessionStore |
|
|
166
|
+
| New: `src/store/file-session-store-factory.ts` | Port factory |
|
|
167
|
+
| `src/store/fix-msg-memory-store.ts` | Align with IFixSessionStore interface |
|
|
168
|
+
| `src/transport/ascii/ascii-session.ts` | Integrate store lifecycle |
|
|
169
|
+
| `src/config/js-fix-config.ts` | Add SessionStoreFactory to config |
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Phase 5: Resend Request Improvements
|
|
174
|
+
|
|
175
|
+
**Priority: Medium | Risk: Low-Medium | Scope: Small**
|
|
176
|
+
|
|
177
|
+
### Problem
|
|
178
|
+
|
|
179
|
+
The TS version sends a simple ResendRequest on gap detection with no protection against request storms or tracking of pending requests.
|
|
180
|
+
|
|
181
|
+
### C# Solution
|
|
182
|
+
|
|
183
|
+
`ResendRequestManager` in the coordinator provides:
|
|
184
|
+
- Pending request tracking (`PendingResendRequests` collection)
|
|
185
|
+
- Storm protection — after N requests without response, accepts the gap
|
|
186
|
+
- Delayed message detection — clears pending requests when gap-filling messages arrive
|
|
187
|
+
- `ResendGapFillOnly` mode — sends GapFill instead of replaying stored messages (prevents duplicate executions)
|
|
188
|
+
|
|
189
|
+
### TS Files to Modify
|
|
190
|
+
|
|
191
|
+
| File | Change |
|
|
192
|
+
|------|--------|
|
|
193
|
+
| New: `src/transport/session/resend-request-manager.ts` | Port manager |
|
|
194
|
+
| `src/transport/ascii/ascii-session.ts` | Integrate with gap detection |
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
198
|
+
## Phase 6: Message Generator / XML Parser (Future)
|
|
199
|
+
|
|
200
|
+
**Priority: Low | Risk: Medium | Scope: Large**
|
|
201
|
+
|
|
202
|
+
- C# uses nested types for groups (sub-types) in generated code
|
|
203
|
+
- QuickFix XML parser has improved design with better error tracking
|
|
204
|
+
- Nice to align for maintenance but not critical
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
## General Principles
|
|
209
|
+
|
|
210
|
+
1. **Incremental PRs** — one phase at a time, smallest safe changes
|
|
211
|
+
2. **Test first** — port test data and write failing tests before fixing
|
|
212
|
+
3. **Maintain compatibility** — existing tests must continue to pass
|
|
213
|
+
4. **Align code structure** — where reasonable, keep TS looking similar to C# for easier future maintenance
|
|
214
|
+
5. **No big bang** — each phase should be independently mergeable and useful
|
package/README.md
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# jspurefix
|
|
2
2
|
|
|
3
|
-
[](https://travis-ci.org/TimelordUK/jspurefix)
|
|
3
|
+
[](https://github.com/TimelordUK/jspurefix/actions/workflows/ci.yml)
|
|
5
4
|
[](https://standardjs.com)
|
|
6
5
|
|
|
7
6
|
## C# Port Available
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
8=FIX.4.4|9=0000095|35=A|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=1|57=|52=20241013-14:03:55.006|98=0|108=30|141=Y|10=000|
|
|
2
|
+
8=FIX.4.4|9=95|35=0|34=1|49=FIXSIMDEMO|52=20241013-14:04:31.878|56=sjames8888@gmail_com|112=0.824042533442398|10=088|
|
|
3
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=2|57=|52=20241013-14:04:32.430|112=heartbeat-10/13/2024 14:04:32|10=248|
|
|
4
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=3|57=|52=20241013-14:05:02.038|112=heartbeat-10/13/2024 14:05:02|10=249|
|
|
5
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=4|57=|52=20241013-14:05:32.041|112=heartbeat-10/13/2024 14:05:32|10=250|
|
|
6
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=5|57=|52=20241013-14:06:02.041|112=heartbeat-10/13/2024 14:06:02|10=247|
|
|
7
|
+
8=FIX.4.4|9=151|35=6|34=2|49=FIXSIMDEMO|52=20241013-14:06:17.412|56=sjames8888@gmail_com|15=GBP|22=5|23=566638644251319700000|27=100|28=N|44=40|48=VOD.L|54=1|55=VOD.L|10=156|
|
|
8
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=6|57=|52=20241013-14:06:32.037|112=heartbeat-10/13/2024 14:06:32|10=003|
|
|
9
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=7|57=|52=20241013-14:07:02.042|112=heartbeat-10/13/2024 14:07:02|10=252|
|
|
10
|
+
8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=8|57=|52=20241013-14:07:32.029|112=heartbeat-10/13/2024 14:07:32|10=008|
|
|
11
|
+
8=FIX.4.4|9=95|35=1|34=3|49=FIXSIMDEMO|52=20241013-14:07:35.444|56=sjames8888@gmail_com|112=0.349266975815067|10=104|
|
|
12
|
+
8=FIX.4.4|9=0000099|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=9|57=|52=20241013-14:07:35.930|112=0.349266975815067|10=011|
|
|
13
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=10|57=|52=20241013-14:08:05.043|112=heartbeat-10/13/2024 14:08:05|10=048|
|
|
14
|
+
8=FIX.4.4|9=141|35=V|34=4|49=FIXSIMDEMO|52=20241013-14:08:12.728|56=sjames8888@gmail_com|262=VOD.L|263=1|264=1|146=1|55=VOD.L|167=CS|267=3|269=0|269=1|269=2|10=128|
|
|
15
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=11|57=|52=20241013-14:08:35.030|112=heartbeat-10/13/2024 14:08:35|10=051|
|
|
16
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=12|57=|52=20241013-14:09:05.043|112=heartbeat-10/13/2024 14:09:05|10=052|
|
|
17
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=13|57=|52=20241013-14:09:35.037|112=heartbeat-10/13/2024 14:09:35|10=062|
|
|
18
|
+
8=FIX.4.4|9=193|35=D|34=5|49=FIXSIMDEMO|52=20241013-14:09:45.126|56=sjames8888@gmail_com|11=567638644253361428000|15=GBP|21=2|22=5|38=100|40=2|44=100|48=VOD.L|54=1|55=VOD.L|59=0|60=20241013-14:09:45.126|388=1|10=091|
|
|
19
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=14|57=|52=20241013-14:10:05.041|112=heartbeat-10/13/2024 14:10:05|10=036|
|
|
20
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=15|57=|52=20241013-14:10:35.043|112=heartbeat-10/13/2024 14:10:35|10=045|
|
|
21
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=16|57=|52=20241013-14:11:05.038|112=heartbeat-10/13/2024 14:11:05|10=046|
|
|
22
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=17|57=|52=20241013-14:11:35.031|112=heartbeat-10/13/2024 14:11:35|10=046|
|
|
23
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=18|57=|52=20241013-14:12:05.041|112=heartbeat-10/13/2024 14:12:05|10=044|
|
|
24
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=19|57=|52=20241013-14:12:35.043|112=heartbeat-10/13/2024 14:12:35|10=053|
|
|
25
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=20|57=|52=20241013-14:13:05.028|112=heartbeat-10/13/2024 14:13:05|10=044|
|
|
26
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=21|57=|52=20241013-14:13:35.029|112=heartbeat-10/13/2024 14:13:35|10=052|
|
|
27
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=22|57=|52=20241013-14:14:05.041|112=heartbeat-10/13/2024 14:14:05|10=043|
|
|
28
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=23|57=|52=20241013-14:14:35.028|112=heartbeat-10/13/2024 14:14:35|10=055|
|
|
29
|
+
8=FIX.4.4|9=261|35=8|34=6|49=FIXSIMDEMO|52=20241013-14:15:00.746|56=sjames8888@gmail_com|6=100|14=100|15=GBP|17=41638644256253512000|18=VOD.L|21=2|22=5|31=100|32=100|37=638644257007460000|38=100|39=2|40=2|44=100|48=VOD.L|54=1|55=VOD.L|59=0|60=20241013-14:15:00.746|150=2|151=0|10=207|
|
|
30
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=24|57=|52=20241013-14:15:05.030|112=heartbeat-10/13/2024 14:15:05|10=045|
|
|
31
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=25|57=|52=20241013-14:15:35.034|112=heartbeat-10/13/2024 14:15:35|10=056|
|
|
32
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=26|57=|52=20241013-14:16:05.033|112=heartbeat-10/13/2024 14:16:05|10=052|
|
|
33
|
+
8=FIX.4.4|9=119|35=R|34=7|49=FIXSIMDEMO|52=20241013-14:16:23.036|56=sjames8888@gmail_com|131=569638644257643472000|146=1|55=VOD.L|54=1|10=113|
|
|
34
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=27|57=|52=20241013-14:16:35.037|112=heartbeat-10/13/2024 14:16:35|10=063|
|
|
35
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=28|57=|52=20241013-14:17:05.033|112=heartbeat-10/13/2024 14:17:05|10=056|
|
|
36
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=29|57=|52=20241013-14:17:35.038|112=heartbeat-10/13/2024 14:17:35|10=068|
|
|
37
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=30|57=|52=20241013-14:18:05.037|112=heartbeat-10/13/2024 14:18:05|10=055|
|
|
38
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=31|57=|52=20241013-14:18:35.029|112=heartbeat-10/13/2024 14:18:35|10=063|
|
|
39
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=32|57=|52=20241013-14:19:05.040|112=heartbeat-10/13/2024 14:19:05|10=053|
|
|
40
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=33|57=|52=20241013-14:19:35.029|112=heartbeat-10/13/2024 14:19:35|10=067|
|
|
41
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=34|57=|52=20241013-14:20:05.031|112=heartbeat-10/13/2024 14:20:05|10=039|
|
|
42
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=35|57=|52=20241013-14:20:35.029|112=heartbeat-10/13/2024 14:20:35|10=053|
|
|
43
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=36|57=|52=20241013-14:21:05.036|112=heartbeat-10/13/2024 14:21:05|10=048|
|
|
44
|
+
8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=37|57=|52=20241013-14:21:35.043|112=heartbeat-10/13/2024 14:21:35|10=053|
|
|
45
|
+
8=FIX.4.4|9=0000095|35=A|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=1|57=|52=20241013-14:31:31.938|98=0|108=30|141=Y|10=009|
|
|
46
|
+
8=FIX.4.4|9=96|35=0|34=8|49=FIXSIMDEMO|52=20241013-14:31:36.182|56=sjames8888@gmail_com|112=0.0534090264949058|10=144|
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"application": {
|
|
3
|
+
"type": "initiator",
|
|
4
|
+
"name": "test_client",
|
|
5
|
+
"tcp": {
|
|
6
|
+
"host": "localhost",
|
|
7
|
+
"port": 2344
|
|
8
|
+
},
|
|
9
|
+
"protocol": "ascii",
|
|
10
|
+
"dictionary": "data/FIX44.xml"
|
|
11
|
+
},
|
|
12
|
+
"Username": "",
|
|
13
|
+
"Password": "",
|
|
14
|
+
"EncryptMethod": 0,
|
|
15
|
+
"ResetSeqNumFlag": true,
|
|
16
|
+
"HeartBtInt": 30,
|
|
17
|
+
"SenderCompId": "sjames8888@gmail_com",
|
|
18
|
+
"TargetCompID": "FIXSIMDEMO",
|
|
19
|
+
"TargetSubID": "",
|
|
20
|
+
"BeginString": "FIX.4.4"
|
|
21
|
+
}
|
|
@@ -73,7 +73,6 @@ let AsciiParserState = class AsciiParserState {
|
|
|
73
73
|
const tag = this.currentTag;
|
|
74
74
|
const locations = this.locations;
|
|
75
75
|
const buffer = this.elasticBuffer;
|
|
76
|
-
const terminates = this.checksumExpectedPos;
|
|
77
76
|
switch (this.parseState) {
|
|
78
77
|
case parse_state_1.ParseState.ParsingValue:
|
|
79
78
|
case parse_state_1.ParseState.ParsingRawData: {
|
|
@@ -115,16 +114,10 @@ let AsciiParserState = class AsciiParserState {
|
|
|
115
114
|
break;
|
|
116
115
|
}
|
|
117
116
|
case tags_1.Tags.CheckSumTag: {
|
|
118
|
-
if (valueEndPos < this.bodyLen) {
|
|
119
|
-
throw new Error(`CheckSumTag: [${valueEndPos}] expected after ${this.bodyLen}`);
|
|
120
|
-
}
|
|
121
117
|
this.parseState = parse_state_1.ParseState.MsgComplete;
|
|
122
118
|
break;
|
|
123
119
|
}
|
|
124
120
|
default: {
|
|
125
|
-
if (terminates && valueEndPos > terminates) {
|
|
126
|
-
throw new Error(`Tag: [${tag}] cant be after ${terminates}`);
|
|
127
|
-
}
|
|
128
121
|
break;
|
|
129
122
|
}
|
|
130
123
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascii-parser-state.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Tags } from '../tag/tags'\nimport { FixDefinitions, MessageDefinition } from '../../dictionary/definition'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { ParseState } from './parse-state'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\n\n@injectable()\nexport class AsciiParserState {\n public message: MessageDefinition | undefined\n public locations: Tags\n public parseState: ParseState\n public bodyLen: number\n public checksumExpectedPos: number\n public tagStartPos: number\n public equalPos: number\n public valueEndPos: number\n public count: number\n public currentTag: number\n public rawDataLen: number\n public rawDataRead: number\n public definitions: FixDefinitions\n public msgType: string | null\n\n constructor (@inject(DITokens.ParseBuffer) public readonly elasticBuffer: ElasticBuffer) {\n }\n\n public beginTag (pos: number): void {\n this.parseState = ParseState.ParsingTag\n this.tagStartPos = pos\n this.equalPos = this.valueEndPos = -1\n this.currentTag = 0\n }\n\n public endTag (pos: number): void {\n this.equalPos = pos\n const state = this.parseState\n switch (state) {\n case ParseState.ParsingTag: {\n this.currentTag = this.elasticBuffer.getWholeNumber(this.tagStartPos, pos - 1)\n break\n }\n\n default:\n throw new Error(`EndTag: unexpected state ${state}`)\n }\n // if a raw tag, then need length to skip that many bytes\n this.checkRawTag()\n }\n\n public incRaw (): boolean {\n ++this.rawDataRead\n return this.rawDataRead === this.rawDataLen + 1\n }\n\n public checkRawTag (): void {\n const msg = this.message\n if (!msg?.containsRaw) {\n // optimisation as will never hit raw data\n this.parseState = ParseState.ParsingValue\n return\n }\n // if this is a raw data tag then need to keep track of the length\n // on this field to skip that many bytes.\n const isDataLength: boolean = msg.containedLength[this.currentTag]\n if (isDataLength) {\n this.parseState = ParseState.ParsingRawDataLength\n } else {\n this.rawDataRead = 0\n const isData: boolean = this.rawDataLen > 0\n if (isData) {\n this.parseState = ParseState.ParsingRawData\n } else {\n this.parseState = ParseState.ParsingValue\n }\n }\n }\n\n public store (): void {\n const valueEndPos: number = this.elasticBuffer.getPos() - 1\n this.valueEndPos = valueEndPos\n const equalPos: number = this.equalPos\n const tag: number = this.currentTag\n const locations: Tags = this.locations\n const buffer = this.elasticBuffer\n const terminates = this.checksumExpectedPos\n\n switch (this.parseState) {\n case ParseState.ParsingValue:\n case ParseState.ParsingRawData: {\n this.rawDataLen = 0\n locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)\n break\n }\n\n case ParseState.ParsingRawDataLength: {\n this.rawDataLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)\n locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)\n break\n }\n }\n\n this.parseState = ParseState.BeginField\n this.count++\n const nextTagPos = locations.nextTagPos\n\n switch (tag) {\n case Tags.BeginString: {\n if (nextTagPos !== 1) {\n throw new Error(`BeginString: not expected at position [${nextTagPos}]`)\n }\n break\n }\n\n case Tags.BodyLengthTag: {\n if (nextTagPos !== 2) {\n throw new Error(`BodyLengthTag: not expected at position [${nextTagPos}]`)\n }\n this.bodyLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)\n this.checksumExpectedPos = this.bodyLen + valueEndPos\n this.elasticBuffer.checkGrowBuffer(this.bodyLen)\n break\n }\n\n case Tags.MsgTag: {\n if (nextTagPos !== 3) {\n throw new Error(`MsgTag: not expected at position [${nextTagPos}]`)\n }\n this.msgType = buffer.getString(equalPos + 1, valueEndPos)\n this.message = this.definitions.message.get(this.msgType)\n break\n }\n\n case Tags.CheckSumTag: {\n if (valueEndPos < this.bodyLen) {\n throw new Error(`CheckSumTag: [${valueEndPos}] expected after ${this.bodyLen}`)\n }\n this.parseState = ParseState.MsgComplete\n break\n }\n\n default: {\n if (terminates && valueEndPos > terminates) {\n throw new Error(`Tag: [${tag}] cant be after ${terminates}`)\n }\n break\n }\n }\n\n switch (nextTagPos) {\n case 1: {\n if (tag !== Tags.BeginString) {\n throw new Error(`position 1 [${tag}] must be BeginString: 8=`)\n }\n break\n }\n case 2: {\n if (tag !== Tags.BodyLengthTag) {\n throw new Error(`position 2 [${tag}] must be BodyLengthTag: 9=`)\n }\n break\n }\n case 3: {\n if (tag !== Tags.MsgTag) {\n throw new Error(`position 3 [${tag}] must be MsgTag: 35=`)\n }\n break\n }\n }\n }\n\n public beginMessage (): void {\n this.elasticBuffer.reset()\n this.locations.reset()\n this.checksumExpectedPos = 0\n this.parseState = ParseState.BeginField\n this.count = 0\n this.currentTag = 0\n this.tagStartPos = 0\n this.valueEndPos = 0\n this.equalPos = 0\n this.rawDataRead = 0\n this.rawDataLen = 0\n this.bodyLen = 0\n this.msgType = null\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ascii-parser-state.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser-state.ts"],"names":[],"mappings":"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","sourcesContent":["import { Tags } from '../tag/tags'\nimport { FixDefinitions, MessageDefinition } from '../../dictionary/definition'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { ParseState } from './parse-state'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\n\n@injectable()\nexport class AsciiParserState {\n public message: MessageDefinition | undefined\n public locations: Tags\n public parseState: ParseState\n public bodyLen: number\n public checksumExpectedPos: number\n public tagStartPos: number\n public equalPos: number\n public valueEndPos: number\n public count: number\n public currentTag: number\n public rawDataLen: number\n public rawDataRead: number\n public definitions: FixDefinitions\n public msgType: string | null\n\n constructor (@inject(DITokens.ParseBuffer) public readonly elasticBuffer: ElasticBuffer) {\n }\n\n public beginTag (pos: number): void {\n this.parseState = ParseState.ParsingTag\n this.tagStartPos = pos\n this.equalPos = this.valueEndPos = -1\n this.currentTag = 0\n }\n\n public endTag (pos: number): void {\n this.equalPos = pos\n const state = this.parseState\n switch (state) {\n case ParseState.ParsingTag: {\n this.currentTag = this.elasticBuffer.getWholeNumber(this.tagStartPos, pos - 1)\n break\n }\n\n default:\n throw new Error(`EndTag: unexpected state ${state}`)\n }\n // if a raw tag, then need length to skip that many bytes\n this.checkRawTag()\n }\n\n public incRaw (): boolean {\n ++this.rawDataRead\n return this.rawDataRead === this.rawDataLen + 1\n }\n\n public checkRawTag (): void {\n const msg = this.message\n if (!msg?.containsRaw) {\n // optimisation as will never hit raw data\n this.parseState = ParseState.ParsingValue\n return\n }\n // if this is a raw data tag then need to keep track of the length\n // on this field to skip that many bytes.\n const isDataLength: boolean = msg.containedLength[this.currentTag]\n if (isDataLength) {\n this.parseState = ParseState.ParsingRawDataLength\n } else {\n this.rawDataRead = 0\n const isData: boolean = this.rawDataLen > 0\n if (isData) {\n this.parseState = ParseState.ParsingRawData\n } else {\n this.parseState = ParseState.ParsingValue\n }\n }\n }\n\n public store (): void {\n const valueEndPos: number = this.elasticBuffer.getPos() - 1\n this.valueEndPos = valueEndPos\n const equalPos: number = this.equalPos\n const tag: number = this.currentTag\n const locations: Tags = this.locations\n const buffer = this.elasticBuffer\n\n switch (this.parseState) {\n case ParseState.ParsingValue:\n case ParseState.ParsingRawData: {\n this.rawDataLen = 0\n locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)\n break\n }\n\n case ParseState.ParsingRawDataLength: {\n this.rawDataLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)\n locations.store(equalPos + 1, valueEndPos - equalPos - 1, tag)\n break\n }\n }\n\n this.parseState = ParseState.BeginField\n this.count++\n const nextTagPos = locations.nextTagPos\n\n switch (tag) {\n case Tags.BeginString: {\n if (nextTagPos !== 1) {\n throw new Error(`BeginString: not expected at position [${nextTagPos}]`)\n }\n break\n }\n\n case Tags.BodyLengthTag: {\n if (nextTagPos !== 2) {\n throw new Error(`BodyLengthTag: not expected at position [${nextTagPos}]`)\n }\n this.bodyLen = buffer.getWholeNumber(equalPos + 1, valueEndPos - 1)\n this.checksumExpectedPos = this.bodyLen + valueEndPos\n this.elasticBuffer.checkGrowBuffer(this.bodyLen)\n break\n }\n\n case Tags.MsgTag: {\n if (nextTagPos !== 3) {\n throw new Error(`MsgTag: not expected at position [${nextTagPos}]`)\n }\n this.msgType = buffer.getString(equalPos + 1, valueEndPos)\n this.message = this.definitions.message.get(this.msgType)\n break\n }\n\n case Tags.CheckSumTag: {\n // do not enforce body length constraint - manually edited messages\n // may have mismatched body length but are otherwise valid\n this.parseState = ParseState.MsgComplete\n break\n }\n\n default: {\n // do not enforce body length boundary - manually edited messages\n // may have fields added or modified beyond the original body length\n break\n }\n }\n\n switch (nextTagPos) {\n case 1: {\n if (tag !== Tags.BeginString) {\n throw new Error(`position 1 [${tag}] must be BeginString: 8=`)\n }\n break\n }\n case 2: {\n if (tag !== Tags.BodyLengthTag) {\n throw new Error(`position 2 [${tag}] must be BodyLengthTag: 9=`)\n }\n break\n }\n case 3: {\n if (tag !== Tags.MsgTag) {\n throw new Error(`position 3 [${tag}] must be MsgTag: 35=`)\n }\n break\n }\n }\n }\n\n public beginMessage (): void {\n this.elasticBuffer.reset()\n this.locations.reset()\n this.checksumExpectedPos = 0\n this.parseState = ParseState.BeginField\n this.count = 0\n this.currentTag = 0\n this.tagStartPos = 0\n this.valueEndPos = 0\n this.equalPos = 0\n this.rawDataRead = 0\n this.rawDataLen = 0\n this.bodyLen = 0\n this.msgType = null\n }\n}\n"]}
|
|
@@ -15,6 +15,7 @@ export declare class AsciiParser extends MsgParser {
|
|
|
15
15
|
readonly writeDelimiter: number;
|
|
16
16
|
constructor(config: IJsFixConfig, readStream: Readable | null, receivingBuffer: ElasticBuffer);
|
|
17
17
|
private subscribe;
|
|
18
|
+
reset(): void;
|
|
18
19
|
private msg;
|
|
19
20
|
parseText(text: string): void;
|
|
20
21
|
private parse;
|
|
@@ -75,6 +75,9 @@ let AsciiParser = AsciiParser_1 = class AsciiParser extends msg_parser_1.MsgPars
|
|
|
75
75
|
this.emit('end');
|
|
76
76
|
});
|
|
77
77
|
}
|
|
78
|
+
reset() {
|
|
79
|
+
this.state.beginMessage();
|
|
80
|
+
}
|
|
78
81
|
msg(ptr) {
|
|
79
82
|
const receivingBuffer = this.receivingBuffer;
|
|
80
83
|
const state = this.state;
|
|
@@ -128,9 +131,12 @@ let AsciiParser = AsciiParser_1 = class AsciiParser extends msg_parser_1.MsgPars
|
|
|
128
131
|
}
|
|
129
132
|
state.store();
|
|
130
133
|
}
|
|
131
|
-
|
|
132
|
-
|
|
134
|
+
}
|
|
135
|
+
else if (charAtPos === delimiter) {
|
|
136
|
+
if (switchDelimiter) {
|
|
137
|
+
receivingBuffer.switchChar(writeDelimiter);
|
|
133
138
|
}
|
|
139
|
+
state.store();
|
|
134
140
|
}
|
|
135
141
|
break;
|
|
136
142
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascii-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsciiChars } from './ascii-chars'\nimport { AsciiView } from './ascii-view'\nimport { AsciiSegmentParser } from './ascii-segment-parser'\nimport { AsciiParserState } from './ascii-parser-state'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport { MsgParser } from '../msg-parser'\nimport { MsgView } from '../msg-view'\nimport { Readable } from 'stream'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { SegmentDescription } from '../segment/segment-description'\nimport { ParseState } from './parse-state'\nimport { IJsFixConfig } from '../../config/js-fix-config'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\n\n@injectable()\nexport class AsciiParser extends MsgParser {\n private static nextId: number = 0\n public readonly id: number\n public readonly state: AsciiParserState\n private readonly segmentParser: AsciiSegmentParser\n public readonly delimiter: number\n public readonly writeDelimiter: number\n\n // allocate enough in receive buffer so buffer does not constant resize back after large messages\n // want to keep one slice of memory and constantly reuse it\n\n constructor (@inject(DITokens.IJsFixConfig) public readonly config: IJsFixConfig,\n @inject(DITokens.readStream) public readonly readStream: Readable | null,\n @inject(DITokens.ParseBuffer) protected readonly receivingBuffer: ElasticBuffer) {\n super()\n\n this.delimiter = config.delimiter ?? AsciiChars.Soh\n this.writeDelimiter = config.logDelimiter ?? AsciiChars.Pipe\n this.id = AsciiParser.nextId++\n this.segmentParser = config.sessionContainer.resolve<AsciiSegmentParser>(AsciiSegmentParser)\n this.state = config.sessionContainer.resolve<AsciiParserState>(AsciiParserState)\n this.state.locations = new Tags(this.receivingBuffer.size / 10)\n this.state.definitions = this.config.definitions\n this.state.beginMessage()\n if (readStream !== null) {\n this.subscribe()\n }\n }\n\n private subscribe (): void {\n const inst: AsciiParser = this\n const Writable = require('stream').Writable\n const stream = this.readStream\n\n const receiver = new Writable({\n write: (data: Buffer, _: any, done: Function) => {\n try {\n inst.parse(data, data.length)\n done()\n } catch (e) {\n done(e)\n }\n }\n })\n receiver.on('error', (e: Error) => {\n this.emit('error', e)\n })\n\n // receive from say a socket or file and pipe to parser which discovers messages\n stream?.pipe(receiver).on('finish', () => {\n this.emit('done')\n })\n stream?.on('error', (e) => {\n this.emit('error', e)\n })\n stream?.on('end', () => {\n this.emit('end')\n })\n }\n\n private msg (ptr: number): void {\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const state = this.state\n if (this.listeners('decoded')) {\n this.emit('decoded', state.msgType, receivingBuffer, ptr)\n }\n this.emit('msg', state.msgType, this.getView(ptr))\n state.beginMessage()\n }\n\n /**\n * useful helper for testing where characters are parsed as if from the transport\n * @param text to be parsed\n */\n public parseText (text: string): void {\n const buff = Buffer.from(text)\n this.parse(buff, buff.length)\n }\n\n private parse (readBuffer: Buffer, end: number): void {\n const state = this.state\n const eq: number = AsciiChars.Eq\n const zero: number = AsciiChars.Zero\n const nine: number = AsciiChars.Nine\n const delimiter: number = this.delimiter\n const writeDelimiter: number = this.writeDelimiter\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const switchDelimiter = writeDelimiter !== delimiter\n let readPtr: number = 0\n\n while (readPtr < end) {\n const charAtPos: number = readBuffer[readPtr]\n\n const writePtr = receivingBuffer.saveChar(charAtPos) - 1\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(writePtr)\n continue\n }\n\n case ParseState.BeginField: {\n const atDigit: boolean = charAtPos >= zero && charAtPos <= nine\n if (atDigit) {\n state.beginTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingTag: {\n const isEquals: boolean = charAtPos === eq\n if (isEquals) {\n state.endTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingRawData: {\n // keep skipping until length read, regardless of delimiter or not\n if (state.incRaw()) {\n // having consumed the raw field expecting delimiter\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n } else {\n throw new Error(`delimiter (${delimiter}) expected at position ${readPtr} when value is ${charAtPos}`)\n }\n }\n break\n }\n\n case ParseState.ParsingRawDataLength:\n case ParseState.ParsingValue: {\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n default: {\n const st = state.parseState\n throw new Error(`fix parser in unknown state ${st}`)\n }\n }\n readPtr++\n }\n\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(receivingBuffer.getPos())\n break\n }\n }\n }\n\n private getView (ptr: number): MsgView | null {\n const state = this.state\n const locations = state.locations\n const source = this.receivingBuffer\n const delimiter = this.delimiter\n const definitions = this.config.definitions\n const replace = this.writeDelimiter\n const msgType = state.msgType ?? null\n if (!msgType) return null\n if (state.message) {\n try {\n const structure: Structure | null = this.segmentParser.parse(msgType, locations,\n locations.nextTagPos - 1)\n if (!structure) return null\n return new AsciiView(definitions, structure.msg(),\n source,\n structure,\n ptr,\n delimiter,\n replace)\n } catch (error) {\n if (error instanceof AsciiParserError) {\n error.summary.buffer = source.toString()\n this.emit('error', error)\n }\n throw error\n }\n }\n\n const structure = new Structure(locations, [])\n const segment = new SegmentDescription('unknown', locations.tagPos[0].tag, null, 0, 1, SegmentType.Unknown)\n segment.endPosition = locations.nextTagPos - 1\n return new AsciiView(this.config.definitions, segment, source, structure, ptr, delimiter, replace)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ascii-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { AsciiChars } from './ascii-chars'\nimport { AsciiView } from './ascii-view'\nimport { AsciiSegmentParser } from './ascii-segment-parser'\nimport { AsciiParserState } from './ascii-parser-state'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport { MsgParser } from '../msg-parser'\nimport { MsgView } from '../msg-view'\nimport { Readable } from 'stream'\nimport { ElasticBuffer } from '../elastic-buffer'\nimport { SegmentDescription } from '../segment/segment-description'\nimport { ParseState } from './parse-state'\nimport { IJsFixConfig } from '../../config/js-fix-config'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\n\n@injectable()\nexport class AsciiParser extends MsgParser {\n private static nextId: number = 0\n public readonly id: number\n public readonly state: AsciiParserState\n private readonly segmentParser: AsciiSegmentParser\n public readonly delimiter: number\n public readonly writeDelimiter: number\n\n // allocate enough in receive buffer so buffer does not constant resize back after large messages\n // want to keep one slice of memory and constantly reuse it\n\n constructor (@inject(DITokens.IJsFixConfig) public readonly config: IJsFixConfig,\n @inject(DITokens.readStream) public readonly readStream: Readable | null,\n @inject(DITokens.ParseBuffer) protected readonly receivingBuffer: ElasticBuffer) {\n super()\n\n this.delimiter = config.delimiter ?? AsciiChars.Soh\n this.writeDelimiter = config.logDelimiter ?? AsciiChars.Pipe\n this.id = AsciiParser.nextId++\n this.segmentParser = config.sessionContainer.resolve<AsciiSegmentParser>(AsciiSegmentParser)\n this.state = config.sessionContainer.resolve<AsciiParserState>(AsciiParserState)\n this.state.locations = new Tags(this.receivingBuffer.size / 10)\n this.state.definitions = this.config.definitions\n this.state.beginMessage()\n if (readStream !== null) {\n this.subscribe()\n }\n }\n\n private subscribe (): void {\n const inst: AsciiParser = this\n const Writable = require('stream').Writable\n const stream = this.readStream\n\n const receiver = new Writable({\n write: (data: Buffer, _: any, done: Function) => {\n try {\n inst.parse(data, data.length)\n done()\n } catch (e) {\n done(e)\n }\n }\n })\n receiver.on('error', (e: Error) => {\n this.emit('error', e)\n })\n\n // receive from say a socket or file and pipe to parser which discovers messages\n stream?.pipe(receiver).on('finish', () => {\n this.emit('done')\n })\n stream?.on('error', (e) => {\n this.emit('error', e)\n })\n stream?.on('end', () => {\n this.emit('end')\n })\n }\n\n public reset (): void {\n this.state.beginMessage()\n }\n\n private msg (ptr: number): void {\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const state = this.state\n if (this.listeners('decoded')) {\n this.emit('decoded', state.msgType, receivingBuffer, ptr)\n }\n this.emit('msg', state.msgType, this.getView(ptr))\n state.beginMessage()\n }\n\n /**\n * useful helper for testing where characters are parsed as if from the transport\n * @param text to be parsed\n */\n public parseText (text: string): void {\n const buff = Buffer.from(text)\n this.parse(buff, buff.length)\n }\n\n private parse (readBuffer: Buffer, end: number): void {\n const state = this.state\n const eq: number = AsciiChars.Eq\n const zero: number = AsciiChars.Zero\n const nine: number = AsciiChars.Nine\n const delimiter: number = this.delimiter\n const writeDelimiter: number = this.writeDelimiter\n const receivingBuffer: ElasticBuffer = this.receivingBuffer\n const switchDelimiter = writeDelimiter !== delimiter\n let readPtr: number = 0\n\n while (readPtr < end) {\n const charAtPos: number = readBuffer[readPtr]\n\n const writePtr = receivingBuffer.saveChar(charAtPos) - 1\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(writePtr)\n continue\n }\n\n case ParseState.BeginField: {\n const atDigit: boolean = charAtPos >= zero && charAtPos <= nine\n if (atDigit) {\n state.beginTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingTag: {\n const isEquals: boolean = charAtPos === eq\n if (isEquals) {\n state.endTag(writePtr)\n }\n break\n }\n\n case ParseState.ParsingRawData: {\n // keep skipping until length read, regardless of delimiter or not\n if (state.incRaw()) {\n // having consumed the declared raw data length, expect delimiter.\n // if not found (e.g. replayed messages with pretty-printed XML where\n // the stored length undershoots), keep scanning forward to the actual\n // delimiter rather than throwing.\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n } else if (charAtPos === delimiter) {\n // hit delimiter before declared length exhausted — store what we have\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n case ParseState.ParsingRawDataLength:\n case ParseState.ParsingValue: {\n if (charAtPos === delimiter) {\n if (switchDelimiter) {\n receivingBuffer.switchChar(writeDelimiter)\n }\n state.store()\n }\n break\n }\n\n default: {\n const st = state.parseState\n throw new Error(`fix parser in unknown state ${st}`)\n }\n }\n readPtr++\n }\n\n switch (state.parseState) {\n case ParseState.MsgComplete: {\n this.msg(receivingBuffer.getPos())\n break\n }\n }\n }\n\n private getView (ptr: number): MsgView | null {\n const state = this.state\n const locations = state.locations\n const source = this.receivingBuffer\n const delimiter = this.delimiter\n const definitions = this.config.definitions\n const replace = this.writeDelimiter\n const msgType = state.msgType ?? null\n if (!msgType) return null\n if (state.message) {\n try {\n const structure: Structure | null = this.segmentParser.parse(msgType, locations,\n locations.nextTagPos - 1)\n if (!structure) return null\n return new AsciiView(definitions, structure.msg(),\n source,\n structure,\n ptr,\n delimiter,\n replace)\n } catch (error) {\n if (error instanceof AsciiParserError) {\n error.summary.buffer = source.toString()\n this.emit('error', error)\n }\n throw error\n }\n }\n\n const structure = new Structure(locations, [])\n const segment = new SegmentDescription('unknown', locations.tagPos[0].tag, null, 0, 1, SegmentType.Unknown)\n segment.endPosition = locations.nextTagPos - 1\n return new AsciiView(this.config.definitions, segment, source, structure, ptr, delimiter, replace)\n }\n}\n"]}
|
|
@@ -21,6 +21,7 @@ const tsyringe_1 = require("tsyringe");
|
|
|
21
21
|
const di_tokens_1 = require("../../runtime/di-tokens");
|
|
22
22
|
const segment_type_1 = require("../segment/segment-type");
|
|
23
23
|
const ascii_segment_parser_error_1 = require("./ascii-segment-parser-error");
|
|
24
|
+
const tag_index_1 = require("./tag-index");
|
|
24
25
|
let AsciiSegmentParser = class AsciiSegmentParser {
|
|
25
26
|
constructor(definitions) {
|
|
26
27
|
this.definitions = definitions;
|
|
@@ -34,6 +35,8 @@ let AsciiSegmentParser = class AsciiSegmentParser {
|
|
|
34
35
|
const structureStack = [];
|
|
35
36
|
let currentTagPosition = 0;
|
|
36
37
|
let peek;
|
|
38
|
+
const exitedDepth1Components = new Set();
|
|
39
|
+
const fragmentedComponents = new Set();
|
|
37
40
|
function unwind(tag) {
|
|
38
41
|
var _a;
|
|
39
42
|
while (structureStack.length > 1) {
|
|
@@ -42,6 +45,9 @@ let AsciiSegmentParser = class AsciiSegmentParser {
|
|
|
42
45
|
continue;
|
|
43
46
|
done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag);
|
|
44
47
|
segments.push(done);
|
|
48
|
+
if (done.depth === 1 && done.name) {
|
|
49
|
+
exitedDepth1Components.add(done.name);
|
|
50
|
+
}
|
|
45
51
|
peek = structureStack[structureStack.length - 1];
|
|
46
52
|
if ((_a = peek.set) === null || _a === void 0 ? void 0 : _a.containedTag[tag]) {
|
|
47
53
|
break;
|
|
@@ -78,6 +84,9 @@ let AsciiSegmentParser = class AsciiSegmentParser {
|
|
|
78
84
|
}
|
|
79
85
|
case contained_1.ContainedFieldType.Component: {
|
|
80
86
|
const cf = currentField;
|
|
87
|
+
if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {
|
|
88
|
+
fragmentedComponents.add(cf.name);
|
|
89
|
+
}
|
|
81
90
|
structure = new segment_description_1.SegmentDescription(cf.name, tag, cf.definition, currentTagPosition, structureStack.length, segment_type_1.SegmentType.Component);
|
|
82
91
|
break;
|
|
83
92
|
}
|
|
@@ -150,10 +159,37 @@ let AsciiSegmentParser = class AsciiSegmentParser {
|
|
|
150
159
|
segments[m1] = segments[m2];
|
|
151
160
|
segments[m2] = tmp;
|
|
152
161
|
}
|
|
162
|
+
function fragments() {
|
|
163
|
+
if (fragmentedComponents.size === 0)
|
|
164
|
+
return;
|
|
165
|
+
const ti = new tag_index_1.TagIndex(msgDefinition, tags, last + 1);
|
|
166
|
+
const seen = new Set();
|
|
167
|
+
for (let i = 1; i < segments.length - 1; i++) {
|
|
168
|
+
const seg = segments[i];
|
|
169
|
+
if (seg.depth !== 1)
|
|
170
|
+
continue;
|
|
171
|
+
if (!seg.name)
|
|
172
|
+
continue;
|
|
173
|
+
if (seg.segmentView)
|
|
174
|
+
continue;
|
|
175
|
+
if (seen.has(seg.name))
|
|
176
|
+
continue;
|
|
177
|
+
if (!fragmentedComponents.has(seg.name))
|
|
178
|
+
continue;
|
|
179
|
+
if (ti.isComponentGroupWrapper(seg.name))
|
|
180
|
+
continue;
|
|
181
|
+
const v = ti.getInstance(seg.name);
|
|
182
|
+
if (!v)
|
|
183
|
+
continue;
|
|
184
|
+
seen.add(seg.name);
|
|
185
|
+
seg.addSegmentView(v);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
153
188
|
const msgStructure = new segment_description_1.SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition, currentTagPosition, structureStack.length, segment_type_1.SegmentType.Msg);
|
|
154
189
|
structureStack.push(msgStructure);
|
|
155
190
|
discover();
|
|
156
191
|
clean();
|
|
192
|
+
fragments();
|
|
157
193
|
return new structure_1.Structure(tags, segments);
|
|
158
194
|
}
|
|
159
195
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const msgDefinition: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!msgDefinition) {\n return null\n }\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\nimport { TagIndex } from './tag-index'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const msgDefinition: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!msgDefinition) {\n return null\n }\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // track depth-1 components that have been exited for fragmentation detection\n const exitedDepth1Components: Set<string> = new Set()\n const fragmentedComponents: Set<string> = new Set()\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n\n // track when we exit depth-1 components for fragmentation detection\n if (done.depth === 1 && done.name) {\n exitedDepth1Components.add(done.name)\n }\n\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n // detect fragmentation: re-entering a depth-1 component we already exited\n if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {\n fragmentedComponents.add(cf.name)\n }\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n function fragments (): void {\n // only build SegmentViews for components detected as fragmented during discover\n // non-fragmented components use their position ranges directly (zero overhead)\n if (fragmentedComponents.size === 0) return\n const ti = new TagIndex(msgDefinition!, tags, last + 1)\n const seen: Set<string> = new Set()\n for (let i = 1; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (seg.depth !== 1) continue\n if (!seg.name) continue\n if (seg.segmentView) continue\n if (seen.has(seg.name)) continue\n if (!fragmentedComponents.has(seg.name)) continue\n if (ti.isComponentGroupWrapper(seg.name)) continue\n const v = ti.getInstance(seg.name)\n if (!v) continue\n seen.add(seg.name)\n seg.addSegmentView(v)\n }\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n fragments()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
|