'use strict'; const stream = require('stream'), Socket = require('net').Socket, assert = require('assert'); /** * Base TCPDevice class for handling TCP socket from tracking device * */ class TCPDevice extends stream.Duplex { constructor(socket, ops) { super(ops); this.ops = Object.assign({}, { maxInvalidReadTry: 5 }, ops); // Perform type assertions assert.ok(socket instanceof Socket, 'socket argument must be an instance of Socket'); // prettier-ignore this.id = null; this.msgReceived = 0; this._invalidTry = 0; this._socket = socket; this._socket.on('close', hadError => this.emit('close', hadError)); // this._socket.on("connect", () => console.log("Client connected !")); this._socket.on('drain', () => this.emit('drain')); this._socket.on('end', () => this.emit('end')); this._socket.on('error', err => this.emit('error', err)); this._socket.on('lookup', (e, a, f, h) => this.emit('lookup', e, a, f, h)); this._socket.on('readable', this._onData.bind(this)); this._socket.on('timeout', () => this.emit('timeout')); } /** * Half-closes the socket. It is still possible that the opposite * side is still sending data. */ end() { this._socket.end(); return this; } /** * Destroys the socket and ensures that no more I/O activity happens * on the socket. When an `err` is included, an 'error' event will * be emitted and all listeners will receive the error as an * argument. * @param err optional error to send */ destroy(err) { this._socket.destroy(err); return this; } _guardInvalidTries() { this._invalidTry++; if (this._invalidTry > this.ops.maxInvalidReadTry) throw new Error('Reached maximum invalid read try'); } /** * _onData is triggered by the "readable" event on the underlying TCP socket. * It is called each time there is new data * received. It is responsible for reading data from the socket and * * performing the appropriate action given the current read state. * @virtual Extenders implementation must override this menthod acccording to the detail of the protocol */ _onData() { } _read() { // Trigger a read but wait until the end of the event loop. // This is necessary when reading in paused mode where // _read was triggered by stream.read() originating inside // a "readable" event handler. Attempting to push more data // synchronously will not trigger another "readable" event. setImmediate(() => this._onData()); } _write() { } _final() { } } module.exports = TCPDevice;