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.
Files changed (92) hide show
  1. package/.gitattributes +4 -0
  2. package/BACKPORT_PLAN.md +71 -0
  3. package/DEMO_PORT_PLAN.md +10 -0
  4. package/README.md +3 -0
  5. package/dist/config/js-fix-config.d.ts +4 -0
  6. package/dist/config/js-fix-config.js.map +1 -1
  7. package/dist/runtime/session-launcher.js +1 -1
  8. package/dist/runtime/session-launcher.js.map +1 -1
  9. package/dist/runtime/session-scope.d.ts +3 -0
  10. package/dist/runtime/session-scope.js +47 -0
  11. package/dist/runtime/session-scope.js.map +1 -0
  12. package/dist/sample/http/oms/app.js +3 -3
  13. package/dist/sample/http/oms/app.js.map +1 -1
  14. package/dist/sample/tcp/qf-md/app.js +3 -3
  15. package/dist/sample/tcp/qf-md/app.js.map +1 -1
  16. package/dist/sample/tcp/skeleton/app.js +1 -1
  17. package/dist/sample/tcp/skeleton/app.js.map +1 -1
  18. package/dist/sample/tcp/trade-capture/app-launcher.js +3 -3
  19. package/dist/sample/tcp/trade-capture/app-launcher.js.map +1 -1
  20. package/dist/transport/ascii/ascii-session.d.ts +17 -3
  21. package/dist/transport/ascii/ascii-session.js +121 -8
  22. package/dist/transport/ascii/ascii-session.js.map +1 -1
  23. package/dist/transport/duplex/fix-duplex.d.ts +1 -0
  24. package/dist/transport/duplex/fix-duplex.js +3 -0
  25. package/dist/transport/duplex/fix-duplex.js.map +1 -1
  26. package/dist/transport/duplex/tcp-duplex.d.ts +1 -0
  27. package/dist/transport/duplex/tcp-duplex.js +5 -0
  28. package/dist/transport/duplex/tcp-duplex.js.map +1 -1
  29. package/dist/transport/factory/msg-transport.d.ts +2 -0
  30. package/dist/transport/factory/msg-transport.js +17 -2
  31. package/dist/transport/factory/msg-transport.js.map +1 -1
  32. package/dist/transport/session/a-session-msg-factory.d.ts +1 -0
  33. package/dist/transport/session/a-session-msg-factory.js +4 -0
  34. package/dist/transport/session/a-session-msg-factory.js.map +1 -1
  35. package/dist/transport/session/clone-session-description.d.ts +6 -0
  36. package/dist/transport/session/clone-session-description.js +11 -0
  37. package/dist/transport/session/clone-session-description.js.map +1 -0
  38. package/dist/transport/session/fix-session.d.ts +5 -1
  39. package/dist/transport/session/fix-session.js +93 -24
  40. package/dist/transport/session/fix-session.js.map +1 -1
  41. package/dist/transport/session/index.d.ts +2 -0
  42. package/dist/transport/session/index.js +2 -0
  43. package/dist/transport/session/index.js.map +1 -1
  44. package/dist/transport/session/session-msg-factory.d.ts +1 -0
  45. package/dist/transport/session/session-msg-factory.js.map +1 -1
  46. package/dist/transport/session/session-registry.d.ts +23 -0
  47. package/dist/transport/session/session-registry.js +59 -0
  48. package/dist/transport/session/session-registry.js.map +1 -0
  49. package/dist/transport/tcp/tcp-acceptor-listener.d.ts +3 -0
  50. package/dist/transport/tcp/tcp-acceptor-listener.js +26 -4
  51. package/dist/transport/tcp/tcp-acceptor-listener.js.map +1 -1
  52. package/dist/transport/tcp/tcp-acceptor.d.ts +5 -0
  53. package/dist/transport/tcp/tcp-acceptor.js +74 -20
  54. package/dist/transport/tcp/tcp-acceptor.js.map +1 -1
  55. package/dist/transport/tcp/tcp-initiator.js +15 -5
  56. package/dist/transport/tcp/tcp-initiator.js.map +1 -1
  57. package/dist/transport/tcp/tcp-transport-description.d.ts +1 -0
  58. package/dist/transport/tcp/tcp-transport-description.js.map +1 -1
  59. package/dist/transport/tcp/tls-diagnostics.d.ts +5 -0
  60. package/dist/transport/tcp/tls-diagnostics.js +64 -0
  61. package/dist/transport/tcp/tls-diagnostics.js.map +1 -0
  62. package/dist/transport/tcp/tls-options-factory.d.ts +1 -0
  63. package/dist/transport/tcp/tls-options-factory.js +24 -2
  64. package/dist/transport/tcp/tls-options-factory.js.map +1 -1
  65. package/docs/acceptor.md +207 -0
  66. package/jsfix.test_client.txt +62 -75
  67. package/jsfix.test_server.txt +72 -72
  68. package/package.json +11 -10
  69. package/script/pack-local.js +68 -0
  70. package/src/config/js-fix-config.ts +8 -0
  71. package/src/runtime/session-launcher.ts +5 -1
  72. package/src/runtime/session-scope.ts +84 -0
  73. package/src/sample/http/oms/app.ts +3 -3
  74. package/src/sample/tcp/qf-md/app.ts +3 -3
  75. package/src/sample/tcp/skeleton/app.ts +1 -1
  76. package/src/sample/tcp/trade-capture/app-launcher.ts +3 -3
  77. package/src/transport/ascii/ascii-session.ts +186 -11
  78. package/src/transport/duplex/fix-duplex.ts +9 -0
  79. package/src/transport/duplex/tcp-duplex.ts +10 -0
  80. package/src/transport/factory/msg-transport.ts +20 -0
  81. package/src/transport/session/a-session-msg-factory.ts +18 -0
  82. package/src/transport/session/clone-session-description.ts +41 -0
  83. package/src/transport/session/fix-session.ts +136 -25
  84. package/src/transport/session/index.ts +2 -0
  85. package/src/transport/session/session-msg-factory.ts +13 -0
  86. package/src/transport/session/session-registry.ts +112 -0
  87. package/src/transport/tcp/tcp-acceptor-listener.ts +43 -5
  88. package/src/transport/tcp/tcp-acceptor.ts +92 -18
  89. package/src/transport/tcp/tcp-initiator.ts +26 -5
  90. package/src/transport/tcp/tcp-transport-description.ts +7 -0
  91. package/src/transport/tcp/tls-diagnostics.ts +76 -0
  92. package/src/transport/tcp/tls-options-factory.ts +34 -2
