UNPKG

jspurefix

Version:
127 lines (115 loc) 4.42 kB
import { TcpDuplex } from '../duplex' import { MsgTransport } from '../factory' import { FixAcceptor } from '../fix-acceptor' import { IJsFixConfig, IJsFixLogger } from '../../config' import { createServer as netCreateServer, Server, Socket } from 'net' import { createServer as tlsCreateServer, TlsOptions, TLSSocket } from 'tls' import { TlsOptionsFactory } from './tls-options-factory' import { inject, injectable } from 'tsyringe' import { DITokens } from '../../runtime/di-tokens' @injectable() export class TcpAcceptor extends FixAcceptor { private server: Server private readonly logger: IJsFixLogger private nextId: number = 0 constructor (@inject(DITokens.IJsFixConfig) public readonly config: IJsFixConfig) { super(config.description.application ?? null) this.logger = config.logFactory.logger(`${config.description.application?.name}:TcpAcceptor`) const tlsOptions: TlsOptions | null = this.tlsOptions() if (tlsOptions) { this.tlsServer() } else { this.unsecureServer() } this.server.on('error', (err: Error) => { throw err }) } getId (): number { this.nextId++ return this.nextId } tlsServer (): void { try { const config: IJsFixConfig = this.config const tcp = this.config.description.application?.tcp const tlsOptions: TlsOptions | null = tcp?.tls ? TlsOptionsFactory.getTlsOptions(tcp.tls) : null this.logger.info('create tls server') if (!tlsOptions) return this.server = tlsCreateServer(tlsOptions, (tlsSocket: TLSSocket) => { if (tcp?.tls?.enableTrace) { this.logger.info('enabling tls session trace') tlsSocket.enableTrace() } if (tlsSocket.authorized) { tlsSocket.setEncoding('utf8') const id: number = this.getId() this.logger.info(`tls creates session ${id} ${tlsSocket.authorized}`) this.onSocket(id, tlsSocket, config) } else { this.logger.info('no transport created on tls with no authorized connection') } }) } catch (e) { this.logger.error(e) throw e } } unsecureServer (): void { try { const config = this.config this.logger.info('create unsecured server') this.server = netCreateServer((socket: Socket) => { const id: number = this.getId() this.logger.info(`net creates session ${id}`) socket.setNoDelay(true) this.onSocket(id, socket, config) }) } catch (e) { this.logger.error(e) throw e } } tlsOptions (): TlsOptions | null { const tcp = this.config.description.application?.tcp return tcp?.tls ? TlsOptionsFactory.getTlsOptions(tcp?.tls) : null } private onSocket (id: number, socket: Socket, config: IJsFixConfig): void { const transport: MsgTransport = new MsgTransport(id, config, new TcpDuplex(socket)) this.saveTransport(id, transport) transport.receiver.on('end', () => { this.harvestTransport(id) }) transport.receiver.on('error', (e: Error) => { this.logger.error(e) this.harvestTransport(id) }) } public listen (): void { const port = this.config.description.application?.tcp?.port this.logger.info(`start to listen ${port}`) this.server.on('connection', () => { this.logger.info('insecure connection established') }) this.server.on('secureConnection', (s) => { this.logger.info(`secure connection; client authorized: ${s.authorized}`) }) this.server.listen(port) } public close (callback?: (err?: Error) => void): void { const port = this.config.description.application?.tcp?.port ?? -1 this.logger.info(`close listener on port ${port}`) this.server.close(callback) } private saveTransport (tid: number, transport: MsgTransport): void { this.transports[tid] = transport const keys: string[] = Object.keys(this.transports) this.logger.info(`new transport id = ${tid} created total transports = ${keys.length}`) this.emit('transport', transport) } private harvestTransport (tid: number): void { delete this.transports[tid] const keys: string[] = Object.keys(this.transports) this.logger.info(`transport ${tid} ends total transports = ${keys.length}`) } }