diff options
Diffstat (limited to 'src/util/RequestThrottler.ts')
-rw-r--r-- | src/util/RequestThrottler.ts | 128 |
1 files changed, 0 insertions, 128 deletions
diff --git a/src/util/RequestThrottler.ts b/src/util/RequestThrottler.ts deleted file mode 100644 index d979fbfcf..000000000 --- a/src/util/RequestThrottler.ts +++ /dev/null @@ -1,128 +0,0 @@ -/* - This file is part of GNU Taler - (C) 2019 GNUnet e.V. - - GNU Taler is free software; you can redistribute it and/or modify it under the - terms of the GNU General Public License as published by the Free Software - Foundation; either version 3, or (at your option) any later version. - - TALER is distributed in the hope that it will be useful, but WITHOUT ANY - WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR - A PARTICULAR PURPOSE. See the GNU General Public License for more details. - - You should have received a copy of the GNU General Public License along with - GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/> - */ - -/** - * Implementation of token bucket throttling. - */ - -/** - * Imports. - */ -import { getTimestampNow, timestampDifference } from "../util/time"; - -/** - * Maximum request per second, per origin. - */ -const MAX_PER_SECOND = 50; - -/** - * Maximum request per minute, per origin. - */ -const MAX_PER_MINUTE = 100; - -/** - * Maximum request per hour, per origin. - */ -const MAX_PER_HOUR = 1000; - -/** - * Throttling state for one origin. - */ -class OriginState { - private tokensSecond: number = MAX_PER_SECOND; - private tokensMinute: number = MAX_PER_MINUTE; - private tokensHour: number = MAX_PER_HOUR; - private lastUpdate = getTimestampNow(); - - private refill(): void { - const now = getTimestampNow(); - const d = timestampDifference(now, this.lastUpdate); - if (d.d_ms === "forever") { - throw Error("assertion failed"); - } - const d_s = d.d_ms / 1000; - this.tokensSecond = Math.min( - MAX_PER_SECOND, - this.tokensSecond + d_s / 1000, - ); - this.tokensMinute = Math.min( - MAX_PER_MINUTE, - this.tokensMinute + (d_s / 1000) * 60, - ); - this.tokensHour = Math.min( - MAX_PER_HOUR, - this.tokensHour + (d_s / 1000) * 60 * 60, - ); - this.lastUpdate = now; - } - - /** - * Return true if the request for this origin should be throttled. - * Otherwise, take a token out of the respective buckets. - */ - applyThrottle(): boolean { - this.refill(); - if (this.tokensSecond < 1) { - console.log("request throttled (per second limit exceeded)"); - return true; - } - if (this.tokensMinute < 1) { - console.log("request throttled (per minute limit exceeded)"); - return true; - } - if (this.tokensHour < 1) { - console.log("request throttled (per hour limit exceeded)"); - return true; - } - this.tokensSecond--; - this.tokensMinute--; - this.tokensHour--; - return false; - } -} - -/** - * Request throttler, used as a "last layer of defense" when some - * other part of the re-try logic is broken and we're sending too - * many requests to the same exchange/bank/merchant. - */ -export class RequestThrottler { - private perOriginInfo: { [origin: string]: OriginState } = {}; - - /** - * Get the throttling state for an origin, or - * initialize if no state is associated with the - * origin yet. - */ - private getState(origin: string): OriginState { - const s = this.perOriginInfo[origin]; - if (s) { - return s; - } - const ns = (this.perOriginInfo[origin] = new OriginState()); - return ns; - } - - /** - * Apply throttling to a request. - * - * @returns whether the request should be throttled. - */ - applyThrottle(requestUrl: string): boolean { - const origin = new URL(requestUrl).origin; - return this.getState(origin).applyThrottle(); - } -} |