93 lines
2.1 KiB
JavaScript
93 lines
2.1 KiB
JavaScript
import {tinyws} from "tinyws";
|
|
import { randomUUID } from 'crypto';
|
|
|
|
export default class SocketHandler {
|
|
|
|
constructor(path, args) {
|
|
this.path = path;
|
|
this.connections = {};
|
|
this.handlers = {
|
|
'join': [],
|
|
'leave': [],
|
|
'message': [],
|
|
};
|
|
|
|
this.pingInterval = null;
|
|
}
|
|
|
|
start(express) {
|
|
express.use(tinyws());
|
|
express.use(this.path, this._receiveRequest.bind(this));
|
|
|
|
this.pingInterval = setInterval(() => {
|
|
Object.values(this.connections).forEach(client => {
|
|
if (++client.failedPings > 3) {
|
|
this.terminateClient(client.id);
|
|
} else {
|
|
client.ws.ping();
|
|
}
|
|
});
|
|
}, 30000);
|
|
|
|
// this.pingInterval
|
|
}
|
|
|
|
stop() {
|
|
clearInterval(this.pingInterval);
|
|
}
|
|
|
|
broadcast(msg) {
|
|
Object.values(this.connections).forEach(client => {
|
|
client.ws.send(msg);
|
|
});
|
|
}
|
|
|
|
async _receiveRequest(req, res) {
|
|
if (req.ws) {
|
|
const ws = await req.ws()
|
|
return this._receiveWebsocket(req, res, ws);
|
|
} else {
|
|
// not handling HTTP
|
|
}
|
|
}
|
|
|
|
async _receiveWebsocket(req, res, ws) {
|
|
ws.id = randomUUID();
|
|
this.connections[ws.id] = {
|
|
ws: ws,
|
|
id: ws.id,
|
|
joined: new Date(),
|
|
failedPings: 0,
|
|
};
|
|
|
|
ws.on('close', () => {
|
|
this._fire('leave', ws);
|
|
delete this.connections[ws.id];
|
|
});
|
|
|
|
ws.on('message', (data, ...args) => {
|
|
this._fire('message', ws, data, ...args);
|
|
});
|
|
|
|
ws.on('pong', () => {
|
|
this.failedPings = 0;
|
|
});
|
|
|
|
this._fire('join', ws);
|
|
}
|
|
|
|
terminateClient(uuid) {
|
|
this.connections[uuid].ws.terminate();
|
|
delete this.connections[uuid];
|
|
}
|
|
|
|
on(event, callback) {
|
|
this.handlers[event].push(callback);
|
|
}
|
|
|
|
_fire(event, ...args) {
|
|
this.handlers[event].forEach(cb => cb(...args));
|
|
}
|
|
|
|
}
|