feat: 加入限流算法,限制搜书时间

This commit is contained in:
zhiyu1998 2023-04-11 13:40:35 +08:00
parent c062229ff1
commit 97b12630b0
2 changed files with 126 additions and 39 deletions

View File

@ -11,6 +11,7 @@ import { CAT_LIMIT } from "../utils/constant.js";
import { getZHelper, getBookDetail, getYiBook, getZBook } from "../utils/books.js"; import { getZHelper, getBookDetail, getYiBook, getZBook } from "../utils/books.js";
// 工具类 // 工具类
import _ from "lodash"; import _ from "lodash";
import TokenBucket from '../utils/token-bucket.js'
export class query extends plugin { export class query extends plugin {
constructor() { constructor() {
@ -56,6 +57,10 @@ export class query extends plugin {
reg: "^#竹白(.*)", reg: "^#竹白(.*)",
fnc: "zhubaiSearch", fnc: "zhubaiSearch",
}, },
{
reg: "^#测试",
fnc: "test1",
},
], ],
}); });
} }
@ -303,40 +308,43 @@ export class query extends plugin {
} }
// 集成易书、zBook // 集成易书、zBook
try { const searchBookFunc = async () => {
const bookList = await Promise.allSettled([ try {
getYiBook(e, keyword), const bookList = await Promise.allSettled([
getZBook(e, keyword), getYiBook(e, keyword),
]); getZBook(e, keyword),
// 压缩直链结果 ]);
const combineRet = bookList // 压缩直链结果
.filter(item => item.status === "fulfilled" && item.value && item.value.length > 0) const combineRet = bookList
.flatMap(item => { .filter(item => item.status === "fulfilled" && item.value && item.value.length > 0)
return item.value.flat(); .flatMap(item => {
}); return item.value.flat();
await e.reply(await Bot.makeForwardMsg(combineRet)); });
// ZHelper 特殊处理 await e.reply(await Bot.makeForwardMsg(combineRet));
const zHelper = await getZHelper(e, keyword); // ZHelper 特殊处理
zHelper.unshift({ const zHelper = await getZHelper(e, keyword);
message: "回复格式如下\n" + zHelper.unshift({
"#bookidid来源\n" + message: "回复格式如下\n" +
"\n" + "#bookidid来源\n" +
"示例⬇️\n" + "\n" +
"#bookid 13366067 superlib \n" + "示例⬇️\n" +
"\n" + "#bookid 13366067 superlib \n" +
"注意‼️\n" + "\n" +
"1⃣数字字母之间空格\n" + "注意‼️\n" +
"2⃣id就是每条介绍最前面那串短数字不是isbn号\n" + "1⃣数字字母之间空格\n" +
"3⃣注意看书籍来源只回复#bookid id 默认来源zlibrary ", "2⃣id就是每条介绍最前面那串短数字不是isbn号\n" +
nickname: e.sender.card || e.user_id, "3⃣注意看书籍来源只回复#bookid id 默认来源zlibrary ",
user_id: e.user_id, nickname: e.sender.card || e.user_id,
}) user_id: e.user_id,
zHelper.length > 1 && })
zHelper.length > 1 &&
e.reply(await Bot.makeForwardMsg(zHelper)); e.reply(await Bot.makeForwardMsg(zHelper));
} catch (err) { } catch (err) {
logger.error(err); logger.error(err);
e.reply("部分搜书正在施工🚧"); e.reply("部分搜书正在施工🚧");
}
} }
await this.limitUserUse(e, searchBookFunc);
return true; return true;
} }
@ -355,13 +363,15 @@ export class query extends plugin {
id = /\d+/.exec(keyword)[0]; id = /\d+/.exec(keyword)[0];
source = ""; source = "";
} }
try { await this.limitUserUse(e, async () => {
const res = await getBookDetail(e, id, source); try {
e.reply(await Bot.makeForwardMsg(res)); const res = await getBookDetail(e, id, source);
} catch (err) { e.reply(await Bot.makeForwardMsg(res));
logger.error(err); } catch (err) {
e.reply("搜书正在施工🚧"); logger.error(err);
} e.reply("搜书正在施工🚧");
}
})
return true; return true;
} }
@ -404,9 +414,29 @@ export class query extends plugin {
return true; return true;
} }
/**
* 限制用户调用默认1分钟1次
* @param e
* @param func
* @return {Promise<void>}
*/
async limitUserUse(e, func) {
if (query.#tokenBucket.consume(e.user_id, 1)) {
await func();
} else {
e.reply(`🙅‍${e.nickname}你已经被限流,请稍后再试!`, true);
}
}
// 删除标签 // 删除标签
removeTag(title) { removeTag(title) {
const titleRex = /<[^>]+>/g; const titleRex = /<[^>]+>/g;
return title.replace(titleRex, ""); return title.replace(titleRex, "");
} }
/**
* 令牌桶 拿来限流
* @type {TokenBucket}
*/
static #tokenBucket = new TokenBucket(1, 1);
} }

57
utils/token-bucket.js Normal file
View File

@ -0,0 +1,57 @@
export default class TokenBucket {
constructor(rate, capacity) {
this.rate = rate / 60; // 修改为每分钟生成的令牌数量
this.capacity = capacity;
this.tokens = capacity;
this.tokens = new Map(); // 使用 Map 存储每个用户的令牌桶
this.lastTime = new Date().getTime();
}
/**
* 消耗令牌
* @param id 用户id
* @param count 请求次数
* @return {boolean}
*/
consume(id, count = 1) {
const now = new Date().getTime();
const elapsed = now - this.lastTime;
const addedTokens = elapsed * (this.rate / 1000);
this.lastTime = now;
// 获取用户的令牌桶,如果不存在则创建一个新的令牌桶
let userTokens = this.tokens.get(id);
if (!userTokens) {
userTokens = { tokens: this.capacity, lastTime: now };
this.tokens.set(id, userTokens);
}
// 更新用户的令牌桶中的令牌数量
userTokens.tokens = Math.min(
userTokens.tokens + addedTokens,
this.capacity
);
userTokens.lastTime = now;
// 判断是否有足够的令牌
if (count <= userTokens.tokens) {
userTokens.tokens -= count;
return true;
} else {
return false;
}
}
/**
* 重置令牌
* @param newCapacity
*/
resetCapacity(newCapacity) {
if (newCapacity >= this.tokens) {
this.capacity = newCapacity;
this.tokens = newCapacity;
} else {
throw new Error('New capacity cannot be less than current tokens');
}
}
}