mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-05 03:39:59 +08:00
✨ feat(limit, message): 引入声明式限流系统并增强消息格式化功能 (#1978)
- 新增 Cooldown、RateLimit、ConcurrencyLimit 三种限流依赖 - MessageUtils 支持动态格式化字符串 (format_args 参数) - 插件CD限制消息显示精确剩余时间 - 重构限流逻辑至 utils/limiters.py,新增时间工具模块 - 整合时间工具函数并优化时区处理 - 新增 limiter_hook 自动释放资源,CooldownError 优化异常处理 - 冷却提示从固定文本改为动态显示剩余时间 - 示例:总结功能冷却中,请等待 1分30秒 后再试~ Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: HibiKier <45528451+HibiKier@users.noreply.github.com>
This commit is contained in:
co-authored by
webjoin111
HibiKier
parent
d218c569d4
commit
b993450a23
+4
-93
@@ -1,19 +1,19 @@
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from datetime import date, datetime
|
||||
from datetime import datetime
|
||||
import os
|
||||
from pathlib import Path
|
||||
import time
|
||||
from typing import Any, ClassVar
|
||||
from typing import ClassVar
|
||||
|
||||
import httpx
|
||||
from nonebot_plugin_uninfo import Uninfo
|
||||
import pypinyin
|
||||
import pytz
|
||||
|
||||
from zhenxun.configs.config import Config
|
||||
from zhenxun.services.log import logger
|
||||
|
||||
from .limiters import CountLimiter, FreqLimiter, UserBlockLimiter # noqa: F401
|
||||
|
||||
|
||||
@dataclass
|
||||
class EntityIDs:
|
||||
@@ -64,78 +64,6 @@ class ResourceDirManager:
|
||||
cls.__tree_append(path, deep)
|
||||
|
||||
|
||||
class CountLimiter:
|
||||
"""
|
||||
每日调用命令次数限制
|
||||
"""
|
||||
|
||||
tz = pytz.timezone("Asia/Shanghai")
|
||||
|
||||
def __init__(self, max_num):
|
||||
self.today = -1
|
||||
self.count = defaultdict(int)
|
||||
self.max = max_num
|
||||
|
||||
def check(self, key) -> bool:
|
||||
day = datetime.now(self.tz).day
|
||||
if day != self.today:
|
||||
self.today = day
|
||||
self.count.clear()
|
||||
return self.count[key] < self.max
|
||||
|
||||
def get_num(self, key):
|
||||
return self.count[key]
|
||||
|
||||
def increase(self, key, num=1):
|
||||
self.count[key] += num
|
||||
|
||||
def reset(self, key):
|
||||
self.count[key] = 0
|
||||
|
||||
|
||||
class UserBlockLimiter:
|
||||
"""
|
||||
检测用户是否正在调用命令
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.flag_data = defaultdict(bool)
|
||||
self.time = time.time()
|
||||
|
||||
def set_true(self, key: Any):
|
||||
self.time = time.time()
|
||||
self.flag_data[key] = True
|
||||
|
||||
def set_false(self, key: Any):
|
||||
self.flag_data[key] = False
|
||||
|
||||
def check(self, key: Any) -> bool:
|
||||
if time.time() - self.time > 30:
|
||||
self.set_false(key)
|
||||
return not self.flag_data[key]
|
||||
|
||||
|
||||
class FreqLimiter:
|
||||
"""
|
||||
命令冷却,检测用户是否处于冷却状态
|
||||
"""
|
||||
|
||||
def __init__(self, default_cd_seconds: int):
|
||||
self.next_time = defaultdict(float)
|
||||
self.default_cd = default_cd_seconds
|
||||
|
||||
def check(self, key: Any) -> bool:
|
||||
return time.time() >= self.next_time[key]
|
||||
|
||||
def start_cd(self, key: Any, cd_time: int = 0):
|
||||
self.next_time[key] = time.time() + (
|
||||
cd_time if cd_time > 0 else self.default_cd
|
||||
)
|
||||
|
||||
def left_time(self, key: Any) -> float:
|
||||
return self.next_time[key] - time.time()
|
||||
|
||||
|
||||
def cn2py(word: str) -> str:
|
||||
"""将字符串转化为拼音
|
||||
|
||||
@@ -277,20 +205,3 @@ def is_number(text: str) -> bool:
|
||||
return True
|
||||
except ValueError:
|
||||
return False
|
||||
|
||||
|
||||
class TimeUtils:
|
||||
@classmethod
|
||||
def get_day_start(cls, target_date: date | datetime | None = None) -> datetime:
|
||||
"""获取某天的0点时间
|
||||
|
||||
返回:
|
||||
datetime: 今天某天的0点时间
|
||||
"""
|
||||
if not target_date:
|
||||
target_date = datetime.now()
|
||||
return (
|
||||
target_date.replace(hour=0, minute=0, second=0, microsecond=0)
|
||||
if isinstance(target_date, datetime)
|
||||
else datetime.combine(target_date, datetime.min.time())
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user