diff options
Diffstat (limited to 'lib/socket.js')
-rw-r--r-- | lib/socket.js | 70 |
1 files changed, 70 insertions, 0 deletions
diff --git a/lib/socket.js b/lib/socket.js new file mode 100644 index 0000000..971bacd --- /dev/null +++ b/lib/socket.js @@ -0,0 +1,70 @@ +"use strict" + +const WebSocket = require("ws"); + +class Client { + constructor(ws) { + this.ws = ws; + this.handlers = {}; + + ws.on("message", msg => { const d = JSON.parse(msg); + (this.handlers[d.type]||[]).forEach(cb => cb(d.data)); + }); + + const closecb = () => + (this.handlers["close"]||[]).forEach(cb => cb()); + + ws.on("close", closecb); + ws.on("error", closecb); + } + + on(type, cb) { + (this.handlers[type]||(this.handlers[type]=[])).push(cb); + } + + send(type, data) { + this.ws.send(JSON.stringify({type, data})); + } +} + +module.exports = class Socket { + constructor(server) { + this.wss = new WebSocket.Server({server}); + this.handlers = {}; + this.clients = []; + + this.wss.on("connection", ws => { + const client = new Client(ws); + this.clients.push(client); + + ws.on("message", msg => { const d = JSON.parse(msg); + (this.handlers[d.type]||[]).forEach(cb => cb(client, d.data)); + }); + + let pingTimeout; + const ping = () => { client.send("ping", {}); + pingTimeout = setTimeout(() => ws.terminate(), 3e4); }; + client.on("pong", () => { clearTimeout(pingTimeout); + setTimeout(ping, 1e3); }); ping(); + + const closecb = () => { + const i = this.clients.indexOf(client); if (i < 0) return; + (this.handlers["close"]||[]).forEach(cb => cb(client)); + this.clients.splice(i, 1); + } + + ws.on("close", closecb); + ws.on("error", closecb); + + (this.handlers["open"]||[]).forEach(cb => cb(client)); + }); + } + + on(type, cb) { + (this.handlers[type]||(this.handlers[type]=[])).push(cb); + } + + sendAll(type, data) { + this.clients.forEach(c => c.send(type, data)); + } +}; |