// @flow
// Copyright (c) 2016 Uber Technologies, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software distributed under the License
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
// or implied. See the License for the specific language governing permissions and limitations under
// the License.
export default class RateLimiter {
_creditsPerSecond: number;
_balance: number;
_maxBalance: number;
_lastTick: number;
constructor(creditsPerSecond: number, maxBalance: number, initBalance: ?number) {
this._creditsPerSecond = creditsPerSecond;
this._balance = initBalance || Math.random() * maxBalance;
this._maxBalance = maxBalance;
this._lastTick = new Date().getTime();
}
update(creditsPerSecond: number, maxBalance: number) {
this._updateBalance();
this._creditsPerSecond = creditsPerSecond;
// The new balance should be proportional to the old balance.
this._balance = maxBalance * this._balance / this._maxBalance;
this._maxBalance = maxBalance;
}
checkCredit(itemCost: number): boolean {
this._updateBalance();
if (this._balance >= itemCost) {
this._balance -= itemCost;
return true;
}
return false;
}
_updateBalance() {
let currentTime: number = new Date().getTime();
let elapsedTime: number = (currentTime - this._lastTick) / 1000;
this._lastTick = currentTime;
this._balance += elapsedTime * this._creditsPerSecond;
if (this._balance > this._maxBalance) {
this._balance = this._maxBalance;
}
}
}
|