mirror of
https://github.com/Jerryplusy/rc-plugin.git
synced 2025-10-14 16:19:18 +00:00
84 lines
3.0 KiB
JavaScript
84 lines
3.0 KiB
JavaScript
export default class TokenBucket {
|
|
constructor(rate, capacity, interval = 1, isMinute = false) {
|
|
this.interval = interval; // 生成令牌的时间间隔
|
|
this.rate = isMinute ? rate / 60 : rate; // 修改为每分钟生成的令牌数量
|
|
this.capacity = capacity; // 令牌容量
|
|
this.tokens = capacity; // 令牌容量
|
|
this.tokens = new Map(); // 使用 Map 存储每个用户的令牌桶
|
|
this.lastTime = new Date().getTime(); // 上次使用时间
|
|
|
|
/**
|
|
* 核心算法
|
|
* @param tokens
|
|
* @param capacity
|
|
* @param rate
|
|
* @param lastTime
|
|
* @param interval
|
|
* @param isMinute
|
|
* @return {{lastTime: number, tokens: number}}
|
|
*/
|
|
this.updateTokens = (tokens, capacity, rate, lastTime, interval) => {
|
|
// 计算从上次请求到现在经过的时间
|
|
const now = new Date().getTime();
|
|
const elapsed = now - lastTime;
|
|
// 根据时间计算出新生成的令牌数量
|
|
const addedTokens = elapsed * (rate / interval / 1000); // 修改为每分钟生成的令牌数量
|
|
tokens = Math.min(tokens + addedTokens, capacity);
|
|
lastTime = now;
|
|
return { tokens, lastTime };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 消耗令牌-一个桶
|
|
* @param count
|
|
* @return {boolean}
|
|
*/
|
|
consumeSingle(count = 1) {
|
|
const { tokens, lastTime } = this.updateTokens(this.tokens, this.capacity, this.rate, this.lastTime, this.interval);
|
|
// 更新令牌桶中的令牌数量
|
|
this.tokens = tokens;
|
|
|
|
// 判断请求是否能够被处理(即令牌桶中是否有足够的令牌)
|
|
if (count <= this.tokens) {
|
|
this.tokens -= count;
|
|
return true; // 返回 true 表示请求被处理
|
|
} else {
|
|
return false; // 返回 false 表示请求被限流
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 消耗令牌
|
|
* @param id 用户id
|
|
* @param count 请求次数
|
|
* @return {boolean}
|
|
*/
|
|
consume(id, count = 1) {
|
|
const { tokens: userTokens, lastTime: userLastTime } = this.tokens.get(id) || { tokens: this.capacity, lastTime: new Date().getTime() };
|
|
const { tokens, lastTime } = this.updateTokens(userTokens, this.capacity, this.rate, userLastTime, this.interval);
|
|
// 更新令牌桶中的令牌数量
|
|
this.tokens.set(id, { tokens, lastTime });
|
|
|
|
// 判断请求是否能够被处理(即令牌桶中是否有足够的令牌)
|
|
if (count <= tokens) {
|
|
this.tokens.set(id, { tokens: tokens - count, lastTime });
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 重置令牌
|
|
* @param newCapacity
|
|
*/
|
|
resetCapacity(newCapacity) {
|
|
if (newCapacity >= this.tokens) {
|
|
this.capacity = newCapacity;
|
|
this.tokens = newCapacity;
|
|
} else {
|
|
throw new Error('分配少于当前的容量!');
|
|
}
|
|
}
|
|
} |