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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"a-session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/session/a-session-msg-factory.ts"],"names":[],"mappings":";;;AAGA,uCAAqC;AAcrC,MAAsB,kBAAkB;IAEtC,YAAuC,WAAgC,EAAS,UAAgC,IAAI;QAA7E,gBAAW,GAAX,WAAW,CAAqB;QAAS,YAAO,GAAP,OAAO,CAA6B;IACpH,CAAC;IAEM,MAAM,CAAE,OAAe,EAAE,KAAa,EAAE,GAAW,EAAE,MAAc;QACxE,MAAM,CAAC,GAAY;YACjB,UAAU,EAAE,OAAO;YACnB,mBAAmB,EAAE,MAAM;YAC3B,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,GAAG;SACC,CAAA;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,eAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAOS,MAAM,CAAE,CAAe,EAAE,IAAY;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACnE,CAAC;IAEM,WAAW,CAAE,QAAgB,QAAQ,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;QACpE,MAAM,CAAC,GAAiB;YACtB,SAAS,EAAE,KAAK;SACD,CAAA;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,WAAW,CAAC,CAAA;IAC5C,CAAC;IAEM,SAAS,CAAE,SAAiB;QACjC,MAAM,CAAC,GAAe;YACpB,SAAS,EAAE,SAAS;SACP,CAAA;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC;IAEM,aAAa,CAAE,IAAY,EAAE,EAAU;QAC5C,MAAM,CAAC,GAAmB;YACxB,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,EAAE;SACK,CAAA;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,aAAa,CAAC,CAAA;IAC9C,CAAC;IAEM,aAAa,CAAE,QAAgB,EAAE,OAAiB;QACvD,MAAM,CAAC,GAAmB;YACxB,WAAW,EAAE,OAAO,KAAK,IAAI;YAC7B,QAAQ,EAAE,QAAQ;SACD,CAAA;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,aAAa,CAAC,CAAA;IAC9C,CAAC;IAEM,OAAO,CAAE,QAAgB;QAC9B,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAA;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG;YACR,QAAQ,EAAE,MAAM;SACG,CAAA;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;IAC1C,CAAC;CACF;
|
|
1
|
+
{"version":3,"file":"a-session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/session/a-session-msg-factory.ts"],"names":[],"mappings":";;;AAGA,uCAAqC;AAcrC,MAAsB,kBAAkB;IAEtC,YAAuC,WAAgC,EAAS,UAAgC,IAAI;QAA7E,gBAAW,GAAX,WAAW,CAAqB;QAAS,YAAO,GAAP,OAAO,CAA6B;IACpH,CAAC;IAYM,QAAQ,CAAE,WAAgC;QAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,WAGK,CAAA;QACvB,OAAO,IAAI,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAC5C,CAAC;IAEM,MAAM,CAAE,OAAe,EAAE,KAAa,EAAE,GAAW,EAAE,MAAc;QACxE,MAAM,CAAC,GAAY;YACjB,UAAU,EAAE,OAAO;YACnB,mBAAmB,EAAE,MAAM;YAC3B,SAAS,EAAE,KAAK;YAChB,IAAI,EAAE,GAAG;SACC,CAAA;QACZ,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,eAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IAC7E,CAAC;IAOS,MAAM,CAAE,CAAe,EAAE,IAAY;QAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACnE,CAAC;IAEM,WAAW,CAAE,QAAgB,QAAQ,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE;QACpE,MAAM,CAAC,GAAiB;YACtB,SAAS,EAAE,KAAK;SACD,CAAA;QACjB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,WAAW,CAAC,CAAA;IAC5C,CAAC;IAEM,SAAS,CAAE,SAAiB;QACjC,MAAM,CAAC,GAAe;YACpB,SAAS,EAAE,SAAS;SACP,CAAA;QACf,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,SAAS,CAAC,CAAA;IAC1C,CAAC;IAEM,aAAa,CAAE,IAAY,EAAE,EAAU;QAC5C,MAAM,CAAC,GAAmB;YACxB,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,EAAE;SACK,CAAA;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,aAAa,CAAC,CAAA;IAC9C,CAAC;IAEM,aAAa,CAAE,QAAgB,EAAE,OAAiB;QACvD,MAAM,CAAC,GAAmB;YACxB,WAAW,EAAE,OAAO,KAAK,IAAI;YAC7B,QAAQ,EAAE,QAAQ;SACD,CAAA;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,aAAa,CAAC,CAAA;IAC9C,CAAC;IAEM,OAAO,CAAE,QAAgB;QAC9B,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAA;QAC7B,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;QACjC,MAAM,CAAC,GAAG;YACR,QAAQ,EAAE,MAAM;SACG,CAAA;QACrB,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,iBAAiB,CAAC,CAAA;IAC1C,CAAC;CACF;AAhFD,gDAgFC","sourcesContent":["import { ISessionMsgFactory } from './session-msg-factory'\nimport { ISessionDescription } from './session-description'\nimport { ILooseObject } from '../../collections/collection'\nimport { MsgType } from '../../types'\n\nimport {\n IHeartbeat,\n IReject,\n IResendRequest,\n ISequenceReset,\n IStandardHeader,\n IStandardTrailer,\n ITestRequest\n} from '../../types/FIX4.4/repo'\n\nexport type ObjectMutator = (description: ISessionDescription, type: string, o: ILooseObject) => ILooseObject\n\nexport abstract class ASessionMsgFactory implements ISessionMsgFactory {\n public isAscii: boolean\n protected constructor (public readonly description: ISessionDescription, public mutator: ObjectMutator | null = null) {\n }\n\n /**\n * Rebuild this factory against another session description, preserving the\n * concrete type. An acceptor needs one factory per accepted connection so that\n * outbound headers carry that session's comp ids; without preserving the type, an\n * application's own factory would be silently replaced by the stock one.\n *\n * Reconstructing through `this.constructor` covers any subclass whose constructor\n * takes (description, mutator) - the shape every factory in this library uses.\n * Override this if yours takes anything else.\n */\n public cloneFor (description: ISessionDescription): ISessionMsgFactory {\n const Ctor = this.constructor as new (\n description: ISessionDescription,\n mutator: ObjectMutator | null\n ) => ISessionMsgFactory\n return new Ctor(description, this.mutator)\n }\n\n public reject (msgType: string, seqNo: number, msg: string, reason: number): ILooseObject {\n const o: IReject = {\n RefMsgType: msgType,\n SessionRejectReason: reason,\n RefSeqNum: seqNo,\n Text: msg\n } as IReject\n return this.mutator ? this.mutator(this.description, MsgType.Reject, o) : o\n }\n\n // see implementations Ascii and Fixml\n public abstract logon (userRequestId?: string, isResponse?: boolean): ILooseObject\n public abstract logout (msgType: string, text: string): ILooseObject\n public abstract header (msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>): ILooseObject\n\n protected mutate (o: ILooseObject, type: string): ILooseObject {\n return this.mutator ? this.mutator(this.description, type, o) : o\n }\n\n public testRequest (reqId: string = `ping-${new Date().toUTCString()}`): ILooseObject {\n const o: ITestRequest = {\n TestReqID: reqId\n } as ITestRequest\n return this.mutate(o, MsgType.TestRequest)\n }\n\n public heartbeat (testReqId: string): ILooseObject {\n const o: IHeartbeat = {\n TestReqID: testReqId\n } as IHeartbeat\n return this.mutate(o, MsgType.Heartbeat)\n }\n\n public resendRequest (from: number, to: number): ILooseObject {\n const o: IResendRequest = {\n BeginSeqNo: from,\n EndSeqNo: to\n } as IResendRequest\n return this.mutate(o, MsgType.ResendRequest)\n }\n\n public sequenceReset (newSeqNo: number, gapFill?: boolean): ILooseObject {\n const o: ISequenceReset = {\n GapFillFlag: gapFill === true,\n NewSeqNo: newSeqNo\n } as ISequenceReset\n return this.mutate(o, MsgType.SequenceReset)\n }\n\n public trailer (checksum: number): ILooseObject {\n const s = checksum.toString()\n const padded = s.padStart(3, '0')\n const o = {\n CheckSum: padded\n } as IStandardTrailer\n return this.mutate(o, 'StandardTrailer')\n }\n}\n"]}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { IDynamicSessionParams, ISessionDescription } from './session-description';
|
|
2
|
+
export type MutableSessionDescription = {
|
|
3
|
+
-readonly [K in keyof ISessionDescription]: ISessionDescription[K];
|
|
4
|
+
};
|
|
5
|
+
export declare function cloneSessionDescription(description: ISessionDescription, overrides?: Partial<IDynamicSessionParams>): ISessionDescription;
|
|
6
|
+
export declare function asMutable(description: ISessionDescription): MutableSessionDescription;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.cloneSessionDescription = cloneSessionDescription;
|
|
4
|
+
exports.asMutable = asMutable;
|
|
5
|
+
function cloneSessionDescription(description, overrides) {
|
|
6
|
+
return Object.assign(Object.assign({}, description), (overrides !== null && overrides !== void 0 ? overrides : {}));
|
|
7
|
+
}
|
|
8
|
+
function asMutable(description) {
|
|
9
|
+
return description;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=clone-session-description.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clone-session-description.js","sourceRoot":"","sources":["../../../src/transport/session/clone-session-description.ts"],"names":[],"mappings":";;AAyBA,0DAOC;AAMD,8BAEC;AAfD,SAAgB,uBAAuB,CACrC,WAAgC,EAChC,SAA0C;IAC1C,uCACK,WAAW,GACX,CAAC,SAAS,aAAT,SAAS,cAAT,SAAS,GAAI,EAAE,CAAC,EACrB;AACH,CAAC;AAMD,SAAgB,SAAS,CAAE,WAAgC;IACzD,OAAO,WAAwC,CAAA;AACjD,CAAC","sourcesContent":["import { IDynamicSessionParams, ISessionDescription } from './session-description'\n\n/**\n * A session description with the readonly modifiers stripped. The description is\n * immutable by design - it is loaded once from JSON and shared by everything in the\n * session - but an acceptor running in wildcard mode has to write the peer's\n * SenderCompID into its own copy once the Logon arrives. Cast through this type so\n * the (deliberately rare) mutation is explicit at every call site.\n */\nexport type MutableSessionDescription = {\n -readonly [K in keyof ISessionDescription]: ISessionDescription[K]\n}\n\n/**\n * Shallow clone a session description, optionally overriding identity fields.\n *\n * Each connection accepted by a FIX acceptor needs its own description: the\n * SessionId (and therefore the message store), the outbound header comp ids and the\n * session registry key are all derived from it. Sharing one description across\n * concurrent sessions makes every client collide on the same store.\n *\n * `application` and `store` are shared by reference - they are read only\n * configuration (host, port, dictionary, store directory) common to every session\n * on the listener.\n */\nexport function cloneSessionDescription (\n description: ISessionDescription,\n overrides?: Partial<IDynamicSessionParams>): ISessionDescription {\n return {\n ...description,\n ...(overrides ?? {})\n }\n}\n\n/**\n * Make a description writable. Use only where the FIX protocol itself forces a\n * late binding - i.e. wildcard TargetCompID resolved from the peer's Logon.\n */\nexport function asMutable (description: ISessionDescription): MutableSessionDescription {\n return description as MutableSessionDescription\n}\n"]}
|
|
@@ -10,13 +10,14 @@ export declare abstract class FixSession extends events.EventEmitter {
|
|
|
10
10
|
logReceivedMsgs: boolean;
|
|
11
11
|
protected timer: NodeJS.Timeout | null;
|
|
12
12
|
protected transport: MsgTransport | null;
|
|
13
|
+
private subscription;
|
|
13
14
|
manageSession: boolean;
|
|
14
15
|
checkMsgIntegrity: boolean;
|
|
15
16
|
protected readonly me: string;
|
|
16
17
|
protected readonly initiator: boolean;
|
|
17
18
|
protected readonly acceptor: boolean;
|
|
18
19
|
protected readonly sessionState: FixSessionState;
|
|
19
|
-
protected
|
|
20
|
+
protected sessionLogger: IJsFixLogger;
|
|
20
21
|
protected requestLogoutType: string;
|
|
21
22
|
protected respondLogoutType: string;
|
|
22
23
|
protected requestLogonType: string;
|
|
@@ -38,6 +39,7 @@ export declare abstract class FixSession extends events.EventEmitter {
|
|
|
38
39
|
protected rxOnDecoded(msgType: string, data: ElasticBuffer, ptr: number): void;
|
|
39
40
|
protected txOnError(e: Error): void;
|
|
40
41
|
protected txOnEncoded(msgType: string, data: string, hdr: ILooseObject): void;
|
|
42
|
+
private isCurrentTransport;
|
|
41
43
|
protected unsubscribe(): void;
|
|
42
44
|
protected subscribe(): void;
|
|
43
45
|
protected validStateApplicationMsg(): boolean;
|
|
@@ -52,7 +54,9 @@ export declare abstract class FixSession extends events.EventEmitter {
|
|
|
52
54
|
done(): void;
|
|
53
55
|
reset(resetSeqNum?: number | null): void;
|
|
54
56
|
protected onPrepareForReconnect(): void;
|
|
57
|
+
protected onSessionStopping(): void;
|
|
55
58
|
protected onPreLogon(): Promise<void>;
|
|
59
|
+
requestStop(reason: string): void;
|
|
56
60
|
protected stop(error?: Error | null): void;
|
|
57
61
|
protected abstract onMsg(msgType: string, view: MsgView): void;
|
|
58
62
|
protected abstract onDecoded(msgType: string, txt: string): void;
|
|
@@ -56,6 +56,7 @@ class FixSession extends events.EventEmitter {
|
|
|
56
56
|
this.logReceivedMsgs = false;
|
|
57
57
|
this.timer = null;
|
|
58
58
|
this.transport = null;
|
|
59
|
+
this.subscription = null;
|
|
59
60
|
this.manageSession = true;
|
|
60
61
|
this.checkMsgIntegrity = false;
|
|
61
62
|
const description = config.description;
|
|
@@ -140,7 +141,7 @@ class FixSession extends events.EventEmitter {
|
|
|
140
141
|
};
|
|
141
142
|
const onError = (e) => {
|
|
142
143
|
cleanup();
|
|
143
|
-
|
|
144
|
+
this.sessionLogger.error(e);
|
|
144
145
|
reject(e);
|
|
145
146
|
};
|
|
146
147
|
const onDone = () => {
|
|
@@ -231,32 +232,89 @@ class FixSession extends events.EventEmitter {
|
|
|
231
232
|
logger.debug(`tx: [${msgType}] ${data.length} bytes seqNo = ${this.lastSentSeqNum()}`);
|
|
232
233
|
this.onEncoded(msgType, data);
|
|
233
234
|
}
|
|
235
|
+
isCurrentTransport(transport, event) {
|
|
236
|
+
var _a, _b, _c;
|
|
237
|
+
if (((_a = this.subscription) === null || _a === void 0 ? void 0 : _a.transport) === transport && this.transport === transport) {
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
const current = (_c = (_b = this.transport) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : 'none';
|
|
241
|
+
this.sessionLogger.warning(`ignoring '${event}' from stale transport ${transport.id} - current transport is ${current}`);
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
234
244
|
unsubscribe() {
|
|
245
|
+
var _a, _b;
|
|
235
246
|
const logger = this.sessionLogger;
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
+
const subscription = this.subscription;
|
|
248
|
+
if (!subscription) {
|
|
249
|
+
logger.debug('unsubscribe called with no active subscription');
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
const transport = subscription.transport;
|
|
253
|
+
logger.info(`unsubscribe transport ${transport.id} sessionState = [${this.sessionState.toString()}]`);
|
|
254
|
+
const rx = transport.receiver;
|
|
255
|
+
const tx = transport.transmitter;
|
|
256
|
+
rx === null || rx === void 0 ? void 0 : rx.removeListener('msg', subscription.rxOnMsg);
|
|
257
|
+
rx === null || rx === void 0 ? void 0 : rx.removeListener('error', subscription.rxOnError);
|
|
258
|
+
rx === null || rx === void 0 ? void 0 : rx.removeListener('done', subscription.rxOnDone);
|
|
259
|
+
rx === null || rx === void 0 ? void 0 : rx.removeListener('end', subscription.rxOnEnd);
|
|
260
|
+
rx === null || rx === void 0 ? void 0 : rx.removeListener('decoded', subscription.rxOnDecoded);
|
|
261
|
+
tx === null || tx === void 0 ? void 0 : tx.removeListener('error', subscription.txOnError);
|
|
262
|
+
tx === null || tx === void 0 ? void 0 : tx.removeListener('encoded', subscription.txOnEncoded);
|
|
263
|
+
this.subscription = null;
|
|
264
|
+
logger.debug(`unsubscribe complete - rx listeners now ${(_a = rx === null || rx === void 0 ? void 0 : rx.listenerCount('msg')) !== null && _a !== void 0 ? _a : 0} msg, ${(_b = rx === null || rx === void 0 ? void 0 : rx.listenerCount('end')) !== null && _b !== void 0 ? _b : 0} end`);
|
|
247
265
|
}
|
|
248
266
|
subscribe() {
|
|
249
267
|
const transport = this.transport;
|
|
250
|
-
|
|
251
|
-
|
|
268
|
+
if (!transport) {
|
|
269
|
+
this.sessionLogger.warning('subscribe called with no transport');
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
if (this.subscription) {
|
|
273
|
+
this.unsubscribe();
|
|
274
|
+
}
|
|
252
275
|
const inst = this;
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
276
|
+
const subscription = {
|
|
277
|
+
transport,
|
|
278
|
+
rxOnMsg: (msgType, view) => {
|
|
279
|
+
if (inst.isCurrentTransport(transport, 'msg'))
|
|
280
|
+
inst.rxOnMsg(msgType, view);
|
|
281
|
+
},
|
|
282
|
+
rxOnError: (e) => {
|
|
283
|
+
if (inst.isCurrentTransport(transport, 'error'))
|
|
284
|
+
inst.rxOnError(e);
|
|
285
|
+
},
|
|
286
|
+
rxOnDone: () => {
|
|
287
|
+
if (inst.isCurrentTransport(transport, 'done'))
|
|
288
|
+
inst.rxOnDone();
|
|
289
|
+
},
|
|
290
|
+
rxOnEnd: () => {
|
|
291
|
+
if (inst.isCurrentTransport(transport, 'end'))
|
|
292
|
+
inst.rxOnEnd();
|
|
293
|
+
},
|
|
294
|
+
rxOnDecoded: (msgType, data, ptr) => {
|
|
295
|
+
if (inst.isCurrentTransport(transport, 'decoded'))
|
|
296
|
+
inst.rxOnDecoded(msgType, data, ptr);
|
|
297
|
+
},
|
|
298
|
+
txOnError: (e) => {
|
|
299
|
+
if (inst.isCurrentTransport(transport, 'tx error'))
|
|
300
|
+
inst.txOnError(e);
|
|
301
|
+
},
|
|
302
|
+
txOnEncoded: (msgType, data, hdr) => {
|
|
303
|
+
if (inst.isCurrentTransport(transport, 'encoded'))
|
|
304
|
+
inst.txOnEncoded(msgType, data, hdr);
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
const rx = transport.receiver;
|
|
308
|
+
const tx = transport.transmitter;
|
|
309
|
+
rx === null || rx === void 0 ? void 0 : rx.on('msg', subscription.rxOnMsg);
|
|
310
|
+
rx === null || rx === void 0 ? void 0 : rx.on('error', subscription.rxOnError);
|
|
311
|
+
rx === null || rx === void 0 ? void 0 : rx.on('done', subscription.rxOnDone);
|
|
312
|
+
rx === null || rx === void 0 ? void 0 : rx.on('end', subscription.rxOnEnd);
|
|
313
|
+
rx === null || rx === void 0 ? void 0 : rx.on('decoded', subscription.rxOnDecoded);
|
|
314
|
+
tx === null || tx === void 0 ? void 0 : tx.on('error', subscription.txOnError);
|
|
315
|
+
tx === null || tx === void 0 ? void 0 : tx.on('encoded', subscription.txOnEncoded);
|
|
316
|
+
this.subscription = subscription;
|
|
317
|
+
this.sessionLogger.info(`subscribed to transport ${transport.id}`);
|
|
260
318
|
}
|
|
261
319
|
validStateApplicationMsg() {
|
|
262
320
|
switch (this.sessionState.state) {
|
|
@@ -292,12 +350,16 @@ class FixSession extends events.EventEmitter {
|
|
|
292
350
|
return;
|
|
293
351
|
this.sessionLogger.error(error);
|
|
294
352
|
this.stopTimer();
|
|
353
|
+
this.unsubscribe();
|
|
295
354
|
if (this.transport) {
|
|
355
|
+
this.sessionLogger.info(`terminate: kill transport ${this.transport.id}`);
|
|
296
356
|
this.transport.end();
|
|
297
357
|
}
|
|
298
358
|
this.transport = null;
|
|
299
359
|
this.setState(session_state_1.SessionState.Stopped);
|
|
360
|
+
this.onSessionStopping();
|
|
300
361
|
this.emit('error', error);
|
|
362
|
+
this.onStopped(error);
|
|
301
363
|
}
|
|
302
364
|
peerLogout(view) {
|
|
303
365
|
const msg = view.getString(types_1.MsgTag.Text);
|
|
@@ -404,19 +466,26 @@ class FixSession extends events.EventEmitter {
|
|
|
404
466
|
}
|
|
405
467
|
onPrepareForReconnect() {
|
|
406
468
|
}
|
|
469
|
+
onSessionStopping() {
|
|
470
|
+
}
|
|
407
471
|
onPreLogon() {
|
|
408
472
|
return __awaiter(this, void 0, void 0, function* () {
|
|
409
473
|
});
|
|
410
474
|
}
|
|
475
|
+
requestStop(reason) {
|
|
476
|
+
this.sessionLogger.info(`requestStop: ${reason}`);
|
|
477
|
+
this.stop(new Error(reason));
|
|
478
|
+
}
|
|
411
479
|
stop(error = null) {
|
|
412
|
-
var _a;
|
|
480
|
+
var _a, _b, _c;
|
|
413
481
|
if (this.sessionState.state === session_state_1.SessionState.Stopped) {
|
|
414
482
|
return;
|
|
415
483
|
}
|
|
416
484
|
this.stopTimer();
|
|
417
485
|
this.unsubscribe();
|
|
418
|
-
this.sessionLogger.info(
|
|
419
|
-
|
|
486
|
+
this.sessionLogger.info(`stop: kill transport ${(_b = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.id) !== null && _b !== void 0 ? _b : 'none'}`);
|
|
487
|
+
this.onSessionStopping();
|
|
488
|
+
(_c = this.transport) === null || _c === void 0 ? void 0 : _c.end();
|
|
420
489
|
if (error) {
|
|
421
490
|
this.sessionLogger.info(`stop: emit error ${error.message}`);
|
|
422
491
|
this.emit('error', error);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fix-session.js","sourceRoot":"","sources":["../../../src/transport/session/fix-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { ElasticBuffer, MsgView } from '../../buffer'\nimport { IJsFixConfig, IJsFixLogger } from '../../config'\nimport { FixSessionState } from './fix-session-state'\nimport { MsgTransport } from '../factory'\nimport { MsgTag } from '../../types'\nimport { ILooseObject } from '../../collections/collection'\n\nimport * as events from 'events'\nimport { SessionState } from './session-state'\nimport { SegmentType } from '../../buffer/segment/segment-type'\n\nexport abstract class FixSession extends events.EventEmitter {\n public logReceivedMsgs: boolean = false\n protected timer: NodeJS.Timeout | null = null\n protected transport: MsgTransport | null = null\n public manageSession: boolean = true\n public checkMsgIntegrity: boolean = false\n protected readonly me: string\n protected readonly initiator: boolean\n protected readonly acceptor: boolean\n protected readonly sessionState: FixSessionState\n protected readonly sessionLogger: IJsFixLogger\n protected requestLogoutType: string\n protected respondLogoutType: string\n protected requestLogonType: string\n\n protected constructor (public readonly config: IJsFixConfig) {\n super()\n const description = config.description\n this.me = description?.application?.name ?? 'me'\n this.sessionState = new FixSessionState(\n {\n heartBeat: config.description.HeartBtInt,\n lastPeerMsgSeqNum: config.description.LastReceivedSeqNum\n })\n this.sessionLogger = config.logFactory.logger(`${this.me}:FixSession`)\n this.initiator = description?.application?.type === 'initiator'\n this.acceptor = !this.initiator\n this.checkMsgIntegrity = this.acceptor\n this.sessionState.compId = description.SenderCompId\n }\n\n stateStr (theState: SessionState): string {\n return SessionState[theState]\n }\n\n assignState (newState: SessionState): void {\n const currentState = this.sessionState.state\n const currentStateStr = this.stateStr(currentState)\n const logger = this.sessionLogger\n const msg = `current state ${currentStateStr} (${currentState}) moves to ${SessionState[newState]} (${newState})`\n logger.info(msg)\n this.sessionState.state = newState\n }\n\n public setState (state: SessionState): void {\n const logger = this.sessionLogger\n const currentState = this.sessionState.state\n const currentStateStr = this.stateStr(currentState)\n if (state === currentState) return\n switch (currentState) {\n case SessionState.ConfirmingLogout:\n case SessionState.Stopped:\n if (state !== SessionState.NetworkConnectionEstablished) {\n logger.info(`ignoring request to change state as now already in ${currentStateStr}`)\n } else {\n this.assignState(state)\n }\n break\n\n default: {\n this.assignState(state)\n }\n }\n }\n\n public getState (): SessionState {\n return this.sessionState.state\n }\n\n public lastSentSeqNum (): number {\n return this.sessionState.lastSentSeqNum()\n }\n\n public lastPeerSeqNum (): number {\n return this.sessionState.lastPeerMsgSeqNum\n }\n\n public sendLogon (): void {\n const lo = this.config.factory?.logon()\n if (lo) {\n this.send(this.requestLogonType, lo)\n }\n }\n\n private async waitPromise (): Promise<number> {\n const logger = this.sessionLogger\n if (this.initiator) {\n // Hook for subclasses to reset sequences when ResetSeqNumFlag=Y is configured —\n // must run after the store is loaded, before sendLogon stamps a seq num.\n await this.onPreLogon()\n }\n return await new Promise<any>((resolve, reject) => {\n if (this.initiator) {\n logger.debug(`initiator sending logon state = ${this.stateString()}`)\n this.sendLogon()\n this.setState(SessionState.InitiationLogonSent)\n } else {\n logger.debug(`acceptor waits for logon state = ${this.stateString()}`)\n this.setState(SessionState.WaitingForALogon)\n }\n\n // Use named handlers and detach BOTH when the promise settles. Only one of\n // 'error'/'done' fires per run; without removing the sibling the unfired\n // listener would leak on every reconnect (issue #146). `once` alone is not\n // enough for the same reason — the sibling never fires, so never self-detaches.\n const cleanup = (): void => {\n this.removeListener('error', onError)\n this.removeListener('done', onDone)\n }\n const onError = (e: Error): void => {\n cleanup()\n logger.error(e)\n reject(e)\n }\n const onDone = (): void => {\n cleanup()\n resolve(this.transport?.id)\n }\n\n this.on('error', onError)\n this.on('done', onDone)\n })\n }\n\n public async run (transport: MsgTransport): Promise<number> {\n const logger = this.sessionLogger\n if (this.transport) {\n logger.info(`reset from previous transport. state ${this.stateString()}`)\n this.reset()\n }\n this.transport = transport\n this.subscribe()\n return await this.waitPromise()\n }\n\n protected expectedEndState (): boolean {\n switch (this.sessionState.state) {\n case SessionState.Stopped:\n case SessionState.ConfirmingLogout:\n return true\n\n default:\n return false\n }\n }\n\n protected rxOnEnd (): void {\n const logger = this.sessionLogger\n logger.info(`rx end received sessionState = [${this.sessionState.toString()}]`)\n const expectedState = this.expectedEndState()\n if (expectedState) {\n logger.info(`rx receives end state = ${this.stateString()} - stop session`)\n this.stop()\n } else {\n this.setState(SessionState.DetectBrokenNetworkConnection)\n const e = new Error(`unexpected state - transport failed? = ${this.stateString()}`)\n logger.info(`rx error ${e.message}`)\n this.terminate(e)\n }\n }\n\n protected rxOnMsg (msgType: string, view: MsgView): void {\n const logger = this.sessionLogger\n\n if (this.logReceivedMsgs) {\n const name = view.segment.type !== SegmentType.Unknown ? view?.segment?.set?.name : 'unknown'\n logger.info(`${msgType}: ${name}`)\n logger.info(`${view.toString()}`)\n }\n this.sessionState.lastReceivedAt = new Date()\n if (this.manageSession) {\n this.onMsg(msgType, view)\n } else {\n this.checkForwardMsg(msgType, view)\n }\n }\n\n protected rxOnDone (): void {\n const logger = this.sessionLogger\n logger.info('rx done received')\n this.done()\n }\n\n protected rxOnError (e: Error): void {\n const logger = this.sessionLogger\n logger.warning(`rx error event: ${e.message} ${JSON.stringify(e)}`)\n this.terminate(e)\n }\n\n protected rxOnDecoded (msgType: string, data: ElasticBuffer, ptr: number): void {\n const logger = this.sessionLogger\n logger.debug(`rx: [${msgType}] ${ptr} bytes`)\n this.onDecoded(msgType, data.toString(ptr))\n }\n\n protected txOnError (e: Error): void {\n const logger = this.sessionLogger\n logger.warning(`tx error event: ${e.message} ${JSON.stringify(e)}`)\n this.terminate(e)\n }\n\n protected txOnEncoded (msgType: string, data: string, hdr: ILooseObject): void {\n const logger = this.sessionLogger\n this.sessionState.lastHeader = hdr\n logger.debug(`tx: [${msgType}] ${data.length} bytes seqNo = ${this.lastSentSeqNum()}`)\n this.onEncoded(msgType, data)\n }\n\n protected unsubscribe (): void {\n const logger = this.sessionLogger\n logger.info(`unsubscribe sessionState = [${this.sessionState.toString()}]`)\n const transport = this.transport\n const rx = transport?.receiver\n const tx = transport?.transmitter\n\n rx?.removeListener('msg', this.rxOnMsg)\n rx?.removeListener('error', this.rxOnError)\n rx?.removeListener('done', this.rxOnDone)\n rx?.removeListener('end', this.rxOnEnd)\n rx?.removeListener('decoded', this.rxOnDecoded)\n tx?.removeListener('error', this.txOnError)\n tx?.removeListener('encoded', this.txOnEncoded)\n }\n\n protected subscribe (): void {\n const transport = this.transport\n\n const rx = transport?.receiver\n const tx = transport?.transmitter\n const inst = this\n rx?.on('msg', (msgType: string, view: MsgView) => { inst.rxOnMsg(msgType, view) })\n rx?.on('error', (e: Error) => { inst.rxOnError(e) })\n rx?.on('done', () => { inst.rxOnDone() })\n rx?.on('end', () => { inst.rxOnEnd() })\n rx?.on('decoded', (msgType: string, data: ElasticBuffer, ptr: number) => { inst.rxOnDecoded(msgType, data, ptr) })\n tx?.on('error', (e: Error) => { inst.txOnError(e) })\n tx?.on('encoded', (msgType: string, data: string, hdr: ILooseObject) => { inst.txOnEncoded(msgType, data, hdr) })\n }\n\n protected validStateApplicationMsg (): boolean {\n switch (this.sessionState.state) {\n case SessionState.Idle:\n case SessionState.InitiateConnection:\n case SessionState.InitiationLogonSent:\n case SessionState.WaitingForALogon:\n case SessionState.HandleResendRequest:\n case SessionState.AwaitingProcessingResponseToTestRequest:\n case SessionState.AwaitingProcessingResponseToResendRequest:\n return false\n default:\n return true\n }\n }\n\n protected stateString (): string {\n return SessionState[this.sessionState.state]\n }\n\n protected checkForwardMsg (msgType: string, view: MsgView): void {\n this.sessionLogger.info(`forwarding msgType = '${msgType}' to application`)\n this.setState(SessionState.ActiveNormalSession)\n this.onApplicationMsg(msgType, view)\n }\n\n private stopTimer (): void {\n if (this.timer) {\n this.sessionLogger.info('stopTimer')\n clearInterval(this.timer)\n this.timer = null\n }\n }\n\n protected terminate (error: Error): void {\n if (this.sessionState.state === SessionState.Stopped) return\n this.sessionLogger.error(error)\n this.stopTimer()\n if (this.transport) {\n this.transport.end()\n }\n this.transport = null\n this.setState(SessionState.Stopped)\n this.emit('error', error)\n }\n\n protected peerLogout (view: MsgView): void {\n const msg = view.getString(MsgTag.Text)\n const state = this.sessionState.state\n switch (state) {\n case SessionState.WaitingLogoutConfirm: {\n this.sessionLogger.info(`peer confirms logout Text = '${msg}'`)\n this.stop()\n break\n }\n\n case SessionState.InitiationLogonResponse:\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonReceived: {\n this.setState(SessionState.ConfirmingLogout)\n this.sessionLogger.info(`peer initiates logout Text = '${msg}'`)\n this.sessionLogout()\n }\n }\n }\n\n protected send (msgType: string, obj: ILooseObject): void {\n const state = this.sessionState.state\n switch (state) {\n case SessionState.Stopped: {\n this.sessionLogger.warning(`can't send in state ${this.stateString()}`)\n break\n }\n\n default: {\n this.sessionState.LastSentAt = new Date()\n this.transport?.transmitter.send(msgType, obj)\n break\n }\n }\n }\n\n protected sendLogout (msg: string): void {\n const factory = this.config.factory\n this.sessionLogger.info(`sending logout with ${msg}`)\n const lo = factory?.logout(this.requestLogoutType, msg)\n if (lo) {\n this.send(this.requestLogoutType, lo)\n }\n }\n\n protected sessionLogout (): void {\n const sessionState = this.sessionState\n if (sessionState.logoutSentAt) {\n return\n }\n\n switch (sessionState.state) {\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonResponse:\n case SessionState.InitiationLogonReceived: {\n // this instance initiates logout\n this.setState(SessionState.WaitingLogoutConfirm)\n sessionState.logoutSentAt = new Date()\n const msg = `${this.me} initiate logout`\n this.sessionLogger.info(msg)\n this.sendLogout(msg)\n break\n }\n\n case SessionState.ConfirmingLogout: {\n // this instance responds to log out\n this.setState(SessionState.ConfirmingLogout)\n sessionState.logoutSentAt = new Date()\n const msg = `${this.me} confirming logout`\n this.sessionLogger.info(msg)\n this.sendLogout(msg)\n break\n }\n\n default: {\n this.sessionLogger.info(`sessionLogout ignored as in state ${sessionState.state}`)\n }\n }\n }\n\n public done (): void {\n switch (this.sessionState.state) {\n case SessionState.InitiationLogonResponse:\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonReceived: {\n this.sessionLogout()\n break\n }\n\n case SessionState.Stopped:\n this.sessionLogger.info('done. session is now stopped')\n break\n\n default: {\n this.stop()\n break\n }\n }\n this.sessionLogger.info(`done. check logout sequence state ${this.stateString()}`)\n }\n\n public reset (resetSeqNum?: number | null): void {\n this.stopTimer()\n // unsubscribe from old transport before clearing reference\n this.unsubscribe()\n // reset parser to clear any partial message state from dropped connection\n const receiver: any = this.transport?.receiver\n if (receiver?.reset) {\n receiver.reset()\n }\n this.transport = null\n const resetFlag = this.config.description.ResetSeqNumFlag\n const seqNum = resetFlag ? 0 : resetSeqNum ?? this.sessionState.lastPeerMsgSeqNum\n this.sessionState.reset(seqNum) // from header def ... eventually\n this.onPrepareForReconnect()\n this.setState(SessionState.NetworkConnectionEstablished)\n }\n\n protected onPrepareForReconnect (): void {\n // Override in subclass to reset coordinator/transient state\n }\n\n /**\n * Called for initiators after the store is loaded but before the Logon is sent.\n * Override to reset sequences/store when ResetSeqNumFlag=Y so the Logon goes out\n * with MsgSeqNum=1 instead of the recovered sender seq num.\n */\n protected async onPreLogon (): Promise<void> {\n // Default no-op\n }\n\n protected stop (error: Error | null = null): void {\n if (this.sessionState.state === SessionState.Stopped) {\n return\n }\n this.stopTimer()\n this.unsubscribe()\n this.sessionLogger.info('stop: kill transport')\n this.transport?.end()\n if (error) {\n this.sessionLogger.info(`stop: emit error ${error.message}`)\n this.emit('error', error)\n } else {\n this.emit('done')\n }\n\n this.setState(SessionState.Stopped)\n this.onStopped(error ?? undefined)\n this.transport = null\n }\n\n /**\n * dispatches a message into the subclass that inherits from FixSession. The view contains\n * the parsed message which has utility methods such as toObject(). The Ascii session provides\n * an implementation to handle admin level messages such as logon, hearbeat and resest request.\n * Any application messges are dispatched via onApplicationMsg where the application can action\n * the message.\n * @param msgType the string based msg type the view represents\n * @param view container for all parsed fields representing the received message.\n * @protected\n */\n protected abstract onMsg (msgType: string, view: MsgView): void\n /**\n * the parsed txt recieved from the peer application. Given the applicaton is\n * responible for maintaining the fix log, this can be used to persist all received\n * messages.\n * @param msgType the string based msg type the view represents\n * @param txt the received message where for Ascii, the wire SOH delimeter is replaced\n * with that specified in the config e.g. '|'\n * @protected\n */\n protected abstract onDecoded (msgType: string, txt: string): void\n /**\n * the formatted txt sent to the peer application as an outbound message. Given the applicaton is\n * responible for maintaining the fix log, this can be used to persist all transmitted\n * messages. use msgType for example to persist only trade capture messages to database\n * @param msgType the msg type representing the message.\n * @param txt the sent message where for Ascii, the wire SOH delimeter is replaced\n * with that specified in the config e.g. '|'\n * @protected\n */\n protected abstract onEncoded (msgType: string, txt: string): void\n /**\n * typically all session level messages are handled by AsciiSession and these are\n * application level such as MarketDataRefresh. This will represent the applications main\n * work functiono where responses can be sent back to the peer. If manageSession has been set false\n * (not recommended) all messages are sent to this function\n * @param msgType the msg type representing the message.\n * @param view a wrapper containing the parsed message received.\n * @protected\n */\n protected abstract onApplicationMsg (msgType: string, view: MsgView): void\n /**\n * at this point the application is ready to send messages - peer login has been achieved\n * and the session can be considered ready to use. In the case of an initiator the application\n * may at this point send for security definitions or send market data subscriptions\n * @param view the login message causing session to be ready\n * @protected\n */\n protected abstract onReady (view: MsgView): void\n\n /**\n * Inform application this session has now ended - either from logout or connection dropped\n * @param error if session has been terminated via an error it is provided\n * @protected\n */\n protected abstract onStopped (error?: Error): void\n /**\n * Placeholder infomring the application of a peer login attempt.\n * @param view the login message\n * @param user extracted user from message\n * @param password extracted password from the message.\n * @protected\n */\n protected abstract onLogon (view: MsgView, user: string, password: string): boolean\n}\n"]}
|
|
1
|
+
{"version":3,"file":"fix-session.js","sourceRoot":"","sources":["../../../src/transport/session/fix-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { ElasticBuffer, MsgView } from '../../buffer'\nimport { IJsFixConfig, IJsFixLogger } from '../../config'\nimport { FixSessionState } from './fix-session-state'\nimport { MsgTransport } from '../factory'\nimport { MsgTag } from '../../types'\nimport { ILooseObject } from '../../collections/collection'\n\nimport * as events from 'events'\nimport { SessionState } from './session-state'\nimport { SegmentType } from '../../buffer/segment/segment-type'\n\n/**\n * The set of listeners this session attached to one specific transport.\n *\n * The handlers must be kept as stable references - `EventEmitter.removeListener`\n * matches on identity, so subscribing with a fresh closure and unsubscribing with\n * a method reference silently leaves the listener attached (issue #153). Holding\n * the transport alongside the handlers also lets `unsubscribe` detach from the\n * transport it actually subscribed to, even when `this.transport` has already\n * moved on to a newer connection.\n */\ninterface ITransportSubscription {\n readonly transport: MsgTransport\n readonly rxOnMsg: (msgType: string, view: MsgView) => void\n readonly rxOnError: (e: Error) => void\n readonly rxOnDone: () => void\n readonly rxOnEnd: () => void\n readonly rxOnDecoded: (msgType: string, data: ElasticBuffer, ptr: number) => void\n readonly txOnError: (e: Error) => void\n readonly txOnEncoded: (msgType: string, data: string, hdr: ILooseObject) => void\n}\n\nexport abstract class FixSession extends events.EventEmitter {\n public logReceivedMsgs: boolean = false\n protected timer: NodeJS.Timeout | null = null\n protected transport: MsgTransport | null = null\n private subscription: ITransportSubscription | null = null\n public manageSession: boolean = true\n public checkMsgIntegrity: boolean = false\n protected readonly me: string\n protected readonly initiator: boolean\n protected readonly acceptor: boolean\n protected readonly sessionState: FixSessionState\n /**\n * Not readonly: a wildcard acceptor does not know which counterparty it is\n * serving until the Logon arrives, and every session on that listener would\n * otherwise log under the same name. Rebound once the identity is known.\n */\n protected sessionLogger: IJsFixLogger\n protected requestLogoutType: string\n protected respondLogoutType: string\n protected requestLogonType: string\n\n protected constructor (public readonly config: IJsFixConfig) {\n super()\n const description = config.description\n this.me = description?.application?.name ?? 'me'\n this.sessionState = new FixSessionState(\n {\n heartBeat: config.description.HeartBtInt,\n lastPeerMsgSeqNum: config.description.LastReceivedSeqNum\n })\n this.sessionLogger = config.logFactory.logger(`${this.me}:FixSession`)\n this.initiator = description?.application?.type === 'initiator'\n this.acceptor = !this.initiator\n this.checkMsgIntegrity = this.acceptor\n this.sessionState.compId = description.SenderCompId\n }\n\n stateStr (theState: SessionState): string {\n return SessionState[theState]\n }\n\n assignState (newState: SessionState): void {\n const currentState = this.sessionState.state\n const currentStateStr = this.stateStr(currentState)\n const logger = this.sessionLogger\n const msg = `current state ${currentStateStr} (${currentState}) moves to ${SessionState[newState]} (${newState})`\n logger.info(msg)\n this.sessionState.state = newState\n }\n\n public setState (state: SessionState): void {\n const logger = this.sessionLogger\n const currentState = this.sessionState.state\n const currentStateStr = this.stateStr(currentState)\n if (state === currentState) return\n switch (currentState) {\n case SessionState.ConfirmingLogout:\n case SessionState.Stopped:\n if (state !== SessionState.NetworkConnectionEstablished) {\n logger.info(`ignoring request to change state as now already in ${currentStateStr}`)\n } else {\n this.assignState(state)\n }\n break\n\n default: {\n this.assignState(state)\n }\n }\n }\n\n public getState (): SessionState {\n return this.sessionState.state\n }\n\n public lastSentSeqNum (): number {\n return this.sessionState.lastSentSeqNum()\n }\n\n public lastPeerSeqNum (): number {\n return this.sessionState.lastPeerMsgSeqNum\n }\n\n public sendLogon (): void {\n const lo = this.config.factory?.logon()\n if (lo) {\n this.send(this.requestLogonType, lo)\n }\n }\n\n private async waitPromise (): Promise<number> {\n const logger = this.sessionLogger\n if (this.initiator) {\n // Hook for subclasses to reset sequences when ResetSeqNumFlag=Y is configured —\n // must run after the store is loaded, before sendLogon stamps a seq num.\n await this.onPreLogon()\n }\n return await new Promise<any>((resolve, reject) => {\n if (this.initiator) {\n logger.debug(`initiator sending logon state = ${this.stateString()}`)\n this.sendLogon()\n this.setState(SessionState.InitiationLogonSent)\n } else {\n logger.debug(`acceptor waits for logon state = ${this.stateString()}`)\n this.setState(SessionState.WaitingForALogon)\n }\n\n // Use named handlers and detach BOTH when the promise settles. Only one of\n // 'error'/'done' fires per run; without removing the sibling the unfired\n // listener would leak on every reconnect (issue #146). `once` alone is not\n // enough for the same reason — the sibling never fires, so never self-detaches.\n const cleanup = (): void => {\n this.removeListener('error', onError)\n this.removeListener('done', onDone)\n }\n const onError = (e: Error): void => {\n cleanup()\n // read the logger now, not the one captured when the run started - a\n // wildcard acceptor rebinds it once it knows which peer it is serving\n this.sessionLogger.error(e)\n reject(e)\n }\n const onDone = (): void => {\n cleanup()\n resolve(this.transport?.id)\n }\n\n this.on('error', onError)\n this.on('done', onDone)\n })\n }\n\n public async run (transport: MsgTransport): Promise<number> {\n const logger = this.sessionLogger\n if (this.transport) {\n logger.info(`reset from previous transport. state ${this.stateString()}`)\n this.reset()\n }\n this.transport = transport\n this.subscribe()\n return await this.waitPromise()\n }\n\n protected expectedEndState (): boolean {\n switch (this.sessionState.state) {\n case SessionState.Stopped:\n case SessionState.ConfirmingLogout:\n return true\n\n default:\n return false\n }\n }\n\n protected rxOnEnd (): void {\n const logger = this.sessionLogger\n logger.info(`rx end received sessionState = [${this.sessionState.toString()}]`)\n const expectedState = this.expectedEndState()\n if (expectedState) {\n logger.info(`rx receives end state = ${this.stateString()} - stop session`)\n this.stop()\n } else {\n this.setState(SessionState.DetectBrokenNetworkConnection)\n const e = new Error(`unexpected state - transport failed? = ${this.stateString()}`)\n logger.info(`rx error ${e.message}`)\n this.terminate(e)\n }\n }\n\n protected rxOnMsg (msgType: string, view: MsgView): void {\n const logger = this.sessionLogger\n\n if (this.logReceivedMsgs) {\n const name = view.segment.type !== SegmentType.Unknown ? view?.segment?.set?.name : 'unknown'\n logger.info(`${msgType}: ${name}`)\n logger.info(`${view.toString()}`)\n }\n this.sessionState.lastReceivedAt = new Date()\n if (this.manageSession) {\n this.onMsg(msgType, view)\n } else {\n this.checkForwardMsg(msgType, view)\n }\n }\n\n protected rxOnDone (): void {\n const logger = this.sessionLogger\n logger.info('rx done received')\n this.done()\n }\n\n protected rxOnError (e: Error): void {\n const logger = this.sessionLogger\n logger.warning(`rx error event: ${e.message} ${JSON.stringify(e)}`)\n this.terminate(e)\n }\n\n protected rxOnDecoded (msgType: string, data: ElasticBuffer, ptr: number): void {\n const logger = this.sessionLogger\n logger.debug(`rx: [${msgType}] ${ptr} bytes`)\n this.onDecoded(msgType, data.toString(ptr))\n }\n\n protected txOnError (e: Error): void {\n const logger = this.sessionLogger\n logger.warning(`tx error event: ${e.message} ${JSON.stringify(e)}`)\n this.terminate(e)\n }\n\n protected txOnEncoded (msgType: string, data: string, hdr: ILooseObject): void {\n const logger = this.sessionLogger\n this.sessionState.lastHeader = hdr\n logger.debug(`tx: [${msgType}] ${data.length} bytes seqNo = ${this.lastSentSeqNum()}`)\n this.onEncoded(msgType, data)\n }\n\n /**\n * true when the event which has just fired came from the transport this session\n * is currently running. A half open socket can keep emitting long after the peer\n * has reconnected on a fresh connection - those events must not be allowed to drive\n * the live session (issue #153).\n */\n private isCurrentTransport (transport: MsgTransport, event: string): boolean {\n if (this.subscription?.transport === transport && this.transport === transport) {\n return true\n }\n const current = this.transport?.id ?? 'none'\n this.sessionLogger.warning(`ignoring '${event}' from stale transport ${transport.id} - current transport is ${current}`)\n return false\n }\n\n protected unsubscribe (): void {\n const logger = this.sessionLogger\n const subscription = this.subscription\n if (!subscription) {\n logger.debug('unsubscribe called with no active subscription')\n return\n }\n const transport = subscription.transport\n logger.info(`unsubscribe transport ${transport.id} sessionState = [${this.sessionState.toString()}]`)\n const rx = transport.receiver\n const tx = transport.transmitter\n\n rx?.removeListener('msg', subscription.rxOnMsg)\n rx?.removeListener('error', subscription.rxOnError)\n rx?.removeListener('done', subscription.rxOnDone)\n rx?.removeListener('end', subscription.rxOnEnd)\n rx?.removeListener('decoded', subscription.rxOnDecoded)\n tx?.removeListener('error', subscription.txOnError)\n tx?.removeListener('encoded', subscription.txOnEncoded)\n this.subscription = null\n logger.debug(`unsubscribe complete - rx listeners now ${rx?.listenerCount('msg') ?? 0} msg, ${rx?.listenerCount('end') ?? 0} end`)\n }\n\n protected subscribe (): void {\n const transport = this.transport\n if (!transport) {\n this.sessionLogger.warning('subscribe called with no transport')\n return\n }\n // detach from any previous transport before attaching to this one\n if (this.subscription) {\n this.unsubscribe()\n }\n const inst = this\n const subscription: ITransportSubscription = {\n transport,\n rxOnMsg: (msgType: string, view: MsgView) => {\n if (inst.isCurrentTransport(transport, 'msg')) inst.rxOnMsg(msgType, view)\n },\n rxOnError: (e: Error) => {\n if (inst.isCurrentTransport(transport, 'error')) inst.rxOnError(e)\n },\n rxOnDone: () => {\n if (inst.isCurrentTransport(transport, 'done')) inst.rxOnDone()\n },\n rxOnEnd: () => {\n if (inst.isCurrentTransport(transport, 'end')) inst.rxOnEnd()\n },\n rxOnDecoded: (msgType: string, data: ElasticBuffer, ptr: number) => {\n if (inst.isCurrentTransport(transport, 'decoded')) inst.rxOnDecoded(msgType, data, ptr)\n },\n txOnError: (e: Error) => {\n if (inst.isCurrentTransport(transport, 'tx error')) inst.txOnError(e)\n },\n txOnEncoded: (msgType: string, data: string, hdr: ILooseObject) => {\n if (inst.isCurrentTransport(transport, 'encoded')) inst.txOnEncoded(msgType, data, hdr)\n }\n }\n const rx = transport.receiver\n const tx = transport.transmitter\n rx?.on('msg', subscription.rxOnMsg)\n rx?.on('error', subscription.rxOnError)\n rx?.on('done', subscription.rxOnDone)\n rx?.on('end', subscription.rxOnEnd)\n rx?.on('decoded', subscription.rxOnDecoded)\n tx?.on('error', subscription.txOnError)\n tx?.on('encoded', subscription.txOnEncoded)\n this.subscription = subscription\n this.sessionLogger.info(`subscribed to transport ${transport.id}`)\n }\n\n protected validStateApplicationMsg (): boolean {\n switch (this.sessionState.state) {\n case SessionState.Idle:\n case SessionState.InitiateConnection:\n case SessionState.InitiationLogonSent:\n case SessionState.WaitingForALogon:\n case SessionState.HandleResendRequest:\n case SessionState.AwaitingProcessingResponseToTestRequest:\n case SessionState.AwaitingProcessingResponseToResendRequest:\n return false\n default:\n return true\n }\n }\n\n protected stateString (): string {\n return SessionState[this.sessionState.state]\n }\n\n protected checkForwardMsg (msgType: string, view: MsgView): void {\n this.sessionLogger.info(`forwarding msgType = '${msgType}' to application`)\n this.setState(SessionState.ActiveNormalSession)\n this.onApplicationMsg(msgType, view)\n }\n\n private stopTimer (): void {\n if (this.timer) {\n this.sessionLogger.info('stopTimer')\n clearInterval(this.timer)\n this.timer = null\n }\n }\n\n protected terminate (error: Error): void {\n if (this.sessionState.state === SessionState.Stopped) return\n this.sessionLogger.error(error)\n this.stopTimer()\n this.unsubscribe()\n if (this.transport) {\n this.sessionLogger.info(`terminate: kill transport ${this.transport.id}`)\n this.transport.end()\n }\n this.transport = null\n this.setState(SessionState.Stopped)\n this.onSessionStopping()\n this.emit('error', error)\n this.onStopped(error)\n }\n\n protected peerLogout (view: MsgView): void {\n const msg = view.getString(MsgTag.Text)\n const state = this.sessionState.state\n switch (state) {\n case SessionState.WaitingLogoutConfirm: {\n this.sessionLogger.info(`peer confirms logout Text = '${msg}'`)\n this.stop()\n break\n }\n\n case SessionState.InitiationLogonResponse:\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonReceived: {\n this.setState(SessionState.ConfirmingLogout)\n this.sessionLogger.info(`peer initiates logout Text = '${msg}'`)\n this.sessionLogout()\n }\n }\n }\n\n protected send (msgType: string, obj: ILooseObject): void {\n const state = this.sessionState.state\n switch (state) {\n case SessionState.Stopped: {\n this.sessionLogger.warning(`can't send in state ${this.stateString()}`)\n break\n }\n\n default: {\n this.sessionState.LastSentAt = new Date()\n this.transport?.transmitter.send(msgType, obj)\n break\n }\n }\n }\n\n protected sendLogout (msg: string): void {\n const factory = this.config.factory\n this.sessionLogger.info(`sending logout with ${msg}`)\n const lo = factory?.logout(this.requestLogoutType, msg)\n if (lo) {\n this.send(this.requestLogoutType, lo)\n }\n }\n\n protected sessionLogout (): void {\n const sessionState = this.sessionState\n if (sessionState.logoutSentAt) {\n return\n }\n\n switch (sessionState.state) {\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonResponse:\n case SessionState.InitiationLogonReceived: {\n // this instance initiates logout\n this.setState(SessionState.WaitingLogoutConfirm)\n sessionState.logoutSentAt = new Date()\n const msg = `${this.me} initiate logout`\n this.sessionLogger.info(msg)\n this.sendLogout(msg)\n break\n }\n\n case SessionState.ConfirmingLogout: {\n // this instance responds to log out\n this.setState(SessionState.ConfirmingLogout)\n sessionState.logoutSentAt = new Date()\n const msg = `${this.me} confirming logout`\n this.sessionLogger.info(msg)\n this.sendLogout(msg)\n break\n }\n\n default: {\n this.sessionLogger.info(`sessionLogout ignored as in state ${sessionState.state}`)\n }\n }\n }\n\n public done (): void {\n switch (this.sessionState.state) {\n case SessionState.InitiationLogonResponse:\n case SessionState.ActiveNormalSession:\n case SessionState.InitiationLogonReceived: {\n this.sessionLogout()\n break\n }\n\n case SessionState.Stopped:\n this.sessionLogger.info('done. session is now stopped')\n break\n\n default: {\n this.stop()\n break\n }\n }\n this.sessionLogger.info(`done. check logout sequence state ${this.stateString()}`)\n }\n\n public reset (resetSeqNum?: number | null): void {\n this.stopTimer()\n // unsubscribe from old transport before clearing reference\n this.unsubscribe()\n // reset parser to clear any partial message state from dropped connection\n const receiver: any = this.transport?.receiver\n if (receiver?.reset) {\n receiver.reset()\n }\n this.transport = null\n const resetFlag = this.config.description.ResetSeqNumFlag\n const seqNum = resetFlag ? 0 : resetSeqNum ?? this.sessionState.lastPeerMsgSeqNum\n this.sessionState.reset(seqNum) // from header def ... eventually\n this.onPrepareForReconnect()\n this.setState(SessionState.NetworkConnectionEstablished)\n }\n\n protected onPrepareForReconnect (): void {\n // Override in subclass to reset coordinator/transient state\n }\n\n /**\n * Called once as the session moves to Stopped, before the application is informed\n * via onStopped. Override to release session scoped resources - the ascii session\n * uses this to remove itself from the session registry. Mirrors cspurefix\n * FixSession.OnSessionStopping.\n */\n protected onSessionStopping (): void {\n // Default no-op\n }\n\n /**\n * Called for initiators after the store is loaded but before the Logon is sent.\n * Override to reset sequences/store when ResetSeqNumFlag=Y so the Logon goes out\n * with MsgSeqNum=1 instead of the recovered sender seq num.\n */\n protected async onPreLogon (): Promise<void> {\n // Default no-op\n }\n\n /**\n * Stop this session on behalf of an external caller - typically the session registry\n * when a new connection for the same SessionId replaces this one, but equally an\n * application which has decided the peer is gone. Mirrors cspurefix\n * FixSession.RequestStop.\n * @param reason recorded in the session log and carried on the emitted error\n */\n public requestStop (reason: string): void {\n this.sessionLogger.info(`requestStop: ${reason}`)\n this.stop(new Error(reason))\n }\n\n protected stop (error: Error | null = null): void {\n if (this.sessionState.state === SessionState.Stopped) {\n return\n }\n this.stopTimer()\n this.unsubscribe()\n this.sessionLogger.info(`stop: kill transport ${this.transport?.id ?? 'none'}`)\n this.onSessionStopping()\n this.transport?.end()\n if (error) {\n this.sessionLogger.info(`stop: emit error ${error.message}`)\n this.emit('error', error)\n } else {\n this.emit('done')\n }\n\n this.setState(SessionState.Stopped)\n this.onStopped(error ?? undefined)\n this.transport = null\n }\n\n /**\n * dispatches a message into the subclass that inherits from FixSession. The view contains\n * the parsed message which has utility methods such as toObject(). The Ascii session provides\n * an implementation to handle admin level messages such as logon, hearbeat and resest request.\n * Any application messges are dispatched via onApplicationMsg where the application can action\n * the message.\n * @param msgType the string based msg type the view represents\n * @param view container for all parsed fields representing the received message.\n * @protected\n */\n protected abstract onMsg (msgType: string, view: MsgView): void\n /**\n * the parsed txt recieved from the peer application. Given the applicaton is\n * responible for maintaining the fix log, this can be used to persist all received\n * messages.\n * @param msgType the string based msg type the view represents\n * @param txt the received message where for Ascii, the wire SOH delimeter is replaced\n * with that specified in the config e.g. '|'\n * @protected\n */\n protected abstract onDecoded (msgType: string, txt: string): void\n /**\n * the formatted txt sent to the peer application as an outbound message. Given the applicaton is\n * responible for maintaining the fix log, this can be used to persist all transmitted\n * messages. use msgType for example to persist only trade capture messages to database\n * @param msgType the msg type representing the message.\n * @param txt the sent message where for Ascii, the wire SOH delimeter is replaced\n * with that specified in the config e.g. '|'\n * @protected\n */\n protected abstract onEncoded (msgType: string, txt: string): void\n /**\n * typically all session level messages are handled by AsciiSession and these are\n * application level such as MarketDataRefresh. This will represent the applications main\n * work functiono where responses can be sent back to the peer. If manageSession has been set false\n * (not recommended) all messages are sent to this function\n * @param msgType the msg type representing the message.\n * @param view a wrapper containing the parsed message received.\n * @protected\n */\n protected abstract onApplicationMsg (msgType: string, view: MsgView): void\n /**\n * at this point the application is ready to send messages - peer login has been achieved\n * and the session can be considered ready to use. In the case of an initiator the application\n * may at this point send for security definitions or send market data subscriptions\n * @param view the login message causing session to be ready\n * @protected\n */\n protected abstract onReady (view: MsgView): void\n\n /**\n * Inform application this session has now ended - either from logout or connection dropped\n * @param error if session has been terminated via an error it is provided\n * @protected\n */\n protected abstract onStopped (error?: Error): void\n /**\n * Placeholder infomring the application of a peer login attempt.\n * @param view the login message\n * @param user extracted user from message\n * @param password extracted password from the message.\n * @protected\n */\n protected abstract onLogon (view: MsgView, user: string, password: string): boolean\n}\n"]}
|
|
@@ -26,4 +26,6 @@ __exportStar(require("./session-sequence-coordinator"), exports);
|
|
|
26
26
|
__exportStar(require("./session-sequence-store"), exports);
|
|
27
27
|
__exportStar(require("./resend-request-manager"), exports);
|
|
28
28
|
__exportStar(require("./fix-clock"), exports);
|
|
29
|
+
__exportStar(require("./session-registry"), exports);
|
|
30
|
+
__exportStar(require("./clone-session-description"), exports);
|
|
29
31
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/session/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAuC;AACvC,gDAA6B;AAC7B,sDAAmC;AACnC,qDAAkC;AAClC,2DAAwC;AACxC,wDAAqC;AACrC,wDAAqC;AACrC,kDAA+B;AAC/B,iEAA8C;AAC9C,2DAAwC;AACxC,2DAAwC;AACxC,8CAA2B","sourcesContent":["export * from './a-session-msg-factory'\nexport * from './fix-session'\nexport * from './fix-session-state'\nexport * from './make-fix-session'\nexport * from './session-50-description'\nexport * from './session-description'\nexport * from './session-msg-factory'\nexport * from './session-state'\nexport * from './session-sequence-coordinator'\nexport * from './session-sequence-store'\nexport * from './resend-request-manager'\nexport * from './fix-clock'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/transport/session/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0DAAuC;AACvC,gDAA6B;AAC7B,sDAAmC;AACnC,qDAAkC;AAClC,2DAAwC;AACxC,wDAAqC;AACrC,wDAAqC;AACrC,kDAA+B;AAC/B,iEAA8C;AAC9C,2DAAwC;AACxC,2DAAwC;AACxC,8CAA2B;AAC3B,qDAAkC;AAClC,8DAA2C","sourcesContent":["export * from './a-session-msg-factory'\nexport * from './fix-session'\nexport * from './fix-session-state'\nexport * from './make-fix-session'\nexport * from './session-50-description'\nexport * from './session-description'\nexport * from './session-msg-factory'\nexport * from './session-state'\nexport * from './session-sequence-coordinator'\nexport * from './session-sequence-store'\nexport * from './resend-request-manager'\nexport * from './fix-clock'\nexport * from './session-registry'\nexport * from './clone-session-description'\n"]}
|
|
@@ -12,4 +12,5 @@ export interface ISessionMsgFactory {
|
|
|
12
12
|
heartbeat: (testReqId: string) => ILooseObject;
|
|
13
13
|
header: (msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>) => ILooseObject;
|
|
14
14
|
trailer: (checksum: number) => ILooseObject;
|
|
15
|
+
cloneFor?: (description: ISessionDescription) => ISessionMsgFactory;
|
|
15
16
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/session/session-msg-factory.ts"],"names":[],"mappings":"","sourcesContent":["import { ILooseObject } from '../../collections/collection'\nimport { IStandardHeader } from '../../types/FIX4.4/repo'\nimport { ISessionDescription } from './session-description'\n\nexport interface ISessionMsgFactory {\n description: ISessionDescription\n reject: (msgType: string, seqNo: number, msg: string, reason: number) => ILooseObject\n logout: (msgType: string, text: string) => ILooseObject\n logon: (userRequestId?: string, isResponse?: boolean) => ILooseObject\n testRequest: (reqId?: string) => ILooseObject\n resendRequest: (from: number, to: number) => ILooseObject\n sequenceReset: (newSeq: number, gapFill?: boolean) => ILooseObject\n heartbeat: (testReqId: string) => ILooseObject\n header: (msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>) => ILooseObject\n trailer: (checksum: number) => ILooseObject\n}\n"]}
|
|
1
|
+
{"version":3,"file":"session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/session/session-msg-factory.ts"],"names":[],"mappings":"","sourcesContent":["import { ILooseObject } from '../../collections/collection'\nimport { IStandardHeader } from '../../types/FIX4.4/repo'\nimport { ISessionDescription } from './session-description'\n\nexport interface ISessionMsgFactory {\n description: ISessionDescription\n reject: (msgType: string, seqNo: number, msg: string, reason: number) => ILooseObject\n logout: (msgType: string, text: string) => ILooseObject\n logon: (userRequestId?: string, isResponse?: boolean) => ILooseObject\n testRequest: (reqId?: string) => ILooseObject\n resendRequest: (from: number, to: number) => ILooseObject\n sequenceReset: (newSeq: number, gapFill?: boolean) => ILooseObject\n heartbeat: (testReqId: string) => ILooseObject\n header: (msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>) => ILooseObject\n trailer: (checksum: number) => ILooseObject\n /**\n * Produce a factory of this same kind bound to another session description.\n *\n * An acceptor builds one of these per accepted connection, because the outbound\n * header carries that session's comp ids - and under a wildcard TargetCompID the\n * target is not known until the peer logs on. Implementing this is what lets an\n * application's own factory survive into those per-session scopes; without it the\n * acceptor can only fall back to the stock factory for the protocol.\n *\n * ASessionMsgFactory supplies a default that reconstructs via the concrete\n * constructor, so a subclass taking (description, mutator) needs to do nothing.\n */\n cloneFor?: (description: ISessionDescription) => ISessionMsgFactory\n}\n"]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SessionId } from '../../store/session-id';
|
|
2
|
+
import { JsFixLoggerFactory } from '../../config/js-fix-logger-factory';
|
|
3
|
+
export interface IStoppableSession {
|
|
4
|
+
requestStop: (reason: string) => void;
|
|
5
|
+
}
|
|
6
|
+
export interface ISessionRegistry {
|
|
7
|
+
register: (sessionId: SessionId, session: IStoppableSession) => boolean;
|
|
8
|
+
unregister: (sessionId: SessionId, session: IStoppableSession) => void;
|
|
9
|
+
readonly count: number;
|
|
10
|
+
keys: () => string[];
|
|
11
|
+
get: (sessionId: SessionId) => IStoppableSession | null;
|
|
12
|
+
}
|
|
13
|
+
export declare const REPLACED_BY_NEW_CONNECTION = "replaced by new connection - stopping old session with stale transport";
|
|
14
|
+
export declare class SessionRegistry implements ISessionRegistry {
|
|
15
|
+
private readonly sessions;
|
|
16
|
+
private readonly logger;
|
|
17
|
+
constructor(logFactory?: JsFixLoggerFactory);
|
|
18
|
+
get count(): number;
|
|
19
|
+
keys(): string[];
|
|
20
|
+
get(sessionId: SessionId): IStoppableSession | null;
|
|
21
|
+
register(sessionId: SessionId, session: IStoppableSession): boolean;
|
|
22
|
+
unregister(sessionId: SessionId, session: IStoppableSession): void;
|
|
23
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SessionRegistry = exports.REPLACED_BY_NEW_CONNECTION = void 0;
|
|
4
|
+
exports.REPLACED_BY_NEW_CONNECTION = 'replaced by new connection - stopping old session with stale transport';
|
|
5
|
+
class SessionRegistry {
|
|
6
|
+
constructor(logFactory) {
|
|
7
|
+
var _a;
|
|
8
|
+
this.sessions = new Map();
|
|
9
|
+
this.logger = (_a = logFactory === null || logFactory === void 0 ? void 0 : logFactory.logger('SessionRegistry')) !== null && _a !== void 0 ? _a : null;
|
|
10
|
+
}
|
|
11
|
+
get count() {
|
|
12
|
+
return this.sessions.size;
|
|
13
|
+
}
|
|
14
|
+
keys() {
|
|
15
|
+
return Array.from(this.sessions.keys());
|
|
16
|
+
}
|
|
17
|
+
get(sessionId) {
|
|
18
|
+
var _a;
|
|
19
|
+
return (_a = this.sessions.get(sessionId.toString())) !== null && _a !== void 0 ? _a : null;
|
|
20
|
+
}
|
|
21
|
+
register(sessionId, session) {
|
|
22
|
+
const key = sessionId.toString();
|
|
23
|
+
const logger = this.logger;
|
|
24
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`register called for SessionId=${key}, activeSessions=${this.sessions.size}`);
|
|
25
|
+
const existing = this.sessions.get(key);
|
|
26
|
+
let stoppedOld = false;
|
|
27
|
+
if (existing && existing !== session) {
|
|
28
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`FOUND EXISTING SESSION for ${key} - this is a reconnection scenario`);
|
|
29
|
+
logger === null || logger === void 0 ? void 0 : logger.info('stopping old session to prevent stale transport writes');
|
|
30
|
+
this.sessions.set(key, session);
|
|
31
|
+
existing.requestStop(exports.REPLACED_BY_NEW_CONNECTION);
|
|
32
|
+
stoppedOld = true;
|
|
33
|
+
logger === null || logger === void 0 ? void 0 : logger.info('old session stopped, new session registered');
|
|
34
|
+
}
|
|
35
|
+
else if (existing === session) {
|
|
36
|
+
logger === null || logger === void 0 ? void 0 : logger.debug(`same session instance already registered for ${key}`);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`no existing session found - registering new session: ${key}`);
|
|
40
|
+
this.sessions.set(key, session);
|
|
41
|
+
}
|
|
42
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`register complete for ${key}: stoppedOldSession=${stoppedOld}, totalActiveSessions=${this.sessions.size}`);
|
|
43
|
+
return stoppedOld;
|
|
44
|
+
}
|
|
45
|
+
unregister(sessionId, session) {
|
|
46
|
+
const key = sessionId.toString();
|
|
47
|
+
const logger = this.logger;
|
|
48
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`unregister called for SessionId=${key}`);
|
|
49
|
+
if (this.sessions.get(key) === session) {
|
|
50
|
+
this.sessions.delete(key);
|
|
51
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`successfully unregistered session: ${key}, remainingActiveSessions=${this.sessions.size}`);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
logger === null || logger === void 0 ? void 0 : logger.info(`session NOT unregistered (already replaced by new connection or not found): ${key}`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.SessionRegistry = SessionRegistry;
|
|
59
|
+
//# sourceMappingURL=session-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../../../src/transport/session/session-registry.ts"],"names":[],"mappings":"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","sourcesContent":["import { SessionId } from '../../store/session-id'\nimport { IJsFixLogger } from '../../config/js-fix-logger'\nimport { JsFixLoggerFactory } from '../../config/js-fix-logger-factory'\n\n/**\n * The registry only ever needs to ask a session to stop, so it is typed against\n * that capability rather than against FixSession. IJsFixConfig carries a registry,\n * and FixSession is constructed from IJsFixConfig - depending on the concrete class\n * here would close an import cycle.\n */\nexport interface IStoppableSession {\n requestStop: (reason: string) => void\n}\n\n/**\n * Tracks the live session for each SessionId served by an acceptor.\n *\n * FIX allows exactly one active session per (BeginString, SenderCompID,\n * TargetCompID). A counterparty whose socket has gone half open - no FIN, no RST,\n * so node never raises 'end' - will happily open a second connection and log on\n * again. Without a registry the acceptor then runs two sessions for one CompID\n * pair, both writing to the same message store and both stamping sequence numbers,\n * which corrupts the store and produces sequence errors the peer cannot recover\n * from. See https://github.com/TimelordUK/jspurefix/issues/153.\n *\n * Ported from cspurefix PureFix.Transport/Session/SessionRegistry.cs.\n */\nexport interface ISessionRegistry {\n /**\n * Claim this SessionId for the given session. Any *different* session already\n * holding it is stopped first, because its transport is by definition stale.\n * @returns true when an existing session was stopped\n */\n register: (sessionId: SessionId, session: IStoppableSession) => boolean\n /**\n * Release this SessionId. A no-op unless the registered session is this exact\n * instance - a session which has already been replaced must not evict its\n * successor on the way out.\n */\n unregister: (sessionId: SessionId, session: IStoppableSession) => void\n /** number of live sessions */\n readonly count: number\n /** the SessionId keys currently held, for logging and diagnostics */\n keys: () => string[]\n get: (sessionId: SessionId) => IStoppableSession | null\n}\n\nexport const REPLACED_BY_NEW_CONNECTION =\n 'replaced by new connection - stopping old session with stale transport'\n\nexport class SessionRegistry implements ISessionRegistry {\n private readonly sessions = new Map<string, IStoppableSession>()\n private readonly logger: IJsFixLogger | null\n\n constructor (logFactory?: JsFixLoggerFactory) {\n this.logger = logFactory?.logger('SessionRegistry') ?? null\n }\n\n public get count (): number {\n return this.sessions.size\n }\n\n public keys (): string[] {\n return Array.from(this.sessions.keys())\n }\n\n public get (sessionId: SessionId): IStoppableSession | null {\n return this.sessions.get(sessionId.toString()) ?? null\n }\n\n public register (sessionId: SessionId, session: IStoppableSession): boolean {\n const key = sessionId.toString()\n const logger = this.logger\n logger?.info(`register called for SessionId=${key}, activeSessions=${this.sessions.size}`)\n\n const existing = this.sessions.get(key)\n let stoppedOld = false\n\n if (existing && existing !== session) {\n logger?.info(`FOUND EXISTING SESSION for ${key} - this is a reconnection scenario`)\n logger?.info('stopping old session to prevent stale transport writes')\n this.sessions.set(key, session)\n // stop after re-pointing the map so the old session's unregister (which runs\n // synchronously inside requestStop) sees it is no longer the holder\n existing.requestStop(REPLACED_BY_NEW_CONNECTION)\n stoppedOld = true\n logger?.info('old session stopped, new session registered')\n } else if (existing === session) {\n logger?.debug(`same session instance already registered for ${key}`)\n } else {\n logger?.info(`no existing session found - registering new session: ${key}`)\n this.sessions.set(key, session)\n }\n\n logger?.info(`register complete for ${key}: stoppedOldSession=${stoppedOld}, totalActiveSessions=${this.sessions.size}`)\n return stoppedOld\n }\n\n public unregister (sessionId: SessionId, session: IStoppableSession): void {\n const key = sessionId.toString()\n const logger = this.logger\n logger?.info(`unregister called for SessionId=${key}`)\n\n if (this.sessions.get(key) === session) {\n this.sessions.delete(key)\n logger?.info(`successfully unregistered session: ${key}, remainingActiveSessions=${this.sessions.size}`)\n } else {\n // expected when a new connection has already taken this SessionId over\n logger?.info(`session NOT unregistered (already replaced by new connection or not found): ${key}`)\n }\n }\n}\n"]}
|
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import { IJsFixConfig } from '../../config';
|
|
2
2
|
import { FixEntity } from '../fix-entity';
|
|
3
|
+
import { ISessionRegistry } from '../session/session-registry';
|
|
3
4
|
export declare class TcpAcceptorListener extends FixEntity {
|
|
4
5
|
readonly config: IJsFixConfig;
|
|
5
6
|
private acceptor;
|
|
6
7
|
private resolveStart;
|
|
8
|
+
readonly sessionRegistry: ISessionRegistry;
|
|
7
9
|
constructor(config: IJsFixConfig);
|
|
8
10
|
start(): Promise<any>;
|
|
11
|
+
private census;
|
|
9
12
|
stop(): void;
|
|
10
13
|
}
|