const Promise = require('bluebird');

const PERIOD_TIME = 30000;
const REQUESTS_PER_PERIOD = 10;

function currentTime() {
    return Date.now();
}

class APILimiter {
    constructor() {
        this.lastPeriod = 0;
        this.requests = 0;
    }

    makeRequest() {
        if(this._isPeriodTimedOut()) {
            this._beginPeriod();
        }

        this.requests = this.requests + 1;

        if(this.requests >= REQUESTS_PER_PERIOD) {
            LOG.warn("Max requests reached! Requests are getting delayed.");
        }
    }

    awaitFreeLimit() {
        if(this.canMakeRequest()) {
            return Promise.resolve();
        } else {
            return Promise.delay(PERIOD_TIME - (currentTime() - this.lastPeriod));
        }
    }

    canMakeRequest() {
        return this._isPeriodTimedOut() || this.requests < REQUESTS_PER_PERIOD;
    }

    _beginPeriod() {
        this.lastPeriod = currentTime();
        this.requests = 0;
    }

    _isPeriodTimedOut() {
        return currentTime() - this.lastPeriod > PERIOD_TIME;
    }
}

module.exports = APILimiter;
const Promise = require('bluebird');

const PERIOD_TIME = 30000;
const REQUESTS_PER_PERIOD = 10;

function currentTime() {
    return Date.now();
}

class APILimiter {
    constructor() {
        this.lastPeriod = 0;
        this.requests = 0;
    }

    makeRequest() {
        if(this._isPeriodTimedOut()) {
            this._beginPeriod();
        }

        this.requests = this.requests + 1;

        if(this.requests >= REQUESTS_PER_PERIOD) {
            LOG.warn("Max requests reached! Requests are getting delayed.");
        }
    }

    awaitFreeLimit() {
        if(this.canMakeRequest()) {
            return Promise.resolve();
        } else {
            return Promise.delay(PERIOD_TIME - (currentTime() - this.lastPeriod)).then(() => {
                return this.awaitFreeLimit();
            });
        }
    }

    canMakeRequest() {
        return this._isPeriodTimedOut() || this.requests < REQUESTS_PER_PERIOD;
    }

    _beginPeriod() {
        this.lastPeriod = currentTime();
        this.requests = 0;
    }

    _isPeriodTimedOut() {
        return currentTime() - this.lastPeriod > PERIOD_TIME;
    }
}

module.exports = APILimiter;
Make sure to wait for a free limit even after delay
Make sure to wait for a free limit even after delay

We have to (possibly) wait again after initially delaying the request
when reaching the API Limit.
Reason being that more requests get piled up than the next limit is
allowing to get through. By waiting for the limit again we ensure that
if more requests than the limit would allow got queued up, don't allow
all of them to go through.

This is subtle but is still important to not run into limits as we're
trying to avoid those.
