Skip to content

Instantly share code, notes, and snippets.

@myndzi
Last active December 26, 2015 14:19
Show Gist options
  • Save myndzi/7164515 to your computer and use it in GitHub Desktop.
Save myndzi/7164515 to your computer and use it in GitHub Desktop.
Pseudo-code implementation of IRC-like flood control
var api = require('socket.io')
, io = null;
var Message = require('./message')
, User = require('./user');
var waitDelay = 1
, linePenalty = 2
, burstThreshold = 10
, numCharsPenalty = 120
, disconnectThreshold = 1500;
var users = []
, messages = []
, msgTimer = null;
exports.listen = function(server) {
io = api.listen(server);
io.sockets.on('connection', function(socket) {
var user = new User(socket);
users.push(user);
socket.on('message', function(data) {
var m = new Message(user, data.text);
messages.push(m);
if (msgTimer) { clearTimeout(msgTimer); }
process.nextTick(processMessages);
});
// FIXME: This doesn't actually trigger when we kill a user. also it should still clear that user's messages
socket.on('disconnect', function () {
users.splice(users.indexOf(user), 1);
});
});
};
var processMessages = function() {
msgTimer = null;
var m
, now = Date.now()
, bt = now + burstThreshold * 1000;
for (var i = 0; i < messages.length; i++) {
m = messages[i];
if (m.source.destroyed) {
messages[i] = null;
continue;
}
// add the character count for this message to the user's tally
m.source.queuedChars += m.text.length;
if (m.source.penalty < bt) {
messages[i] = null;
io.sockets.emit('message', { source: m.source.socket.id, text: m.text });
// take it away after sending
m.source.queuedChars -= m.text.length;
// updates the time-based penalty on the source user
m.source.updatePenalty(m.text, linePenalty, numCharsPenalty);
} else if (m.source.queuedChars > disconnectThreshold) {
m.source.kill('Excess Flood');
}
}
messages = messages.filter(function (a) { return a !== null; });
if (messages.length) {
msgTimer = setTimeout(processMessages, 1000);
}
};
function User(socket) {
this.destroyed = false;
this.socket = socket;
this.queuedChars = 0;
this.penalty = Date.now();
};
// Unused.
User.prototype.send = function(source, text) {
this.socket.emit('message', { source: source, text: text });
};
User.prototype.kill = function(text) {
this.socket.emit('message', { source: 'system', text: text });
this.destroy();
};
User.prototype.updatePenalty = function (text, linePenalty, numCharsPenalty) {
this.penalty = Math.max(this.penalty, Date.now()) + (linePenalty +
Math.floor(text.length / numCharsPenalty))*1000;
};
User.prototype.destroy = function () {
this.destroyed = true;
this.socket.disconnect();
};
function Message(fromUser, text) {
this.source = fromUser;
this.text = text;
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment