File size: 1,460 Bytes
9438a57
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
/**
 * Jeton kovası (token bucket) hız sınırlayıcı. Saat dışarıdan verilir (test edilebilirlik).
 * Kova en fazla `capacity` jeton tutar ve saniyede `refillPerSec` jeton dolar.
 */
class RateLimiter {
  constructor({ capacity, refillPerSec, now = () => Date.now() }) {
    if (!(capacity > 0)) throw new RangeError('capacity pozitif olmalı');
    if (!(refillPerSec >= 0)) throw new RangeError('refillPerSec negatif olamaz');
    this.capacity = capacity;
    this.refillPerSec = refillPerSec;
    this.now = now;
    this.tokens = capacity;
    this.last = now();
  }

  _refill() {
    const t = this.now();
    const elapsed = (t - this.last) / 1000;
    if (elapsed > 0) {
      this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillPerSec);
      this.last = t;
    }
  }

  /** Yeterli jeton varsa harcar ve true döner; yoksa hiçbir şey harcamadan false. */
  tryRemove(cost = 1) {
    if (cost <= 0) throw new RangeError('cost pozitif olmalı');
    this._refill();
    if (this.tokens >= cost) {
      this.tokens -= cost;
      return true;
    }
    return false;
  }

  /** Bir sonraki `cost` jetonluk istek için beklenmesi gereken süre (ms, yukarı yuvarlanmış). */
  waitTime(cost = 1) {
    this._refill();
    if (this.tokens >= cost) return 0;
    if (this.refillPerSec === 0) return Infinity;
    return Math.ceil(((cost - this.tokens) / this.refillPerSec) * 1000);
  }
}

module.exports = { RateLimiter };