jspurefix 5.8.5 → 5.9.1
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/.gitattributes +4 -0
- package/BACKPORT_PLAN.md +71 -0
- package/DEMO_PORT_PLAN.md +10 -0
- package/README.md +3 -0
- package/dist/config/js-fix-config.d.ts +4 -0
- package/dist/config/js-fix-config.js.map +1 -1
- package/dist/runtime/session-launcher.js +1 -1
- package/dist/runtime/session-launcher.js.map +1 -1
- package/dist/runtime/session-scope.d.ts +3 -0
- package/dist/runtime/session-scope.js +47 -0
- package/dist/runtime/session-scope.js.map +1 -0
- package/dist/sample/http/oms/app.js +3 -3
- package/dist/sample/http/oms/app.js.map +1 -1
- package/dist/sample/tcp/qf-md/app.js +3 -3
- package/dist/sample/tcp/qf-md/app.js.map +1 -1
- package/dist/sample/tcp/skeleton/app.js +1 -1
- package/dist/sample/tcp/skeleton/app.js.map +1 -1
- package/dist/sample/tcp/trade-capture/app-launcher.js +3 -3
- package/dist/sample/tcp/trade-capture/app-launcher.js.map +1 -1
- package/dist/transport/ascii/ascii-session.d.ts +17 -3
- package/dist/transport/ascii/ascii-session.js +121 -8
- package/dist/transport/ascii/ascii-session.js.map +1 -1
- package/dist/transport/duplex/fix-duplex.d.ts +1 -0
- package/dist/transport/duplex/fix-duplex.js +3 -0
- package/dist/transport/duplex/fix-duplex.js.map +1 -1
- package/dist/transport/duplex/tcp-duplex.d.ts +1 -0
- package/dist/transport/duplex/tcp-duplex.js +5 -0
- package/dist/transport/duplex/tcp-duplex.js.map +1 -1
- package/dist/transport/factory/msg-transport.d.ts +2 -0
- package/dist/transport/factory/msg-transport.js +17 -2
- package/dist/transport/factory/msg-transport.js.map +1 -1
- package/dist/transport/session/a-session-msg-factory.d.ts +1 -0
- package/dist/transport/session/a-session-msg-factory.js +4 -0
- package/dist/transport/session/a-session-msg-factory.js.map +1 -1
- package/dist/transport/session/clone-session-description.d.ts +6 -0
- package/dist/transport/session/clone-session-description.js +11 -0
- package/dist/transport/session/clone-session-description.js.map +1 -0
- package/dist/transport/session/fix-session.d.ts +5 -1
- package/dist/transport/session/fix-session.js +93 -24
- package/dist/transport/session/fix-session.js.map +1 -1
- package/dist/transport/session/index.d.ts +2 -0
- package/dist/transport/session/index.js +2 -0
- package/dist/transport/session/index.js.map +1 -1
- package/dist/transport/session/session-msg-factory.d.ts +1 -0
- package/dist/transport/session/session-msg-factory.js.map +1 -1
- package/dist/transport/session/session-registry.d.ts +23 -0
- package/dist/transport/session/session-registry.js +59 -0
- package/dist/transport/session/session-registry.js.map +1 -0
- package/dist/transport/tcp/tcp-acceptor-listener.d.ts +3 -0
- package/dist/transport/tcp/tcp-acceptor-listener.js +26 -4
- package/dist/transport/tcp/tcp-acceptor-listener.js.map +1 -1
- package/dist/transport/tcp/tcp-acceptor.d.ts +5 -0
- package/dist/transport/tcp/tcp-acceptor.js +74 -20
- package/dist/transport/tcp/tcp-acceptor.js.map +1 -1
- package/dist/transport/tcp/tcp-initiator.js +15 -5
- package/dist/transport/tcp/tcp-initiator.js.map +1 -1
- package/dist/transport/tcp/tcp-transport-description.d.ts +1 -0
- package/dist/transport/tcp/tcp-transport-description.js.map +1 -1
- package/dist/transport/tcp/tls-diagnostics.d.ts +5 -0
- package/dist/transport/tcp/tls-diagnostics.js +64 -0
- package/dist/transport/tcp/tls-diagnostics.js.map +1 -0
- package/dist/transport/tcp/tls-options-factory.d.ts +1 -0
- package/dist/transport/tcp/tls-options-factory.js +24 -2
- package/dist/transport/tcp/tls-options-factory.js.map +1 -1
- package/docs/acceptor.md +207 -0
- package/jsfix.test_client.txt +62 -75
- package/jsfix.test_server.txt +72 -72
- package/package.json +11 -10
- package/script/pack-local.js +68 -0
- package/src/config/js-fix-config.ts +8 -0
- package/src/runtime/session-launcher.ts +5 -1
- package/src/runtime/session-scope.ts +84 -0
- package/src/sample/http/oms/app.ts +3 -3
- package/src/sample/tcp/qf-md/app.ts +3 -3
- package/src/sample/tcp/skeleton/app.ts +1 -1
- package/src/sample/tcp/trade-capture/app-launcher.ts +3 -3
- package/src/transport/ascii/ascii-session.ts +186 -11
- package/src/transport/duplex/fix-duplex.ts +9 -0
- package/src/transport/duplex/tcp-duplex.ts +10 -0
- package/src/transport/factory/msg-transport.ts +20 -0
- package/src/transport/session/a-session-msg-factory.ts +18 -0
- package/src/transport/session/clone-session-description.ts +41 -0
- package/src/transport/session/fix-session.ts +136 -25
- package/src/transport/session/index.ts +2 -0
- package/src/transport/session/session-msg-factory.ts +13 -0
- package/src/transport/session/session-registry.ts +112 -0
- package/src/transport/tcp/tcp-acceptor-listener.ts +43 -5
- package/src/transport/tcp/tcp-acceptor.ts +92 -18
- package/src/transport/tcp/tcp-initiator.ts +26 -5
- package/src/transport/tcp/tcp-transport-description.ts +7 -0
- package/src/transport/tcp/tls-diagnostics.ts +76 -0
- package/src/transport/tcp/tls-options-factory.ts +34 -2
package/.gitattributes
ADDED
package/BACKPORT_PLAN.md
CHANGED
|
@@ -372,6 +372,77 @@ The parser is the foundation of the entire system. Test strategy must be compreh
|
|
|
372
372
|
3. **Micro-dictionary tests** (future hardening): use Trim to create single-message dictionaries, then mutate them (remove fields, duplicate tags, etc.) to test validator edge cases
|
|
373
373
|
4. **Regression anchor**: snapshot the `FixDefinitions` output for each FIX version before any changes — tests assert against snapshots
|
|
374
374
|
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Phase 7: Acceptor Hardening (issue #153)
|
|
379
|
+
|
|
380
|
+
**Priority: High | Risk: Medium | Scope: `src/transport/`, `src/runtime/`**
|
|
381
|
+
|
|
382
|
+
### Problem
|
|
383
|
+
|
|
384
|
+
The acceptor was written as a smoke-test harness for the initiator and was never
|
|
385
|
+
multi-client safe. [Issue #153](https://github.com/TimelordUK/jspurefix/issues/153)
|
|
386
|
+
reported the visible symptom - a counterparty's socket went half open (no FIN, no
|
|
387
|
+
RST), the counterparty reconnected, and the library had no coherent answer for what
|
|
388
|
+
should happen to the first session - and correctly identified a concrete bug behind
|
|
389
|
+
it: `FixSession.subscribe()` attached closures while `unsubscribe()` removed method
|
|
390
|
+
references, so unsubscribe removed nothing.
|
|
391
|
+
|
|
392
|
+
Underneath that sat four more:
|
|
393
|
+
|
|
394
|
+
| Defect | Consequence |
|
|
395
|
+
|--------|-------------|
|
|
396
|
+
| `ParseBuffer` / `TransmitBuffer` are registerInstance singletons | concurrent clients interleave bytes in one buffer |
|
|
397
|
+
| one shared `ISessionDescription` per listener | every accepted session computes the same `SessionId`, so one store |
|
|
398
|
+
| no session registry | a reconnect runs alongside its own stale session |
|
|
399
|
+
| no wildcard `TargetCompID` | an acceptor can only serve statically configured counterparties |
|
|
400
|
+
|
|
401
|
+
### C# Solution
|
|
402
|
+
|
|
403
|
+
| File | Purpose |
|
|
404
|
+
|------|---------|
|
|
405
|
+
| `PureFix.Transport/Session/SessionRegistry.cs` | one live session per SessionId, stop the old on reconnect |
|
|
406
|
+
| `PureFix.Transport/Session/FixSession.cs` | `RequestStop`, `OnSessionStopping` |
|
|
407
|
+
| `PureFix.Transport/Ascii/AsciiSession.cs` | wildcard TargetCompID adopted from the peer Logon |
|
|
408
|
+
| `purefix-standalone-demo/Infrastructure/TradeCaptureSessionFactory.cs` | per-session config, parser and encoder |
|
|
409
|
+
|
|
410
|
+
### TypeScript Solution
|
|
411
|
+
|
|
412
|
+
1. **Transport subscription** — bound handlers held in an `ITransportSubscription`
|
|
413
|
+
alongside the transport they attached to; events from a superseded transport are
|
|
414
|
+
ignored and logged. `terminate()` also informs the application via `onStopped`,
|
|
415
|
+
which it never did, so application timers leaked on every broken connection.
|
|
416
|
+
2. **Session scopes** — `makeSessionScope` builds a tsyringe child container per
|
|
417
|
+
connection with fresh buffers, a cloned description and a matching message
|
|
418
|
+
factory. `SessionLauncher` passes the resolving container's config to
|
|
419
|
+
`EngineFactory.makeSession`.
|
|
420
|
+
3. **SessionRegistry** — ported, with identity-checked unregister so a displaced
|
|
421
|
+
session cannot evict its successor.
|
|
422
|
+
4. **Wildcard TargetCompID** — bound *after* the Logon rather than at construction,
|
|
423
|
+
so each counterparty gets its own store file. cspurefix binds in the constructor
|
|
424
|
+
and therefore keys a wildcard store on the literal `*`; this is the one place the
|
|
425
|
+
TS version deliberately improves on the C#.
|
|
426
|
+
5. **Transport lifecycle** — TCP keep-alive, `FixDuplex.destroy()`, linger-then-destroy
|
|
427
|
+
on `end()`, harvest on socket `close`, and a census line whenever the connected
|
|
428
|
+
population changes.
|
|
429
|
+
|
|
430
|
+
See [`docs/acceptor.md`](docs/acceptor.md) for the resulting model.
|
|
431
|
+
|
|
432
|
+
### Status: **DONE**
|
|
433
|
+
|
|
434
|
+
Note this supersedes phase D6 of `DEMO_PORT_PLAN.md`, which had placed the registry
|
|
435
|
+
and wildcard handling in the demo. Issue #153 showed they belong in the engine - the
|
|
436
|
+
reporter hit them without writing a demo.
|
|
437
|
+
|
|
438
|
+
### Follow-up found while testing
|
|
439
|
+
|
|
440
|
+
The demo's `server-bounce` scenario does not pass, on this branch or on published
|
|
441
|
+
5.8.5. The acceptor's persisted sender sequence lags what it actually sent, because
|
|
442
|
+
`AsciiSession.txOnEncoded` writes to the store fire-and-forget; if the process exits
|
|
443
|
+
first the store is behind, and on restart the client sees a sequence below what it
|
|
444
|
+
has already recorded and drops the session. Needs its own phase.
|
|
445
|
+
|
|
375
446
|
---
|
|
376
447
|
|
|
377
448
|
## General Principles
|
package/DEMO_PORT_PLAN.md
CHANGED
|
@@ -154,6 +154,16 @@ The good news: many of the underlying engine bugs are already fixed in jspurefix
|
|
|
154
154
|
|
|
155
155
|
### PR D6: Multi-client + session registry (medium-high risk)
|
|
156
156
|
|
|
157
|
+
> **Superseded, and re-scoped.** Everything below assumed the session registry, the
|
|
158
|
+
> wildcard `TargetCompID` handling and the per-session parser were application-level
|
|
159
|
+
> concerns. Issue [#153](https://github.com/TimelordUK/jspurefix/issues/153) showed
|
|
160
|
+
> otherwise: the reporter hit all of them without writing a demo at all. They now
|
|
161
|
+
> live in jspurefix itself - see Phase 7 of `BACKPORT_PLAN.md` and
|
|
162
|
+
> `docs/acceptor.md`. What remains for the demo is configuration and demonstration:
|
|
163
|
+
> a `multi-client` mode with a `TargetCompID: "*"` acceptor config, `--clients <n>`
|
|
164
|
+
> to spawn suffixed initiators, and the `multi-client` and `stale-transport`
|
|
165
|
+
> scenarios. **Done** in jspf-demo.
|
|
166
|
+
|
|
157
167
|
**Goal**: Support multiple concurrent clients to the same acceptor without state corruption. This is where the hardest soak-test bugs lived in C#.
|
|
158
168
|
|
|
159
169
|
**Note**: the C# `SessionRegistry` is itself work-in-progress (lost when leaving the hedge fund where the original was written). The broader vision is loading ~20 broker dictionaries and using first-message metadata to dispatch — that's a future expansion. For D6 we're building the **minimum viable registry** to fix the stale-transport bug.
|
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ A fast, fully native TypeScript [FIX protocol](https://www.fixtrading.org/) engi
|
|
|
34
34
|
- Repeating groups, components, nested structures and raw data fields
|
|
35
35
|
- Dictionary-driven: load QuickFIX XML or FIX repository definitions, compile typed interfaces
|
|
36
36
|
- Full session lifecycle: logon, heartbeats, test requests, resend requests, logout
|
|
37
|
+
- Multi-client acceptor: per-connection isolation, one session per SessionId, wildcard `TargetCompID` — see [docs/acceptor.md](docs/acceptor.md)
|
|
37
38
|
- TLS-encrypted sessions over TCP
|
|
38
39
|
- Pluggable persistent message store (in-memory or file) with sequence recovery
|
|
39
40
|
- HTTP initiator/acceptor for FIXML
|
|
@@ -51,6 +52,8 @@ cd node_modules/jspurefix && npm run unzip-repo
|
|
|
51
52
|
|
|
52
53
|
A standalone demo project lives at [TimelordUK/jspf-demo](https://github.com/TimelordUK/jspf-demo) — the fastest way to see a working initiator/acceptor.
|
|
53
54
|
|
|
55
|
+
To try an unpublished build of this library in your own project, `npm run pack:local` builds and packs a tarball you can `npm install` directly.
|
|
56
|
+
|
|
54
57
|
## Examples
|
|
55
58
|
|
|
56
59
|
| description | link |
|
|
@@ -4,6 +4,7 @@ import { ISessionMsgFactory } from '../transport/session/session-msg-factory';
|
|
|
4
4
|
import { JsFixLoggerFactory } from './js-fix-logger-factory';
|
|
5
5
|
import { DependencyContainer } from 'tsyringe';
|
|
6
6
|
import { IFixSessionStoreFactory } from '../store/fix-session-store-factory';
|
|
7
|
+
import { ISessionRegistry } from '../transport/session/session-registry';
|
|
7
8
|
export interface IJsFixConfig {
|
|
8
9
|
factory: ISessionMsgFactory | null;
|
|
9
10
|
definitions: FixDefinitions;
|
|
@@ -13,6 +14,7 @@ export interface IJsFixConfig {
|
|
|
13
14
|
logFactory: JsFixLoggerFactory;
|
|
14
15
|
sessionContainer: DependencyContainer;
|
|
15
16
|
sessionStoreFactory?: IFixSessionStoreFactory;
|
|
17
|
+
sessionRegistry?: ISessionRegistry;
|
|
16
18
|
}
|
|
17
19
|
export declare class JsFixConfig implements IJsFixConfig {
|
|
18
20
|
readonly factory: ISessionMsgFactory | null;
|
|
@@ -22,5 +24,7 @@ export declare class JsFixConfig implements IJsFixConfig {
|
|
|
22
24
|
readonly logFactory: JsFixLoggerFactory;
|
|
23
25
|
logDelimiter: number;
|
|
24
26
|
sessionContainer: DependencyContainer;
|
|
27
|
+
sessionStoreFactory?: IFixSessionStoreFactory;
|
|
28
|
+
sessionRegistry?: ISessionRegistry;
|
|
25
29
|
constructor(factory: ISessionMsgFactory | null, definitions: FixDefinitions, description: ISessionDescription, delimiter?: number, logFactory?: JsFixLoggerFactory);
|
|
26
30
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"js-fix-config.js","sourceRoot":"","sources":["../../src/config/js-fix-config.ts"],"names":[],"mappings":";;;AAIA,2DAAqD;AACrD,6DAAwD;
|
|
1
|
+
{"version":3,"file":"js-fix-config.js","sourceRoot":"","sources":["../../src/config/js-fix-config.ts"],"names":[],"mappings":";;;AAIA,2DAAqD;AACrD,6DAAwD;AAqBxD,MAAa,WAAW;IAKtB,YACkB,OAAkC,EAClC,WAA2B,EAC3B,WAAgC,EAChC,YAAoB,wBAAU,CAAC,GAAG,EAClC,aAAiC,IAAI,mCAAe,EAAE;QAJtD,YAAO,GAAP,OAAO,CAA2B;QAClC,gBAAW,GAAX,WAAW,CAAgB;QAC3B,gBAAW,GAAX,WAAW,CAAqB;QAChC,cAAS,GAAT,SAAS,CAAyB;QAClC,eAAU,GAAV,UAAU,CAA4C;QATjE,iBAAY,GAAW,wBAAU,CAAC,IAAI,CAAA;IAU7C,CAAC;CACF;AAZD,kCAYC","sourcesContent":["import { FixDefinitions } from '../dictionary/definition'\nimport { ISessionDescription } from '../transport/session/session-description'\nimport { ISessionMsgFactory } from '../transport/session/session-msg-factory'\nimport { JsFixLoggerFactory } from './js-fix-logger-factory'\nimport { EmptyLogFactory } from './empty-log-factory'\nimport { AsciiChars } from '../buffer/ascii/ascii-chars'\nimport { DependencyContainer } from 'tsyringe'\nimport { IFixSessionStoreFactory } from '../store/fix-session-store-factory'\nimport { ISessionRegistry } from '../transport/session/session-registry'\n\nexport interface IJsFixConfig {\n factory: ISessionMsgFactory | null\n definitions: FixDefinitions\n description: ISessionDescription\n delimiter?: number\n logDelimiter?: number\n logFactory: JsFixLoggerFactory\n sessionContainer: DependencyContainer\n sessionStoreFactory?: IFixSessionStoreFactory\n /**\n * Tracks the live session per SessionId. Set by the acceptor listener so a\n * reconnecting counterparty replaces - rather than duplicates - its session.\n */\n sessionRegistry?: ISessionRegistry\n}\n\nexport class JsFixConfig implements IJsFixConfig {\n public logDelimiter: number = AsciiChars.Pipe\n public sessionContainer: DependencyContainer\n public sessionStoreFactory?: IFixSessionStoreFactory\n public sessionRegistry?: ISessionRegistry\n constructor (\n public readonly factory: ISessionMsgFactory | null,\n public readonly definitions: FixDefinitions,\n public readonly description: ISessionDescription,\n public readonly delimiter: number = AsciiChars.Soh,\n public readonly logFactory: JsFixLoggerFactory = new EmptyLogFactory()) {\n }\n}\n"]}
|
|
@@ -148,7 +148,7 @@ class SessionLauncher {
|
|
|
148
148
|
else {
|
|
149
149
|
if (factory.makeSession) {
|
|
150
150
|
container.register(di_tokens_1.DITokens.FixSession, {
|
|
151
|
-
useFactory: () => factory.makeSession(
|
|
151
|
+
useFactory: (c) => factory.makeSession(c.resolve(di_tokens_1.DITokens.IJsFixConfig))
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-launcher.js","sourceRoot":"","sources":["../../src/runtime/session-launcher.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2CAA4B;AAC5B,sCAAiH;AAIjH,2DAAsD;AACtD,2CAAsC;AAEtC,MAAM,oBAAoB,GAAG,IAAI,+BAAsB,CAAC,sBAAa,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAA;AAE7F,MAAsB,eAAe;IAMnC,YACE,kBAAuD,IAAI,EAC3D,iBAAsD,IAAI,EACzC,gBAAoC,oBAAoB;QAAxD,kBAAa,GAAb,aAAa,CAA2C;QARpE,SAAI,GAAW,QAAQ,CAAA;QAepB,qBAAgB,GAAqB,IAAI,oCAAgB,EAAE,CAAA;QAe7D,mBAAc,GAAqB,IAAI,CAAA;QApB7C,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,UAAU,CAAC,CAAA;QACnD,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;QAChF,IAAI,CAAC,cAAc,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IAC/E,CAAC;IAIa,KAAK;;YACjB,OAAO,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC3C,IAAI,CAAC;oBACH,YAAY,CAAC,GAAG,EAAE;wBAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAA;wBAC9C,OAAO,CAAC,IAAI,CAAC,CAAA;oBACf,CAAC,CAAC,CAAA;gBACJ,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACX,MAAM,CAAC,CAAC,CAAC,CAAA;gBACX,CAAC;YACH,CAAC,CAAC,CAAA;QACJ,CAAC;KAAA;IAIe,WAAW,CAAE,gBAAqC;;YAChE,IAAI,gBAAgB,CAAC,YAAY,CAAY,oBAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAY,oBAAQ,CAAC,SAAS,CAAC,CAAA;gBACtE,IAAI,CAAC,cAAc,GAAG,MAAM,CAAA;gBAC5B,OAAO,MAAM,CAAC,KAAK,EAAE,CAAA;YACvB,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAC,KAAK,EAAE,CAAA;YACrB,CAAC;QACH,CAAC;KAAA;IAEe,YAAY,CAAE,gBAAqC;;YACjE,IAAI,gBAAgB,CAAC,YAAY,CAAY,oBAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;gBACjE,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,CAAY,oBAAQ,CAAC,SAAS,CAAC,CAAA;gBACtE,OAAO,MAAM,CAAC,KAAK,EAAE,CAAA;YACvB,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAC,KAAK,EAAE,CAAA;YACrB,CAAC;QACH,CAAC;KAAA;IAQS,WAAW,CAAE,MAAoB;QACzC,OAAO,IAAI,CAAA;IACb,CAAC;IAEY,GAAG;;YACd,OAAO,MAAM,IAAI,OAAO,CAAM,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAChD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;gBAC1B,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;gBAC3B,IAAI,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;oBACrB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;oBACtB,OAAO,CAAC,IAAI,CAAC,CAAA;gBACf,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAQ,EAAE,EAAE;oBACpB,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;oBACf,MAAM,CAAC,CAAC,CAAC,CAAA;gBACX,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;KAAA;IAEM,IAAI;QACT,IAAI,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE;YACnB,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAAA;QAC1B,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;YACX,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;QAClB,CAAC,CAAC,CAAA;IACJ,CAAC;IAMM,OAAO,CAAE,WAAgC;QAC9C,OAAO,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACnD,CAAC;IAMM,WAAW,CAAE,WAAgC;QAClD,OAAO,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC,WAAW,CAAC,CAAA;IACvD,CAAC;IAES,mBAAmB,CAAE,CAAsB;QACnD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wBAAwB,CAAC,CAAA;IAC5C,CAAC;IAEa,UAAU,CAAE,WAAgC;;;YACxD,MAAM,IAAI,GAAG,MAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,IAAI,mCAAI,IAAI,CAAA;YAClD,MAAM,QAAQ,GAAG,MAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,mCAAI,OAAO,CAAA;YAC7D,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,IAAI,cAAc,QAAQ,GAAG,CAAC,CAAA;YAC/D,OAAO,MAAM,IAAI,CAAC,gBAAgB,CAAC,UAAU,CAAC,WAAW,CAAC,CAAA;QAC5D,CAAC;KAAA;IAEO,QAAQ,CAAE,SAA8B;QAC9C,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAe,oBAAQ,CAAC,YAAY,CAAC,CAAA;QACrE,MAAM,OAAO,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,CAAA;QACxC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,IAAI,CAAC,mBAAmB,CAAC,SAAS,CAAC,CAAA;QACrC,CAAC;aAAM,CAAC;YACN,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,SAAS,CAAC,QAAQ,CAAa,oBAAQ,CAAC,UAAU,EAAE;oBAClD,UAAU,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC;iBAC9C,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAEa,UAAU;;YACtB,IAAI,CAAC,IAAI,CAAC,eAAe;gBAAE,OAAM;YACjC,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,eAAe,CAAC,CAAA;YACpE,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;YACpC,OAAO,MAAM,IAAI,CAAC,YAAY,CAAC,gBAAgB,CAAC,CAAA;QAClD,CAAC;KAAA;IAEa,UAAU;;YACtB,IAAI,CAAC,IAAI,CAAC,cAAc;gBAAE,OAAM;YAChC,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAA;YACnE,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAA;YAC/B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAA;YACnC,OAAO,MAAM,IAAI,CAAC,WAAW,CAAC,gBAAgB,CAAC,CAAA;QACjD,CAAC;KAAA;IAEK,aAAa;;YACjB,OAAO,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;QAC/D,CAAC;KAAA;IAEK,aAAa;;YACjB,OAAO,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAA;QAChE,CAAC;KAAA;IAEa,KAAK;;YACjB,IAAI,CAAC,gBAAgB,CAAC,cAAc,CAAC,IAAI,CAAC,aAAa,CAAC,CAAA;YACxD,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;YACnC,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,EAAE,CAAA;YACnC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAA;YAClC,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;gBAGhD,MAAM,MAAM,CAAA;gBACZ,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,CAAC,CAAA;gBACtD,IAAI,CAAC,YAAY,EAAE,CAAA;gBACnB,OAAO,IAAI,CAAA;YACb,CAAC;YACD,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;QAC5C,CAAC;KAAA;IAEO,YAAY;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,cAAqB,CAAA;QACzC,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChD,MAAM,CAAC,IAAI,EAAE,CAAA;QACf,CAAC;IACH,CAAC;IAEO,UAAU,CAAE,MAAoC;QACtD,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;YAC/B,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAA;QAC9C,CAAC;QACD,OAAO,MAAM,CAAA;IACf,CAAC;CACF;AAlLD,0CAkLC","sourcesContent":["import * as path from 'path'\nimport { IJsFixConfig, IJsFixLogger, JsFixLoggerFactory, JsFixWinstonLogFactory, WinstonLogger } from '../config'\nimport { FixEntity, FixSession, ISessionDescription } from '../transport'\nimport { DependencyContainer } from 'tsyringe'\nimport { EngineFactory } from './engine-factory'\nimport { SessionContainer } from './session-container'\nimport { DITokens } from './di-tokens'\n\nconst defaultLoggerFactory = new JsFixWinstonLogFactory(WinstonLogger.consoleOptions('info'))\n\nexport abstract class SessionLauncher {\n public root: string = '../../'\n protected readonly logger: IJsFixLogger\n public readonly initiatorConfig: ISessionDescription | null\n public readonly acceptorConfig: ISessionDescription | null\n\n protected constructor (\n initiatorConfig: string | ISessionDescription | null = null,\n acceptorConfig: string | ISessionDescription | null = null,\n private readonly loggerFactory: JsFixLoggerFactory = defaultLoggerFactory\n ) {\n this.logger = this.loggerFactory.logger('launcher')\n this.initiatorConfig = initiatorConfig ? this.loadConfig(initiatorConfig) : null\n this.acceptorConfig = acceptorConfig ? this.loadConfig(acceptorConfig) : null\n }\n\n protected sessionContainer: SessionContainer = new SessionContainer()\n\n private async empty (): Promise<any> {\n return await new Promise((resolve, reject) => {\n try {\n setImmediate(() => {\n this.logger.info('resolving an empty promise')\n resolve(null)\n })\n } catch (e) {\n reject(e)\n }\n })\n }\n\n private acceptorEntity: FixEntity | null = null\n\n protected async getAcceptor (sessionContainer: DependencyContainer): Promise<any> {\n if (sessionContainer.isRegistered<FixEntity>(DITokens.FixEntity)) {\n const entity = sessionContainer.resolve<FixEntity>(DITokens.FixEntity)\n this.acceptorEntity = entity\n return entity.start()\n } else {\n return this.empty()\n }\n }\n\n protected async getInitiator (sessionContainer: DependencyContainer): Promise<any> {\n if (sessionContainer.isRegistered<FixEntity>(DITokens.FixEntity)) {\n const entity = sessionContainer.resolve<FixEntity>(DITokens.FixEntity)\n return entity.start()\n } else {\n return this.empty()\n }\n }\n\n /**\n * provide a factory which will be invoked with a config where an instance of the application\n * should be constructed and returned.\n * @param config to be provided to the constucted application representing this session\n * @protected\n */\n protected makeFactory (config: IJsFixConfig): EngineFactory | null {\n return null\n }\n\n public async run (): Promise<boolean> {\n return await new Promise<any>((resolve, reject) => {\n const logger = this.logger\n logger.info('launching ..')\n this.setup().then(() => {\n logger.info('.. done')\n resolve(true)\n }).catch((e: Error) => {\n logger.error(e)\n reject(e)\n })\n })\n }\n\n public exec (): void {\n this.run().then(() => {\n console.log('finished.')\n }).catch(e => {\n console.error(e)\n })\n }\n\n /**\n * is this session config representing an ascii based session\n * @param description config to be tested.\n */\n public isAscii (description: ISessionDescription): boolean {\n return this.sessionContainer.isAscii(description)\n }\n\n /**\n * is this session config representing an initiator based session\n * @param description config to be tested.\n */\n public isInitiator (description: ISessionDescription): boolean {\n return this.sessionContainer.isInitiator(description)\n }\n\n protected registerApplication (_: DependencyContainer): void {\n this.logger.info('bypass register via DI')\n }\n\n private async makeSystem (description: ISessionDescription): Promise<DependencyContainer> {\n const name = description.application?.name ?? 'na'\n const protocol = description.application?.protocol ?? 'ascii'\n this.logger.info(`creating app ${name} [protocol ${protocol}]`)\n return await this.sessionContainer.makeSystem(description)\n }\n\n private register (container: DependencyContainer): void {\n const config = container.resolve<IJsFixConfig>(DITokens.IJsFixConfig)\n const factory = this.makeFactory(config)\n if (!factory) {\n this.registerApplication(container)\n } else {\n if (factory.makeSession) {\n container.register<FixSession>(DITokens.FixSession, {\n useFactory: () => factory.makeSession(config)\n })\n }\n }\n }\n\n private async makeClient (): Promise<any> {\n if (!this.initiatorConfig) return\n const sessionContainer = await this.makeSystem(this.initiatorConfig)\n this.register(sessionContainer)\n this.logger.info('create initiator')\n return await this.getInitiator(sessionContainer)\n }\n\n private async makeServer (): Promise<any> {\n if (!this.acceptorConfig) return\n const sessionContainer = await this.makeSystem(this.acceptorConfig)\n this.register(sessionContainer)\n this.logger.info('create acceptor')\n return await this.getAcceptor(sessionContainer)\n }\n\n async serverOrEmpty (): Promise<any> {\n return this.acceptorConfig ? this.makeServer() : this.empty()\n }\n\n async clientOrEmpty (): Promise<any> {\n return this.initiatorConfig ? this.makeClient() : this.empty()\n }\n\n private async setup (): Promise<any> {\n this.sessionContainer.registerGlobal(this.loggerFactory)\n const server = this.serverOrEmpty()\n const client = this.clientOrEmpty()\n this.logger.info('launching ....')\n if (this.acceptorConfig && this.initiatorConfig) {\n // Both mode: client drives the lifecycle. When client finishes,\n // stop the acceptor so the process can exit cleanly.\n await client\n this.logger.info('client finished, stopping acceptor')\n this.stopAcceptor()\n return true\n }\n return await Promise.all([server, client])\n }\n\n private stopAcceptor (): void {\n const entity = this.acceptorEntity as any\n if (entity && typeof entity.stop === 'function') {\n entity.stop()\n }\n }\n\n private loadConfig (config: string | ISessionDescription): ISessionDescription {\n if (typeof config === 'string') {\n return require(path.join(this.root, config))\n }\n return config\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-launcher.js","sourceRoot":"","sources":["../../src/runtime/session-launcher.ts"],"names":[],"mappings":"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","sourcesContent":["import * as path from 'path'\nimport { IJsFixConfig, IJsFixLogger, JsFixLoggerFactory, JsFixWinstonLogFactory, WinstonLogger } from '../config'\nimport { FixEntity, FixSession, ISessionDescription } from '../transport'\nimport { DependencyContainer } from 'tsyringe'\nimport { EngineFactory } from './engine-factory'\nimport { SessionContainer } from './session-container'\nimport { DITokens } from './di-tokens'\n\nconst defaultLoggerFactory = new JsFixWinstonLogFactory(WinstonLogger.consoleOptions('info'))\n\nexport abstract class SessionLauncher {\n public root: string = '../../'\n protected readonly logger: IJsFixLogger\n public readonly initiatorConfig: ISessionDescription | null\n public readonly acceptorConfig: ISessionDescription | null\n\n protected constructor (\n initiatorConfig: string | ISessionDescription | null = null,\n acceptorConfig: string | ISessionDescription | null = null,\n private readonly loggerFactory: JsFixLoggerFactory = defaultLoggerFactory\n ) {\n this.logger = this.loggerFactory.logger('launcher')\n this.initiatorConfig = initiatorConfig ? this.loadConfig(initiatorConfig) : null\n this.acceptorConfig = acceptorConfig ? this.loadConfig(acceptorConfig) : null\n }\n\n protected sessionContainer: SessionContainer = new SessionContainer()\n\n private async empty (): Promise<any> {\n return await new Promise((resolve, reject) => {\n try {\n setImmediate(() => {\n this.logger.info('resolving an empty promise')\n resolve(null)\n })\n } catch (e) {\n reject(e)\n }\n })\n }\n\n private acceptorEntity: FixEntity | null = null\n\n protected async getAcceptor (sessionContainer: DependencyContainer): Promise<any> {\n if (sessionContainer.isRegistered<FixEntity>(DITokens.FixEntity)) {\n const entity = sessionContainer.resolve<FixEntity>(DITokens.FixEntity)\n this.acceptorEntity = entity\n return entity.start()\n } else {\n return this.empty()\n }\n }\n\n protected async getInitiator (sessionContainer: DependencyContainer): Promise<any> {\n if (sessionContainer.isRegistered<FixEntity>(DITokens.FixEntity)) {\n const entity = sessionContainer.resolve<FixEntity>(DITokens.FixEntity)\n return entity.start()\n } else {\n return this.empty()\n }\n }\n\n /**\n * provide a factory which will be invoked with a config where an instance of the application\n * should be constructed and returned.\n * @param config to be provided to the constucted application representing this session\n * @protected\n */\n protected makeFactory (config: IJsFixConfig): EngineFactory | null {\n return null\n }\n\n public async run (): Promise<boolean> {\n return await new Promise<any>((resolve, reject) => {\n const logger = this.logger\n logger.info('launching ..')\n this.setup().then(() => {\n logger.info('.. done')\n resolve(true)\n }).catch((e: Error) => {\n logger.error(e)\n reject(e)\n })\n })\n }\n\n public exec (): void {\n this.run().then(() => {\n console.log('finished.')\n }).catch(e => {\n console.error(e)\n })\n }\n\n /**\n * is this session config representing an ascii based session\n * @param description config to be tested.\n */\n public isAscii (description: ISessionDescription): boolean {\n return this.sessionContainer.isAscii(description)\n }\n\n /**\n * is this session config representing an initiator based session\n * @param description config to be tested.\n */\n public isInitiator (description: ISessionDescription): boolean {\n return this.sessionContainer.isInitiator(description)\n }\n\n protected registerApplication (_: DependencyContainer): void {\n this.logger.info('bypass register via DI')\n }\n\n private async makeSystem (description: ISessionDescription): Promise<DependencyContainer> {\n const name = description.application?.name ?? 'na'\n const protocol = description.application?.protocol ?? 'ascii'\n this.logger.info(`creating app ${name} [protocol ${protocol}]`)\n return await this.sessionContainer.makeSystem(description)\n }\n\n private register (container: DependencyContainer): void {\n const config = container.resolve<IJsFixConfig>(DITokens.IJsFixConfig)\n const factory = this.makeFactory(config)\n if (!factory) {\n this.registerApplication(container)\n } else {\n if (factory.makeSession) {\n // resolve the config from the container doing the resolving, not the one\n // captured here. An acceptor resolves each session from a per-connection\n // child scope which re-registers IJsFixConfig, so this is how an application\n // receives that session's own description, store and message factory.\n container.register<FixSession>(DITokens.FixSession, {\n useFactory: (c) => factory.makeSession(c.resolve<IJsFixConfig>(DITokens.IJsFixConfig))\n })\n }\n }\n }\n\n private async makeClient (): Promise<any> {\n if (!this.initiatorConfig) return\n const sessionContainer = await this.makeSystem(this.initiatorConfig)\n this.register(sessionContainer)\n this.logger.info('create initiator')\n return await this.getInitiator(sessionContainer)\n }\n\n private async makeServer (): Promise<any> {\n if (!this.acceptorConfig) return\n const sessionContainer = await this.makeSystem(this.acceptorConfig)\n this.register(sessionContainer)\n this.logger.info('create acceptor')\n return await this.getAcceptor(sessionContainer)\n }\n\n async serverOrEmpty (): Promise<any> {\n return this.acceptorConfig ? this.makeServer() : this.empty()\n }\n\n async clientOrEmpty (): Promise<any> {\n return this.initiatorConfig ? this.makeClient() : this.empty()\n }\n\n private async setup (): Promise<any> {\n this.sessionContainer.registerGlobal(this.loggerFactory)\n const server = this.serverOrEmpty()\n const client = this.clientOrEmpty()\n this.logger.info('launching ....')\n if (this.acceptorConfig && this.initiatorConfig) {\n // Both mode: client drives the lifecycle. When client finishes,\n // stop the acceptor so the process can exit cleanly.\n await client\n this.logger.info('client finished, stopping acceptor')\n this.stopAcceptor()\n return true\n }\n return await Promise.all([server, client])\n }\n\n private stopAcceptor (): void {\n const entity = this.acceptorEntity as any\n if (entity && typeof entity.stop === 'function') {\n entity.stop()\n }\n }\n\n private loadConfig (config: string | ISessionDescription): ISessionDescription {\n if (typeof config === 'string') {\n return require(path.join(this.root, config))\n }\n return config\n }\n}\n"]}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.makeSessionScope = makeSessionScope;
|
|
4
|
+
const config_1 = require("../config");
|
|
5
|
+
const di_tokens_1 = require("./di-tokens");
|
|
6
|
+
const elastic_buffer_1 = require("../buffer/elastic-buffer");
|
|
7
|
+
const clone_session_description_1 = require("../transport/session/clone-session-description");
|
|
8
|
+
const ascii_session_msg_factory_1 = require("../transport/ascii/ascii-session-msg-factory");
|
|
9
|
+
const fixml_session_msg_factory_1 = require("../transport/fixml/fixml-session-msg-factory");
|
|
10
|
+
function makeSessionScope(config, overrides) {
|
|
11
|
+
var _a;
|
|
12
|
+
const parent = config.sessionContainer;
|
|
13
|
+
const scope = parent.createChildContainer();
|
|
14
|
+
const description = (0, clone_session_description_1.cloneSessionDescription)(config.description, overrides);
|
|
15
|
+
const factory = makeSessionMsgFactory(description, config.factory);
|
|
16
|
+
scope.registerInstance(di_tokens_1.DITokens.ISessionDescription, description);
|
|
17
|
+
scope.registerInstance(di_tokens_1.DITokens.ISessionMsgFactory, factory);
|
|
18
|
+
scope.registerInstance(di_tokens_1.DITokens.TransmitBuffer, cloneBuffer(parent, di_tokens_1.DITokens.TransmitBuffer));
|
|
19
|
+
scope.registerInstance(di_tokens_1.DITokens.ParseBuffer, cloneBuffer(parent, di_tokens_1.DITokens.ParseBuffer));
|
|
20
|
+
const scoped = new config_1.JsFixConfig(factory, config.definitions, description, config.delimiter, config.logFactory);
|
|
21
|
+
scoped.logDelimiter = (_a = config.logDelimiter) !== null && _a !== void 0 ? _a : scoped.logDelimiter;
|
|
22
|
+
scoped.sessionStoreFactory = config.sessionStoreFactory;
|
|
23
|
+
scoped.sessionRegistry = config.sessionRegistry;
|
|
24
|
+
scoped.sessionContainer = scope;
|
|
25
|
+
scope.registerInstance(di_tokens_1.DITokens.IJsFixConfig, scoped);
|
|
26
|
+
scope.registerInstance(di_tokens_1.DITokens.Definitions, config.definitions);
|
|
27
|
+
return scoped;
|
|
28
|
+
}
|
|
29
|
+
function cloneBuffer(parent, token) {
|
|
30
|
+
if (!parent.isRegistered(token, true)) {
|
|
31
|
+
return new elastic_buffer_1.ElasticBuffer();
|
|
32
|
+
}
|
|
33
|
+
const existing = parent.resolve(token);
|
|
34
|
+
return new elastic_buffer_1.ElasticBuffer(existing.size);
|
|
35
|
+
}
|
|
36
|
+
function makeSessionMsgFactory(description, current) {
|
|
37
|
+
var _a, _b;
|
|
38
|
+
if (current === null || current === void 0 ? void 0 : current.cloneFor) {
|
|
39
|
+
return current.cloneFor(description);
|
|
40
|
+
}
|
|
41
|
+
const ascii = ((_a = description.application) === null || _a === void 0 ? void 0 : _a.protocol) === 'ascii';
|
|
42
|
+
const mutator = (_b = current === null || current === void 0 ? void 0 : current.mutator) !== null && _b !== void 0 ? _b : null;
|
|
43
|
+
return ascii
|
|
44
|
+
? new ascii_session_msg_factory_1.AsciiSessionMsgFactory(description, mutator)
|
|
45
|
+
: new fixml_session_msg_factory_1.FixmlSessionMsgFactory(description, mutator);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=session-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-scope.js","sourceRoot":"","sources":["../../src/runtime/session-scope.ts"],"names":[],"mappings":";;AA2BA,4CAuBC;AAjDD,sCAAqD;AACrD,2CAAsC;AACtC,6DAAwD;AAGxD,8FAAwF;AACxF,4FAAqF;AACrF,4FAAqF;AAmBrF,SAAgB,gBAAgB,CAC9B,MAAoB,EACpB,SAAwC;;IACxC,MAAM,MAAM,GAAwB,MAAM,CAAC,gBAAgB,CAAA;IAC3D,MAAM,KAAK,GAAG,MAAM,CAAC,oBAAoB,EAAE,CAAA;IAE3C,MAAM,WAAW,GAAG,IAAA,mDAAuB,EAAC,MAAM,CAAC,WAAW,EAAE,SAAS,CAAC,CAAA;IAC1E,MAAM,OAAO,GAAG,qBAAqB,CAAC,WAAW,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;IAElE,KAAK,CAAC,gBAAgB,CAAC,oBAAQ,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAA;IACjE,KAAK,CAAC,gBAAgB,CAAC,oBAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC,CAAA;IAC5D,KAAK,CAAC,gBAAgB,CAAgB,oBAAQ,CAAC,cAAc,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAQ,CAAC,cAAc,CAAC,CAAC,CAAA;IAC5G,KAAK,CAAC,gBAAgB,CAAgB,oBAAQ,CAAC,WAAW,EAAE,WAAW,CAAC,MAAM,EAAE,oBAAQ,CAAC,WAAW,CAAC,CAAC,CAAA;IAEtG,MAAM,MAAM,GAAG,IAAI,oBAAW,CAAC,OAAO,EAAE,MAAM,CAAC,WAAW,EAAE,WAAW,EAAE,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAA;IAC7G,MAAM,CAAC,YAAY,GAAG,MAAA,MAAM,CAAC,YAAY,mCAAI,MAAM,CAAC,YAAY,CAAA;IAChE,MAAM,CAAC,mBAAmB,GAAG,MAAM,CAAC,mBAAmB,CAAA;IACvD,MAAM,CAAC,eAAe,GAAG,MAAM,CAAC,eAAe,CAAA;IAC/C,MAAM,CAAC,gBAAgB,GAAG,KAAK,CAAA;IAC/B,KAAK,CAAC,gBAAgB,CAAC,oBAAQ,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;IACrD,KAAK,CAAC,gBAAgB,CAAC,oBAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,WAAW,CAAC,CAAA;IAEhE,OAAO,MAAM,CAAA;AACf,CAAC;AAOD,SAAS,WAAW,CAAE,MAA2B,EAAE,KAAe;IAChE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,IAAI,CAAC,EAAE,CAAC;QACtC,OAAO,IAAI,8BAAa,EAAE,CAAA;IAC5B,CAAC;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAgB,KAAK,CAAC,CAAA;IACrD,OAAO,IAAI,8BAAa,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;AACzC,CAAC;AASD,SAAS,qBAAqB,CAC5B,WAAgC,EAChC,OAAkC;;IAClC,IAAI,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,QAAQ,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;IACtC,CAAC;IACD,MAAM,KAAK,GAAG,CAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,MAAK,OAAO,CAAA;IAC3D,MAAM,OAAO,GAAG,MAAC,OAAe,aAAf,OAAO,uBAAP,OAAO,CAAU,OAAO,mCAAI,IAAI,CAAA;IACjD,OAAO,KAAK;QACV,CAAC,CAAC,IAAI,kDAAsB,CAAC,WAAW,EAAE,OAAO,CAAC;QAClD,CAAC,CAAC,IAAI,kDAAsB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;AACtD,CAAC","sourcesContent":["import { DependencyContainer } from 'tsyringe'\nimport { IJsFixConfig, JsFixConfig } from '../config'\nimport { DITokens } from './di-tokens'\nimport { ElasticBuffer } from '../buffer/elastic-buffer'\nimport { ISessionDescription } from '../transport/session/session-description'\nimport { ISessionMsgFactory } from '../transport/session/session-msg-factory'\nimport { cloneSessionDescription } from '../transport/session/clone-session-description'\nimport { AsciiSessionMsgFactory } from '../transport/ascii/ascii-session-msg-factory'\nimport { FixmlSessionMsgFactory } from '../transport/fixml/fixml-session-msg-factory'\n\n/**\n * A FIX acceptor serves many connections from one listener configuration. Until\n * this existed every accepted connection shared the *same* parse buffer, transmit\n * buffer, session description and message factory, because those are registered as\n * instances on the single session container built at start up. Two clients talking\n * to one acceptor would therefore interleave bytes in a shared ElasticBuffer and\n * compute the same SessionId - so the same message store file.\n *\n * A session scope is a tsyringe child container which re-registers exactly the\n * per-connection state. Everything else (dictionary, transient parser/transmitter\n * classes, logger factory) is inherited from the parent, and resolving a parent\n * registration from the child still injects the child's instances, so an\n * AsciiParser resolved here receives this scope's ParseBuffer.\n *\n * Mirrors cspurefix TradeCaptureSessionFactory.CreatePerSessionConfigAndEncoder,\n * which had to do the same thing for the same reason.\n */\nexport function makeSessionScope (\n config: IJsFixConfig,\n overrides?: Partial<ISessionDescription>): IJsFixConfig {\n const parent: DependencyContainer = config.sessionContainer\n const scope = parent.createChildContainer()\n\n const description = cloneSessionDescription(config.description, overrides)\n const factory = makeSessionMsgFactory(description, config.factory)\n\n scope.registerInstance(DITokens.ISessionDescription, description)\n scope.registerInstance(DITokens.ISessionMsgFactory, factory)\n scope.registerInstance<ElasticBuffer>(DITokens.TransmitBuffer, cloneBuffer(parent, DITokens.TransmitBuffer))\n scope.registerInstance<ElasticBuffer>(DITokens.ParseBuffer, cloneBuffer(parent, DITokens.ParseBuffer))\n\n const scoped = new JsFixConfig(factory, config.definitions, description, config.delimiter, config.logFactory)\n scoped.logDelimiter = config.logDelimiter ?? scoped.logDelimiter\n scoped.sessionStoreFactory = config.sessionStoreFactory\n scoped.sessionRegistry = config.sessionRegistry\n scoped.sessionContainer = scope\n scope.registerInstance(DITokens.IJsFixConfig, scoped)\n scope.registerInstance(DITokens.Definitions, config.definitions)\n\n return scoped\n}\n\n/**\n * A fresh buffer of the same capacity as the one the parent container holds, so the\n * sizing decisions made in SessionContainer.asAscii are honoured without repeating\n * them here.\n */\nfunction cloneBuffer (parent: DependencyContainer, token: DITokens): ElasticBuffer {\n if (!parent.isRegistered(token, true)) {\n return new ElasticBuffer()\n }\n const existing = parent.resolve<ElasticBuffer>(token)\n return new ElasticBuffer(existing.size)\n}\n\n/**\n * The scope needs a factory bound to *its* description, because the outbound header\n * carries this session's comp ids. Applications may supply their own factory (by\n * overriding SessionContainer.makeSessionFactory), and that must survive into the\n * per-session scope - building a stock one here would silently drop custom header\n * handling on the acceptor path. See issue #87.\n */\nfunction makeSessionMsgFactory (\n description: ISessionDescription,\n current: ISessionMsgFactory | null): ISessionMsgFactory {\n if (current?.cloneFor) {\n return current.cloneFor(description)\n }\n const ascii = description.application?.protocol === 'ascii'\n const mutator = (current as any)?.mutator ?? null\n return ascii\n ? new AsciiSessionMsgFactory(description, mutator)\n : new FixmlSessionMsgFactory(description, mutator)\n}\n"]}
|
|
@@ -54,9 +54,9 @@ class AppLauncher extends runtime_1.SessionLauncher {
|
|
|
54
54
|
makeFactory(config) {
|
|
55
55
|
const isInitiator = this.isInitiator(config.description);
|
|
56
56
|
return {
|
|
57
|
-
makeSession: () => isInitiator
|
|
58
|
-
? new http_client_1.HttpClient(
|
|
59
|
-
: new http_server_1.HttpServer(
|
|
57
|
+
makeSession: (sessionConfig) => isInitiator
|
|
58
|
+
? new http_client_1.HttpClient(sessionConfig)
|
|
59
|
+
: new http_server_1.HttpServer(sessionConfig)
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
waitFor(ms) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/http/oms/app.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4BAAyB;AAEzB,+CAA0C;AAC1C,+CAA0C;AAE1C,8CAA2E;AAI3E,2CAA4B;AAE5B,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,uCAAuC,EACvC,sCAAsC,CAAC,CAAA;IAC3C,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/http/oms/app.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,4BAAyB;AAEzB,+CAA0C;AAC1C,+CAA0C;AAE1C,8CAA2E;AAI3E,2CAA4B;AAE5B,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,uCAAuC,EACvC,sCAAsC,CAAC,CAAA;IAC3C,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,CAAC,aAA2B,EAAE,EAAE,CAAC,WAAW;gBACvD,CAAC,CAAC,IAAI,wBAAU,CAAC,aAAa,CAAC;gBAC/B,CAAC,CAAC,IAAI,wBAAU,CAAC,aAAa,CAAC;SACjB,CAAA;IACpB,CAAC;IAEK,OAAO,CAAE,EAAU;;YACvB,MAAM,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAA;YACrC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBACrC,EAAE,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE;oBACf,OAAO,CAAC,IAAI,CAAC,CAAA;gBACf,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE;oBACX,MAAM,CAAC,CAAC,CAAC,CAAA;gBACX,CAAC,CAAC,CAAA;YACJ,CAAC,CAAC,CAAA;QACJ,CAAC;KAAA;IAEwB,YAAY,CAAE,gBAAqC;;;YAC1E,MAAM,MAAM,GAAiB,gBAAgB,CAAC,OAAO,CAAe,kBAAQ,CAAC,YAAY,CAAC,CAAA;YAC1F,MAAM,IAAI,GAAG,MAAA,MAAA,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,WAAW,0CAAE,WAAW,0CAAE,IAAI,CAAA;YACnD,IAAI,IAAI,EAAE,CAAC;gBACT,IAAI,CAAC,OAAO,GAAG,gBAAgB,CAAC,OAAO,CAAe,kBAAQ,CAAC,YAAY,CAAC,CAAA;gBAC5E,MAAM,SAAS,GAAG,gBAAgB,CAAC,OAAO,CAAY,kBAAQ,CAAC,SAAS,CAAC,CAAA;gBACzE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAS,EAAE;oBACxC,OAAO,SAAS,CAAC,KAAK,EAAE,CAAA;gBAC1B,CAAC,CAAA,CAAC,CAAA;YACJ,CAAC;QACH,CAAC;KAAA;CACF;AAED,MAAM,CAAC,GAAG,IAAI,WAAW,EAAE,CAAA;AAC3B,CAAC,CAAC,IAAI,EAAE,CAAA","sourcesContent":["import 'reflect-metadata'\n\nimport { HttpServer } from './http-server'\nimport { HttpClient } from './http-client'\nimport { IJsFixConfig } from '../../../config'\nimport { DITokens, EngineFactory, SessionLauncher } from '../../../runtime'\nimport { DependencyContainer } from 'tsyringe'\nimport { FixEntity } from '../../../transport'\nimport { IHttpAdapter } from '../../../transport/http/http-adapter'\nimport * as util from 'util'\n\nclass AppLauncher extends SessionLauncher {\n public constructor () {\n super(\n 'data/session/test-http-initiator.json',\n 'data/session/test-http-acceptor.json')\n }\n\n protected override makeFactory (config: IJsFixConfig): EngineFactory {\n const isInitiator = this.isInitiator(config.description)\n return {\n makeSession: (sessionConfig: IJsFixConfig) => isInitiator\n ? new HttpClient(sessionConfig)\n : new HttpServer(sessionConfig)\n } as EngineFactory\n }\n\n async waitFor (ms: number): Promise<any> {\n const to = util.promisify(setTimeout)\n return new Promise((resolve, reject) => {\n to(ms).then(() => {\n resolve(null)\n }).catch(e => {\n reject(e)\n })\n })\n }\n\n protected override async getInitiator (sessionContainer: DependencyContainer): Promise<any> {\n const config: IJsFixConfig = sessionContainer.resolve<IJsFixConfig>(DITokens.IJsFixConfig)\n const http = config?.description?.application?.http\n if (http) {\n http.adapter = sessionContainer.resolve<IHttpAdapter>(DITokens.IHttpAdapter)\n const initiator = sessionContainer.resolve<FixEntity>(DITokens.FixEntity)\n return this.waitFor(1000).then(async () => {\n return initiator.start()\n })\n }\n }\n}\n\nconst l = new AppLauncher()\nl.exec()\n"]}
|
|
@@ -11,9 +11,9 @@ class AppLauncher extends runtime_1.SessionLauncher {
|
|
|
11
11
|
makeFactory(config) {
|
|
12
12
|
const isInitiator = this.isInitiator(config.description);
|
|
13
13
|
return {
|
|
14
|
-
makeSession: () => isInitiator
|
|
15
|
-
? new md_client_1.MDClient(
|
|
16
|
-
: new md_server_1.MDServer(
|
|
14
|
+
makeSession: (sessionConfig) => isInitiator
|
|
15
|
+
? new md_client_1.MDClient(sessionConfig)
|
|
16
|
+
: new md_server_1.MDServer(sessionConfig)
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/tcp/qf-md/app.ts"],"names":[],"mappings":";;AAAA,4BAAyB;AAEzB,2CAAsC;AACtC,2CAAsC;AAEtC,8CAAiE;AAEjE,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,uCAAuC,EACvC,sCAAsC,CAAC,CAAA;IAC3C,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/tcp/qf-md/app.ts"],"names":[],"mappings":";;AAAA,4BAAyB;AAEzB,2CAAsC;AACtC,2CAAsC;AAEtC,8CAAiE;AAEjE,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,uCAAuC,EACvC,sCAAsC,CAAC,CAAA;IAC3C,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,CAAC,aAA2B,EAAE,EAAE,CAAC,WAAW;gBACvD,CAAC,CAAC,IAAI,oBAAQ,CAAC,aAAa,CAAC;gBAC7B,CAAC,CAAC,IAAI,oBAAQ,CAAC,aAAa,CAAC;SACf,CAAA;IACpB,CAAC;CACF;AAED,MAAM,CAAC,GAAG,IAAI,WAAW,EAAE,CAAA;AAC3B,CAAC,CAAC,IAAI,EAAE,CAAA","sourcesContent":["import 'reflect-metadata'\n\nimport { MDClient } from './md-client'\nimport { MDServer } from './md-server'\nimport { IJsFixConfig } from '../../../config'\nimport { EngineFactory, SessionLauncher } from '../../../runtime'\n\nclass AppLauncher extends SessionLauncher {\n public constructor () {\n super(\n 'data/session/test-qf44-initiator.json',\n 'data/session/test-qf44-acceptor.json')\n }\n\n protected override makeFactory (config: IJsFixConfig): EngineFactory {\n const isInitiator = this.isInitiator(config.description)\n return {\n makeSession: (sessionConfig: IJsFixConfig) => isInitiator\n ? new MDClient(sessionConfig)\n : new MDServer(sessionConfig)\n } as EngineFactory\n }\n}\n\nconst l = new AppLauncher()\nl.exec()\n"]}
|
|
@@ -9,7 +9,7 @@ class AppLauncher extends runtime_1.SessionLauncher {
|
|
|
9
9
|
}
|
|
10
10
|
makeFactory(config) {
|
|
11
11
|
return {
|
|
12
|
-
makeSession: () => new skeleton_session_1.SkeletonSession(
|
|
12
|
+
makeSession: (sessionConfig) => new skeleton_session_1.SkeletonSession(sessionConfig, 45, false)
|
|
13
13
|
};
|
|
14
14
|
}
|
|
15
15
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/tcp/skeleton/app.ts"],"names":[],"mappings":";;AAAA,4BAAyB;AAEzB,8CAAiE;AACjE,yDAAoD;AAGpD,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,kCAAkC,EAClC,iCAAiC,CAAC,CAAA;IACtC,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,OAAO;YACL,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"app.js","sourceRoot":"","sources":["../../../../src/sample/tcp/skeleton/app.ts"],"names":[],"mappings":";;AAAA,4BAAyB;AAEzB,8CAAiE;AACjE,yDAAoD;AAGpD,MAAM,WAAY,SAAQ,yBAAe;IACvC;QACE,KAAK,CACH,kCAAkC,EAClC,iCAAiC,CAAC,CAAA;IACtC,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,OAAO;YACL,WAAW,EAAE,CAAC,aAA2B,EAAE,EAAE,CAAC,IAAI,kCAAe,CAAC,aAAa,EAAE,EAAE,EAAE,KAAK,CAAC;SAC3E,CAAA;IACpB,CAAC;CACF;AAED,MAAM,CAAC,GAAG,IAAI,WAAW,EAAE,CAAA;AAC3B,CAAC,CAAC,IAAI,EAAE,CAAA","sourcesContent":["import 'reflect-metadata'\n\nimport { SessionLauncher, EngineFactory } from '../../../runtime'\nimport { SkeletonSession } from './skeleton-session'\nimport { IJsFixConfig } from '../../../config'\n\nclass AppLauncher extends SessionLauncher {\n public constructor () {\n super(\n 'data/session/test-initiator.json',\n 'data/session/test-acceptor.json')\n }\n\n protected override makeFactory (config: IJsFixConfig): EngineFactory {\n return {\n makeSession: (sessionConfig: IJsFixConfig) => new SkeletonSession(sessionConfig, 45, false)\n } as EngineFactory\n }\n}\n\nconst l = new AppLauncher()\nl.exec()\n"]}
|
|
@@ -11,9 +11,9 @@ class AppLauncher extends runtime_1.SessionLauncher {
|
|
|
11
11
|
makeFactory(config) {
|
|
12
12
|
const isInitiator = this.isInitiator(config.description);
|
|
13
13
|
return {
|
|
14
|
-
makeSession: () => isInitiator
|
|
15
|
-
? new trade_capture_client_1.TradeCaptureClient(
|
|
16
|
-
: new trade_capture_server_1.TradeCaptureServer(
|
|
14
|
+
makeSession: (sessionConfig) => isInitiator
|
|
15
|
+
? new trade_capture_client_1.TradeCaptureClient(sessionConfig)
|
|
16
|
+
: new trade_capture_server_1.TradeCaptureServer(sessionConfig)
|
|
17
17
|
};
|
|
18
18
|
}
|
|
19
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"app-launcher.js","sourceRoot":"","sources":["../../../../src/sample/tcp/trade-capture/app-launcher.ts"],"names":[],"mappings":";;;AAAA,8CAAiE;AAEjE,iEAA2D;AAC3D,iEAA2D;AAE3D,MAAa,WAAY,SAAQ,yBAAe;IAC9C,YAAoB,SAAiB,kCAAkC,EACrE,SAAiB,iCAAiC;QAClD,KAAK,CACH,MAAM,EACN,MAAM,CAAC,CAAA;IACX,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"app-launcher.js","sourceRoot":"","sources":["../../../../src/sample/tcp/trade-capture/app-launcher.ts"],"names":[],"mappings":";;;AAAA,8CAAiE;AAEjE,iEAA2D;AAC3D,iEAA2D;AAE3D,MAAa,WAAY,SAAQ,yBAAe;IAC9C,YAAoB,SAAiB,kCAAkC,EACrE,SAAiB,iCAAiC;QAClD,KAAK,CACH,MAAM,EACN,MAAM,CAAC,CAAA;IACX,CAAC;IAEkB,WAAW,CAAE,MAAoB;QAClD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;QACxD,OAAO;YACL,WAAW,EAAE,CAAC,aAA2B,EAAE,EAAE,CAAC,WAAW;gBACvD,CAAC,CAAC,IAAI,yCAAkB,CAAC,aAAa,CAAC;gBACvC,CAAC,CAAC,IAAI,yCAAkB,CAAC,aAAa,CAAC;SACzB,CAAA;IACpB,CAAC;CACF;AAhBD,kCAgBC","sourcesContent":["import { EngineFactory, SessionLauncher } from '../../../runtime'\nimport { IJsFixConfig } from '../../../config'\nimport { TradeCaptureClient } from './trade-capture-client'\nimport { TradeCaptureServer } from './trade-capture-server'\n\nexport class AppLauncher extends SessionLauncher {\n public constructor (client: string = 'data/session/test-initiator.json',\n server: string = 'data/session/test-acceptor.json') {\n super(\n client,\n server)\n }\n\n protected override makeFactory (config: IJsFixConfig): EngineFactory {\n const isInitiator = this.isInitiator(config.description)\n return {\n makeSession: (sessionConfig: IJsFixConfig) => isInitiator\n ? new TradeCaptureClient(sessionConfig)\n : new TradeCaptureServer(sessionConfig)\n } as EngineFactory\n }\n}\n"]}
|
|
@@ -7,13 +7,21 @@ import { MsgTransport } from '../factory';
|
|
|
7
7
|
import { ILooseObject } from '../../collections/collection';
|
|
8
8
|
export declare abstract class AsciiSession extends FixSession {
|
|
9
9
|
readonly config: IJsFixConfig;
|
|
10
|
+
static readonly WildcardCompId = "*";
|
|
10
11
|
heartbeat: boolean;
|
|
11
12
|
protected store: IFixMsgStore | null;
|
|
12
13
|
protected resender: FixMsgAsciiStoreResend;
|
|
13
|
-
protected
|
|
14
|
-
protected
|
|
15
|
-
protected
|
|
14
|
+
protected coordinator: SessionSequenceCoordinator;
|
|
15
|
+
protected sessionStore: IFixSessionStore;
|
|
16
|
+
protected sessionId: SessionId;
|
|
17
|
+
private registered;
|
|
18
|
+
protected readonly wildcardTarget: boolean;
|
|
19
|
+
private identityBound;
|
|
20
|
+
private bindInProgress;
|
|
21
|
+
private readonly pendingRx;
|
|
22
|
+
private readonly clock;
|
|
16
23
|
protected constructor(config: IJsFixConfig);
|
|
24
|
+
private storeFactory;
|
|
17
25
|
run(transport: MsgTransport): Promise<number>;
|
|
18
26
|
private checkSeqNo;
|
|
19
27
|
protected checkForwardMsg(msgType: string, view: MsgView): void;
|
|
@@ -22,6 +30,8 @@ export declare abstract class AsciiSession extends FixSession {
|
|
|
22
30
|
private checkIntegrity;
|
|
23
31
|
protected onResendRequest(view: MsgView): void;
|
|
24
32
|
protected onPrepareForReconnect(): void;
|
|
33
|
+
private claimSessionId;
|
|
34
|
+
protected onSessionStopping(): void;
|
|
25
35
|
protected onPreLogon(): Promise<void>;
|
|
26
36
|
protected txOnEncoded(msgType: string, data: string, hdr: ILooseObject): void;
|
|
27
37
|
private static readonly MaxLogonRetries;
|
|
@@ -31,6 +41,10 @@ export declare abstract class AsciiSession extends FixSession {
|
|
|
31
41
|
okForLogon(): boolean;
|
|
32
42
|
protected onSessionMsg(msgType: string, view: MsgView): void;
|
|
33
43
|
protected onMsg(msgType: string, view: MsgView): void;
|
|
44
|
+
private onMsgBeforeIdentity;
|
|
45
|
+
private drainPendingRx;
|
|
46
|
+
private bindIdentity;
|
|
47
|
+
private dispatchMsg;
|
|
34
48
|
private startTimer;
|
|
35
49
|
private peerLogon;
|
|
36
50
|
private sendTestRequest;
|