/*jshint laxcomma: true, smarttabs: true, node: true, esnext: true */ 'use strict'; /** * A No op resource throttle implementation, for testing / debuging * @module tastypie/lib/throttle * @author Eric Satterwhite * @since 0.2.2 * @requires tastypie/lib/class * @requires tastypie/lib/class/options * @requires mout/string/slugify * @requires tastypie/lib/class/parent */ var Class = require( './class' ) , Options = require( './class/options' ) , Parent = require( './class/parent' ) , slugify = require('mout/string/slugify') , debug = require('debug')('tastypie:throttle') , Throttle , Memory ; /** * @constructor * @alias module:tastypie/lib/throttle * @param {Object} [options] * @param {Number} [options.at=150] number of request to start throttling */ Throttle = new Class({ mixin:[ Options, Parent ] ,options:{ at:150 } ,constructor: function( options ){ this.setOptions( options ); } /** * Records an entry for a given keyf * @chainable * @method module:tastypie/lib/throttle#incr * @param {String} id the internal key to record **/ ,incr: function incr(){ return this; } /** * Checks if a given key has reached the configured throttling limit * @method module:tastypie/lib/throttle#toThrottle * @param {String} id the internal key to record * @returns {Boolean} **/ ,toThrottle: function toThrottle(){ return false; } /** * creates a namespaced key based on an id * @method module:tastypie/lib/throttle#convert * @param {String} id the internal key to record * @return {String} key **/ ,convert: function convert( id ){ return `access-${slugify( id )}`; } }); /** * An in memory throttle implementation. For testing and debugging purposes only * @class module:tastypie/lib/throttle.Memory * @param {Object} [options] * @param {Number} [options.at=150] The number of requests allowed during a timeframe before they should be throttled * @param {Number} [options.timeframe=30000] The time frame in miliseconds to determine number of attempts before throttling * @param {?Number} [options.expires=null] time in ms after which to expire throttle records */ Memory = new Class({ inherits:Throttle ,options:{ at: 150, timeframe: ( 1000 * 60 * 5), expires: null } ,constructor: function( options ){ this.setOptions( options ); this._mem = Object.create(null) const expires = this.options.expires; expires && setInterval(() => { for( var key in this._mem ) { const now = new Date(); const first = this._mem[key][0]; const diff = first ? now - first : 0; if( diff > expires ){ debug("purging record for %s ", key ); this._mem[key].shift(); } } }, expires).unref(); } /** * Records an entry for a given keyf * @chainable * @method module:tastypie/lib/throttle.Memory#incr * @param {String} id the internal key to record **/ ,incr: function incr( id ){ var key = this.convert( id ); ( this._mem[ key ] = this._mem[ key ] || [] ).push( new Date() ); return this; } /** * Checks if a given key has reached the configured throttling limit * @method module:tastypie/lib/throttle.Memory#toThrottle * @param {String} id the internal key to record * @returns {Boolean} **/ ,toThrottle: function toThrottle( id ){ var that // reference to this , key // lookup key , now // current date , attempts // number of attempts for lookup key ; that = this; key = this.convert( id ); now = new Date(); attempts = ( this._mem [ key ] || []) .filter( function( time ){ return ( now - time ) < that.options.timeframe; }); return attempts.length >= this.options.at; } /** * Returns internal memory * @private * @method module:tastypie/lib/throttle.Memory#toJSON * @returns {Object} **/ ,toJSON: function toJSON(){ return this._mem; } /** * creates a namespaced key based on an id * @method module:tastypie/lib/throttle.Memory#convert * @param {String} id the internal key to record * @return {String} key **/ ,convert: function convert( id ){ return `access-${slugify( id )}`; } }); module.exports = Throttle; module.exports.Memory = Memory;