Skip to content

Instantly share code, notes, and snippets.

@kepstin
Last active January 6, 2016 10:43
Show Gist options
  • Save kepstin/2364412 to your computer and use it in GitHub Desktop.
Save kepstin/2364412 to your computer and use it in GitHub Desktop.
More accurate copyright date.
/*
* Copyright (c) 2012 Calvin Walton <calvin.walton@kepstin.ca>
*
* This program can be used under the terms of either of the two
* licenses below, at your option.
*
* The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* - or -
*
* The WTFPL-2 License
* This program is free software. It comes without any warranty, to
* the extent permitted by applicable law. You can redistribute it
* and/or modify it under the terms of the Do What The Fuck You Want
* To Public License, Version 2, as published by Sam Hocevar. See
* http://sam.zoy.org/wtfpl/COPYING for more details.
*/
/*
* Usage:
* var rl = new RateLimiter(1100, 10); // 1100 ms per request, burst 10 requests
* rl.queue(function() { do stuff });
* rl.queue(function() { do more stuff });
* rl.queue(function() { do nothing, but waste a queue slot anyways });
* ...
*/
function RateLimiter(period, burst) {
this.inQueue = [];
this.outQueue = []
this.period = period || 1100;
this.burst = burst || 10;
this.burstPeriod = this.period * this.burst;
this.active = false;
this.queue = function(request) {
// If there is space in the outqueue, do the request immediately.
if (this.outQueue.length < this.burst) {
console.log("RateLimiter: Performing immediate request");
request();
this.outQueue.push(new Date().getTime());
} else {
this.inQueue.push(request);
console.log("RateLimiter: Queueing request");
}
console.log("RateLimiter: outQueue: " + this.outQueue.length + " inQueue: " + this.inQueue.length);
// Start the timer if it wasn't previously running.
if (!this.active) {
console.log("RateLimiter: starting timer");
this.startTimer();
}
}
this.startTimer = function() {
this.active = true;
var delay = Math.max(this.period, this.burstPeriod - (new Date().getTime() - this.outQueue[0]));
console.log("RateLimiter: Timer delay: " + delay);
setTimeout(function(foo) {foo.next();}, delay , this);
}
this.next = function() {
console.log("RateLimiter: timer tick");
// If the oldest element in outQueue is more than period * burst old, remove it
if (this.outQueue.length > 0) {
if (this.outQueue[0] + this.burstPeriod <= new Date().getTime()) {
this.outQueue.shift();
console.log("RateLimiter: dropping old request from outQueue");
}
}
// Do more requests if we have available space in outQueue
while (this.outQueue.length < this.burst && this.inQueue.length > 0) {
var request = this.inQueue.shift();
console.log("RateLimiter: Performing queued request");
request();
this.outQueue.push(new Date().getTime());
}
console.log("RateLimiter: outQueue: " + this.outQueue.length + " inQueue: " + this.inQueue.length);
// Queue the next timer tick if outQueue isn't empty
if (this.outQueue.length > 0) {
this.startTimer();
} else {
this.active = false;
console.log("RateLimiter: stopping timer");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment