jspurefix
Version:
pure node js fix engine
149 lines (125 loc) • 5.17 kB
text/typescript
import { ElasticBuffer } from '../buffer'
import moment = require('moment')
export enum SessionState {
Connected = 1,
PeerLoggedOn = 2,
PeerLogonRejected = 3,
WaitingLogoutConfirm = 4,
ConfirmingLogout = 5,
Stopped = 6
}
export enum TickAction {
Nothing = 1,
Heartbeat = 2,
TestRequest = 3,
TerminateOnError = 4,
WaitLogoutConfirmExpired = 5,
Stop = 6
}
export class FixSessionState {
public nextTickAction: TickAction = TickAction.Nothing
public lastReceivedAt: Date = null
public LastSentAt: Date = null
public lastTestRequestAt: Date = null
public logoutSentAt: Date = null
public now: Date = new Date()
public compId: string = ''
public peerCompId: string = ''
public peerHeartBeatSecs: number = 0
public lastPeerMsgSeqNum: number = 0
private secondsSinceLogoutSent: number = -1
private secondsSinceSent: number = -1
private secondsSinceReceive: number = -1
public constructor (public readonly heartBeat: number,
public state: SessionState = SessionState.Connected,
public readonly waitLogoutConfirmSeconds: number = 5,
public readonly stopSeconds: number = 2) {
}
private static dateAsString (d: Date) {
if (!d) {
return 'null'
}
return moment(d).format('HH:mm:ss.SSS')
}
public toString (): string {
const buffer = new ElasticBuffer(1024)
buffer.writeString(`compId = ${this.compId}, `)
buffer.writeString(`heartBeat = ${this.heartBeat}, `)
buffer.writeString(`state = ${this.state}, `)
buffer.writeString(`nextTickAction = ${this.nextTickAction}, `)
buffer.writeString(`now = ${FixSessionState.dateAsString(this.now)}, `)
buffer.writeString(`timeToDie = ${this.timeToDie()}, `)
buffer.writeString(`timeToHeartbeat = ${this.timeToHeartbeat()}, `)
buffer.writeString(`timeToTerminate = ${this.timeToTerminate()}, `)
buffer.writeString(`timeToTestRequest = ${this.timeToTestRequest()}, `)
buffer.writeString(`lastReceivedAt = ${FixSessionState.dateAsString(this.lastReceivedAt)}, `)
buffer.writeString(`LastSentAt = ${FixSessionState.dateAsString(this.LastSentAt)}, `)
buffer.writeString(`lastTestRequestAt = ${FixSessionState.dateAsString(this.lastTestRequestAt)}, `)
buffer.writeString(`logoutSentAt = ${FixSessionState.dateAsString(this.logoutSentAt)}, `)
buffer.writeString(`peerHeartBeatSecs = ${this.peerHeartBeatSecs}, `)
buffer.writeString(`peerCompId = ${this.peerCompId}, `)
buffer.writeString(`lastPeerMsgSeqNum = ${this.lastPeerMsgSeqNum}, `)
buffer.writeString(`secondsSinceLogoutSent = ${this.secondsSinceLogoutSent}, `)
buffer.writeString(`secondsSinceSent = ${this.secondsSinceSent}, `)
buffer.writeString(`secondsSinceReceive = ${this.secondsSinceReceive}`)
return buffer.toString()
}
public calcAction (now: Date): TickAction {
this.now = now
this.calcState()
switch (this.state) {
case SessionState.PeerLogonRejected: {
if (this.secondsSinceSent >= this.stopSeconds) {
this.nextTickAction = TickAction.Stop
}
break
}
case SessionState.WaitingLogoutConfirm:
case SessionState.ConfirmingLogout: {
if (this.timeToDie()) {
this.nextTickAction = TickAction.Stop
}
break
}
case SessionState.PeerLoggedOn: {
if (this.timeToHeartbeat()) {
// have not sent anything for heartbeat period so let other side know still alive.
this.nextTickAction = TickAction.Heartbeat
} else {
// console.log(`${application.name}: secondsSinceSent = ${secondsSinceSent} secondsSinceReceive = ${secondsSinceReceive}`)
if (this.timeToTerminate()) {
this.nextTickAction = TickAction.TerminateOnError
} else if (this.timeToTestRequest()) {
if (!this.lastTestRequestAt) {
// not received anything from peer
this.nextTickAction = TickAction.TestRequest
this.lastTestRequestAt = this.now
}
}
}
break
}
}
return this.nextTickAction
}
public timeToDie (): boolean {
return this.secondsSinceLogoutSent > this.waitLogoutConfirmSeconds ||
this.secondsSinceLogoutSent > this.stopSeconds
}
public timeToHeartbeat (): boolean {
return this.secondsSinceSent >= this.heartBeat
}
public timeToTerminate (): boolean {
return this.secondsSinceReceive >= 2.5 * this.peerHeartBeatSecs
}
public timeToTestRequest (): boolean {
return this.secondsSinceReceive >= 1.5 * this.peerHeartBeatSecs
}
private calcState (): void {
const time = this.now.getTime()
this.nextTickAction = TickAction.Nothing
this.secondsSinceLogoutSent = this.logoutSentAt ? (time - this.logoutSentAt.getTime()) / 1000 : -1
this.secondsSinceSent = (time - this.LastSentAt.getTime()) / 1000
this.secondsSinceReceive = (time - this.lastReceivedAt.getTime()) / 1000
}
}