sync/notwebsocket.js

184 lines
4.1 KiB
JavaScript

var Logger = require("./logger");
const chars = "abcdefghijklmnopqsrtuvwxyz" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"0123456789";
var NotWebsocket = function() {
this.hash = "";
for(var i = 0; i < 30; i++) {
this.hash += chars[parseInt(Math.random() * (chars.length - 1))];
}
this.pktqueue = [];
this.handlers = {};
this.room = "";
this.lastpoll = Date.now();
this.noflood = {};
}
NotWebsocket.prototype.checkFlood = function(id, rate) {
if(id in this.noflood) {
this.noflood[id].push(Date.now());
}
else {
this.noflood[id] = [Date.now()];
}
if(this.noflood[id].length > 10) {
this.noflood[id].shift();
var hz = 10000 / (this.noflood[id][9] - this.noflood[id][0]);
if(hz > rate) {
throw "Rate is too high: " + id;
}
}
}
NotWebsocket.prototype.emit = function(msg, data) {
var pkt = [msg, data];
this.pktqueue.push(pkt);
}
NotWebsocket.prototype.poll = function() {
this.checkFlood("poll", 100);
this.lastpoll = Date.now();
var q = [];
for(var i = 0; i < this.pktqueue.length; i++) {
q.push(this.pktqueue[i]);
}
this.pktqueue.length = 0;
return q;
}
NotWebsocket.prototype.on = function(msg, callback) {
if(!(msg in this.handlers))
this.handlers[msg] = [];
this.handlers[msg].push(callback);
}
NotWebsocket.prototype.recv = function(urlstr) {
this.checkFlood("recv", 100);
var msg, data;
try {
var js = JSON.parse(urlstr);
msg = js[0];
data = js[1];
}
catch(e) {
Logger.errlog.log("Failed to parse NWS string");
Logger.errlog.log(urlstr);
}
if(!msg)
return;
if(!(msg in this.handlers))
return;
for(var i = 0; i < this.handlers[msg].length; i++) {
this.handlers[msg][i](data);
}
}
NotWebsocket.prototype.join = function(rm) {
if(!(rm in rooms)) {
rooms[rm] = [];
}
rooms[rm].push(this);
}
NotWebsocket.prototype.leave = function(rm) {
if(rm in rooms) {
var idx = rooms[rm].indexOf(this);
if(idx >= 0) {
rooms[rm].splice(idx, 1);
}
}
}
NotWebsocket.prototype.disconnect = function() {
for(var rm in rooms) {
this.leave(rm);
}
this.recv(JSON.stringify(["disconnect", undefined]));
this.emit("disconnect");
clients[this.hash] = null;
delete clients[this.hash];
}
function sendJSON(res, obj) {
var response = JSON.stringify(obj, null, 4);
if(res.callback) {
response = res.callback + "(" + response + ")";
}
var len = unescape(encodeURIComponent(response)).length;
res.setHeader("Content-Type", "application/json");
res.setHeader("Content-Length", len);
res.end(response);
}
var clients = {};
var rooms = {};
function newConnection(req, res) {
var nws = new NotWebsocket();
clients[nws.hash] = nws;
res.callback = req.query.callback;
sendJSON(res, nws.hash);
return nws;
}
exports.newConnection = newConnection;
function msgReceived(req, res) {
var h = req.params.hash;
if(h in clients && clients[h] != null) {
var str = req.params.str;
res.callback = req.query.callback;
try {
if(str == "poll") {
sendJSON(res, clients[h].poll());
}
else {
clients[h].recv(unescape(str));
sendJSON(res, "");
}
}
catch(e) {
res.send(429); // 429 Too Many Requests
}
}
else {
res.send(404);
}
}
exports.msgReceived = msgReceived;
function inRoom(rm) {
var cl = [];
if(rm in rooms) {
for(var i = 0; i < rooms[rm].length; i++) {
cl.push(rooms[rm][i]);
}
}
cl.emit = function(msg, data) {
for(var i = 0; i < this.length; i++) {
this[i].emit(msg, data);
}
};
return cl;
}
exports.inRoom = inRoom;
function checkDeadSockets() {
for(var h in clients) {
if(Date.now() - clients[h].lastpoll >= 2000) {
clients[h].disconnect();
}
}
}
setInterval(checkDeadSockets, 2000);