package/.gitattributes ADDED
@@ -0,0 +1,4 @@
1
+ # pem encoded test fixtures - keep byte for byte identical on every platform rather than
2
+ # letting eol normalisation rewrite them on checkout.
3
+ *.crt -text
4
+ *.key -text
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;AAexD,MAAa,WAAW;IAGtB,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;QAPjE,iBAAY,GAAW,wBAAU,CAAC,IAAI,CAAA;IAQ7C,CAAC;CACF;AAVD,kCAUC","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'\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\nexport class JsFixConfig implements IJsFixConfig {\n public logDelimiter: number = AsciiChars.Pipe\n public sessionContainer: DependencyContainer\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"]}
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(config)
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":"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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 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,3 @@
1
+ import { IJsFixConfig } from '../config';
2
+ import { ISessionDescription } from '../transport/session/session-description';
3
+ export declare function makeSessionScope(config: IJsFixConfig, overrides?: Partial<ISessionDescription>): IJsFixConfig;
@@ -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(config)
59
- : new http_server_1.HttpServer(config)
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,GAAG,EAAE,CAAC,WAAW;gBAC5B,CAAC,CAAC,IAAI,wBAAU,CAAC,MAAM,CAAC;gBACxB,CAAC,CAAC,IAAI,wBAAU,CAAC,MAAM,CAAC;SACV,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: () => isInitiator\n ? new HttpClient(config)\n : new HttpServer(config)\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"]}
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(config)
16
- : new md_server_1.MDServer(config)
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,GAAG,EAAE,CAAC,WAAW;gBAC5B,CAAC,CAAC,IAAI,oBAAQ,CAAC,MAAM,CAAC;gBACtB,CAAC,CAAC,IAAI,oBAAQ,CAAC,MAAM,CAAC;SACR,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: () => isInitiator\n ? new MDClient(config)\n : new MDServer(config)\n } as EngineFactory\n }\n}\n\nconst l = new AppLauncher()\nl.exec()\n"]}
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(config, 45, false)
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,GAAG,EAAE,CAAC,IAAI,kCAAe,CAAC,MAAM,EAAE,EAAE,EAAE,KAAK,CAAC;SACzC,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: () => new SkeletonSession(config, 45, false)\n } as EngineFactory\n }\n}\n\nconst l = new AppLauncher()\nl.exec()\n"]}
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(config)
16
- : new trade_capture_server_1.TradeCaptureServer(config)
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,GAAG,EAAE,CAAC,WAAW;gBAC5B,CAAC,CAAC,IAAI,yCAAkB,CAAC,MAAM,CAAC;gBAChC,CAAC,CAAC,IAAI,yCAAkB,CAAC,MAAM,CAAC;SAClB,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: () => isInitiator\n ? new TradeCaptureClient(config)\n : new TradeCaptureServer(config)\n } as EngineFactory\n }\n}\n"]}
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 readonly coordinator: SessionSequenceCoordinator;
14
- protected readonly sessionStore: IFixSessionStore;
15
- protected readonly sessionId: SessionId;
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;