jspurefix 5.10.5 → 5.10.6
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/README.md +24 -0
- package/dist/transport/ascii/ascii-session-msg-factory.d.ts +1 -1
- package/dist/transport/ascii/ascii-session-msg-factory.js +2 -2
- package/dist/transport/ascii/ascii-session-msg-factory.js.map +1 -1
- package/dist/transport/ascii/ascii-session.d.ts +6 -0
- package/dist/transport/ascii/ascii-session.js +72 -8
- package/dist/transport/ascii/ascii-session.js.map +1 -1
- package/dist/transport/session/fix-session.d.ts +1 -1
- package/dist/transport/session/fix-session.js.map +1 -1
- package/jsfix.test_client.txt +62 -62
- package/jsfix.test_server.txt +72 -72
- package/package.json +1 -1
- package/src/transport/ascii/ascii-session-msg-factory.ts +8 -2
- package/src/transport/ascii/ascii-session.ts +115 -7
- package/src/transport/session/fix-session.ts +12 -2
package/README.md
CHANGED
|
@@ -13,6 +13,7 @@ A fast, fully native TypeScript [FIX protocol](https://www.fixtrading.org/) engi
|
|
|
13
13
|
- [Quickstart](#quickstart)
|
|
14
14
|
- [Session Configuration](#session-configuration)
|
|
15
15
|
- [Customising the Logon](#customising-the-logon)
|
|
16
|
+
- [Accepting or refusing a logon](#accepting-or-refusing-a-logon)
|
|
16
17
|
- [TLS](#tls)
|
|
17
18
|
- [Body length padding](#body-length-padding)
|
|
18
19
|
- [Persistence & Recovery](#persistence--recovery)
|
|
@@ -168,6 +169,29 @@ Most counterparties want a tag on the Logon the standard message does not carry.
|
|
|
168
169
|
|
|
169
170
|
A field named here must also be declared on `Logon` in the dictionary the session loads, or the encoder has no tag to write it to and will say so in the log. For values computed at run time, or for a header a counterparty stamps differently, supply your own session message factory. See [docs/custom-logon.md](docs/custom-logon.md) for the whole picture.
|
|
170
171
|
|
|
172
|
+
### Accepting or refusing a logon
|
|
173
|
+
|
|
174
|
+
`onLogon` is where an acceptor decides who gets a session. Return `true` to let the handshake finish; return `false` and the peer is sent a `Logout` explaining why and then disconnected — `onReady` is never reached and no heartbeat starts. The application learns the outcome through `onStopped(error)`.
|
|
175
|
+
|
|
176
|
+
```ts
|
|
177
|
+
protected onLogon (view: MsgView, user: string, password: string): boolean {
|
|
178
|
+
return user === 'js-client' && password === this.expectedPassword
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
Credentials usually have to be checked against something the engine cannot wait on synchronously — an http api, a database, a secrets store. Return a promise and the session waits for it:
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
protected async onLogon (view: MsgView, user: string, password: string): Promise<boolean> {
|
|
186
|
+
const account = await this.directory.lookup(user)
|
|
187
|
+
return account?.enabled === true && await account.verify(password)
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
While that promise is pending the transport is paused and anything the peer sends is queued, then replayed in order once the verdict arrives — a counterparty that pipelines messages behind its Logon will not have them dropped or reordered. If the promise rejects, the logon is refused rather than allowed through, and the rejection message is carried to the peer.
|
|
192
|
+
|
|
193
|
+
An initiator can use the same hook: there `onLogon` fires on the acceptor's logon response, so returning `false` refuses the counterparty that answered.
|
|
194
|
+
|
|
171
195
|
### TLS
|
|
172
196
|
|
|
173
197
|
Add a `tls` block under `application.tcp`. The `ca` field is only needed for self-signed certificates; commercial vendors will supply this for you. `script/getKey.ps1` will generate a self-signed CA + client/server pair (requires `openssl` on the path).
|
|
@@ -6,7 +6,7 @@ export declare class AsciiSessionMsgFactory extends ASessionMsgFactory {
|
|
|
6
6
|
readonly description: ISessionDescription;
|
|
7
7
|
constructor(description: ISessionDescription, mutator?: ObjectMutator | null);
|
|
8
8
|
logon(): ILooseObject;
|
|
9
|
-
logout(text: string): ILooseObject;
|
|
9
|
+
logout(msgType: string, text: string): ILooseObject;
|
|
10
10
|
header(msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>): ILooseObject;
|
|
11
11
|
}
|
|
12
12
|
export declare class SessionMsgFactory extends AsciiSessionMsgFactory {
|
|
@@ -16,11 +16,11 @@ class AsciiSessionMsgFactory extends a_session_msg_factory_1.ASessionMsgFactory
|
|
|
16
16
|
const o = Object.assign({ Username: description.Username, Password: description.Password, HeartBtInt: description.HeartBtInt, ResetSeqNumFlag: description.ResetSeqNumFlag, EncryptMethod: repo_1.EncryptMethod.None }, description.Logon);
|
|
17
17
|
return this.mutate(o, types_1.MsgType.Logon);
|
|
18
18
|
}
|
|
19
|
-
logout(text) {
|
|
19
|
+
logout(msgType, text) {
|
|
20
20
|
const o = {
|
|
21
21
|
Text: text
|
|
22
22
|
};
|
|
23
|
-
return this.mutate(o, types_1.MsgType.Logout);
|
|
23
|
+
return this.mutate(o, msgType !== null && msgType !== void 0 ? msgType : types_1.MsgType.Logout);
|
|
24
24
|
}
|
|
25
25
|
header(msgType, seqNum, time, overrideData) {
|
|
26
26
|
var _a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascii-session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/ascii/ascii-session-msg-factory.ts"],"names":[],"mappings":";;;AAEA,uCAAqC;AACrC,4EAAoF;AAEpF,kDAKgC;AAEhC,MAAa,sBAAuB,SAAQ,0CAAkB;IAC5D,YAAsB,WAAgC,EAAE,UAAgC,IAAI;;QAC1F,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QADP,gBAAW,GAAX,WAAW,CAAqB;QAEpD,IAAI,CAAC,OAAO,GAAG,CAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,MAAK,OAAO,CAAA;IAC9D,CAAC;IAEM,KAAK;QACV,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QACpC,MAAM,CAAC,GAAW,gBAChB,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAC9B,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,EAClC,eAAe,EAAE,WAAW,CAAC,eAAe,EAC5C,aAAa,EAAE,oBAAa,CAAC,IAAI,IAK9B,WAAW,CAAC,KAAK,CACX,CAAA;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,KAAK,CAAC,CAAA;IACtC,CAAC;
|
|
1
|
+
{"version":3,"file":"ascii-session-msg-factory.js","sourceRoot":"","sources":["../../../src/transport/ascii/ascii-session-msg-factory.ts"],"names":[],"mappings":";;;AAEA,uCAAqC;AACrC,4EAAoF;AAEpF,kDAKgC;AAEhC,MAAa,sBAAuB,SAAQ,0CAAkB;IAC5D,YAAsB,WAAgC,EAAE,UAAgC,IAAI;;QAC1F,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QADP,gBAAW,GAAX,WAAW,CAAqB;QAEpD,IAAI,CAAC,OAAO,GAAG,CAAA,MAAA,WAAW,CAAC,WAAW,0CAAE,QAAQ,MAAK,OAAO,CAAA;IAC9D,CAAC;IAEM,KAAK;QACV,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QACpC,MAAM,CAAC,GAAW,gBAChB,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAC9B,QAAQ,EAAE,WAAW,CAAC,QAAQ,EAC9B,UAAU,EAAE,WAAW,CAAC,UAAU,EAClC,eAAe,EAAE,WAAW,CAAC,eAAe,EAC5C,aAAa,EAAE,oBAAa,CAAC,IAAI,IAK9B,WAAW,CAAC,KAAK,CACX,CAAA;QACX,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,eAAO,CAAC,KAAK,CAAC,CAAA;IACtC,CAAC;IAQM,MAAM,CAAE,OAAe,EAAE,IAAY;QAC1C,MAAM,CAAC,GAAY;YACjB,IAAI,EAAE,IAAI;SACA,CAAA;QACZ,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,OAAO,aAAP,OAAO,cAAP,OAAO,GAAI,eAAO,CAAC,MAAM,CAAC,CAAA;IAClD,CAAC;IAEM,MAAM,CAAE,OAAe,EAAE,MAAc,EAAE,IAAU,EAAE,YAAuC;;QACjG,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAA;QACpC,MAAM,UAAU,GAAW,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,MAAA,WAAW,CAAC,eAAe,mCAAI,CAAC,CAAC,CAAA;QACxE,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC,GAAG,CAAC,CAAA;QACpD,MAAM,CAAC,mBACL,WAAW,EAAE,WAAW,CAAC,WAAW,EACpC,UAAU,EAAE,WAAW,EACvB,OAAO,EAAE,OAAO,EAChB,YAAY,EAAE,WAAW,CAAC,YAAY,EACtC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,IAAI,EACjB,YAAY,EAAE,WAAW,CAAC,YAAY,EACtC,WAAW,EAAE,WAAW,CAAC,WAAW,EACpC,WAAW,EAAE,WAAW,CAAC,WAAW,IACjC,YAAY,CAChB,CAAA;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAA;IACzC,CAAC;CACF;AAtDD,wDAsDC;AAED,MAAa,iBAAkB,SAAQ,sBAAsB;IAC3D,YAA6B,WAAgC,EAAS,UAAgC,IAAI;QACxG,KAAK,CAAC,WAAW,EAAE,OAAO,CAAC,CAAA;QADA,gBAAW,GAAX,WAAW,CAAqB;QAAS,YAAO,GAAP,OAAO,CAA6B;IAE1G,CAAC;CACF;AAJD,8CAIC","sourcesContent":["import { ISessionDescription } from '../session/session-description'\nimport { ILooseObject } from '../../collections/collection'\nimport { MsgType } from '../../types'\nimport { ASessionMsgFactory, ObjectMutator } from '../session/a-session-msg-factory'\n\nimport {\n EncryptMethod,\n ILogon,\n ILogout,\n IStandardHeader\n} from '../../types/FIX4.4/repo'\n\nexport class AsciiSessionMsgFactory extends ASessionMsgFactory {\n constructor (readonly description: ISessionDescription, mutator: ObjectMutator | null = null) {\n super(description, mutator)\n this.isAscii = description.application?.protocol === 'ascii'\n }\n\n public logon (): ILooseObject {\n const description = this.description\n const o: ILogon = {\n Username: description.Username,\n Password: description.Password,\n HeartBtInt: description.HeartBtInt,\n ResetSeqNumFlag: description.ResetSeqNumFlag,\n EncryptMethod: EncryptMethod.None,\n // a counterparty demanding a tag the standard Logon does not carry needs no\n // code at all - name it under \"Logon\" in the session description. Spread last\n // so an application can also override what the engine derived, or null out a\n // field it does not want sent. See issue #93.\n ...description.Logon\n } as ILogon\n return this.mutate(o, MsgType.Logon)\n }\n\n /**\n * ISessionMsgFactory declares logout (msgType, text) and FixSession calls it that\n * way. This override used to take the text alone, so it silently bound the msg\n * type to Text and every Logout jspurefix sent carried '58=5' in place of the\n * reason - the caller's message was dropped on the floor.\n */\n public logout (msgType: string, text: string): ILooseObject {\n const o: ILogout = {\n Text: text\n } as ILogout\n return this.mutate(o, msgType ?? MsgType.Logout)\n }\n\n public header (msgType: string, seqNum: number, time: Date, overrideData?: Partial<IStandardHeader>): ILooseObject {\n const description = this.description\n const bodyLength: number = Math.max(4, description.BodyLengthChars ?? 7)\n const placeHolder = Math.pow(10, bodyLength - 1) + 1\n const o: IStandardHeader = {\n BeginString: description.BeginString,\n BodyLength: placeHolder,\n MsgType: msgType,\n SenderCompID: description.SenderCompId,\n MsgSeqNum: seqNum,\n SendingTime: time,\n TargetCompID: description.TargetCompID,\n TargetSubID: description.TargetSubID,\n SenderSubID: description.SenderSubID,\n ...overrideData\n }\n return this.mutate(o, 'StandardHeader')\n }\n}\n\nexport class SessionMsgFactory extends AsciiSessionMsgFactory {\n constructor (public readonly description: ISessionDescription, public mutator: ObjectMutator | null = null) {\n super(description, mutator)\n }\n}\n"]}
|
|
@@ -18,6 +18,7 @@ export declare abstract class AsciiSession extends FixSession {
|
|
|
18
18
|
protected readonly wildcardTarget: boolean;
|
|
19
19
|
private identityBound;
|
|
20
20
|
private bindInProgress;
|
|
21
|
+
private logonVerdictPending;
|
|
21
22
|
private readonly pendingRx;
|
|
22
23
|
private readonly clock;
|
|
23
24
|
protected constructor(config: IJsFixConfig);
|
|
@@ -42,11 +43,16 @@ export declare abstract class AsciiSession extends FixSession {
|
|
|
42
43
|
protected onSessionMsg(msgType: string, view: MsgView): void;
|
|
43
44
|
protected onMsg(msgType: string, view: MsgView): void;
|
|
44
45
|
private onMsgBeforeIdentity;
|
|
46
|
+
private rxGated;
|
|
47
|
+
private resumeRx;
|
|
45
48
|
private drainPendingRx;
|
|
46
49
|
private bindIdentity;
|
|
47
50
|
private dispatchMsg;
|
|
48
51
|
private startTimer;
|
|
49
52
|
private peerLogon;
|
|
53
|
+
private awaitLogonVerdict;
|
|
54
|
+
private completePeerLogon;
|
|
55
|
+
private rejectLogon;
|
|
50
56
|
private sendTestRequest;
|
|
51
57
|
private sendHeartbeat;
|
|
52
58
|
private tick;
|
|
@@ -29,6 +29,7 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
29
29
|
this.store = null;
|
|
30
30
|
this.registered = false;
|
|
31
31
|
this.bindInProgress = false;
|
|
32
|
+
this.logonVerdictPending = false;
|
|
32
33
|
this.pendingRx = [];
|
|
33
34
|
this.clock = new fix_clock_1.DefaultFixClock();
|
|
34
35
|
this.requestLogoutType = this.respondLogoutType = types_1.MsgType.Logout;
|
|
@@ -419,6 +420,11 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
419
420
|
this.onMsgBeforeIdentity(msgType, view);
|
|
420
421
|
return;
|
|
421
422
|
}
|
|
423
|
+
if (this.logonVerdictPending) {
|
|
424
|
+
this.sessionLogger.info(`queueing '${msgType}' received while awaiting logon verdict`);
|
|
425
|
+
this.pendingRx.push({ msgType, view: view.clone() });
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
422
428
|
this.dispatchMsg(msgType, view);
|
|
423
429
|
}
|
|
424
430
|
onMsgBeforeIdentity(msgType, view) {
|
|
@@ -441,20 +447,34 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
441
447
|
const logon = view.clone();
|
|
442
448
|
(_b = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.duplex.readable) === null || _b === void 0 ? void 0 : _b.pause();
|
|
443
449
|
this.bindIdentity(peerCompId).then(() => {
|
|
444
|
-
var _a, _b;
|
|
445
450
|
this.bindInProgress = false;
|
|
446
451
|
this.identityBound = true;
|
|
447
452
|
this.dispatchMsg(types_1.MsgType.Logon, logon);
|
|
448
|
-
this.
|
|
449
|
-
(_b = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.duplex.readable) === null || _b === void 0 ? void 0 : _b.resume();
|
|
453
|
+
this.resumeRx();
|
|
450
454
|
}).catch((e) => {
|
|
451
455
|
this.bindInProgress = false;
|
|
452
456
|
this.pendingRx.length = 0;
|
|
453
457
|
this.terminate(new Error(`failed to bind session identity for peer '${peerCompId}': ${e.message}`));
|
|
454
458
|
});
|
|
455
459
|
}
|
|
460
|
+
rxGated() {
|
|
461
|
+
return this.bindInProgress || this.logonVerdictPending;
|
|
462
|
+
}
|
|
463
|
+
resumeRx() {
|
|
464
|
+
var _a, _b;
|
|
465
|
+
if (this.rxGated())
|
|
466
|
+
return;
|
|
467
|
+
this.drainPendingRx();
|
|
468
|
+
if (this.rxGated())
|
|
469
|
+
return;
|
|
470
|
+
(_b = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.duplex.readable) === null || _b === void 0 ? void 0 : _b.resume();
|
|
471
|
+
}
|
|
456
472
|
drainPendingRx() {
|
|
457
473
|
while (this.pendingRx.length > 0) {
|
|
474
|
+
if (this.rxGated()) {
|
|
475
|
+
this.sessionLogger.info('suspending replay - logon handshake gated again');
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
458
478
|
const queued = this.pendingRx.shift();
|
|
459
479
|
if (!queued)
|
|
460
480
|
break;
|
|
@@ -528,7 +548,7 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
528
548
|
}, interval);
|
|
529
549
|
}
|
|
530
550
|
peerLogon(view) {
|
|
531
|
-
var _a, _b
|
|
551
|
+
var _a, _b;
|
|
532
552
|
const logger = this.sessionLogger;
|
|
533
553
|
const [heartBtInt, peerCompId, userName, password] = view.getTypedTags([types_1.MsgTag.HeartBtInt, types_1.MsgTag.SenderCompID, types_1.MsgTag.Username, types_1.MsgTag.Password]);
|
|
534
554
|
const resetSeqNumFlag = view.getTyped(types_1.MsgTag.ResetSeqNumFlag);
|
|
@@ -557,18 +577,57 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
557
577
|
const state = this.sessionState;
|
|
558
578
|
state.peerHeartBeatSecs = view.getTyped(types_1.MsgTag.HeartBtInt);
|
|
559
579
|
state.peerCompId = view.getTyped(types_1.MsgTag.SenderCompID);
|
|
560
|
-
const
|
|
561
|
-
|
|
580
|
+
const verdict = this.onLogon(view, userName, password);
|
|
581
|
+
if (typeof verdict === 'boolean') {
|
|
582
|
+
this.completePeerLogon(view, verdict, resetSeqNumFlag);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
this.awaitLogonVerdict(view, verdict, resetSeqNumFlag);
|
|
586
|
+
}
|
|
587
|
+
awaitLogonVerdict(view, verdict, peerReset) {
|
|
588
|
+
var _a, _b;
|
|
589
|
+
const logger = this.sessionLogger;
|
|
590
|
+
logger.info('onLogon returned a promise - awaiting logon verdict');
|
|
591
|
+
this.logonVerdictPending = true;
|
|
592
|
+
const logon = view.clone();
|
|
593
|
+
(_b = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.duplex.readable) === null || _b === void 0 ? void 0 : _b.pause();
|
|
594
|
+
verdict.then((accepted) => {
|
|
595
|
+
this.logonVerdictPending = false;
|
|
596
|
+
if (this.sessionState.state === tcp_1.SessionState.Stopped) {
|
|
597
|
+
logger.info('session stopped while awaiting logon verdict - discarding');
|
|
598
|
+
this.pendingRx.length = 0;
|
|
599
|
+
return;
|
|
600
|
+
}
|
|
601
|
+
this.completePeerLogon(logon, accepted, peerReset);
|
|
602
|
+
if (!accepted) {
|
|
603
|
+
this.pendingRx.length = 0;
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
this.resumeRx();
|
|
607
|
+
}).catch((e) => {
|
|
608
|
+
this.logonVerdictPending = false;
|
|
609
|
+
this.pendingRx.length = 0;
|
|
610
|
+
this.rejectLogon(`onLogon failed: ${e.message}`);
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
completePeerLogon(view, accepted, peerReset) {
|
|
614
|
+
var _a;
|
|
615
|
+
const logger = this.sessionLogger;
|
|
616
|
+
logger.info(`peerLogon onLogon returns ${accepted}`);
|
|
617
|
+
if (!accepted) {
|
|
618
|
+
this.rejectLogon('logon rejected by application');
|
|
619
|
+
return;
|
|
620
|
+
}
|
|
562
621
|
if (this.acceptor) {
|
|
563
622
|
this.setState(tcp_1.SessionState.InitiationLogonResponse);
|
|
564
623
|
logger.info('acceptor responds to logon request');
|
|
565
624
|
const weReset = this.config.description.ResetSeqNumFlag;
|
|
566
|
-
if (weReset &&
|
|
625
|
+
if (weReset && peerReset !== true) {
|
|
567
626
|
logger.info('acceptor sending ResetSeqNumFlag=Y (peer sent N), resetting sequences');
|
|
568
627
|
this.coordinator.resetAsAcceptor().catch((e) => {
|
|
569
628
|
this.sessionLogger.warning(`coordinator.resetAsAcceptor store persist failed: ${e.message}`);
|
|
570
629
|
});
|
|
571
|
-
const transmitter = (
|
|
630
|
+
const transmitter = (_a = this.transport) === null || _a === void 0 ? void 0 : _a.transmitter;
|
|
572
631
|
if (transmitter) {
|
|
573
632
|
transmitter.msgSeqNum = 1;
|
|
574
633
|
}
|
|
@@ -593,6 +652,11 @@ class AsciiSession extends fix_session_1.FixSession {
|
|
|
593
652
|
logger.info('system ready, inform app');
|
|
594
653
|
this.onReady(view);
|
|
595
654
|
}
|
|
655
|
+
rejectLogon(reason) {
|
|
656
|
+
this.sessionLogger.warning(`refusing peer logon: ${reason}`);
|
|
657
|
+
this.sendLogout(reason);
|
|
658
|
+
this.terminate(new Error(reason));
|
|
659
|
+
}
|
|
596
660
|
sendTestRequest() {
|
|
597
661
|
const factory = this.config.factory;
|
|
598
662
|
this.setState(tcp_1.SessionState.AwaitingProcessingResponseToTestRequest);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascii-session.js","sourceRoot":"","sources":["../../../src/transport/ascii/ascii-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { MsgView } from '../../buffer'\nimport { MsgTag, MsgType, SessionRejectReason } from '../../types'\nimport { IJsFixConfig } from '../../config'\nimport { FixSession } from '../session/fix-session'\nimport {\n FixMsgAsciiStoreResend, FixMsgMemoryStore, FixMsgStoreRecord,\n IFixMsgStore, IFixMsgStoreRecord,\n IFixSessionStore, IFixSessionStoreFactory,\n MemorySessionStore, MemorySessionStoreFactory, FileSessionStoreFactory, SessionId\n} from '../../store'\nimport { asMutable } from '../session/clone-session-description'\nimport { SessionState } from '../tcp'\nimport { TickAction } from '../tick-action'\nimport { IMsgApplication } from '../msg-application'\nimport { SegmentType } from '../../buffer/segment/segment-type'\nimport { SessionSequenceCoordinator } from '../session/session-sequence-coordinator'\nimport { DefaultFixClock } from '../session/fix-clock'\nimport { ResendActionType } from '../session/resend-request-manager'\nimport { AsciiMsgTransmitter } from './ascii-msg-transmitter'\nimport { MsgTransport } from '../factory'\nimport { ILooseObject } from '../../collections/collection'\n\nexport abstract class AsciiSession extends FixSession {\n /**\n * TargetCompID value which tells an acceptor to take its target from whichever\n * counterparty logs on, rather than from static configuration.\n */\n public static readonly WildcardCompId = '*'\n public heartbeat: boolean = true\n protected store: IFixMsgStore | null = null\n protected resender: FixMsgAsciiStoreResend\n protected coordinator: SessionSequenceCoordinator\n protected sessionStore: IFixSessionStore\n protected sessionId: SessionId\n private registered: boolean = false\n /** acceptor configured with TargetCompID '*' - identity comes from the peer Logon */\n protected readonly wildcardTarget: boolean\n private identityBound: boolean\n private bindInProgress: boolean = false\n private readonly pendingRx: Array<{ msgType: string, view: MsgView }> = []\n private readonly clock: DefaultFixClock = new DefaultFixClock()\n\n protected constructor (public readonly config: IJsFixConfig) {\n super(config)\n this.requestLogoutType = this.respondLogoutType = MsgType.Logout\n this.requestLogonType = MsgType.Logon\n this.store = new FixMsgMemoryStore(this.config.description.SenderCompId, this.config)\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n\n // A wildcard TargetCompID lets one acceptor serve counterparties it was not\n // statically configured for - the peer's SenderCompID becomes our target, and\n // therefore our SessionId and store, once the Logon arrives. An initiator has\n // to know who it is calling, so '*' is meaningless there.\n this.wildcardTarget = config.description.TargetCompID === AsciiSession.WildcardCompId\n if (this.wildcardTarget && this.initiator) {\n throw new Error(`TargetCompID '${AsciiSession.WildcardCompId}' is only valid for acceptors, not initiators`)\n }\n this.identityBound = !this.wildcardTarget\n\n this.sessionId = new SessionId(\n config.description.BeginString,\n config.description.SenderCompId,\n config.description.TargetCompID\n )\n // Until the peer identifies itself there is nothing worth persisting, so a\n // wildcard session starts on a throwaway in-memory store. The real store -\n // keyed on the peer's comp id - is created by bindIdentity.\n this.sessionStore = this.wildcardTarget\n ? new MemorySessionStore(this.sessionId)\n : this.storeFactory().create(this.sessionId)\n\n this.coordinator = new SessionSequenceCoordinator(this.sessionStore, this.clock)\n const lastReceivedSeqNum = config.description.LastReceivedSeqNum ?? 0\n this.coordinator.initializeFromConfig(undefined, lastReceivedSeqNum + 1)\n }\n\n private storeFactory (): IFixSessionStoreFactory {\n // Priority: programmatic config > JSON store config > default in-memory\n return this.config.sessionStoreFactory ?? AsciiSession.createStoreFactory(this.config.description.store)\n }\n\n /**\n * Initialize the session store (reads persisted sequences from file if using FileSessionStore),\n * sync the coordinator and transmitter from the store, then start the session.\n *\n * The transport's readable stream is paused during async store initialization to prevent\n * the AsciiParser (which starts reading immediately in its constructor) from consuming\n * and emitting messages before subscribe() hooks up the message handler.\n */\n public async run (transport: MsgTransport): Promise<number> {\n // Pause the readable stream to prevent data loss during async init.\n // The AsciiParser starts reading from the socket in its constructor,\n // but FixSession.subscribe() hasn't been called yet. Without pausing,\n // the client's Logon can arrive and be parsed into the void.\n transport.duplex.readable?.pause()\n\n if (this.wildcardTarget && !this.identityBound) {\n // Nothing to recover yet - the SessionId is not known until the peer logs on,\n // so store initialisation, sequence sync and registry claim all happen in\n // bindIdentity. Resume and wait for the Logon.\n this.sessionLogger.info('wildcard acceptor: awaiting peer Logon to establish session identity')\n transport.duplex.readable?.resume()\n return await super.run(transport)\n }\n\n // Initialize store — reads persisted .seqnums file if using FileSessionStore.\n // For MemorySessionStore this is a no-op.\n await this.sessionStore.initialize()\n\n // Coordinator becomes the source of truth for sequences\n this.coordinator.initializeFromStore()\n\n // Sync encoder's outgoing sequence from the store\n const transmitter = transport.transmitter as AsciiMsgTransmitter\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n\n // Sync session state's last received sequence from the store\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n this.sessionLogger.info(`store initialized: nextSender=${this.coordinator.nextSenderSeqNum}, expectedTarget=${this.coordinator.expectedTargetSeqNum}`)\n\n // Claim this SessionId. A counterparty which reconnected before its previous\n // socket was detected as dead would otherwise leave two live sessions writing\n // to one store - see issue #153.\n this.claimSessionId()\n\n // Resume the stream — super.run() will call subscribe() to hook up the message handler,\n // then the buffered data (including the client's Logon) will be delivered.\n transport.duplex.readable?.resume()\n\n return await super.run(transport)\n }\n\n private checkSeqNo (msgType: string, view: MsgView): boolean {\n switch (msgType) {\n case MsgType.SequenceReset: {\n return true\n }\n\n case MsgType.Logon: {\n // If peer sends ResetSeqNumFlag=Y, accept any sequence number.\n // PeerLogon handles the full sequence reset.\n if (view.getTyped(MsgTag.ResetSeqNumFlag) === true) {\n this.sessionLogger.info('logon with ResetSeqNumFlag=Y, accepting regardless of sequence')\n const seqNo = view.getTyped(MsgTag.MsgSeqNum) as number\n this.sessionState.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n }\n // falls through\n\n default: {\n const state = this.sessionState\n const lastSeq: number = state.lastPeerMsgSeqNum\n const seqNo: number = view.getTyped(MsgTag.MsgSeqNum) as number\n let ret: boolean = false\n const seqDelta: number = seqNo - lastSeq\n if (seqDelta <= 0) {\n // Check if this is a PossDupFlag=Y message (resend replay) before rejecting.\n // PossDupFlag messages have old sequence numbers and bypass normal checks.\n const possDupFlag = view.getTyped(MsgTag.PossDupFlag) as boolean | undefined\n if (possDupFlag === true) {\n this.sessionLogger.debug(`message '${msgType}' has PossDupFlag=Y, bypassing sequence check`)\n this.coordinator.onMessageReceived(seqNo, true).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n // Check if this is a delayed message that fills a pending gap range.\n const pendingRequests = this.coordinator.pendingResendRequests\n const inPendingGapRange = pendingRequests.some(p => seqNo >= p.begin && seqNo <= p.end)\n if (inPendingGapRange) {\n this.sessionLogger.info(`accepting delayed message seq ${seqNo} (in pending gap range)`)\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n // serious problem ... drop immediately\n this.sessionLogger.warning(`terminate as seqDelta (${seqDelta}) < 0 lastSeq = ${lastSeq} seqNo = ${seqNo}`)\n this.stop()\n } else if (seqDelta > 1) {\n // resend request required as have missed messages.\n const expectedSeq = lastSeq + 1\n\n // We process a Logon beforehand to confirm the connection even we out of sync\n if (msgType === MsgType.Logon) {\n this.peerLogon(view)\n }\n // If the out of sync message is a resend request itself, then we handle it first in order\n // to avoid triggering an endless loop of both sides sending resend requests in response to resend requests.\n if (msgType === MsgType.ResendRequest) {\n this.onResendRequest(view)\n }\n\n // Use coordinator to determine what action to take for the gap\n const action = this.coordinator.onGapDetected(expectedSeq, seqNo)\n this.sessionLogger.info(`gap action: ${action}`)\n\n switch (action.type) {\n case ResendActionType.SendResendRequest: {\n if (action.begin != null && action.end != null) {\n this.sendResendRequest(lastSeq, seqNo)\n this.coordinator.recordResendRequestSent(action.begin, action.end)\n }\n break\n }\n case ResendActionType.Wait: {\n this.sessionLogger.info(`waiting for existing resend request: ${action.reason}`)\n break\n }\n case ResendActionType.SendGapFill: {\n this.sessionLogger.warning(`gap recovery abandoned (storm protection): ${action.reason}`)\n break\n }\n }\n\n // Update sequence state regardless — the gap-triggering message is valid.\n state.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n\n // Logon and ResendRequest were already fully handled above (peerLogon / onResendRequest).\n // Don't return true for them — they must not be dispatched to onSessionMsg again.\n // Application messages (and everything else) should be forwarded normally.\n if (msgType !== MsgType.Logon && msgType !== MsgType.ResendRequest) {\n ret = true\n }\n } else {\n ret = true\n state.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n }\n\n // Reset timeout recovery on successful message receipt\n if (ret) {\n this.coordinator.resetTimeoutRecovery()\n }\n return ret\n }\n }\n }\n\n protected checkForwardMsg (msgType: string, view: MsgView): void {\n const okToForward = this.validStateApplicationMsg()\n if (okToForward) {\n this.sessionLogger.info(`ascii forwarding msgType = '${msgType}' to application`)\n this.setState(SessionState.ActiveNormalSession)\n this.onApplicationMsg(msgType, view)\n } else {\n this.terminate(new Error(`msgType ${msgType} received in state ${this.stateString()}`))\n }\n }\n\n private sendReject (msgType: string, seqNo: number, msg: string, reason: number): void {\n const factory = this.config.factory\n const reject = factory?.reject(msgType, seqNo, msg, reason)\n if (reject) {\n this.sessionLogger.warning(`rejecting with ${JSON.stringify(reject)}`)\n this.send(MsgType.Reject, reject)\n }\n }\n\n protected sendResendRequest (lastSeq: number, receivedSeq: number): void {\n const resend = this.config.factory?.resendRequest(lastSeq + 1, 0)\n if (resend) {\n this.sessionLogger.warning(`received seq ${receivedSeq}, but last known seq is ${lastSeq}. Sending resend request for all messages > ${lastSeq}`)\n this.send(MsgType.ResendRequest, resend)\n }\n }\n\n private checkIntegrity (msgType: string, view: MsgView): boolean {\n const state = this.sessionState\n const seqNum = view.getTyped(MsgTag.MsgSeqNum) as number\n\n const received: number = parseInt(view.getString(MsgTag.CheckSum) ?? '', 10)\n const computed = view.checksum()\n if (received !== computed) {\n const msg: string = `msgType ${msgType} checksum failed. received = ${received} computed = ${computed}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.ValueIsIncorrect)\n return false\n }\n\n if (view.segment.type === SegmentType.Unknown) {\n const msg: string = `msgType ${msgType} unknown`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.InvalidMsgType)\n return false\n }\n\n const invalid = view.invalid()\n if (invalid.length > 0) {\n const msg: string = `msgType ${msgType} invalid tag${invalid.length > 1 ? 's' : ''} ${invalid.join(', ')}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.InvalidTagNumber)\n return false\n }\n\n const undefinedMsg: string | null = view.undefinedForMsg()\n if (undefinedMsg) {\n const msg: string = `msgType ${msgType} ${undefinedMsg}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.TagNotDefinedForThisMessageType)\n return false\n }\n\n const missingRequired = view.missing()\n if (missingRequired.length > 0) {\n const msg: string = `msgType ${msgType} missing required tag${missingRequired.length > 1 ? 's' : ''} ${missingRequired.join(', ')}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.RequiredTagMissing)\n return false\n }\n\n switch (state.state) {\n case SessionState.InitiationLogonReceived:\n case SessionState.InitiationLogonResponse: {\n const targetCompId = view.getString(MsgTag.TargetCompID)\n if (targetCompId !== state.compId) {\n const msg: string = `msgType ${msgType} unexpected TargetCompID ${targetCompId} expecting ${state.compId})`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.CompIDProblem)\n return false\n }\n\n const peerCompId = view.getString(MsgTag.SenderCompID)\n if (peerCompId !== state.peerCompId) {\n const msg: string = `msgType ${msgType} unexpected SenderCompID ${peerCompId} expecting ${state.compId}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.CompIDProblem)\n return false\n }\n }\n break\n\n default: {\n break\n }\n }\n\n return true\n }\n\n /**\n * Override to resend stored messages following a sequence reset.\n * @protected\n */\n protected onResendRequest (view: MsgView): void {\n // if no records are in store then send a gap fill for entire sequence\n this.setState(SessionState.HandleResendRequest)\n const [beginSeqNo, requestedEndSeqNo] = view.getTypedTags([MsgTag.BeginSeqNo, MsgTag.EndSeqNo])\n const endSeqNo = requestedEndSeqNo === 0\n ? this.sessionState.lastSentSeqNum()\n : requestedEndSeqNo\n\n this.sessionLogger.info(`onResendRequest getResendRequest beginSeqNo = ${beginSeqNo}, endSeqNo = ${endSeqNo}`)\n this.resender.getResendRequest(beginSeqNo as number, endSeqNo as number).then((records: IFixMsgStoreRecord[]) => {\n const validRecords = records.filter(rec => rec.obj !== null)\n this.sessionLogger.info(`sending ${validRecords.length}`)\n validRecords.forEach(rec => {\n if (rec.obj) {\n this.send(rec.msgType, rec.obj)\n }\n })\n this.setState(SessionState.ActiveNormalSession)\n }).catch((e: Error) => {\n this.sessionLogger.error(e)\n })\n }\n\n protected override onPrepareForReconnect (): void {\n this.coordinator.prepareForReconnect()\n this.sessionLogger.info('coordinator reset transient state for reconnect')\n }\n\n /**\n * Take ownership of this SessionId in the registry, stopping whatever session\n * held it before. Idempotent - a session reused across reconnects (the\n * RecoveringTcpInitiator pattern) simply re-registers itself.\n */\n private claimSessionId (): void {\n const registry = this.config.sessionRegistry\n if (!registry) return\n const stoppedOld = registry.register(this.sessionId, this)\n if (stoppedOld) {\n this.sessionLogger.info(`session registry stopped previous session for ${this.sessionId.toString()}`)\n }\n this.registered = true\n }\n\n protected override onSessionStopping (): void {\n super.onSessionStopping()\n const registry = this.config.sessionRegistry\n if (!registry || !this.registered) return\n this.registered = false\n this.sessionLogger.info(`session stopping - unregistering from registry: ${this.sessionId.toString()}`)\n registry.unregister(this.sessionId, this)\n }\n\n protected override async onPreLogon (): Promise<void> {\n if (!this.config.description.ResetSeqNumFlag) return\n\n this.sessionLogger.info('initiator has ResetSeqNumFlag=Y, resetting sequences before logon')\n await this.coordinator.resetSession('initiator ResetSeqNumFlag=Y')\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n }\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n\n this.sessionLogger.info(`pre-logon reset complete: encoderSeqNum=${transmitter?.msgSeqNum}`)\n }\n\n protected override txOnEncoded (msgType: string, data: string, hdr: ILooseObject): void {\n super.txOnEncoded(msgType, data, hdr)\n // Store the encoded message in the session store for recovery/resend\n const seqNum = hdr?.MsgSeqNum as number | undefined\n if (seqNum != null) {\n const record = new FixMsgStoreRecord(msgType, new Date(), seqNum, undefined, data)\n this.sessionStore.put(record).catch((e: Error) => {\n // Never block sends on store errors\n this.sessionLogger.warning(`failed to store message seq=${seqNum}: ${e.message}`)\n })\n // Update store's sender sequence number (next outgoing seq = seqNum + 1)\n this.sessionStore.setSenderSeqNum(seqNum + 1).catch((e: Error) => {\n this.sessionLogger.warning(`failed to update sender seq: ${e.message}`)\n })\n }\n }\n\n private static readonly MaxLogonRetries = 100\n private static readonly MaxTimeoutRecoveryAttempts = 0\n\n private static createStoreFactory (storeConfig?: { type: string, directory?: string }): IFixSessionStoreFactory {\n if (!storeConfig) return new MemorySessionStoreFactory()\n switch (storeConfig.type?.toLowerCase()) {\n case 'file':\n return new FileSessionStoreFactory(storeConfig.directory ?? 'store')\n default:\n return new MemorySessionStoreFactory()\n }\n }\n\n private handleLogonRejected (text: string | null): void {\n if (!this.coordinator.onLogonRejectedForSequence(AsciiSession.MaxLogonRetries)) {\n this.sessionLogger.warning(`max logon retries (${AsciiSession.MaxLogonRetries}) exceeded, giving up. Text='${text}'`)\n this.setState(SessionState.PeerLogonRejected)\n this.stop()\n return\n }\n\n // The encoder's msgSeqNum is already incremented after each message is sent,\n // so we just need to retry the logon. The next logon will use the next sequence number.\n this.sessionLogger.info(`LOGON_SEQ_RETRY: attempt=${this.coordinator.logonRetryCount}/${AsciiSession.MaxLogonRetries}, reason='${text}'`)\n this.sendLogon()\n }\n\n okForLogon (): boolean {\n const state = this.sessionState.state\n if (this.acceptor) {\n return state === SessionState.WaitingForALogon\n }\n return state === SessionState.InitiationLogonSent\n }\n\n protected onSessionMsg (msgType: string, view: MsgView): void {\n const logger = this.sessionLogger\n\n switch (msgType) {\n case MsgType.Logon: {\n // only valid to receive a logon when in LogonSent or WaitingALogon\n // else will drop connection immediately.\n if (this.okForLogon()) {\n this.peerLogon(view)\n } else {\n this.terminate(new Error(`state ${this.stateString()} is illegal for Logon`))\n }\n break\n }\n\n case MsgType.Logout: {\n this.peerLogout(view)\n break\n }\n\n case MsgType.TestRequest: {\n const req: string | null = view.getString(MsgTag.TestReqID)\n if (req) {\n this.sendHeartbeat(req)\n }\n break\n }\n\n case MsgType.Heartbeat: {\n this.sessionState.lastTestRequestAt = null\n this.setState(SessionState.ActiveNormalSession)\n break\n }\n\n case MsgType.ResendRequest: {\n logger.info(`peer sends '${msgType}' resend request.`)\n this.onResendRequest(view)\n break\n }\n\n case MsgType.SequenceReset: {\n const newSeqNo: number = view.getTyped(MsgTag.NewSeqNo) as number\n const gapFillSeq: number = view.getTyped(MsgTag.MsgSeqNum) as number\n logger.info(`peer sends '${msgType}' sequence reset. newSeqNo = ${newSeqNo}`)\n // expect newSeqNo to be the next message's sequence number.\n this.sessionState.lastPeerMsgSeqNum = newSeqNo - 1\n // Notify coordinator to update expected target and clear pending resend requests\n this.coordinator.onGapFillReceived(gapFillSeq, newSeqNo).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onGapFillReceived store persist failed: ${e.message}`)\n })\n break\n }\n\n case MsgType.Reject: {\n const refMsgType = view.getString(MsgTag.RefMsgType)\n const text = view.getString(MsgTag.Text)\n const reason = view.getTyped(MsgTag.SessionRejectReason) as number | undefined\n logger.info(`peer rejects RefMsgType='${refMsgType}', reason=${reason}, text='${text}'`)\n\n // Check if this is a logon rejection due to sequence mismatch while we're waiting for logon response.\n // Only retry for ValueIsIncorrect (sequence too low) — structural rejections (RequiredTagMissing etc.)\n // indicate a config problem that retrying won't fix.\n if (refMsgType === MsgType.Logon &&\n this.sessionState.state === SessionState.InitiationLogonSent &&\n reason === SessionRejectReason.ValueIsIncorrect) {\n this.handleLogonRejected(text)\n }\n break\n }\n }\n }\n\n protected onMsg (msgType: string, view: MsgView): void {\n if (this.wildcardTarget && !this.identityBound) {\n this.onMsgBeforeIdentity(msgType, view)\n return\n }\n this.dispatchMsg(msgType, view)\n }\n\n /**\n * Message handling for a wildcard acceptor which has not yet learned who it is\n * talking to. The first message must be a Logon; it carries the peer's\n * SenderCompID, which becomes our TargetCompID and hence our SessionId and store.\n *\n * Binding is asynchronous (the store may have to be read from disk) while message\n * delivery is not: the parser emits every message it finds in a TCP segment in one\n * synchronous burst, and a view is only valid for the duration of its own event -\n * AsciiParser recycles the tag index and buffer immediately afterwards. So each\n * message that arrives mid-bind is cloned and queued, then replayed in order.\n */\n private onMsgBeforeIdentity (msgType: string, view: MsgView): void {\n if (this.bindInProgress) {\n this.sessionLogger.info(`queueing '${msgType}' received while binding session identity`)\n this.pendingRx.push({ msgType, view: view.clone() })\n return\n }\n\n if (msgType !== MsgType.Logon) {\n this.terminate(new Error(`wildcard acceptor expects Logon as the first message, received '${msgType}'`))\n return\n }\n\n const peerCompId = view.getString(MsgTag.SenderCompID)\n if (!peerCompId) {\n this.terminate(new Error('Logon has no SenderCompID - cannot establish session identity'))\n return\n }\n\n this.bindInProgress = true\n const logon = view.clone()\n this.transport?.duplex.readable?.pause()\n\n this.bindIdentity(peerCompId).then(() => {\n this.bindInProgress = false\n this.identityBound = true\n this.dispatchMsg(MsgType.Logon, logon)\n this.drainPendingRx()\n this.transport?.duplex.readable?.resume()\n }).catch((e: Error) => {\n this.bindInProgress = false\n this.pendingRx.length = 0\n this.terminate(new Error(`failed to bind session identity for peer '${peerCompId}': ${e.message}`))\n })\n }\n\n private drainPendingRx (): void {\n while (this.pendingRx.length > 0) {\n const queued = this.pendingRx.shift()\n if (!queued) break\n if (this.sessionState.state === SessionState.Stopped) {\n this.sessionLogger.info(`dropping queued '${queued.msgType}' - session stopped during bind`)\n continue\n }\n this.dispatchMsg(queued.msgType, queued.view)\n }\n }\n\n /**\n * Adopt the peer's comp id as our TargetCompID, then build the identity derived\n * state: SessionId, message store, sequence coordinator, registry claim. This is\n * the wildcard equivalent of the work run() does up front for a statically\n * configured session.\n */\n private async bindIdentity (peerCompId: string): Promise<void> {\n const logger = this.sessionLogger\n logger.info(`wildcard acceptor: binding session identity to peer SenderCompID '${peerCompId}'`)\n\n // the description is this session's own clone (see makeSessionScope), and the\n // session message factory holds the same object, so outbound headers pick the\n // new target up immediately\n asMutable(this.config.description).TargetCompID = peerCompId\n\n // every session on a wildcard listener shared one logger name until now, which\n // makes a multi-client server log impossible to follow\n this.sessionLogger = this.config.logFactory.logger(`${this.me}:${peerCompId}:FixSession`)\n\n this.sessionId = new SessionId(\n this.config.description.BeginString,\n this.config.description.SenderCompId,\n peerCompId\n )\n this.sessionStore = this.storeFactory().create(this.sessionId)\n await this.sessionStore.initialize()\n\n this.coordinator = new SessionSequenceCoordinator(this.sessionStore, this.clock)\n this.coordinator.initializeFromStore()\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n }\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n logger.info(`session identity bound: ${this.sessionId.toString()} ` +\n `nextSender=${this.coordinator.nextSenderSeqNum}, expectedTarget=${this.coordinator.expectedTargetSeqNum}`)\n\n this.claimSessionId()\n }\n\n private dispatchMsg (msgType: string, view: MsgView): void {\n if (!this.checkSeqNo(msgType, view)) {\n this.sessionLogger.info(`message '${msgType}' failed checkSeqNo.`)\n return\n }\n\n if (this.checkMsgIntegrity && !this.checkIntegrity(msgType, view)) {\n this.sessionLogger.info(`message '${msgType}' failed checkIntegrity.`)\n switch (msgType) {\n case MsgType.Logon: {\n this.setState(SessionState.PeerLogonRejected)\n this.startTimer()\n break\n }\n }\n return\n }\n\n switch (msgType) {\n case MsgType.Logon:\n case MsgType.Logout:\n case MsgType.TestRequest:\n case MsgType.Reject:\n case MsgType.SequenceReset:\n case MsgType.Heartbeat:\n case MsgType.ResendRequest: {\n this.onSessionMsg(msgType, view)\n break\n }\n\n default: {\n this.checkForwardMsg(msgType, view)\n break\n }\n }\n }\n\n private startTimer (interval: number = 200): void {\n const logger = this.sessionLogger\n logger.info(`start heartbeat timer. interval = ${interval}`)\n this.timer = setInterval(() => {\n this.tick()\n }, interval)\n }\n\n private peerLogon (view: MsgView): void {\n const logger = this.sessionLogger\n const [heartBtInt, peerCompId, userName, password] = view.getTypedTags([MsgTag.HeartBtInt, MsgTag.SenderCompID, MsgTag.Username, MsgTag.Password])\n const resetSeqNumFlag = view.getTyped(MsgTag.ResetSeqNumFlag) as boolean | undefined\n logger.info(`peerLogon Username = ${userName}, heartBtInt = ${heartBtInt}, peerCompId = ${peerCompId}, resetSeqNumFlag = ${resetSeqNumFlag}`)\n\n // Handle ResetSeqNumFlag from peer's logon\n if (resetSeqNumFlag === true) {\n const peerSeqNum = (view.getTyped(MsgTag.MsgSeqNum) as number) ?? 1\n const weAlsoReset = this.config.description.ResetSeqNumFlag\n logger.info(`peer sent ResetSeqNumFlag=Y with seqNum=${peerSeqNum}, weAlsoReset=${weAlsoReset}`)\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n const savedEncoderSeqNum = weAlsoReset && transmitter ? transmitter.msgSeqNum : null\n\n // Fire-and-forget the async coordinator call (store updates resolve on next microtask)\n // but compute the expected values synchronously since we know the reset outcome\n this.coordinator.handlePeerReset(peerSeqNum, weAlsoReset).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.handlePeerReset store persist failed: ${e.message}`)\n })\n if (transmitter) {\n transmitter.msgSeqNum = savedEncoderSeqNum ?? 1\n }\n this.sessionState.lastPeerMsgSeqNum = peerSeqNum\n\n // Recreate resender with empty store\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n logger.info(`reset complete: encoderSeqNum=${transmitter?.msgSeqNum}, lastPeerMsgSeqNum=${peerSeqNum}`)\n }\n\n const state = this.sessionState\n state.peerHeartBeatSecs = view.getTyped(MsgTag.HeartBtInt) as number\n state.peerCompId = view.getTyped(MsgTag.SenderCompID) as string\n const res = this.onLogon(view, userName as string, password as string)\n // currently not using this.\n logger.info(`peerLogon onLogon returns ${res}`)\n if (this.acceptor) {\n this.setState(SessionState.InitiationLogonResponse)\n logger.info('acceptor responds to logon request')\n\n // If WE (acceptor) are sending ResetSeqNumFlag=Y but peer didn't request it,\n // reset our sequences before sending our logon response.\n // This handles the broker-reset pattern where client sends N, we respond with Y.\n const weReset = this.config.description.ResetSeqNumFlag\n if (weReset && resetSeqNumFlag !== true) {\n logger.info('acceptor sending ResetSeqNumFlag=Y (peer sent N), resetting sequences')\n // Fire-and-forget async coordinator call, set values synchronously\n this.coordinator.resetAsAcceptor().catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.resetAsAcceptor store persist failed: ${e.message}`)\n })\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = 1\n }\n this.sessionState.lastPeerMsgSeqNum = 0\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n }\n\n this.sendLogon() // if res send response else reject, terminate\n } else { // as an initiator the acceptor has responded\n logger.info('initiator receives logon response')\n this.setState(SessionState.InitiationLogonReceived)\n }\n // Reset logon retry counter on successful logon\n this.coordinator.resetLogonRetryCount()\n\n if (this.heartbeat) {\n this.startTimer()\n }\n logger.info('system ready, inform app')\n this.onReady(view)\n }\n\n private sendTestRequest (): void {\n const factory = this.config.factory\n this.setState(SessionState.AwaitingProcessingResponseToTestRequest)\n const tr = factory?.testRequest()\n if (tr) {\n this.send(MsgType.TestRequest, tr)\n }\n }\n\n private sendHeartbeat (testReqId: string): void {\n const factory = this.config.factory\n const hb = factory?.heartbeat(testReqId)\n if (hb) {\n this.send(MsgType.Heartbeat, hb)\n }\n }\n\n private tick (): void {\n if (!this.transport) return\n const sessionState = this.sessionState\n const action: TickAction = sessionState.calcAction(new Date())\n const application: IMsgApplication | null = this.transport.config.description.application ?? null\n const logger = this.sessionLogger\n // Clean up timed-out resend requests\n this.coordinator.tick()\n\n switch (action) {\n case TickAction.Nothing: {\n // all is well\n break\n }\n\n case TickAction.TestRequest: {\n logger.debug(`send test req. state = ${sessionState.toString()}`)\n this.sendTestRequest()\n break\n }\n\n case TickAction.Heartbeat: {\n logger.debug(`send heartbeat. state = ${sessionState.toString()}`)\n this.sendHeartbeat(sessionState.now.toUTCString())\n break\n }\n\n case TickAction.TerminateOnError: {\n if (this.coordinator.incrementTimeoutRecovery(AsciiSession.MaxTimeoutRecoveryAttempts)) {\n // Try to recover — reset timeout state to give session a fresh window.\n // This helps survive sleep/wake scenarios where TCP connection may still be alive.\n logger.info(`timeout recovery attempt ${this.coordinator.timeoutRecoveryAttempts}, resetting timeout state`)\n sessionState.lastTestRequestAt = null\n sessionState.lastReceivedAt = new Date()\n this.setState(SessionState.ActiveNormalSession)\n } else {\n logger.info(sessionState.toString())\n this.terminate(new Error(`${application?.name}: peer not responding`))\n }\n break\n }\n\n case TickAction.Stop: {\n logger.info(sessionState.toString())\n logger.info('stopping')\n this.stop()\n break\n }\n\n default:\n throw new Error('unexpected action')\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"ascii-session.js","sourceRoot":"","sources":["../../../src/transport/ascii/ascii-session.ts"],"names":[],"mappings":"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","sourcesContent":["import { MsgView } from '../../buffer'\nimport { MsgTag, MsgType, SessionRejectReason } from '../../types'\nimport { IJsFixConfig } from '../../config'\nimport { FixSession } from '../session/fix-session'\nimport {\n FixMsgAsciiStoreResend, FixMsgMemoryStore, FixMsgStoreRecord,\n IFixMsgStore, IFixMsgStoreRecord,\n IFixSessionStore, IFixSessionStoreFactory,\n MemorySessionStore, MemorySessionStoreFactory, FileSessionStoreFactory, SessionId\n} from '../../store'\nimport { asMutable } from '../session/clone-session-description'\nimport { SessionState } from '../tcp'\nimport { TickAction } from '../tick-action'\nimport { IMsgApplication } from '../msg-application'\nimport { SegmentType } from '../../buffer/segment/segment-type'\nimport { SessionSequenceCoordinator } from '../session/session-sequence-coordinator'\nimport { DefaultFixClock } from '../session/fix-clock'\nimport { ResendActionType } from '../session/resend-request-manager'\nimport { AsciiMsgTransmitter } from './ascii-msg-transmitter'\nimport { MsgTransport } from '../factory'\nimport { ILooseObject } from '../../collections/collection'\n\nexport abstract class AsciiSession extends FixSession {\n /**\n * TargetCompID value which tells an acceptor to take its target from whichever\n * counterparty logs on, rather than from static configuration.\n */\n public static readonly WildcardCompId = '*'\n public heartbeat: boolean = true\n protected store: IFixMsgStore | null = null\n protected resender: FixMsgAsciiStoreResend\n protected coordinator: SessionSequenceCoordinator\n protected sessionStore: IFixSessionStore\n protected sessionId: SessionId\n private registered: boolean = false\n /** acceptor configured with TargetCompID '*' - identity comes from the peer Logon */\n protected readonly wildcardTarget: boolean\n private identityBound: boolean\n private bindInProgress: boolean = false\n private logonVerdictPending: boolean = false\n private readonly pendingRx: Array<{ msgType: string, view: MsgView }> = []\n private readonly clock: DefaultFixClock = new DefaultFixClock()\n\n protected constructor (public readonly config: IJsFixConfig) {\n super(config)\n this.requestLogoutType = this.respondLogoutType = MsgType.Logout\n this.requestLogonType = MsgType.Logon\n this.store = new FixMsgMemoryStore(this.config.description.SenderCompId, this.config)\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n\n // A wildcard TargetCompID lets one acceptor serve counterparties it was not\n // statically configured for - the peer's SenderCompID becomes our target, and\n // therefore our SessionId and store, once the Logon arrives. An initiator has\n // to know who it is calling, so '*' is meaningless there.\n this.wildcardTarget = config.description.TargetCompID === AsciiSession.WildcardCompId\n if (this.wildcardTarget && this.initiator) {\n throw new Error(`TargetCompID '${AsciiSession.WildcardCompId}' is only valid for acceptors, not initiators`)\n }\n this.identityBound = !this.wildcardTarget\n\n this.sessionId = new SessionId(\n config.description.BeginString,\n config.description.SenderCompId,\n config.description.TargetCompID\n )\n // Until the peer identifies itself there is nothing worth persisting, so a\n // wildcard session starts on a throwaway in-memory store. The real store -\n // keyed on the peer's comp id - is created by bindIdentity.\n this.sessionStore = this.wildcardTarget\n ? new MemorySessionStore(this.sessionId)\n : this.storeFactory().create(this.sessionId)\n\n this.coordinator = new SessionSequenceCoordinator(this.sessionStore, this.clock)\n const lastReceivedSeqNum = config.description.LastReceivedSeqNum ?? 0\n this.coordinator.initializeFromConfig(undefined, lastReceivedSeqNum + 1)\n }\n\n private storeFactory (): IFixSessionStoreFactory {\n // Priority: programmatic config > JSON store config > default in-memory\n return this.config.sessionStoreFactory ?? AsciiSession.createStoreFactory(this.config.description.store)\n }\n\n /**\n * Initialize the session store (reads persisted sequences from file if using FileSessionStore),\n * sync the coordinator and transmitter from the store, then start the session.\n *\n * The transport's readable stream is paused during async store initialization to prevent\n * the AsciiParser (which starts reading immediately in its constructor) from consuming\n * and emitting messages before subscribe() hooks up the message handler.\n */\n public async run (transport: MsgTransport): Promise<number> {\n // Pause the readable stream to prevent data loss during async init.\n // The AsciiParser starts reading from the socket in its constructor,\n // but FixSession.subscribe() hasn't been called yet. Without pausing,\n // the client's Logon can arrive and be parsed into the void.\n transport.duplex.readable?.pause()\n\n if (this.wildcardTarget && !this.identityBound) {\n // Nothing to recover yet - the SessionId is not known until the peer logs on,\n // so store initialisation, sequence sync and registry claim all happen in\n // bindIdentity. Resume and wait for the Logon.\n this.sessionLogger.info('wildcard acceptor: awaiting peer Logon to establish session identity')\n transport.duplex.readable?.resume()\n return await super.run(transport)\n }\n\n // Initialize store — reads persisted .seqnums file if using FileSessionStore.\n // For MemorySessionStore this is a no-op.\n await this.sessionStore.initialize()\n\n // Coordinator becomes the source of truth for sequences\n this.coordinator.initializeFromStore()\n\n // Sync encoder's outgoing sequence from the store\n const transmitter = transport.transmitter as AsciiMsgTransmitter\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n\n // Sync session state's last received sequence from the store\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n this.sessionLogger.info(`store initialized: nextSender=${this.coordinator.nextSenderSeqNum}, expectedTarget=${this.coordinator.expectedTargetSeqNum}`)\n\n // Claim this SessionId. A counterparty which reconnected before its previous\n // socket was detected as dead would otherwise leave two live sessions writing\n // to one store - see issue #153.\n this.claimSessionId()\n\n // Resume the stream — super.run() will call subscribe() to hook up the message handler,\n // then the buffered data (including the client's Logon) will be delivered.\n transport.duplex.readable?.resume()\n\n return await super.run(transport)\n }\n\n private checkSeqNo (msgType: string, view: MsgView): boolean {\n switch (msgType) {\n case MsgType.SequenceReset: {\n return true\n }\n\n case MsgType.Logon: {\n // If peer sends ResetSeqNumFlag=Y, accept any sequence number.\n // PeerLogon handles the full sequence reset.\n if (view.getTyped(MsgTag.ResetSeqNumFlag) === true) {\n this.sessionLogger.info('logon with ResetSeqNumFlag=Y, accepting regardless of sequence')\n const seqNo = view.getTyped(MsgTag.MsgSeqNum) as number\n this.sessionState.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n }\n // falls through\n\n default: {\n const state = this.sessionState\n const lastSeq: number = state.lastPeerMsgSeqNum\n const seqNo: number = view.getTyped(MsgTag.MsgSeqNum) as number\n let ret: boolean = false\n const seqDelta: number = seqNo - lastSeq\n if (seqDelta <= 0) {\n // Check if this is a PossDupFlag=Y message (resend replay) before rejecting.\n // PossDupFlag messages have old sequence numbers and bypass normal checks.\n const possDupFlag = view.getTyped(MsgTag.PossDupFlag) as boolean | undefined\n if (possDupFlag === true) {\n this.sessionLogger.debug(`message '${msgType}' has PossDupFlag=Y, bypassing sequence check`)\n this.coordinator.onMessageReceived(seqNo, true).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n // Check if this is a delayed message that fills a pending gap range.\n const pendingRequests = this.coordinator.pendingResendRequests\n const inPendingGapRange = pendingRequests.some(p => seqNo >= p.begin && seqNo <= p.end)\n if (inPendingGapRange) {\n this.sessionLogger.info(`accepting delayed message seq ${seqNo} (in pending gap range)`)\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n return true\n }\n // serious problem ... drop immediately\n this.sessionLogger.warning(`terminate as seqDelta (${seqDelta}) < 0 lastSeq = ${lastSeq} seqNo = ${seqNo}`)\n this.stop()\n } else if (seqDelta > 1) {\n // resend request required as have missed messages.\n const expectedSeq = lastSeq + 1\n\n // We process a Logon beforehand to confirm the connection even we out of sync\n if (msgType === MsgType.Logon) {\n this.peerLogon(view)\n }\n // If the out of sync message is a resend request itself, then we handle it first in order\n // to avoid triggering an endless loop of both sides sending resend requests in response to resend requests.\n if (msgType === MsgType.ResendRequest) {\n this.onResendRequest(view)\n }\n\n // Use coordinator to determine what action to take for the gap\n const action = this.coordinator.onGapDetected(expectedSeq, seqNo)\n this.sessionLogger.info(`gap action: ${action}`)\n\n switch (action.type) {\n case ResendActionType.SendResendRequest: {\n if (action.begin != null && action.end != null) {\n this.sendResendRequest(lastSeq, seqNo)\n this.coordinator.recordResendRequestSent(action.begin, action.end)\n }\n break\n }\n case ResendActionType.Wait: {\n this.sessionLogger.info(`waiting for existing resend request: ${action.reason}`)\n break\n }\n case ResendActionType.SendGapFill: {\n this.sessionLogger.warning(`gap recovery abandoned (storm protection): ${action.reason}`)\n break\n }\n }\n\n // Update sequence state regardless — the gap-triggering message is valid.\n state.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n\n // Logon and ResendRequest were already fully handled above (peerLogon / onResendRequest).\n // Don't return true for them — they must not be dispatched to onSessionMsg again.\n // Application messages (and everything else) should be forwarded normally.\n if (msgType !== MsgType.Logon && msgType !== MsgType.ResendRequest) {\n ret = true\n }\n } else {\n ret = true\n state.lastPeerMsgSeqNum = seqNo\n this.coordinator.onMessageReceived(seqNo, false).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onMessageReceived store persist failed: ${e.message}`)\n })\n }\n\n // Reset timeout recovery on successful message receipt\n if (ret) {\n this.coordinator.resetTimeoutRecovery()\n }\n return ret\n }\n }\n }\n\n protected checkForwardMsg (msgType: string, view: MsgView): void {\n const okToForward = this.validStateApplicationMsg()\n if (okToForward) {\n this.sessionLogger.info(`ascii forwarding msgType = '${msgType}' to application`)\n this.setState(SessionState.ActiveNormalSession)\n this.onApplicationMsg(msgType, view)\n } else {\n this.terminate(new Error(`msgType ${msgType} received in state ${this.stateString()}`))\n }\n }\n\n private sendReject (msgType: string, seqNo: number, msg: string, reason: number): void {\n const factory = this.config.factory\n const reject = factory?.reject(msgType, seqNo, msg, reason)\n if (reject) {\n this.sessionLogger.warning(`rejecting with ${JSON.stringify(reject)}`)\n this.send(MsgType.Reject, reject)\n }\n }\n\n protected sendResendRequest (lastSeq: number, receivedSeq: number): void {\n const resend = this.config.factory?.resendRequest(lastSeq + 1, 0)\n if (resend) {\n this.sessionLogger.warning(`received seq ${receivedSeq}, but last known seq is ${lastSeq}. Sending resend request for all messages > ${lastSeq}`)\n this.send(MsgType.ResendRequest, resend)\n }\n }\n\n private checkIntegrity (msgType: string, view: MsgView): boolean {\n const state = this.sessionState\n const seqNum = view.getTyped(MsgTag.MsgSeqNum) as number\n\n const received: number = parseInt(view.getString(MsgTag.CheckSum) ?? '', 10)\n const computed = view.checksum()\n if (received !== computed) {\n const msg: string = `msgType ${msgType} checksum failed. received = ${received} computed = ${computed}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.ValueIsIncorrect)\n return false\n }\n\n if (view.segment.type === SegmentType.Unknown) {\n const msg: string = `msgType ${msgType} unknown`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.InvalidMsgType)\n return false\n }\n\n const invalid = view.invalid()\n if (invalid.length > 0) {\n const msg: string = `msgType ${msgType} invalid tag${invalid.length > 1 ? 's' : ''} ${invalid.join(', ')}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.InvalidTagNumber)\n return false\n }\n\n const undefinedMsg: string | null = view.undefinedForMsg()\n if (undefinedMsg) {\n const msg: string = `msgType ${msgType} ${undefinedMsg}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.TagNotDefinedForThisMessageType)\n return false\n }\n\n const missingRequired = view.missing()\n if (missingRequired.length > 0) {\n const msg: string = `msgType ${msgType} missing required tag${missingRequired.length > 1 ? 's' : ''} ${missingRequired.join(', ')}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.RequiredTagMissing)\n return false\n }\n\n switch (state.state) {\n case SessionState.InitiationLogonReceived:\n case SessionState.InitiationLogonResponse: {\n const targetCompId = view.getString(MsgTag.TargetCompID)\n if (targetCompId !== state.compId) {\n const msg: string = `msgType ${msgType} unexpected TargetCompID ${targetCompId} expecting ${state.compId})`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.CompIDProblem)\n return false\n }\n\n const peerCompId = view.getString(MsgTag.SenderCompID)\n if (peerCompId !== state.peerCompId) {\n const msg: string = `msgType ${msgType} unexpected SenderCompID ${peerCompId} expecting ${state.compId}`\n this.sendReject(msgType, seqNum, msg, SessionRejectReason.CompIDProblem)\n return false\n }\n }\n break\n\n default: {\n break\n }\n }\n\n return true\n }\n\n /**\n * Override to resend stored messages following a sequence reset.\n * @protected\n */\n protected onResendRequest (view: MsgView): void {\n // if no records are in store then send a gap fill for entire sequence\n this.setState(SessionState.HandleResendRequest)\n const [beginSeqNo, requestedEndSeqNo] = view.getTypedTags([MsgTag.BeginSeqNo, MsgTag.EndSeqNo])\n const endSeqNo = requestedEndSeqNo === 0\n ? this.sessionState.lastSentSeqNum()\n : requestedEndSeqNo\n\n this.sessionLogger.info(`onResendRequest getResendRequest beginSeqNo = ${beginSeqNo}, endSeqNo = ${endSeqNo}`)\n this.resender.getResendRequest(beginSeqNo as number, endSeqNo as number).then((records: IFixMsgStoreRecord[]) => {\n const validRecords = records.filter(rec => rec.obj !== null)\n this.sessionLogger.info(`sending ${validRecords.length}`)\n validRecords.forEach(rec => {\n if (rec.obj) {\n this.send(rec.msgType, rec.obj)\n }\n })\n this.setState(SessionState.ActiveNormalSession)\n }).catch((e: Error) => {\n this.sessionLogger.error(e)\n })\n }\n\n protected override onPrepareForReconnect (): void {\n this.coordinator.prepareForReconnect()\n this.sessionLogger.info('coordinator reset transient state for reconnect')\n }\n\n /**\n * Take ownership of this SessionId in the registry, stopping whatever session\n * held it before. Idempotent - a session reused across reconnects (the\n * RecoveringTcpInitiator pattern) simply re-registers itself.\n */\n private claimSessionId (): void {\n const registry = this.config.sessionRegistry\n if (!registry) return\n const stoppedOld = registry.register(this.sessionId, this)\n if (stoppedOld) {\n this.sessionLogger.info(`session registry stopped previous session for ${this.sessionId.toString()}`)\n }\n this.registered = true\n }\n\n protected override onSessionStopping (): void {\n super.onSessionStopping()\n const registry = this.config.sessionRegistry\n if (!registry || !this.registered) return\n this.registered = false\n this.sessionLogger.info(`session stopping - unregistering from registry: ${this.sessionId.toString()}`)\n registry.unregister(this.sessionId, this)\n }\n\n protected override async onPreLogon (): Promise<void> {\n if (!this.config.description.ResetSeqNumFlag) return\n\n this.sessionLogger.info('initiator has ResetSeqNumFlag=Y, resetting sequences before logon')\n await this.coordinator.resetSession('initiator ResetSeqNumFlag=Y')\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n }\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n\n this.sessionLogger.info(`pre-logon reset complete: encoderSeqNum=${transmitter?.msgSeqNum}`)\n }\n\n protected override txOnEncoded (msgType: string, data: string, hdr: ILooseObject): void {\n super.txOnEncoded(msgType, data, hdr)\n // Store the encoded message in the session store for recovery/resend\n const seqNum = hdr?.MsgSeqNum as number | undefined\n if (seqNum != null) {\n const record = new FixMsgStoreRecord(msgType, new Date(), seqNum, undefined, data)\n this.sessionStore.put(record).catch((e: Error) => {\n // Never block sends on store errors\n this.sessionLogger.warning(`failed to store message seq=${seqNum}: ${e.message}`)\n })\n // Update store's sender sequence number (next outgoing seq = seqNum + 1)\n this.sessionStore.setSenderSeqNum(seqNum + 1).catch((e: Error) => {\n this.sessionLogger.warning(`failed to update sender seq: ${e.message}`)\n })\n }\n }\n\n private static readonly MaxLogonRetries = 100\n private static readonly MaxTimeoutRecoveryAttempts = 0\n\n private static createStoreFactory (storeConfig?: { type: string, directory?: string }): IFixSessionStoreFactory {\n if (!storeConfig) return new MemorySessionStoreFactory()\n switch (storeConfig.type?.toLowerCase()) {\n case 'file':\n return new FileSessionStoreFactory(storeConfig.directory ?? 'store')\n default:\n return new MemorySessionStoreFactory()\n }\n }\n\n private handleLogonRejected (text: string | null): void {\n if (!this.coordinator.onLogonRejectedForSequence(AsciiSession.MaxLogonRetries)) {\n this.sessionLogger.warning(`max logon retries (${AsciiSession.MaxLogonRetries}) exceeded, giving up. Text='${text}'`)\n this.setState(SessionState.PeerLogonRejected)\n this.stop()\n return\n }\n\n // The encoder's msgSeqNum is already incremented after each message is sent,\n // so we just need to retry the logon. The next logon will use the next sequence number.\n this.sessionLogger.info(`LOGON_SEQ_RETRY: attempt=${this.coordinator.logonRetryCount}/${AsciiSession.MaxLogonRetries}, reason='${text}'`)\n this.sendLogon()\n }\n\n okForLogon (): boolean {\n const state = this.sessionState.state\n if (this.acceptor) {\n return state === SessionState.WaitingForALogon\n }\n return state === SessionState.InitiationLogonSent\n }\n\n protected onSessionMsg (msgType: string, view: MsgView): void {\n const logger = this.sessionLogger\n\n switch (msgType) {\n case MsgType.Logon: {\n // only valid to receive a logon when in LogonSent or WaitingALogon\n // else will drop connection immediately.\n if (this.okForLogon()) {\n this.peerLogon(view)\n } else {\n this.terminate(new Error(`state ${this.stateString()} is illegal for Logon`))\n }\n break\n }\n\n case MsgType.Logout: {\n this.peerLogout(view)\n break\n }\n\n case MsgType.TestRequest: {\n const req: string | null = view.getString(MsgTag.TestReqID)\n if (req) {\n this.sendHeartbeat(req)\n }\n break\n }\n\n case MsgType.Heartbeat: {\n this.sessionState.lastTestRequestAt = null\n this.setState(SessionState.ActiveNormalSession)\n break\n }\n\n case MsgType.ResendRequest: {\n logger.info(`peer sends '${msgType}' resend request.`)\n this.onResendRequest(view)\n break\n }\n\n case MsgType.SequenceReset: {\n const newSeqNo: number = view.getTyped(MsgTag.NewSeqNo) as number\n const gapFillSeq: number = view.getTyped(MsgTag.MsgSeqNum) as number\n logger.info(`peer sends '${msgType}' sequence reset. newSeqNo = ${newSeqNo}`)\n // expect newSeqNo to be the next message's sequence number.\n this.sessionState.lastPeerMsgSeqNum = newSeqNo - 1\n // Notify coordinator to update expected target and clear pending resend requests\n this.coordinator.onGapFillReceived(gapFillSeq, newSeqNo).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.onGapFillReceived store persist failed: ${e.message}`)\n })\n break\n }\n\n case MsgType.Reject: {\n const refMsgType = view.getString(MsgTag.RefMsgType)\n const text = view.getString(MsgTag.Text)\n const reason = view.getTyped(MsgTag.SessionRejectReason) as number | undefined\n logger.info(`peer rejects RefMsgType='${refMsgType}', reason=${reason}, text='${text}'`)\n\n // Check if this is a logon rejection due to sequence mismatch while we're waiting for logon response.\n // Only retry for ValueIsIncorrect (sequence too low) — structural rejections (RequiredTagMissing etc.)\n // indicate a config problem that retrying won't fix.\n if (refMsgType === MsgType.Logon &&\n this.sessionState.state === SessionState.InitiationLogonSent &&\n reason === SessionRejectReason.ValueIsIncorrect) {\n this.handleLogonRejected(text)\n }\n break\n }\n }\n }\n\n protected onMsg (msgType: string, view: MsgView): void {\n if (this.wildcardTarget && !this.identityBound) {\n this.onMsgBeforeIdentity(msgType, view)\n return\n }\n if (this.logonVerdictPending) {\n // the application is still deciding whether to accept this peer - hold anything\n // it sends in the meantime rather than acting on it (see awaitLogonVerdict)\n this.sessionLogger.info(`queueing '${msgType}' received while awaiting logon verdict`)\n this.pendingRx.push({ msgType, view: view.clone() })\n return\n }\n this.dispatchMsg(msgType, view)\n }\n\n /**\n * Message handling for a wildcard acceptor which has not yet learned who it is\n * talking to. The first message must be a Logon; it carries the peer's\n * SenderCompID, which becomes our TargetCompID and hence our SessionId and store.\n *\n * Binding is asynchronous (the store may have to be read from disk) while message\n * delivery is not: the parser emits every message it finds in a TCP segment in one\n * synchronous burst, and a view is only valid for the duration of its own event -\n * AsciiParser recycles the tag index and buffer immediately afterwards. So each\n * message that arrives mid-bind is cloned and queued, then replayed in order.\n */\n private onMsgBeforeIdentity (msgType: string, view: MsgView): void {\n if (this.bindInProgress) {\n this.sessionLogger.info(`queueing '${msgType}' received while binding session identity`)\n this.pendingRx.push({ msgType, view: view.clone() })\n return\n }\n\n if (msgType !== MsgType.Logon) {\n this.terminate(new Error(`wildcard acceptor expects Logon as the first message, received '${msgType}'`))\n return\n }\n\n const peerCompId = view.getString(MsgTag.SenderCompID)\n if (!peerCompId) {\n this.terminate(new Error('Logon has no SenderCompID - cannot establish session identity'))\n return\n }\n\n this.bindInProgress = true\n const logon = view.clone()\n this.transport?.duplex.readable?.pause()\n\n this.bindIdentity(peerCompId).then(() => {\n this.bindInProgress = false\n this.identityBound = true\n // dispatching the logon can itself open a second gate - an application whose\n // onLogon returns a promise is now deciding - so let resumeRx work out whether\n // it is actually safe to let the socket run again\n this.dispatchMsg(MsgType.Logon, logon)\n this.resumeRx()\n }).catch((e: Error) => {\n this.bindInProgress = false\n this.pendingRx.length = 0\n this.terminate(new Error(`failed to bind session identity for peer '${peerCompId}': ${e.message}`))\n })\n }\n\n /**\n * True while an asynchronous step in the logon handshake is still running and no\n * received message may be acted on: either the identity bind of a wildcard acceptor\n * or an application still deciding the logon verdict.\n */\n private rxGated (): boolean {\n return this.bindInProgress || this.logonVerdictPending\n }\n\n /**\n * Let the socket run again now a gate has opened - but only if no other gate is\n * still shut. Draining can re-gate (a replayed message could start another async\n * step) so the check is repeated after the queue is played out; whichever gate\n * closes last is the one that resumes.\n */\n private resumeRx (): void {\n if (this.rxGated()) return\n this.drainPendingRx()\n if (this.rxGated()) return\n this.transport?.duplex.readable?.resume()\n }\n\n private drainPendingRx (): void {\n while (this.pendingRx.length > 0) {\n if (this.rxGated()) {\n this.sessionLogger.info('suspending replay - logon handshake gated again')\n return\n }\n const queued = this.pendingRx.shift()\n if (!queued) break\n if (this.sessionState.state === SessionState.Stopped) {\n this.sessionLogger.info(`dropping queued '${queued.msgType}' - session stopped during bind`)\n continue\n }\n this.dispatchMsg(queued.msgType, queued.view)\n }\n }\n\n /**\n * Adopt the peer's comp id as our TargetCompID, then build the identity derived\n * state: SessionId, message store, sequence coordinator, registry claim. This is\n * the wildcard equivalent of the work run() does up front for a statically\n * configured session.\n */\n private async bindIdentity (peerCompId: string): Promise<void> {\n const logger = this.sessionLogger\n logger.info(`wildcard acceptor: binding session identity to peer SenderCompID '${peerCompId}'`)\n\n // the description is this session's own clone (see makeSessionScope), and the\n // session message factory holds the same object, so outbound headers pick the\n // new target up immediately\n asMutable(this.config.description).TargetCompID = peerCompId\n\n // every session on a wildcard listener shared one logger name until now, which\n // makes a multi-client server log impossible to follow\n this.sessionLogger = this.config.logFactory.logger(`${this.me}:${peerCompId}:FixSession`)\n\n this.sessionId = new SessionId(\n this.config.description.BeginString,\n this.config.description.SenderCompId,\n peerCompId\n )\n this.sessionStore = this.storeFactory().create(this.sessionId)\n await this.sessionStore.initialize()\n\n this.coordinator = new SessionSequenceCoordinator(this.sessionStore, this.clock)\n this.coordinator.initializeFromStore()\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = this.coordinator.nextSenderSeqNum\n }\n this.sessionState.lastPeerMsgSeqNum = this.coordinator.lastProcessedPeerSeqNum\n\n logger.info(`session identity bound: ${this.sessionId.toString()} ` +\n `nextSender=${this.coordinator.nextSenderSeqNum}, expectedTarget=${this.coordinator.expectedTargetSeqNum}`)\n\n this.claimSessionId()\n }\n\n private dispatchMsg (msgType: string, view: MsgView): void {\n if (!this.checkSeqNo(msgType, view)) {\n this.sessionLogger.info(`message '${msgType}' failed checkSeqNo.`)\n return\n }\n\n if (this.checkMsgIntegrity && !this.checkIntegrity(msgType, view)) {\n this.sessionLogger.info(`message '${msgType}' failed checkIntegrity.`)\n switch (msgType) {\n case MsgType.Logon: {\n this.setState(SessionState.PeerLogonRejected)\n this.startTimer()\n break\n }\n }\n return\n }\n\n switch (msgType) {\n case MsgType.Logon:\n case MsgType.Logout:\n case MsgType.TestRequest:\n case MsgType.Reject:\n case MsgType.SequenceReset:\n case MsgType.Heartbeat:\n case MsgType.ResendRequest: {\n this.onSessionMsg(msgType, view)\n break\n }\n\n default: {\n this.checkForwardMsg(msgType, view)\n break\n }\n }\n }\n\n private startTimer (interval: number = 200): void {\n const logger = this.sessionLogger\n logger.info(`start heartbeat timer. interval = ${interval}`)\n this.timer = setInterval(() => {\n this.tick()\n }, interval)\n }\n\n private peerLogon (view: MsgView): void {\n const logger = this.sessionLogger\n const [heartBtInt, peerCompId, userName, password] = view.getTypedTags([MsgTag.HeartBtInt, MsgTag.SenderCompID, MsgTag.Username, MsgTag.Password])\n const resetSeqNumFlag = view.getTyped(MsgTag.ResetSeqNumFlag) as boolean | undefined\n logger.info(`peerLogon Username = ${userName}, heartBtInt = ${heartBtInt}, peerCompId = ${peerCompId}, resetSeqNumFlag = ${resetSeqNumFlag}`)\n\n // Handle ResetSeqNumFlag from peer's logon\n if (resetSeqNumFlag === true) {\n const peerSeqNum = (view.getTyped(MsgTag.MsgSeqNum) as number) ?? 1\n const weAlsoReset = this.config.description.ResetSeqNumFlag\n logger.info(`peer sent ResetSeqNumFlag=Y with seqNum=${peerSeqNum}, weAlsoReset=${weAlsoReset}`)\n\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n const savedEncoderSeqNum = weAlsoReset && transmitter ? transmitter.msgSeqNum : null\n\n // Fire-and-forget the async coordinator call (store updates resolve on next microtask)\n // but compute the expected values synchronously since we know the reset outcome\n this.coordinator.handlePeerReset(peerSeqNum, weAlsoReset).catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.handlePeerReset store persist failed: ${e.message}`)\n })\n if (transmitter) {\n transmitter.msgSeqNum = savedEncoderSeqNum ?? 1\n }\n this.sessionState.lastPeerMsgSeqNum = peerSeqNum\n\n // Recreate resender with empty store\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n logger.info(`reset complete: encoderSeqNum=${transmitter?.msgSeqNum}, lastPeerMsgSeqNum=${peerSeqNum}`)\n }\n\n const state = this.sessionState\n state.peerHeartBeatSecs = view.getTyped(MsgTag.HeartBtInt) as number\n state.peerCompId = view.getTyped(MsgTag.SenderCompID) as string\n\n const verdict = this.onLogon(view, userName as string, password as string)\n if (typeof verdict === 'boolean') {\n // the common case - finish the handshake in this same event, so an application\n // with a synchronous onLogon sees exactly the timing it always has\n this.completePeerLogon(view, verdict, resetSeqNumFlag)\n return\n }\n this.awaitLogonVerdict(view, verdict, resetSeqNumFlag)\n }\n\n /**\n * onLogon handed back a promise - the application is checking the credentials\n * against something asynchronous. Nothing may be sent or acted on until it\n * answers, so pause the socket and queue whatever the peer says in the meantime.\n *\n * The view has to be cloned: AsciiParser recycles its tag index and buffer as soon\n * as the current event returns, so the original is meaningless by the time the\n * promise settles. Anything already read off it - peerReset here - is carried\n * across as a value rather than read again from the clone.\n */\n private awaitLogonVerdict (view: MsgView, verdict: Promise<boolean>, peerReset: boolean | undefined): void {\n const logger = this.sessionLogger\n logger.info('onLogon returned a promise - awaiting logon verdict')\n this.logonVerdictPending = true\n const logon = view.clone()\n this.transport?.duplex.readable?.pause()\n\n verdict.then((accepted: boolean) => {\n this.logonVerdictPending = false\n if (this.sessionState.state === SessionState.Stopped) {\n logger.info('session stopped while awaiting logon verdict - discarding')\n this.pendingRx.length = 0\n return\n }\n this.completePeerLogon(logon, accepted, peerReset)\n if (!accepted) {\n // completePeerLogon has torn the session down - nothing queued can be acted on\n this.pendingRx.length = 0\n return\n }\n this.resumeRx()\n }).catch((e: Error) => {\n this.logonVerdictPending = false\n this.pendingRx.length = 0\n // a credential check that throws is a refusal, not a reason to let the peer in\n this.rejectLogon(`onLogon failed: ${e.message}`)\n })\n }\n\n /**\n * The application has accepted or refused the peer - finish the handshake either way.\n */\n private completePeerLogon (view: MsgView, accepted: boolean, peerReset: boolean | undefined): void {\n const logger = this.sessionLogger\n logger.info(`peerLogon onLogon returns ${accepted}`)\n if (!accepted) {\n this.rejectLogon('logon rejected by application')\n return\n }\n if (this.acceptor) {\n this.setState(SessionState.InitiationLogonResponse)\n logger.info('acceptor responds to logon request')\n\n // If WE (acceptor) are sending ResetSeqNumFlag=Y but peer didn't request it,\n // reset our sequences before sending our logon response.\n // This handles the broker-reset pattern where client sends N, we respond with Y.\n const weReset = this.config.description.ResetSeqNumFlag\n if (weReset && peerReset !== true) {\n logger.info('acceptor sending ResetSeqNumFlag=Y (peer sent N), resetting sequences')\n // Fire-and-forget async coordinator call, set values synchronously\n this.coordinator.resetAsAcceptor().catch((e: Error) => {\n this.sessionLogger.warning(`coordinator.resetAsAcceptor store persist failed: ${e.message}`)\n })\n const transmitter = this.transport?.transmitter as AsciiMsgTransmitter | undefined\n if (transmitter) {\n transmitter.msgSeqNum = 1\n }\n this.sessionState.lastPeerMsgSeqNum = 0\n if (this.store) {\n this.store.clear().catch((e: Error) => {\n this.sessionLogger.warning(`store.clear failed: ${e.message}`)\n })\n this.resender = new FixMsgAsciiStoreResend(this.store, this.config)\n }\n }\n\n this.sendLogon()\n } else { // as an initiator the acceptor has responded\n logger.info('initiator receives logon response')\n this.setState(SessionState.InitiationLogonReceived)\n }\n // Reset logon retry counter on successful logon\n this.coordinator.resetLogonRetryCount()\n\n if (this.heartbeat) {\n this.startTimer()\n }\n logger.info('system ready, inform app')\n this.onReady(view)\n }\n\n /**\n * The application refused this peer. FIX expects the refusing side to say why and\n * then hang up rather than simply going quiet, so send a Logout carrying the reason\n * before dropping the transport - the order matters, send() discards anything\n * offered once the session has stopped.\n *\n * onReady is never reached and no heartbeat timer starts; the application learns the\n * outcome through onStopped(error).\n */\n private rejectLogon (reason: string): void {\n this.sessionLogger.warning(`refusing peer logon: ${reason}`)\n this.sendLogout(reason)\n this.terminate(new Error(reason))\n }\n\n private sendTestRequest (): void {\n const factory = this.config.factory\n this.setState(SessionState.AwaitingProcessingResponseToTestRequest)\n const tr = factory?.testRequest()\n if (tr) {\n this.send(MsgType.TestRequest, tr)\n }\n }\n\n private sendHeartbeat (testReqId: string): void {\n const factory = this.config.factory\n const hb = factory?.heartbeat(testReqId)\n if (hb) {\n this.send(MsgType.Heartbeat, hb)\n }\n }\n\n private tick (): void {\n if (!this.transport) return\n const sessionState = this.sessionState\n const action: TickAction = sessionState.calcAction(new Date())\n const application: IMsgApplication | null = this.transport.config.description.application ?? null\n const logger = this.sessionLogger\n // Clean up timed-out resend requests\n this.coordinator.tick()\n\n switch (action) {\n case TickAction.Nothing: {\n // all is well\n break\n }\n\n case TickAction.TestRequest: {\n logger.debug(`send test req. state = ${sessionState.toString()}`)\n this.sendTestRequest()\n break\n }\n\n case TickAction.Heartbeat: {\n logger.debug(`send heartbeat. state = ${sessionState.toString()}`)\n this.sendHeartbeat(sessionState.now.toUTCString())\n break\n }\n\n case TickAction.TerminateOnError: {\n if (this.coordinator.incrementTimeoutRecovery(AsciiSession.MaxTimeoutRecoveryAttempts)) {\n // Try to recover — reset timeout state to give session a fresh window.\n // This helps survive sleep/wake scenarios where TCP connection may still be alive.\n logger.info(`timeout recovery attempt ${this.coordinator.timeoutRecoveryAttempts}, resetting timeout state`)\n sessionState.lastTestRequestAt = null\n sessionState.lastReceivedAt = new Date()\n this.setState(SessionState.ActiveNormalSession)\n } else {\n logger.info(sessionState.toString())\n this.terminate(new Error(`${application?.name}: peer not responding`))\n }\n break\n }\n\n case TickAction.Stop: {\n logger.info(sessionState.toString())\n logger.info('stopping')\n this.stop()\n break\n }\n\n default:\n throw new Error('unexpected action')\n }\n }\n}\n"]}
|
|
@@ -65,5 +65,5 @@ export declare abstract class FixSession extends events.EventEmitter {
|
|
|
65
65
|
protected abstract onApplicationMsg(msgType: string, view: MsgView): void;
|
|
66
66
|
protected abstract onReady(view: MsgView): void;
|
|
67
67
|
protected abstract onStopped(error?: Error): void;
|
|
68
|
-
protected abstract onLogon(view: MsgView, user: string, password: string): boolean
|
|
68
|
+
protected abstract onLogon(view: MsgView, user: string, password: string): boolean | Promise<boolean>;
|
|
69
69
|
}
|