Last active
May 19, 2021 00:03
-
-
Save tiagosiebler/2aaae16001168b1766f7c99aa5f57402 to your computer and use it in GitHub Desktop.
Websocket monitoring service class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { EventEmitter } from 'events'; | |
const debug = require('debug')('wsmonitor'); | |
/* | |
Give it a websocket to monitor and it'll assert connectivity, handling ping/pong events, and emit actionable state events. | |
Emits events: | |
- connected : connection successfully opened | |
- disconnected : connection dropped or was terminated, reconnect required if desired | |
- wserror : connection saw error | |
Debug this by launching with `DEBUG=exchange:wsmonitor node index.js ......` | |
*/ | |
class WSMonitoringService extends EventEmitter { | |
aliveCheckSeconds: number; | |
ws: any; | |
socketMonitoringTimer: any; | |
isAlive: boolean; | |
lastAlive: Date; | |
constructor(webSocket, aliveCheckSeconds = 10) { | |
super(); | |
this.ws = webSocket; | |
this.aliveCheckSeconds = aliveCheckSeconds; | |
this.isAlive = false; | |
this.setup(webSocket); | |
} | |
setup(ws) { | |
ws.on('error', e => { | |
this.isAlive = true; | |
this.handleError(e); | |
}); | |
ws.on('close', e => { | |
this.isAlive = true; | |
this.handleClosed(e); | |
}); | |
ws.on('open', () => { | |
this.isAlive = true; | |
this.emit('connected', ws); | |
}); | |
ws.on('pong', () => { | |
this.receivedAliveResponse(); | |
}); | |
ws.on('ping', () => { | |
this.receivedPing(ws); | |
}); | |
this.socketMonitoringTimer = setInterval(() => this.checkSocketState(), this.aliveCheckSeconds * 1000); | |
} | |
receivedPing(ws) { | |
debug('received ping, sending response'); | |
try { | |
ws.pong(); | |
} catch (e) { | |
debug(`error in sending ping:pong response: ${e.stack || e.message || e}`); | |
this.handleError(e); | |
} | |
} | |
receivedAliveResponse() { | |
debug('received pong'); | |
this.isAlive = true; | |
this.lastAlive = new Date(); | |
} | |
sendAliveRequest() { | |
// if alive, we'll get a pong back and and isAlive will be set back to true | |
this.ws.ping(); | |
} | |
checkSocketState() { | |
const ws = this.ws; | |
if (!this.isAlive) { | |
debug('isAlive == false'); | |
return ws.terminate(); | |
} | |
this.isAlive = false; | |
// ping will throw an exception if the ws closed earlier (e.g no network), so we'll only ping if the socket's still open | |
if (ws.readyState === ws.OPEN) { | |
debug('sending ping'); | |
this.sendAliveRequest(); | |
} | |
} | |
handleError(e) { | |
debug('error: ', e); | |
this.emit('wserror', e); | |
} | |
handleClosed(e) { | |
clearInterval(this.socketMonitoringTimer); | |
debug('disconnected: ', e); | |
this.emit('disconnected', e); | |
} | |
} | |
export default WSMonitoringService; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment