Last active
December 26, 2015 14:19
-
-
Save myndzi/7164515 to your computer and use it in GitHub Desktop.
Pseudo-code implementation of IRC-like flood control
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
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