优化manager代码

This commit is contained in:
HibiKier 2022-11-21 20:43:41 +08:00
parent 49e38862af
commit cd66b7f5b8
41 changed files with 1974 additions and 1760 deletions

View File

@ -296,6 +296,10 @@ PS: **ARM平台** 请使用全量版 同时 **如果你的机器 RAM < 1G 可能
## 更新 ## 更新
### 2022/11/21
* 优化manager, hook代码
### 2022/11/19 ### 2022/11/19
* 修改优化帮助图片生成逻辑 * 修改优化帮助图片生成逻辑

View File

@ -23,7 +23,7 @@ except ModuleNotFoundError:
import json import json
async def group_current_status(group_id: int) -> str: def group_current_status(group_id: int) -> str:
""" """
获取当前所有通知的开关 获取当前所有通知的开关
:param group_id: 群号 :param group_id: 群号
@ -31,17 +31,17 @@ async def group_current_status(group_id: int) -> str:
rst = "[被动技能 状态]\n" rst = "[被动技能 状态]\n"
_data = group_manager.get_task_data() _data = group_manager.get_task_data()
for task in _data.keys(): for task in _data.keys():
rst += f'{_data[task]}: {"" if await group_manager.check_group_task_status(group_id, task) else "×"}\n' rst += f'{_data[task]}: {"" if group_manager.check_group_task_status(group_id, task) else "×"}\n'
return rst.strip() return rst.strip()
custom_welcome_msg_json = ( custom_welcome_msg_json = (
Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json" Path() / "data" / "custom_welcome_msg" / "custom_welcome_msg.json"
) )
async def custom_group_welcome( async def custom_group_welcome(
msg: str, imgs: List[str], user_id: int, group_id: int msg: str, imgs: List[str], user_id: int, group_id: int
) -> str: ) -> str:
""" """
替换群欢迎消息 替换群欢迎消息
@ -104,20 +104,21 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
if cmd == "全部被动": if cmd == "全部被动":
for task in task_data: for task in task_data:
if status == "开启": if status == "开启":
if not await group_manager.check_group_task_status(group_id, task): if not group_manager.check_group_task_status(group_id, task):
await group_manager.open_group_task(group_id, task) group_manager.open_group_task(group_id, task)
else: else:
if await group_manager.check_group_task_status(group_id, task): if group_manager.check_group_task_status(group_id, task):
await group_manager.close_group_task(group_id, task) group_manager.close_group_task(group_id, task)
if group_help_file.exists(): if group_help_file.exists():
group_help_file.unlink() group_help_file.unlink()
return f"{status} 全部被动技能!" return f"{status} 全部被动技能!"
if cmd == "全部功能": if cmd == "全部功能":
for f in plugins2settings_manager.get_data(): for f in plugins2settings_manager.get_data():
if status == "开启": if status == "开启":
group_manager.unblock_plugin(f, group_id) group_manager.unblock_plugin(f, group_id, False)
else: else:
group_manager.block_plugin(f, group_id) group_manager.block_plugin(f, group_id, False)
group_manager.save()
if group_help_file.exists(): if group_help_file.exists():
group_help_file.unlink() group_help_file.unlink()
return f"{status} 全部功能!" return f"{status} 全部功能!"
@ -129,18 +130,18 @@ async def change_group_switch(cmd: str, group_id: int, is_super: bool = False):
module = f"{module}:super" module = f"{module}:super"
if status == "开启": if status == "开启":
if type_ == "task": if type_ == "task":
if await group_manager.check_group_task_status(group_id, module): if group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于开启状态!不要重复开启." return f"被动 {task_data[module]} 正处于开启状态!不要重复开启."
await group_manager.open_group_task(group_id, module) group_manager.open_group_task(group_id, module)
else: else:
if group_manager.get_plugin_status(module, group_id): if group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于开启状态!不要重复开启." return f"功能 {cmd} 正处于开启状态!不要重复开启."
group_manager.unblock_plugin(module, group_id) group_manager.unblock_plugin(module, group_id)
else: else:
if type_ == "task": if type_ == "task":
if not await group_manager.check_group_task_status(group_id, module): if not group_manager.check_group_task_status(group_id, module):
return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭." return f"被动 {task_data[module]} 正处于关闭状态!不要重复关闭."
await group_manager.close_group_task(group_id, module) group_manager.close_group_task(group_id, module)
else: else:
if not group_manager.get_plugin_status(module, group_id): if not group_manager.get_plugin_status(module, group_id):
return f"功能 {cmd} 正处于关闭状态!不要重复关闭." return f"功能 {cmd} 正处于关闭状态!不要重复关闭."
@ -197,17 +198,17 @@ def _get_plugin_status() -> MessageSegment:
flag = plugins_manager.get_plugin_block_type(module) flag = plugins_manager.get_plugin_block_type(module)
flag = flag.upper() + " CLOSE" if flag else "OPEN" flag = flag.upper() + " CLOSE" if flag else "OPEN"
try: try:
plugin_name = plugins_manager.get(module)["plugin_name"] plugin_name = plugins_manager.get(module).plugin_name
if ( if (
"[Hidden]" in plugin_name "[Hidden]" in plugin_name
or "[Admin]" in plugin_name or "[Admin]" in plugin_name
or "[Superuser]" in plugin_name or "[Superuser]" in plugin_name
): ):
continue continue
rst += f"{plugin_name}" rst += f"{plugin_name}"
except KeyError: except KeyError:
rst += f"{module}" rst += f"{module}"
if plugins_manager.get(module)["error"]: if plugins_manager.get(module).error:
rst += "[ERROR]" rst += "[ERROR]"
rst += "\n" rst += "\n"
flag_str += f"{flag}\n" flag_str += f"{flag}\n"
@ -238,12 +239,12 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
async with db.transaction(): async with db.transaction():
# 更新权限 # 更新权限
if ( if (
user_info["role"] user_info["role"]
in [ in [
"owner", "owner",
"admin", "admin",
] ]
and not await LevelUser.is_group_flag(user_info["user_id"], group_id) and not await LevelUser.is_group_flag(user_info["user_id"], group_id)
): ):
await LevelUser.set_level( await LevelUser.set_level(
user_info["user_id"], user_info["user_id"],
@ -272,10 +273,10 @@ async def update_member_info(group_id: int, remind_superuser: bool = False) -> b
"%Y-%m-%d %H:%M:%S", "%Y-%m-%d %H:%M:%S",
) )
if await GroupInfoUser.add_member_info( if await GroupInfoUser.add_member_info(
user_info["user_id"], user_info["user_id"],
user_info["group_id"], user_info["group_id"],
nickname, nickname,
join_time, join_time,
): ):
_exist_member_list.append(int(user_info["user_id"])) _exist_member_list.append(int(user_info["user_id"]))
logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功") logger.info(f"用户{user_info['user_id']} 所属{user_info['group_id']} 更新成功")
@ -317,7 +318,4 @@ def set_group_bot_status(group_id: int, status: bool) -> str:
return "呜..醒来了..." return "呜..醒来了..."
else: else:
group_manager.shutdown_group_bot_status(group_id) group_manager.shutdown_group_bot_status(group_id)
# for x in group_manager.get_task_data():
# group_manager.close_group_task(group_id, x)
return "那我先睡觉了..." return "那我先睡觉了..."

View File

@ -2,18 +2,23 @@ from nonebot.adapters.onebot.v11 import Event
from utils.manager import group_manager, plugins2settings_manager from utils.manager import group_manager, plugins2settings_manager
from utils.utils import get_message_text from utils.utils import get_message_text
from services.log import logger from services.log import logger
import time
cmd = [] cmd = []
v = time.time()
def switch_rule(event: Event) -> bool: def switch_rule(event: Event) -> bool:
""" """
检测文本是否是关闭功能命令 说明:
:param event: pass 检测文本是否是关闭功能命令
参数:
:param event: pass
""" """
global cmd global cmd
try: try:
if not cmd: if not cmd or time.time() - v > 60 * 60:
cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"] cmd = ["关闭全部被动", "开启全部被动", "开启全部功能", "关闭全部功能"]
_data = group_manager.get_task_data() _data = group_manager.get_task_data()
for key in _data: for key in _data:
@ -22,10 +27,10 @@ def switch_rule(event: Event) -> bool:
cmd.append(f"开启 {_data[key]}") cmd.append(f"开启 {_data[key]}")
cmd.append(f"关闭 {_data[key]}") cmd.append(f"关闭 {_data[key]}")
_data = plugins2settings_manager.get_data() _data = plugins2settings_manager.get_data()
for key in _data: for key in _data.keys():
try: try:
if isinstance(_data[key]["cmd"], list): if isinstance(_data[key].cmd, list):
for x in _data[key]["cmd"]: for x in _data[key].cmd:
cmd.append(f"开启{x}") cmd.append(f"开启{x}")
cmd.append(f"关闭{x}") cmd.append(f"关闭{x}")
cmd.append(f"开启 {x}") cmd.append(f"开启 {x}")

View File

@ -110,7 +110,7 @@ async def _():
@group_task_status.handle() @group_task_status.handle()
async def _(event: GroupMessageEvent): async def _(event: GroupMessageEvent):
await group_task_status.send(await group_current_status(event.group_id)) await group_task_status.send(group_current_status(event.group_id))
@group_status.handle() @group_status.handle()

View File

@ -16,9 +16,9 @@ admin_help_image = IMAGE_PATH / 'admin_help_img.png'
@driver.on_bot_connect @driver.on_bot_connect
async def init_task(bot: Bot = None): async def init_task():
if not group_manager.get_task_data(): if not group_manager.get_task_data():
await group_manager.init_group_task() group_manager.load_task()
logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.') logger.info(f'已成功加载 {len(group_manager.get_task_data())} 个被动技能.')

View File

@ -44,7 +44,7 @@ async def _(bot: Bot, event: MessageEvent, arg: Message = CommandArg()):
gl = [ gl = [
g["group_id"] g["group_id"]
for g in gl for g in gl
if await group_manager.check_group_task_status(g["group_id"], "broadcast") if group_manager.check_group_task_status(g["group_id"], "broadcast")
] ]
g_cnt = len(gl) g_cnt = len(gl)
cnt = 0 cnt = 0

View File

@ -40,16 +40,14 @@ async def _create_help_img(
:param help_image: 图片路径 :param help_image: 图片路径
:param simple_help_image: 简易帮助图片路径 :param simple_help_image: 简易帮助图片路径
""" """
_matchers = get_matchers(True)
width = 0 width = 0
matchers_data = {} matchers_data = {}
_des_tmp = {} _des_tmp = {}
_plugin_name_tmp = []
_tmp = [] _tmp = []
tmp_img = BuildImage(0, 0, plain_text="1", font_size=24) tmp_img = BuildImage(0, 0, plain_text="1", font_size=24)
font_height = tmp_img.h font_height = tmp_img.h
# 插件分类 # 插件分类
for matcher in _matchers: for matcher in get_matchers(True):
plugin_name = None plugin_name = None
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin: if not _plugin:
@ -67,7 +65,6 @@ async def _create_help_img(
"[hidden]" in plugin_name.lower() "[hidden]" in plugin_name.lower()
or "[admin]" in plugin_name.lower() or "[admin]" in plugin_name.lower()
or "[superuser]" in plugin_name.lower() or "[superuser]" in plugin_name.lower()
or plugin_name in _plugin_name_tmp
or plugin_name == "帮助" or plugin_name == "帮助"
): ):
continue continue
@ -75,11 +72,9 @@ async def _create_help_img(
text_type = 0 text_type = 0
if plugins2settings_manager.get( if plugins2settings_manager.get(
matcher.plugin_name matcher.plugin_name
) and plugins2settings_manager[matcher.plugin_name].get("plugin_type"): ) and plugins2settings_manager.get(matcher.plugin_name).plugin_type:
plugin_type = tuple( plugin_type = tuple(
plugins2settings_manager.get_plugin_data(matcher.plugin_name)[ plugins2settings_manager.get_plugin_data(matcher.plugin_name).plugin_type
"plugin_type"
]
) )
else: else:
try: try:
@ -128,10 +123,7 @@ async def _create_help_img(
if plugin_des not in _des_tmp: if plugin_des not in _des_tmp:
_des_tmp[plugin_des] = plugin_name _des_tmp[plugin_des] = plugin_name
except AttributeError as e: except AttributeError as e:
if plugin_name not in _plugin_name_tmp: logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e{e}")
logger.warning(f"获取功能 {matcher.plugin_name}: {plugin_name} 设置失败...e{e}")
if plugin_name not in _plugin_name_tmp:
_plugin_name_tmp.append(plugin_name)
help_img_list = [] help_img_list = []
simple_help_img_list = [] simple_help_img_list = []
types = list(matchers_data.keys()) types = list(matchers_data.keys())
@ -284,45 +276,13 @@ async def _create_help_img(
B.save(simple_help_image) B.save(simple_help_image)
def get_max_width_or_paste(
simple_help_img_list: List[BuildImage], B: BuildImage = None, is_paste: bool = False
) -> Tuple[int, BuildImage]:
"""
获取最大宽度或直接贴图
:param simple_help_img_list: 简单帮助图片列表
:param B: 背景图
:param is_paste: 是否直接贴图
"""
current_width = 50
current_height = 180
max_width = simple_help_img_list[0].w
for i in range(len(simple_help_img_list)):
try:
if is_paste and B:
B.paste(simple_help_img_list[i], (current_width, current_height), True)
current_height += simple_help_img_list[i].h + 40
if current_height + simple_help_img_list[i + 1].h > B.h - 10:
current_height = 180
current_width += max_width + 30
max_width = 0
elif simple_help_img_list[i].w > max_width:
max_width = simple_help_img_list[i].w
except IndexError:
pass
if current_width > simple_help_img_list[0].w + 50:
current_width += simple_help_img_list[-1].w
return current_width, B
def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]: def get_plugin_help(msg: str, is_super: bool = False) -> Optional[str]:
""" """
获取功能的帮助信息 获取功能的帮助信息
:param msg: 功能cmd :param msg: 功能cmd
:param is_super: 是否为超级用户 :param is_super: 是否为超级用户
""" """
module = plugins2settings_manager.get_plugin_module(msg) module = plugins2settings_manager.get_plugin_module(msg) or admin_manager.get_plugin_module(msg)
if not module:
module = admin_manager.get_plugin_module(msg)
if module: if module:
try: try:
plugin = nonebot.plugin.get_plugin(module) plugin = nonebot.plugin.get_plugin(module)

View File

@ -1,5 +1,37 @@
from nonebot.adapters.onebot.v11 import GroupMessageEvent, PrivateMessageEvent from typing import Optional
from utils.manager import plugins2block_manager, StaticData
import nonebot
from nonebot.adapters.onebot.v11 import (
GroupMessageEvent,
PrivateMessageEvent,
Bot,
Event,
MessageEvent,
Message,
PokeNotifyEvent,
)
from nonebot.exception import ActionFailed, IgnoredException
from nonebot.internal.matcher import Matcher
from models.bag_user import BagUser
from models.ban_user import BanUser
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.level_user import LevelUser
from models.user_shop_gold_log import UserShopGoldLog
from utils.manager import (
plugins2block_manager,
StaticData,
plugins2settings_manager,
group_manager,
admin_manager,
plugins_manager,
plugins2cd_manager,
plugins2count_manager,
)
from utils.message_builder import at
from utils.utils import FreqLimiter
from configs.config import Config
import time import time
ignore_rst_module = ["ai", "poke", "dialogue"] ignore_rst_module = ["ai", "poke", "dialogue"]
@ -8,7 +40,6 @@ other_limit_plugins = ["poke"]
class StatusMessageManager(StaticData): class StatusMessageManager(StaticData):
def __init__(self): def __init__(self):
super().__init__(None) super().__init__(None)
@ -39,8 +70,8 @@ def set_block_limit_false(event, module):
""" """
if plugins2block_manager.check_plugin_block_status(module): if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module) plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"] check_type = plugin_block_data.check_type
limit_type = plugin_block_data["limit_type"] limit_type = plugin_block_data.limit_type
if not ( if not (
(isinstance(event, GroupMessageEvent) and check_type == "private") (isinstance(event, GroupMessageEvent) and check_type == "private")
or (isinstance(event, PrivateMessageEvent) and check_type == "group") or (isinstance(event, PrivateMessageEvent) and check_type == "group")
@ -50,3 +81,436 @@ def set_block_limit_false(event, module):
block_type_ = event.group_id block_type_ = event.group_id
plugins2block_manager.set_false(block_type_, module) plugins2block_manager.set_false(block_type_, module)
async def send_msg(msg: str, bot: Bot, event: MessageEvent):
"""
说明:
发送信息
参数:
:param msg: pass
:param bot: pass
:param event: pass
"""
if "[uname]" in msg:
uname = event.sender.card or event.sender.nickname
msg = msg.replace("[uname]", uname)
if "[nickname]" in msg:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
msg = msg.replace("[nickname]", nickname)
if "[at]" in msg and isinstance(event, GroupMessageEvent):
msg = msg.replace("[at]", str(at(event.user_id)))
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(msg))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(msg))
except ActionFailed:
pass
class ReturnException(Exception):
pass
class AuthChecker:
"""
权限检查
"""
checker: Optional["AuthChecker"] = None
def __init__(self):
self._flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
self._flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD"))
def __new__(cls, *args, **kwargs):
if not cls.checker:
cls.checker = super().__new__(cls)
return cls.checker
async def auth(self, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
权限检查
参数:
:param matcher: matcher
:param bot: bot
:param event: event
"""
try:
plugin_name = matcher.plugin_name
cost_gold = await self.auth_cost(plugin_name, bot, event)
await self.auth_basic(plugin_name, bot, event)
self.auth_group(plugin_name, bot, event)
await self.auth_admin(plugin_name, matcher, bot, event)
await self.auth_plugin(plugin_name, matcher, bot, event)
await self.auth_limit(plugin_name, bot, event)
if cost_gold and str(event.user_id) not in bot.config.superusers:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
except ReturnException:
return
async def auth_limit(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
插件限制
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if plugins2cd_manager.check_plugin_cd_status(plugin_name):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(plugin_name)
check_type = plugin_cd_data.check_type
limit_type = plugin_cd_data.limit_type
msg = plugin_cd_data.rst
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(plugin_name).check_type == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(plugin_name, cd_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} 正在cd中...")
else:
plugins2cd_manager.start_cd(plugin_name, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(plugin_name):
plugin_block_data = plugins2block_manager.get_plugin_block_data(plugin_name)
check_type = plugin_block_data.check_type
limit_type = plugin_block_data.limit_type
msg = plugin_block_data.rst
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, plugin_name):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{plugin_name}....")
else:
plugins2block_manager.set_true(block_type_, plugin_name)
# Count
if (
plugins2count_manager.check_plugin_count_status(plugin_name)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(plugin_name)
limit_type = plugin_count_data.limit_type
msg = plugin_count_data.rst
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(plugin_name, count_type_):
if msg:
await send_msg(msg, bot, event)
raise IgnoredException(f"{plugin_name} count次数限制...")
else:
plugins2count_manager.increase(plugin_name, count_type_)
async def auth_plugin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
插件状态
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in plugins2settings_manager.keys() and matcher.priority not in [
1,
999,
]:
# 戳一戳单独判断
if (
isinstance(event, GroupMessageEvent)
or isinstance(event, PokeNotifyEvent)
or matcher.plugin_name in other_limit_plugins
):
if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
if plugins2settings_manager[
plugin_name
].level > group_manager.get_group_level(event.group_id):
try:
if (
self._flmt_g.check(event.user_id)
and plugin_name not in ignore_rst_module
):
self._flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(plugin_name, event.group_id):
try:
if plugin_name not in ignore_rst_module and self._flmt_s.check(
event.group_id
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(
f"{plugin_name}:super", event.group_id
):
try:
if (
self._flmt_s.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="group"
):
try:
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(
plugin_name, block_type="private"
):
try:
if self._flmt_c.check(event.user_id):
self._flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, plugin_name)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(plugin_name, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
raise ReturnException()
try:
if isinstance(event, GroupMessageEvent):
if (
self._flmt_c.check(event.group_id)
and plugin_name not in ignore_rst_module
):
self._flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, plugin_name)
raise IgnoredException("此功能正在维护...")
async def auth_admin(self, plugin_name: str, matcher: Matcher, bot: Bot, event: Event):
"""
说明:
管理员命令 个人权限
参数:
:param plugin_name: 模块名
:param matcher: matcher
:param bot: bot
:param event: event
"""
if plugin_name in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if (
not await LevelUser.check_level(
event.user_id,
event.group_id,
admin_manager.get_plugin_level(plugin_name),
)
and admin_manager.get_plugin_level(plugin_name) > 0
):
try:
if self._flmt.check(event.user_id):
self._flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_manager.get_plugin_level(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(plugin_name)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(plugin_name)}",
)
except ActionFailed:
pass
set_block_limit_false(event, plugin_name)
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
def auth_group(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
群黑名单检测 群总开关检测
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
if isinstance(event, GroupMessageEvent) or plugin_name in other_limit_plugins:
try:
if (
group_manager.get_group_level(event.group_id) < 0
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("群黑名单")
if not group_manager.check_group_bot_status(event.group_id):
try:
if str(event.get_message()) != "醒来":
raise IgnoredException("功能总开关关闭状态")
except ValueError:
raise IgnoredException("功能总开关关闭状态")
except AttributeError:
pass
async def auth_basic(self, plugin_name: str, bot: Bot, event: Event):
"""
说明:
检测是否满足超级用户权限是否被ban等
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
ban = await BanUser.is_ban(event.user_id)
try:
if (
(
not isinstance(event, MessageEvent)
and plugin_name not in other_limit_plugins
)
or await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2settings_manager.get_plugin_data(plugin_name)
and not plugins2settings_manager.get_plugin_data(
plugin_name
).limit_superuser
):
raise ReturnException()
_plugin = nonebot.plugin.get_plugin(plugin_name)
_module = _plugin.module
_plugin_name = _module.__getattribute__("__zx_plugin_name__")
if (
"[superuser]" in _plugin_name.lower()
and str(event.user_id) in bot.config.superusers
):
raise ReturnException()
except AttributeError:
pass
async def auth_cost(self, plugin_name: str, bot: Bot, event: Event) -> int:
"""
说明:
检测是否满足金币条件
参数:
:param plugin_name: 模块名
:param bot: bot
:param event: event
"""
cost_gold = 0
if isinstance(event, GroupMessageEvent) and (
psm := plugins2settings_manager.get_plugin_data(plugin_name)
):
if psm.cost_gold > 0:
if (
await BagUser.get_gold(event.user_id, event.group_id)
< psm.cost_gold
):
await send_msg(f"金币不足..该功能需要{psm.cost_gold}金币..", bot, event)
raise IgnoredException(f"{plugin_name} 金币限制...")
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not psm.limit_superuser
):
await BagUser.spend_gold(
event.user_id, event.group_id, psm.cost_gold
)
await UserShopGoldLog.add_shop_log(
event.user_id, event.group_id, 2, plugin_name, psm.cost_gold, 1
)
cost_gold = psm.cost_gold
return cost_gold

View File

@ -1,395 +1,36 @@
from nonebot.matcher import Matcher
from nonebot.message import run_preprocessor, run_postprocessor, IgnoredException
from models.friend_user import FriendUser
from models.group_member_info import GroupInfoUser
from models.bag_user import BagUser
from models.user_shop_gold_log import UserShopGoldLog
from utils.manager import (
plugins2settings_manager,
admin_manager,
group_manager,
plugins_manager,
plugins2cd_manager,
plugins2block_manager,
plugins2count_manager,
)
from ._utils import (
set_block_limit_false,
status_message_manager,
ignore_rst_module,
other_limit_plugins,
)
from nonebot.typing import T_State
from typing import Optional from typing import Optional
from nonebot.adapters.onebot.v11 import ( from nonebot.adapters.onebot.v11 import (
Bot, Bot,
ActionFailed,
MessageEvent, MessageEvent,
GroupMessageEvent,
PokeNotifyEvent,
PrivateMessageEvent,
Message,
Event, Event,
) )
from configs.config import Config from nonebot.matcher import Matcher
from models.ban_user import BanUser from nonebot.message import run_preprocessor, run_postprocessor
from utils.utils import FreqLimiter from nonebot.typing import T_State
from utils.message_builder import at
from models.level_user import LevelUser
import nonebot
_flmt = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) from ._utils import (
_flmt_g = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) set_block_limit_false,
_flmt_s = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) AuthChecker,
_flmt_c = FreqLimiter(Config.get_config("hook", "CHECK_NOTICE_INFO_CD")) )
# 权限检测 # # 权限检测
@run_preprocessor @run_preprocessor
async def _(matcher: Matcher, bot: Bot, event: Event, state: T_State): async def _(matcher: Matcher, bot: Bot, event: Event):
module = matcher.plugin_name await AuthChecker().auth(matcher, bot, event)
plugins2info_dict = plugins2settings_manager.get_data()
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
# 功能的金币检测 #######################################
cost_gold = 0
if isinstance(
event, GroupMessageEvent
) and plugins2settings_manager.get_plugin_data(module).get("cost_gold"):
cost_gold = plugins2settings_manager.get_plugin_data(module).get("cost_gold")
if await BagUser.get_gold(event.user_id, event.group_id) < cost_gold:
await send_msg(f"金币不足..该功能需要{cost_gold}金币..", bot, event)
raise IgnoredException(f"{module} 金币限制...")
await UserShopGoldLog.add_shop_log(event.user_id, event.group_id, 2, matcher.plugin_name, cost_gold, 1)
# 当插件不阻塞超级用户时,超级用户提前扣除金币
if (
str(event.user_id) in bot.config.superusers
and not plugins2info_dict[module]["limit_superuser"]
):
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
try:
if (
(not isinstance(event, MessageEvent) and module not in other_limit_plugins)
or await BanUser.is_ban(event.user_id)
and str(event.user_id) not in bot.config.superusers
) or (
str(event.user_id) in bot.config.superusers
and plugins2info_dict.get(module)
and not plugins2info_dict[module]["limit_superuser"]
):
return
except AttributeError:
pass
# 超级用户命令
try:
_plugin = nonebot.plugin.get_plugin(module)
_module = _plugin.module
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if (
"[superuser]" in plugin_name.lower()
and str(event.user_id) in bot.config.superusers
):
return
except AttributeError:
pass
# 群黑名单检测 群总开关检测
if (
isinstance(event, GroupMessageEvent)
or matcher.plugin_name in other_limit_plugins
):
try:
if (
group_manager.get_group_level(event.group_id) < 0
and str(event.user_id) not in bot.config.superusers
):
raise IgnoredException("群黑名单")
if not group_manager.check_group_bot_status(event.group_id):
try:
if str(event.get_message()) != "醒来":
raise IgnoredException("功能总开关关闭状态")
except ValueError:
raise IgnoredException("功能总开关关闭状态")
except AttributeError:
pass
if module in admin_manager.keys() and matcher.priority not in [1, 999]:
if isinstance(event, GroupMessageEvent):
# 个人权限
if (
not await LevelUser.check_level(
event.user_id,
event.group_id,
admin_manager.get_plugin_level(module),
)
and admin_manager.get_plugin_level(module) > 0
):
try:
if _flmt.check(event.user_id):
_flmt.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id,
message=f"{at(event.user_id)}你的权限不足喔,该功能需要的权限等级:"
f"{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.group_id)
raise IgnoredException("权限不足")
else:
if not await LevelUser.check_level(
event.user_id, 0, admin_manager.get_plugin_level(module)
):
try:
await bot.send_private_msg(
user_id=event.user_id,
message=f"你的权限不足喔,该功能需要的权限等级:{admin_manager.get_plugin_level(module)}",
)
except ActionFailed:
pass
set_block_limit_false(event, module)
if event.is_tome():
status_message_manager.add(event.user_id)
raise IgnoredException("权限不足")
if module in plugins2info_dict.keys() and matcher.priority not in [1, 999]:
# 戳一戳单独判断
if (
isinstance(event, GroupMessageEvent)
or isinstance(event, PokeNotifyEvent)
or matcher.plugin_name in other_limit_plugins
):
if status_message_manager.get(event.group_id) is None:
status_message_manager.delete(event.group_id)
if plugins2info_dict[module]["level"] > group_manager.get_group_level(
event.group_id
):
try:
if _flmt_g.check(event.user_id) and module not in ignore_rst_module:
_flmt_g.start_cd(event.user_id)
await bot.send_group_msg(
group_id=event.group_id, message="群权限不足..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("群权限不足")
# 插件状态
if not group_manager.get_plugin_status(module, event.group_id):
try:
if module not in ignore_rst_module and _flmt_s.check(
event.group_id
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该群未开启此功能.."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("未开启此功能...")
# 管理员禁用
if not group_manager.get_plugin_status(f"{module}:super", event.group_id):
try:
if (
_flmt_s.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_s.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="管理员禁用了此群该功能..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("管理员禁用了此群该功能...")
# 群聊禁用
if not plugins_manager.get_plugin_status(module, block_type="group"):
try:
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="该功能在群聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.group_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在群聊中已被禁用...")
else:
# 私聊禁用
if not plugins_manager.get_plugin_status(module, block_type="private"):
try:
if _flmt_c.check(event.user_id):
_flmt_c.start_cd(event.user_id)
await bot.send_private_msg(
user_id=event.user_id, message="该功能在私聊中已被禁用..."
)
except ActionFailed:
pass
if event.is_tome():
status_message_manager.add(event.user_id)
set_block_limit_false(event, module)
raise IgnoredException("该插件在私聊中已被禁用...")
# 维护
if not plugins_manager.get_plugin_status(module, block_type="all"):
if isinstance(
event, GroupMessageEvent
) and group_manager.check_group_is_white(event.group_id):
return
try:
if isinstance(event, GroupMessageEvent):
if (
_flmt_c.check(event.group_id)
and module not in ignore_rst_module
):
_flmt_c.start_cd(event.group_id)
await bot.send_group_msg(
group_id=event.group_id, message="此功能正在维护..."
)
else:
await bot.send_private_msg(
user_id=event.user_id, message="此功能正在维护..."
)
except ActionFailed:
pass
if event.is_tome():
id_ = (
event.group_id
if isinstance(event, GroupMessageEvent)
else event.user_id
)
status_message_manager.add(id_)
set_block_limit_false(event, module)
raise IgnoredException("此功能正在维护...")
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# 以下为限制检测 #######################################################
# Cd
if plugins2cd_manager.check_plugin_cd_status(module):
plugin_cd_data = plugins2cd_manager.get_plugin_cd_data(module)
check_type = plugin_cd_data["check_type"]
limit_type = plugin_cd_data["limit_type"]
rst = plugin_cd_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or plugins2cd_manager.get_plugin_data(module).get("check_type") == "all"
):
cd_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
cd_type_ = event.group_id
if not plugins2cd_manager.check(module, cd_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} 正在cd中...")
else:
plugins2cd_manager.start_cd(module, cd_type_)
# Block
if plugins2block_manager.check_plugin_block_status(module):
plugin_block_data = plugins2block_manager.get_plugin_block_data(module)
check_type = plugin_block_data["check_type"]
limit_type = plugin_block_data["limit_type"]
rst = plugin_block_data["rst"]
if (
(isinstance(event, PrivateMessageEvent) and check_type == "private")
or (isinstance(event, GroupMessageEvent) and check_type == "group")
or check_type == "all"
):
block_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
block_type_ = event.group_id
if plugins2block_manager.check(block_type_, module):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{event.user_id}正在调用{module}....")
else:
plugins2block_manager.set_true(block_type_, module)
# Count
if (
plugins2count_manager.check_plugin_count_status(module)
and event.user_id not in bot.config.superusers
):
plugin_count_data = plugins2count_manager.get_plugin_count_data(module)
limit_type = plugin_count_data["limit_type"]
rst = plugin_count_data["rst"]
count_type_ = event.user_id
if limit_type == "group" and isinstance(event, GroupMessageEvent):
count_type_ = event.group_id
if not plugins2count_manager.check(module, count_type_):
if rst:
rst = await init_rst(rst, event)
await send_msg(rst, bot, event)
raise IgnoredException(f"{module} count次数限制...")
else:
plugins2count_manager.increase(module, count_type_)
# 功能花费的金币 #######################################
# 功能花费的金币 #######################################
if cost_gold:
await BagUser.spend_gold(event.user_id, event.group_id, cost_gold)
async def send_msg(rst: str, bot: Bot, event: MessageEvent):
"""
发送信息
:param rst: pass
:param bot: pass
:param event: pass
"""
rst = await init_rst(rst, event)
try:
if isinstance(event, GroupMessageEvent):
status_message_manager.add(event.group_id)
await bot.send_group_msg(group_id=event.group_id, message=Message(rst))
else:
status_message_manager.add(event.user_id)
await bot.send_private_msg(user_id=event.user_id, message=Message(rst))
except ActionFailed:
pass
# 解除命令block阻塞 # 解除命令block阻塞
@run_postprocessor @run_postprocessor
async def _( async def _(
matcher: Matcher, matcher: Matcher,
exception: Optional[Exception], exception: Optional[Exception],
bot: Bot, bot: Bot,
event: Event, event: Event,
state: T_State, state: T_State,
): ):
if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke": if not isinstance(event, MessageEvent) and matcher.plugin_name != "poke":
return return
module = matcher.plugin_name module = matcher.plugin_name
set_block_limit_false(event, module) set_block_limit_false(event, module)
async def init_rst(rst: str, event: MessageEvent):
if "[uname]" in rst:
uname = event.sender.card or event.sender.nickname
rst = rst.replace("[uname]", uname)
if "[nickname]" in rst:
if isinstance(event, GroupMessageEvent):
nickname = await GroupInfoUser.get_group_member_nickname(
event.user_id, event.group_id
)
else:
nickname = await FriendUser.get_friend_nickname(event.user_id)
rst = rst.replace("[nickname]", nickname)
if "[at]" in rst and isinstance(event, GroupMessageEvent):
rst = rst.replace("[at]", str(at(event.user_id)))
return rst

View File

@ -39,7 +39,7 @@ async def _(bot: Bot, api: str, data: Dict[str, Any]):
group_id = data["group_id"] group_id = data["group_id"]
if group_manager.get_group_level( if group_manager.get_group_level(
group_id group_id
) < 0 or not await group_manager.check_group_task_status(group_id, task): ) < 0 or not group_manager.check_group_task_status(group_id, task):
raise MockApiException(f"被动技能 {task} 处于关闭状态...") raise MockApiException(f"被动技能 {task} 处于关闭状态...")
else: else:
msg = str(data["message"]).strip() msg = str(data["message"]).strip()

View File

@ -1,3 +1,4 @@
from configs.path_config import DATA_PATH
from .init_group_manager import init_group_manager, group_manager from .init_group_manager import init_group_manager, group_manager
from .init_plugins_config import init_plugins_config from .init_plugins_config import init_plugins_config
from .init_plugins_data import init_plugins_data, plugins_manager from .init_plugins_data import init_plugins_data, plugins_manager
@ -12,7 +13,6 @@ from .init_plugins_limit import (
from .init import init from .init import init
from .check_plugin_status import check_plugin_status from .check_plugin_status import check_plugin_status
from nonebot.adapters.onebot.v11 import Bot from nonebot.adapters.onebot.v11 import Bot
from configs.path_config import DATA_PATH
from services.log import logger from services.log import logger
from nonebot import Driver from nonebot import Driver
import nonebot import nonebot
@ -31,23 +31,21 @@ async def _():
""" """
初始化数据 初始化数据
""" """
_flag = False
config_file = DATA_PATH / "configs" / "plugins2config.yaml" config_file = DATA_PATH / "configs" / "plugins2config.yaml"
if not config_file.exists(): _flag = not config_file.exists()
_flag = True
init() init()
init_plugins_settings(DATA_PATH) init_plugins_settings()
init_plugins_cd_limit(DATA_PATH) init_plugins_cd_limit()
init_plugins_block_limit(DATA_PATH) init_plugins_block_limit()
init_plugins_count_limit(DATA_PATH) init_plugins_count_limit()
init_plugins_data(DATA_PATH) init_plugins_data()
init_plugins_config(DATA_PATH) init_plugins_config()
init_plugins_resources() init_plugins_resources()
init_none_plugin_count_manager() init_none_plugin_count_manager()
x = group_manager.get_super_old_data() # x = group_manager.get_super_old_data()
if x: # if x:
for key in x.keys(): # for key in x.keys():
plugins_manager.block_plugin(key, block_type=x[key]) # plugins_manager.block_plugin(key, block_type=x[key])
if _flag: if _flag:
raise Exception("首次运行已在configs目录下生成配置文件config.yaml修改后重启即可...") raise Exception("首次运行已在configs目录下生成配置文件config.yaml修改后重启即可...")
logger.info("初始化数据完成...") logger.info("初始化数据完成...")
@ -55,5 +53,5 @@ async def _():
@driver.on_bot_connect @driver.on_bot_connect
async def _(bot: Bot): async def _(bot: Bot):
await init_group_manager() # await init_group_manager()
await check_plugin_status(bot) await check_plugin_status(bot)

View File

@ -6,13 +6,13 @@ async def check_plugin_status(bot: Bot):
""" """
遍历查看插件加载情况 遍历查看插件加载情况
""" """
rst = "" msg = ""
for plugin in plugins_manager.keys(): for plugin in plugins_manager.keys():
data = plugins_manager.get(plugin) data = plugins_manager.get(plugin)
if data.get("error") or data.get("error") is None: if not data.error:
rst += f'{plugin}:{data["plugin_name"]}\n' msg += f'{plugin}:{data.plugin_name}\n'
if rst: if msg and bot.config.superusers:
rst = "以下插件加载失败..\n" + rst msg = "以下插件加载失败..\n" + msg
await bot.send_private_msg( await bot.send_private_msg(
user_id=int(list(bot.config.superusers)[0]), message=rst[:-1] user_id=int(list(bot.config.superusers)[0]), message=msg.strip()
) )

View File

@ -19,36 +19,44 @@ def init_none_plugin_count_manager():
""" """
清除已删除插件数据 清除已删除插件数据
""" """
modules = [x.plugin_name for x in get_matchers()] modules = [x.plugin_name for x in get_matchers(True)]
plugins_manager_list = list(plugins_manager.keys()) plugins_manager_list = list(plugins_manager.keys())
for module in plugins_manager_list: for module in plugins_manager_list:
if module not in modules or none_plugin_count_manager.check(module): try:
try: if module not in modules or none_plugin_count_manager.check(module):
plugin_name = plugins_manager.get(module)["plugin_name"]
except (AttributeError, KeyError):
plugin_name = ""
if none_plugin_count_manager.check(module):
try: try:
plugins2settings_manager.delete(module) plugin_name = plugins_manager.get(module).plugin_name
plugins2settings_manager.save() except (AttributeError, KeyError):
plugins2count_manager.delete(module) plugin_name = ""
plugins2count_manager.save() if none_plugin_count_manager.check(module):
plugins2cd_manager.delete(module) try:
plugins2cd_manager.save() plugins2settings_manager.delete(module)
plugins2block_manager.delete(module) plugins2count_manager.delete(module)
plugins2block_manager.save() plugins2cd_manager.delete(module)
plugins_manager.delete(module) plugins2block_manager.delete(module)
plugins_manager.save() plugins_manager.delete(module)
# resources_manager.remove_resource(module) plugins_manager.save()
none_plugin_count_manager.delete(module) # resources_manager.remove_resource(module)
logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...") none_plugin_count_manager.delete(module)
except Exception as e: logger.info(f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据...")
logger.exception( except Exception as e:
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}{e}") logger.exception(
f"{module}:{plugin_name} 插件疑似已删除,清除对应插件数据失败...{type(e)}{e}"
)
else:
none_plugin_count_manager.add_count(module)
logger.info(
f"{module}:{plugin_name} 插件疑似已删除,"
f"加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,"
f"当前次数:{none_plugin_count_manager._data[module]}"
)
else: else:
none_plugin_count_manager.add_count(module) none_plugin_count_manager.reset(module)
logger.info( except Exception as e:
f"{module}:{plugin_name} 插件疑似已删除,加载{none_plugin_count_manager._max_count}次失败后将清除对应插件数据,当前次数:{none_plugin_count_manager._data[module]}") logger.error(f"清除插件数据错误 {type(e)}{e}")
else: plugins2settings_manager.save()
none_plugin_count_manager.reset(module) plugins2count_manager.save()
plugins2cd_manager.save()
plugins2block_manager.save()
plugins_manager.save()
none_plugin_count_manager.save() none_plugin_count_manager.save()

View File

@ -8,40 +8,32 @@ from services.log import logger
from utils.text_utils import prompt2cn from utils.text_utils import prompt2cn
from utils.utils import get_matchers from utils.utils import get_matchers
from utils.utils import scheduler from utils.utils import scheduler
from configs.path_config import DATA_PATH
from ruamel import yaml from ruamel import yaml
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_config(data_path): def init_plugins_config():
""" """
初始化插件数据配置 初始化插件数据配置
""" """
plugins2config_file = data_path / "configs" / "plugins2config.yaml" plugins2config_file = DATA_PATH / "configs" / "plugins2config.yaml"
plugins2config_file.parent.mkdir(parents=True, exist_ok=True) plugins2config_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} _data = {}
if plugins2config_file.exists(): if plugins2config_file.exists():
_data = _yaml.load(open(plugins2config_file, "r", encoding="utf8")) _data = _yaml.load(open(plugins2config_file, "r", encoding="utf8"))
_matchers = get_matchers(True)
# 优先使用 metadata 数据 # 优先使用 metadata 数据
for matcher in _matchers: for matcher in [matcher for matcher in get_matchers(True) if matcher.plugin and matcher.plugin.module]:
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata metadata = _plugin.metadata
try: _module = _plugin.module
_module = _plugin.module
except AttributeError:
continue
plugin_version = None plugin_version = None
if metadata: if metadata:
plugin_version = metadata.extra.get("version") plugin_version = metadata.extra.get("version")
if not plugin_version: if not plugin_version and hasattr(_module, "__plugin_version__"):
try: plugin_version = _module.__getattribute__("__plugin_version__")
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
pass
if metadata and metadata.config: if metadata and metadata.config:
plugin_configs = {} plugin_configs = {}
for key, value in metadata.config.__fields__.items(): for key, value in metadata.config.__fields__.items():
@ -61,7 +53,7 @@ def init_plugins_config(data_path):
_data.get(matcher.plugin_name) _data.get(matcher.plugin_name)
and _data[matcher.plugin_name].keys() != plugin_configs.keys() and _data[matcher.plugin_name].keys() != plugin_configs.keys()
) )
or plugin_version > plugins_manager.get(matcher.plugin_name)["version"] or plugin_version > plugins_manager.get(matcher.plugin_name).version
or matcher.plugin_name not in _data.keys() or matcher.plugin_name not in _data.keys()
): ):
for key in plugin_configs: for key in plugin_configs:
@ -94,16 +86,16 @@ def init_plugins_config(data_path):
_data = round_trip_load(open(plugins2config_file, encoding="utf8")) _data = round_trip_load(open(plugins2config_file, encoding="utf8"))
for plugin in _data.keys(): for plugin in _data.keys():
try: try:
plugin_name = plugins_manager.get(plugin)["plugin_name"] plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError): except (AttributeError, TypeError):
plugin_name = plugin plugin_name = plugin
_data[plugin].yaml_set_start_comment(plugin_name, indent=2) _data[plugin].yaml_set_start_comment(plugin_name, indent=2)
# 初始化未设置的管理员权限等级 # 初始化未设置的管理员权限等级
for k, v in Config.get_admin_level_data(): for k, v in Config.get_admin_level_data():
try: # try:
admin_manager.set_admin_level(k, v) admin_manager.set_admin_level(k, v)
except KeyError as e: # except KeyError as e:
raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******") # raise KeyError(f"{e} ****** 请检查是否有插件加载失败 ******")
# 存完插件基本设置 # 存完插件基本设置
with open(plugins2config_file, "w", encoding="utf8") as wf: with open(plugins2config_file, "w", encoding="utf8") as wf:
round_trip_dump( round_trip_dump(
@ -181,7 +173,7 @@ def _replace_config():
plugin_name = None plugin_name = None
if not plugin_name: if not plugin_name:
try: try:
plugin_name = plugins_manager.get(plugin)["plugin_name"] plugin_name = plugins_manager.get(plugin).plugin_name
except (AttributeError, TypeError): except (AttributeError, TypeError):
plugin_name = plugin plugin_name = plugin
plugin_name = ( plugin_name = (

View File

@ -3,6 +3,7 @@ from ruamel.yaml import YAML
from utils.manager import plugins_manager from utils.manager import plugins_manager
from utils.utils import get_matchers from utils.utils import get_matchers
from services.log import logger from services.log import logger
from configs.path_config import DATA_PATH
try: try:
import ujson as json import ujson as json
@ -13,17 +14,13 @@ except ModuleNotFoundError:
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
def init_plugins_data(data_path): def init_plugins_data():
""" """
初始化插件数据信息 初始化插件数据信息
""" """
plugin2data_file = data_path / "manager" / "plugin_manager.json" plugin2data_file = DATA_PATH / "manager" / "plugin_manager.json"
plugin2data_file.parent.mkdir(parents=True, exist_ok=True) plugin2data_file.parent.mkdir(parents=True, exist_ok=True)
_data = {} for matcher in get_matchers(True):
if plugin2data_file.exists():
_data = json.load(open(plugin2data_file, "r", encoding="utf8"))
_matchers = get_matchers(True)
for matcher in _matchers:
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin: if not _plugin:
continue continue
@ -31,27 +28,19 @@ def init_plugins_data(data_path):
try: try:
_module = _plugin.module _module = _plugin.module
except AttributeError: except AttributeError:
if matcher.plugin_name not in _data.keys(): if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.plugin_name, matcher.plugin_name, error=True matcher.plugin_name, matcher.plugin_name, error=True
) )
else: else:
plugins_manager.set_module_data(matcher.plugin_name, "error", True) plugins_manager[matcher.plugin_name].error = True
plugin_data = plugins_manager.get(matcher.plugin_name)
if plugin_data:
plugins_manager.set_module_data(
matcher.plugin_name, "version", plugin_data.get("version")
)
else: else:
try: try:
plugin_version = None plugin_version = None
if metadata: if metadata:
plugin_version = metadata.extra.get("version") plugin_version = metadata.extra.get("version")
if not plugin_version: if not plugin_version and hasattr(_module, "__plugin_version__"):
try: plugin_version = _module.__getattribute__("__plugin_version__")
plugin_version = _module.__getattribute__("__plugin_version__")
except AttributeError:
pass
if metadata: if metadata:
plugin_name = metadata.name plugin_name = metadata.name
else: else:
@ -62,12 +51,10 @@ def init_plugins_data(data_path):
plugin_author = None plugin_author = None
if metadata: if metadata:
plugin_author = metadata.extra.get('author') plugin_author = metadata.extra.get('author')
try: if not plugin_author and hasattr(_module, "__plugin_author__"):
plugin_author = _module.__getattribute__("__plugin_author__") plugin_author = _module.__getattribute__("__plugin_author__")
except AttributeError:
pass
if matcher.plugin_name in plugins_manager.keys(): if matcher.plugin_name in plugins_manager.keys():
plugins_manager.set_module_data(matcher.plugin_name, "error", False) plugins_manager[matcher.plugin_name].error = False
if matcher.plugin_name not in plugins_manager.keys(): if matcher.plugin_name not in plugins_manager.keys():
plugins_manager.add_plugin_data( plugins_manager.add_plugin_data(
matcher.plugin_name, matcher.plugin_name,
@ -76,24 +63,21 @@ def init_plugins_data(data_path):
version=plugin_version, version=plugin_version,
) )
# metadata不检测version # metadata不检测version
elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name]["version"] is None or ( elif isinstance(plugin_version, str) or plugins_manager[matcher.plugin_name].version is None or (
plugin_version is not None plugin_version is not None
and plugin_version > float(plugins_manager[matcher.plugin_name]["version"]) and plugin_version > float(plugins_manager[matcher.plugin_name].version)
): ):
plugins_manager.set_module_data( plugins_manager[matcher.plugin_name].plugin_name = plugin_name
matcher.plugin_name, "plugin_name", plugin_name plugins_manager[matcher.plugin_name].author = plugin_author
) plugins_manager[matcher.plugin_name].version = plugin_version
plugins_manager.set_module_data(matcher.plugin_name, "author", plugin_author) # if matcher.plugin_name in _data.keys():
plugins_manager.set_module_data( # plugins_manager[matcher.plugin_name].error = _data[matcher.plugin_name]["error"]
matcher.plugin_name, "version", plugin_version # plugins_manager.set_module_data(
) # matcher.plugin_name, "error", _data[matcher.plugin_name]["error"]
if matcher.plugin_name in _data.keys(): # )
plugins_manager.set_module_data( # plugins_manager.set_module_data(
matcher.plugin_name, "error", _data[matcher.plugin_name]["error"] # matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
) # )
plugins_manager.set_module_data(
matcher.plugin_name, "plugin_name", _data[matcher.plugin_name]["plugin_name"]
)
except Exception as e: except Exception as e:
logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}{e}") logger.error(f"插件数据 {matcher.plugin_name} 加载发生错误 {type(e)}{e}")
plugins_manager.save() plugins_manager.save()

View File

@ -1,27 +1,21 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import ( from utils.manager import (
plugins2cd_manager, plugins2cd_manager,
plugins2block_manager, plugins2block_manager,
plugins2count_manager, plugins2count_manager,
) )
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml from configs.path_config import DATA_PATH
import nonebot import nonebot
_yaml = YAML(typ="safe") def init_plugins_cd_limit():
def init_plugins_cd_limit(data_path):
""" """
加载 cd 限制 加载 cd 限制
""" """
plugins2cd_file = data_path / "configs" / "plugins2cd.yaml" plugins2cd_file = DATA_PATH / "configs" / "plugins2cd.yaml"
plugins2cd_file.parent.mkdir(exist_ok=True, parents=True) plugins2cd_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() for matcher in get_matchers(True):
for matcher in _matchers:
if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name): if not plugins2cd_manager.get_plugin_cd_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try: try:
@ -36,42 +30,19 @@ def init_plugins_cd_limit(data_path):
plugins2cd_manager.add_cd_limit( plugins2cd_manager.add_cd_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCdLimit": plugins2cd_manager.get_data()} plugins2cd_manager.save()
with open(plugins2cd_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2cd_file, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能
# 自定义的功能需要cd也可以在此配置
# key模块名称
# cdcd 时长(秒)
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user'用户N秒内触发1次'group'群N秒内触发1次
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2cd_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2cd_manager.reload_cd_limit() plugins2cd_manager.reload_cd_limit()
def init_plugins_block_limit(data_path): def init_plugins_block_limit():
""" """
加载阻塞限制 加载阻塞限制
""" """
plugins2block_file = data_path / "configs" / "plugins2block.yaml" plugins2block_file = DATA_PATH / "configs" / "plugins2block.yaml"
plugins2block_file.parent.mkdir(exist_ok=True, parents=True) plugins2block_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} for matcher in get_matchers(True):
_matchers = get_matchers()
for matcher in _matchers:
if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name): if not plugins2block_manager.get_plugin_block_data(matcher.plugin_name):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name) _plugin = matcher.plugin
try: try:
_module = _plugin.module _module = _plugin.module
plugin_block_limit = _module.__getattribute__("__plugin_block_limit__") plugin_block_limit = _module.__getattribute__("__plugin_block_limit__")
@ -84,36 +55,15 @@ def init_plugins_block_limit(data_path):
plugins2block_manager.add_block_limit( plugins2block_manager.add_block_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginBlockLimit": plugins2block_manager.get_data()} plugins2block_manager.save()
with open(plugins2block_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2block_file, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key模块名称
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':阻塞用户,'group':阻塞群聊
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2block_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2block_manager.reload_block_limit() plugins2block_manager.reload_block_limit()
def init_plugins_count_limit(data_path): def init_plugins_count_limit():
""" """
加载次数限制 加载次数限制
""" """
plugins2count_file = data_path / "configs" / "plugins2count.yaml" plugins2count_file = DATA_PATH / "configs" / "plugins2count.yaml"
plugins2count_file.parent.mkdir(exist_ok=True, parents=True) plugins2count_file.parent.mkdir(exist_ok=True, parents=True)
_data = {} _data = {}
_matchers = get_matchers() _matchers = get_matchers()
@ -132,26 +82,5 @@ def init_plugins_count_limit(data_path):
plugins2count_manager.add_count_limit( plugins2count_manager.add_count_limit(
"这是一个示例" "这是一个示例"
) )
_tmp_data = {"PluginCountLimit": plugins2count_manager.get_data()} plugins2count_manager.save()
with open(plugins2count_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2count_file, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新
# key模块名称
# max_count: 每日调用上限
# status此限制的开关状态
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':用户上限,'group':群聊上限
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(plugins2count_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
plugins2count_manager.reload_count_limit() plugins2count_manager.reload_count_limit()

View File

@ -1,24 +1,14 @@
from pathlib import Path
from ruamel.yaml import round_trip_load, round_trip_dump, YAML
from utils.manager import plugins2settings_manager, admin_manager from utils.manager import plugins2settings_manager, admin_manager
from services.log import logger from services.log import logger
from utils.utils import get_matchers from utils.utils import get_matchers
from ruamel import yaml
import nonebot import nonebot
_yaml = YAML(typ="safe") def init_plugins_settings():
def init_plugins_settings(data_path: str):
""" """
初始化插件设置从插件中获取 __zx_plugin_name____plugin_cmd____plugin_settings__ 初始化插件设置从插件中获取 __zx_plugin_name____plugin_cmd____plugin_settings__
""" """
plugins2settings_file = data_path / "configs" / "plugins2settings.yaml"
plugins2settings_file.parent.mkdir(exist_ok=True, parents=True)
_matchers = get_matchers(True)
_tmp_module = {} _tmp_module = {}
_tmp = []
for x in plugins2settings_manager.keys(): for x in plugins2settings_manager.keys():
try: try:
_plugin = nonebot.plugin.get_plugin(x) _plugin = nonebot.plugin.get_plugin(x)
@ -33,12 +23,10 @@ def init_plugins_settings(data_path: str):
except (KeyError, AttributeError) as e: except (KeyError, AttributeError) as e:
logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}") logger.warning(f"配置文件 模块:{x} 获取 plugin_name 失败...{e}")
_tmp_module[x] = "" _tmp_module[x] = ""
for matcher in _matchers: for matcher in [x for x in get_matchers(True) if x.plugin]:
try: try:
if matcher.plugin_name not in plugins2settings_manager.keys(): if matcher.plugin_name not in plugins2settings_manager.keys():
_plugin = matcher.plugin _plugin = matcher.plugin
if not _plugin:
continue
metadata = _plugin.metadata metadata = _plugin.metadata
try: try:
_module = _plugin.module _module = _plugin.module
@ -46,22 +34,17 @@ def init_plugins_settings(data_path: str):
logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.") logger.warning(f"插件 {matcher.plugin_name} 加载失败...,插件控制未加载.")
else: else:
try: try:
if metadata: plugin_name = metadata.name if metadata else _module.__getattribute__("__zx_plugin_name__")
plugin_name = metadata.name # 管理员命令
else:
plugin_name = _module.__getattribute__("__zx_plugin_name__")
if "[admin]" in plugin_name.lower(): if "[admin]" in plugin_name.lower():
try: level = 5
cmd = None
if hasattr(_module, "__plugin_settings__"):
admin_settings = _module.__getattribute__( admin_settings = _module.__getattribute__(
"__plugin_settings__" "__plugin_settings__"
) )
level = admin_settings["admin_level"] level = admin_settings.get("admin_level", 5)
cmd = admin_settings.get("cmd") cmd = admin_settings.get("cmd")
except (AttributeError, KeyError):
level = 5
cmd = None
if level is None:
level = 5
admin_manager.add_admin_plugin_settings( admin_manager.add_admin_plugin_settings(
matcher.plugin_name, cmd, level matcher.plugin_name, cmd, level
) )
@ -73,19 +56,18 @@ def init_plugins_settings(data_path: str):
): ):
continue continue
except AttributeError: except AttributeError:
if matcher.plugin_name not in _tmp: logger.warning(
logger.warning( f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载."
f"获取插件 {matcher.plugin_name} __zx_plugin_name__ 失败...,插件控制未加载." )
)
else: else:
_tmp_module[matcher.plugin_name] = plugin_name _tmp_module[matcher.plugin_name] = plugin_name
try: if hasattr(_module, "__plugin_settings__"):
plugin_settings = _module.__getattribute__( plugin_settings = _module.__getattribute__(
"__plugin_settings__" "__plugin_settings__"
) )
except AttributeError: else:
plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]} plugin_settings = {"cmd": [matcher.plugin_name, plugin_name]}
if not plugin_settings.get("cost_gold"): if plugin_settings.get("cost_gold") is None:
plugin_settings["cost_gold"] = 0 plugin_settings["cost_gold"] = 0
if ( if (
plugin_settings.get("cmd") is not None plugin_settings.get("cmd") is not None
@ -100,12 +82,12 @@ def init_plugins_settings(data_path: str):
plugin_type = tuple( plugin_type = tuple(
plugins2settings_manager.get_plugin_data( plugins2settings_manager.get_plugin_data(
matcher.plugin_name matcher.plugin_name
)["plugin_type"] ).plugin_type
) )
else: else:
try: if hasattr(_module, "__plugin_type__"):
plugin_type = _module.__getattribute__("__plugin_type__") plugin_type = _module.__getattribute__("__plugin_type__")
except AttributeError: else:
plugin_type = ("normal",) plugin_type = ("normal",)
if plugin_settings and matcher.plugin_name: if plugin_settings and matcher.plugin_name:
plugins2settings_manager.add_plugin_settings( plugins2settings_manager.add_plugin_settings(
@ -115,26 +97,5 @@ def init_plugins_settings(data_path: str):
) )
except Exception as e: except Exception as e:
logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}{e}') logger.error(f'{matcher.plugin_name} 初始化 plugin_settings 发生错误 {type(e)}{e}')
_tmp.append(matcher.plugin_name) plugins2settings_manager.save()
_tmp_data = {"PluginSettings": plugins2settings_manager.get_data()}
with open(plugins2settings_file, "w", encoding="utf8") as wf:
yaml.dump(_tmp_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
_data = round_trip_load(open(plugins2settings_file, encoding="utf8"))
_data["PluginSettings"].yaml_set_start_comment(
"""# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key模块名称
# level需要的群等级
# default_status加入群时功能的默认开关状态
# limit_superuser: 功能状态是否限制超级用户
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能cmd列表第一个词为统计的功能名称
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1)1代表帮助命令列向排列否则为横向排列""",
indent=2,
)
for plugin in _data["PluginSettings"].keys():
_data["PluginSettings"][plugin].yaml_set_start_comment(
f"{plugin}{_tmp_module[plugin]}", indent=2
)
with open(plugins2settings_file, "w", encoding="utf8") as wf:
round_trip_dump(_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True)
logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.") logger.info(f"已成功加载 {len(plugins2settings_manager.get_data())} 个非限制插件.")

View File

@ -122,8 +122,8 @@ async def _(event: GroupMessageEvent):
tmp = "" tmp = ""
data = plugins2settings_manager.get_data() data = plugins2settings_manager.get_data()
for module in data: for module in data:
if data[module]["level"] > level: if data[module].level > level:
plugin_name = data[module]["cmd"][0] plugin_name = data[module].cmd[0]
if plugin_name == "pixiv": if plugin_name == "pixiv":
plugin_name = "搜图 p站排行" plugin_name = "搜图 p站排行"
tmp += f"{plugin_name}\n" tmp += f"{plugin_name}\n"

View File

@ -67,7 +67,7 @@ async def _():
gl = [g["group_id"] for g in gl] gl = [g["group_id"] for g in gl]
msg_list, code = await get_epic_free(bot, "Group") msg_list, code = await get_epic_free(bot, "Group")
for g in gl: for g in gl:
if await group_manager.check_group_task_status(g, "epic_free_game"): if group_manager.check_group_task_status(g, "epic_free_game"):
try: try:
if msg_list and code == 200: if msg_list and code == 200:
await bot.send_group_forward_msg(group_id=g, messages=msg_list) await bot.send_group_forward_msg(group_id=g, messages=msg_list)

View File

@ -71,5 +71,5 @@ async def _():
if alc_img: if alc_img:
mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub" mes = "[[_task|genshin_alc]]" + alc_img + "\n ※ 黄历数据来源于 genshin.pub"
for gid in gl: for gid in gl:
if await group_manager.check_group_task_status(gid, "genshin_alc"): if group_manager.check_group_task_status(gid, "genshin_alc"):
await bot.send_group_msg(group_id=int(gid), message="" + mes) await bot.send_group_msg(group_id=int(gid), message="" + mes)

View File

@ -172,7 +172,7 @@ async def generate_statistics_img(
data: dict, arg: str, name: str, plugin: str, day_index: int data: dict, arg: str, name: str, plugin: str, day_index: int
): ):
try: try:
plugin = plugins2settings_manager.get_plugin_data(plugin)['cmd'][0] plugin = plugins2settings_manager.get_plugin_data(plugin).cmd[0]
except (KeyError, IndexError): except (KeyError, IndexError):
pass pass
bar_graph = None bar_graph = None

View File

@ -107,8 +107,8 @@ async def _(
group_id = "total" group_id = "total"
user_id = str(event.user_id) user_id = str(event.user_id)
plugin_name = plugins2settings_manager.get_plugin_data(module) plugin_name = plugins2settings_manager.get_plugin_data(module)
if plugin_name and plugin_name.get('cmd'): if plugin_name and plugin_name.cmd:
plugin_name = plugin_name.get('cmd')[0] plugin_name = plugin_name.cmd[0]
check_exists_key(group_id, user_id, plugin_name) check_exists_key(group_id, user_id, plugin_name)
for data in [_prefix_count_dict, _prefix_user_count_dict]: for data in [_prefix_count_dict, _prefix_user_count_dict]:
data["total_statistics"]["total"][plugin_name] += 1 data["total_statistics"]["total"][plugin_name] += 1

View File

@ -23,11 +23,11 @@ gConfig.add_plugin_config("web-ui", "password", None, name="web-ui", help_="前
async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State): async def _(matcher: Matcher, bot: Bot, event: MessageEvent, state: T_State):
flag = False flag = False
for module in plugins2settings_manager.keys(): for module in plugins2settings_manager.keys():
if isinstance(plugins2settings_manager.get_plugin_data(module).get("cmd"), str): if isinstance(plugins2settings_manager.get_plugin_data(module).cmd, str):
plugins2settings_manager.set_module_data( plugins2settings_manager.set_module_data(
module, module,
"cmd", "cmd",
plugins2settings_manager.get_plugin_data(module).get("cmd").split(","), plugins2settings_manager.get_plugin_data(module).cmd.split(","),
False False
) )
flag = True flag = True

View File

@ -61,8 +61,8 @@ def _(type_: Optional[str], user: User = Depends(token_to_user)) -> Result:
) )
data["plugin_manager"] = PluginManager(**x) data["plugin_manager"] = PluginManager(**x)
if x := plugins2settings_manager.get(model): if x := plugins2settings_manager.get(model):
if x.get("cmd") and isinstance(x.get("cmd"), list): if x.cmd and isinstance(x.cmd, list):
x["cmd"] = ",".join(x["cmd"]) x.cmd = ",".join(x.cmd)
data["plugin_settings"] = PluginSettings(**x) data["plugin_settings"] = PluginSettings(**x)
if x := plugins2cd_manager.get(model): if x := plugins2cd_manager.get(model):
data["cd_limit"] = CdLimit(**x) data["cd_limit"] = CdLimit(**x)

View File

@ -10,8 +10,6 @@
"poetry.lock", "poetry.lock",
"pyproject.toml" "pyproject.toml"
], ],
"add_file": [ "add_file": [],
"resources/image/shop_icon"
],
"delete_file": [] "delete_file": []
} }

View File

@ -14,6 +14,9 @@ from .requests_manager import RequestManager
from configs.path_config import DATA_PATH from configs.path_config import DATA_PATH
# 管理员命令管理器
admin_manager = AdminManager()
# 群功能开关 | 群被动技能 | 群权限 管理 # 群功能开关 | 群被动技能 | 群权限 管理
group_manager: Optional[GroupManager] = GroupManager( group_manager: Optional[GroupManager] = GroupManager(
DATA_PATH / "manager" / "group_manager.json" DATA_PATH / "manager" / "group_manager.json"
@ -62,5 +65,3 @@ requests_manager: Optional[RequestManager] = RequestManager(
DATA_PATH / "manager" / "requests_manager.json" DATA_PATH / "manager" / "requests_manager.json"
) )
# 管理员命令管理器
admin_manager = AdminManager()

64
utils/manager/admin_manager.py Executable file → Normal file
View File

@ -1,5 +1,6 @@
from .data_class import StaticData from .models import AdminSetting
from typing import List, Optional from utils.manager.data_class import StaticData
from typing import List, Optional, Dict
class AdminManager(StaticData): class AdminManager(StaticData):
@ -9,60 +10,71 @@ class AdminManager(StaticData):
def __init__(self): def __init__(self):
super().__init__(None) super().__init__(None)
self._data: Dict[str, AdminSetting] = {}
def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int): def add_admin_plugin_settings(self, plugin: str, cmd: List[str], level: int):
""" """
添加一个管理员命令 说明:
:param plugin: 模块 添加一个管理员命令
:param cmd: 别名 参数:
:param level: 等级 :param plugin: 模块
:param cmd: 别名
:param level: 等级
""" """
self._data[plugin] = { self._data[plugin] = AdminSetting(level=level, cmd=cmd)
"level": level,
"cmd": cmd,
}
def set_admin_level(self, plugin: str, level: int): def set_admin_level(self, plugin: str, level: int):
""" """
设置管理员命令等级 说明:
:param plugin: 模块名 设置管理员命令等级
:param level: 权限等级 参数:
:param plugin: 模块名
:param level: 权限等级
""" """
self._data[plugin]["level"] = level if plugin in self._data.keys():
self._data[plugin].level = level
def remove_admin_plugin_settings(self, plugin: str): def remove_admin_plugin_settings(self, plugin: str):
""" """
删除一个管理员命令 说明:
:param plugin: 模块名 删除一个管理员命令
参数:
:param plugin: 模块名
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
del self._data[plugin] del self._data[plugin]
def check(self, plugin: str, level: int) -> bool: def check(self, plugin: str, level: int) -> bool:
""" """
检查是否满足权限 说明:
:param plugin: 模块名 检查是否满足权限
:param level: 权限等级 参数:
:param plugin: 模块名
:param level: 权限等级
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
return level >= self._data[plugin]["level"] return level >= self._data[plugin].level
return True return True
def get_plugin_level(self, plugin: str) -> int: def get_plugin_level(self, plugin: str) -> int:
""" """
获取插件等级 说明:
:param plugin: 模块名 获取插件等级
参数:
:param plugin: 模块名
""" """
if plugin in self._data.keys(): if plugin in self._data.keys():
return self._data[plugin]["level"] return self._data[plugin].level
return 0 return 0
def get_plugin_module(self, cmd: str) -> Optional[str]: def get_plugin_module(self, cmd: str) -> Optional[str]:
""" """
根据 cmd 获取功能 modules 说明:
:param cmd: 命令 根据 cmd 获取功能 modules
参数:
:param cmd: 命令
""" """
for key in self._data.keys(): for key in self._data.keys():
if self._data[key].get("cmd") and cmd in self._data[key]["cmd"]: if self._data[key].cmd and cmd in self._data[key].cmd:
return key return key
return None return None

0
utils/manager/configs_manager.py Executable file → Normal file
View File

View File

@ -1,24 +1,29 @@
from typing import Union, Optional from typing import Union, Optional, TypeVar, Generic, Dict, NoReturn, Any
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from ruamel import yaml from ruamel import yaml
import ujson as json import ujson as json
import copy import copy
from .models import *
_yaml = YAML(typ="safe") _yaml = YAML(typ="safe")
class StaticData: T = TypeVar("T", AdminSetting, BaseData, PluginBlock, PluginCd, PluginCount, PluginSetting, Plugin)
class StaticData(Generic[T]):
""" """
静态数据共享类 静态数据共享类
""" """
def __init__(self, file: Optional[Path]): def __init__(self, file: Optional[Path], load_file: bool = True):
self._data: dict = {} self._data: dict = {}
if file: if file:
file.parent.mkdir(exist_ok=True, parents=True) file.parent.mkdir(exist_ok=True, parents=True)
self.file = file self.file = file
if file.exists(): if file.exists() and load_file:
with open(file, "r", encoding="utf8") as f: with open(file, "r", encoding="utf8") as f:
if file.name.endswith("json"): if file.name.endswith("json"):
try: try:
@ -29,30 +34,39 @@ class StaticData:
elif file.name.endswith("yaml"): elif file.name.endswith("yaml"):
self._data = _yaml.load(f) self._data = _yaml.load(f)
def set(self, key, value): def set(self, key, value) -> NoReturn:
self._data[key] = value self._data[key] = value
self.save() self.save()
def set_module_data(self, module, key, value, auto_save: bool = True): def set_module_data(self, module, key, value, auto_save: bool = True) -> NoReturn:
if module in self._data.keys(): if module in self._data.keys():
self._data[module][key] = value self._data[module][key] = value
if auto_save: if auto_save:
self.save() self.save()
def get(self, key): def get(self, key) -> T:
return self._data.get(key) return self._data.get(key)
def keys(self): def keys(self) -> List[str]:
return self._data.keys() return self._data.keys()
def delete(self, key): def delete(self, key) -> NoReturn:
if self._data.get(key) is not None: if self._data.get(key) is not None:
del self._data[key] del self._data[key]
def get_data(self) -> dict: def get_data(self) -> Dict[str, T]:
return copy.deepcopy(self._data) return copy.deepcopy(self._data)
def save(self, path: Union[str, Path] = None): def dict(self) -> Dict[str, Any]:
temp = {}
for k, v in self._data.items():
try:
temp[k] = v.dict()
except AttributeError:
temp[k] = copy.deepcopy(v)
return temp
def save(self, path: Union[str, Path] = None) -> NoReturn:
path = path or self.file path = path or self.file
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
@ -61,26 +75,26 @@ class StaticData:
if path.name.endswith("yaml"): if path.name.endswith("yaml"):
yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(self._data, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True)
else: else:
json.dump(self._data, f, ensure_ascii=False, indent=4) json.dump(self.dict(), f, ensure_ascii=False, indent=4)
def reload(self): def reload(self) -> NoReturn:
if self.file.exists(): if self.file.exists():
if self.file.name.endswith("json"): if self.file.name.endswith("json"):
self._data: dict = json.load(open(self.file, "r", encoding="utf8")) self._data: dict = json.load(open(self.file, "r", encoding="utf8"))
elif self.file.name.endswith("yaml"): elif self.file.name.endswith("yaml"):
self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8")) self._data: dict = _yaml.load(open(self.file, "r", encoding="utf8"))
def is_exists(self): def is_exists(self) -> bool:
return self.file.exists() return self.file.exists()
def is_empty(self): def is_empty(self) -> bool:
return bool(len(self._data)) return bool(len(self._data))
def __str__(self): def __str__(self) -> str:
return str(self._data) return str(self._data)
def __setitem__(self, key, value): def __setitem__(self, key, value) -> NoReturn:
self._data[key] = value self._data[key] = value
def __getitem__(self, key): def __getitem__(self, key) -> T:
return self._data[key] return self._data[key]

314
utils/manager/group_manager.py Executable file → Normal file
View File

@ -1,9 +1,11 @@
from typing import Optional, List, Union, Dict from typing import List, Union, Dict, Callable
from pathlib import Path from pathlib import Path
from .data_class import StaticData from .models import BaseData, BaseGroup
from utils.utils import get_matchers, get_bot from utils.manager.data_class import StaticData
from utils.utils import get_matchers, is_number
from configs.config import Config from configs.config import Config
import nonebot import nonebot
import ujson as json
Config.add_plugin_config( Config.add_plugin_config(
@ -15,39 +17,75 @@ Config.add_plugin_config(
) )
def init_group(func: Callable):
"""
说明:
初始化群数据
参数:
:param func: func
"""
def wrapper(*args, **kwargs):
self = args[0]
group_id = list(filter(lambda x: is_number(x), args[1:]))[0]
if self and group_id and not self._data.group_manager.get(str(group_id)):
self._data.group_manager[str(group_id)] = BaseGroup()
return func(*args, **kwargs)
return wrapper
def init_task(func: Callable):
"""
说明:
初始化群被动
参数:
:param func: func
"""
def wrapper(*args, **kwargs):
self = args[0]
group_id = str(args[1])
task = args[2] if len(args) > 1 else None
if group_id and task and self._data.group_manager[group_id].group_task_status.get(task) is None:
for task in self._data.task:
if self._data.group_manager[group_id].group_task_status.get(task) is None:
self._data.group_manager[group_id].group_task_status[task] = Config.get_config('_task', f'DEFAULT_{task}', default=True)
for task in list(self._data.group_manager[group_id].group_task_status):
if task not in self._data.task:
del self._data.group_manager[group_id].group_task_status[task]
self.save()
return func(*args, **kwargs)
return wrapper
class GroupManager(StaticData): class GroupManager(StaticData):
""" """
群权限 | 功能 | 总开关 | 聊天时间 管理器 群权限 | 功能 | 总开关 | 聊天时间 管理器
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
super().__init__(file) super().__init__(file, False)
if not self._data: self._data = BaseData.parse_file(file) if file.exists() else BaseData()
self._data = {
"super": {"white_group_list": []},
"group_manager": {},
}
self._task = {}
def block_plugin(self, module: str, group_id: int): def block_plugin(self, module: str, group_id: int, is_save: bool = True):
""" """
说明: 说明:
锁定插件 锁定插件
参数: 参数:
:param module: 功能模块名 :param module: 功能模块名
:param group_id: 群组None时为超级用户禁用 :param group_id: 群组None时为超级用户禁用
:param is_save: 是否保存文件
""" """
self._set_plugin_status(module, "block", group_id) self._set_plugin_status(module, "block", group_id, is_save)
def unblock_plugin(self, module: str, group_id: int): def unblock_plugin(self, module: str, group_id: int, is_save: bool = True):
""" """
说明: 说明:
解锁插件 解锁插件
参数: 参数:
:param module: 功能模块名 :param module: 功能模块名
:param group_id: 群组 :param group_id: 群组
:param is_save: 是否保存文件
""" """
self._set_plugin_status(module, "unblock", group_id) self._set_plugin_status(module, "unblock", group_id, is_save)
def turn_on_group_bot_status(self, group_id: int): def turn_on_group_bot_status(self, group_id: int):
""" """
@ -67,6 +105,7 @@ class GroupManager(StaticData):
""" """
self._set_group_bot_status(group_id, False) self._set_group_bot_status(group_id, False)
@init_group
def check_group_bot_status(self, group_id: int) -> bool: def check_group_bot_status(self, group_id: int) -> bool:
""" """
说明: 说明:
@ -74,16 +113,9 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 说明 :param group_id: 说明
""" """
group_id = str(group_id) return self._data.group_manager[str(group_id)].status
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
if self._data["group_manager"][group_id].get("status") is None:
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS")
if default_group_bot_status:
default_group_bot_status = True
self._data["group_manager"][group_id]["status"] = default_group_bot_status
return self._data["group_manager"][group_id]["status"]
@init_group
def set_group_level(self, group_id: int, level: int): def set_group_level(self, group_id: int, level: int):
""" """
说明: 说明:
@ -92,12 +124,10 @@ class GroupManager(StaticData):
:param group_id: 群组 :param group_id: 群组
:param level: 权限等级 :param level: 权限等级
""" """
group_id = str(group_id) self._data.group_manager[str(group_id)].level = level
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
self._data["group_manager"][group_id]["level"] = level
self.save() self.save()
@init_group
def get_plugin_status(self, module: str, group_id: int) -> bool: def get_plugin_status(self, module: str, group_id: int) -> bool:
""" """
说明: 说明:
@ -106,14 +136,9 @@ class GroupManager(StaticData):
:param module: 功能模块名 :param module: 功能模块名
:param group_id: 群组 :param group_id: 群组
""" """
group_id = str(group_id) if group_id else group_id return module not in self._data.group_manager[str(group_id)].close_plugins
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
return True
if module in self._data["group_manager"][group_id]["close_plugins"]:
return False
return True
@init_group
def get_group_level(self, group_id: int) -> int: def get_group_level(self, group_id: int) -> int:
""" """
说明: 说明:
@ -121,10 +146,7 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
group_id = str(group_id) return self._data.group_manager[str(group_id)].level
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
return self._data["group_manager"][group_id]["level"]
def check_group_is_white(self, group_id: int) -> bool: def check_group_is_white(self, group_id: int) -> bool:
""" """
@ -133,7 +155,7 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
return group_id in self._data["super"]["white_group_list"] return group_id in self._data.white_group
def add_group_white_list(self, group_id: int): def add_group_white_list(self, group_id: int):
""" """
@ -142,8 +164,8 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
if group_id not in self._data["super"]["white_group_list"]: if group_id not in self._data.white_group:
self._data["super"]["white_group_list"].append(group_id) self._data.white_group.append(group_id)
def delete_group_white_list(self, group_id: int): def delete_group_white_list(self, group_id: int):
""" """
@ -152,16 +174,34 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
if group_id in self._data["super"]["white_group_list"]: if group_id in self._data.white_group:
self._data["super"]["white_group_list"].remove(group_id) self._data.white_group.remove(group_id)
def get_group_white_list(self) -> List[str]: def get_group_white_list(self) -> List[int]:
""" """
说明: 说明:
获取所有群白名单 获取所有群白名单
""" """
return self._data["super"]["white_group_list"] return self._data.white_group
def load_task(self):
"""
说明:
加载被动技能
"""
for matcher in get_matchers(True):
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
plugin_task = _module.__getattribute__("__plugin_task__")
for key in plugin_task.keys():
if key in self._data.task.keys():
raise ValueError(f"plugin_task{key} 已存在!")
self._data.task[key] = plugin_task[key]
except AttributeError:
pass
@init_group
def delete_group(self, group_id: int): def delete_group(self, group_id: int):
""" """
说明: 说明:
@ -169,13 +209,11 @@ class GroupManager(StaticData):
参数: 参数:
:param group_id: 群号 :param group_id: 群号
""" """
if group_id in self._data["group_manager"]: if group_id in self._data.white_group:
del self._data["group_manager"][str(group_id)] self._data.white_group.remove(group_id)
if group_id in self._data["super"]["white_group_list"]: self.save()
self._data["super"]["white_group_list"].remove(group_id)
self.save()
async def open_group_task(self, group_id: int, task: str): def open_group_task(self, group_id: int, task: str):
""" """
说明: 说明:
开启群被动技能 开启群被动技能
@ -183,9 +221,9 @@ class GroupManager(StaticData):
:param group_id: 群号 :param group_id: 群号
:param task: 被动技能名称 :param task: 被动技能名称
""" """
await self._set_group_task_status(group_id, task, True) self._set_group_group_task_status(group_id, task, True)
async def close_group_task(self, group_id: int, task: str): def close_group_task(self, group_id: int, task: str):
""" """
说明: 说明:
关闭群被动技能 关闭群被动技能
@ -193,9 +231,10 @@ class GroupManager(StaticData):
:param group_id: 群号 :param group_id: 群号
:param task: 被动技能名称 :param task: 被动技能名称
""" """
await self._set_group_task_status(group_id, task, False) self._set_group_group_task_status(group_id, task, False)
async def check_group_task_status(self, group_id: int, task: str) -> bool: @init_task
def check_group_task_status(self, group_id: int, task: str) -> bool:
""" """
说明: 说明:
查看群被动技能状态 查看群被动技能状态
@ -203,23 +242,17 @@ class GroupManager(StaticData):
:param group_id: 群号 :param group_id: 群号
:param task: 被动技能名称 :param task: 被动技能名称
""" """
group_id = str(group_id) return self._data.group_manager[str(group_id)].group_task_status.get(task, False)
if (
not self._data["group_manager"][group_id].get("group_task_status")
or self._data["group_manager"][group_id]["group_task_status"].get(task)
is None
):
await self.init_group_task(group_id)
return self._data["group_manager"][group_id]["group_task_status"][task]
def get_task_data(self) -> Dict[str, str]: def get_task_data(self) -> Dict[str, str]:
""" """
说明: 说明:
获取所有被动任务 获取所有被动任务
""" """
return self._task return self._data.task
async def group_task_status(self, group_id: int) -> str: @init_task
def group_group_task_status(self, group_id: int) -> str:
""" """
说明: 说明:
查看群被全部动技能状态 查看群被全部动技能状态
@ -228,13 +261,13 @@ class GroupManager(StaticData):
""" """
x = "[群被动技能]:\n" x = "[群被动技能]:\n"
group_id = str(group_id) group_id = str(group_id)
if not self._data["group_manager"][group_id].get("group_task_status"): for key in self._data.group_manager[group_id].group_task_status.keys():
await self.init_group_task(group_id) x += f'{self._data.task[key]}{"" if self.check_group_task_status(int(group_id), key) else "×"}\n'
for key in self._data["group_manager"][group_id]["group_task_status"].keys():
x += f'{self._task[key]}{"" if await self.check_group_task_status(int(group_id), key) else "×"}\n'
return x[:-1] return x[:-1]
async def _set_group_task_status(self, group_id: int, task: str, status: bool): @init_task
@init_group
def _set_group_group_task_status(self, group_id: int, task: str, status: bool):
""" """
说明: 说明:
管理群被动技能状态 管理群被动技能状态
@ -243,74 +276,16 @@ class GroupManager(StaticData):
:param task: 被动技能 :param task: 被动技能
:param status: 状态 :param status: 状态
""" """
group_id = str(group_id) self._data.group_manager[str(group_id)].group_task_status[task] = status
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
if (
not self._data["group_manager"][group_id].get("group_task_status")
or self._data["group_manager"][group_id]["group_task_status"].get(task)
is None
):
await self.init_group_task(group_id)
self._data["group_manager"][group_id]["group_task_status"][task] = status
self.save()
async def init_group_task(self, group_id: Optional[Union[int, str]] = None):
"""
说明:
初始化群聊 被动技能 状态
"""
if not self._task:
_m = []
for matcher in get_matchers():
if matcher.plugin_name not in _m:
_m.append(matcher.plugin_name)
_plugin = nonebot.plugin.get_plugin(matcher.plugin_name)
try:
_module = _plugin.module
plugin_task = _module.__getattribute__("__plugin_task__")
for key in plugin_task.keys():
if key in self._task.keys():
raise ValueError(f"plugin_task{key} 已存在!")
self._task[key] = plugin_task[key]
except AttributeError:
pass
bot = get_bot()
if bot or group_id:
if group_id:
_group_list = [group_id]
else:
_group_list = [x["group_id"] for x in await bot.get_group_list()]
for group_id in _group_list:
group_id = str(group_id)
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
if not self._data["group_manager"][group_id].get("group_task_status"):
self._data["group_manager"][group_id]["group_task_status"] = {}
for task in self._task:
if (
self._data["group_manager"][group_id]["group_task_status"].get(
task
)
is None
):
self._data["group_manager"][group_id]["group_task_status"][
task
] = Config.get_config('_task', f'DEFAULT_{task}', default=True)
for task in list(
self._data["group_manager"][group_id]["group_task_status"]
):
if task not in self._task:
del self._data["group_manager"][group_id]["group_task_status"][
task
]
self.save() self.save()
@init_group
def _set_plugin_status( def _set_plugin_status(
self, self,
module: str, module: str,
status: str, status: str,
group_id: int, group_id: int,
is_save: bool
): ):
""" """
说明: 说明:
@ -319,39 +294,19 @@ class GroupManager(StaticData):
:param module: 功能模块名 :param module: 功能模块名
:param status: 功能状态 :param status: 功能状态
:param group_id: 群组 :param group_id: 群组
:param is_save: 是否保存
""" """
group_id = str(group_id) if group_id else group_id group_id = str(group_id) if group_id else group_id
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
if status == "block": if status == "block":
if module not in self._data["group_manager"][group_id]["close_plugins"]: if module not in self._data.group_manager[group_id].close_plugins:
self._data["group_manager"][group_id]["close_plugins"].append(module) self._data.group_manager[group_id].close_plugins.append(module)
else: else:
if module in self._data["group_manager"][group_id]["close_plugins"]: if module in self._data.group_manager[group_id].close_plugins:
self._data["group_manager"][group_id]["close_plugins"].remove(module) self._data.group_manager[group_id].close_plugins.remove(module)
self.save() if is_save:
self.save()
def _init_group(self, group_id: str):
"""
说明:
初始化群数据
参数:
:param group_id: 群号
"""
default_group_level = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL")
if default_group_level is None:
default_group_level = 5
default_group_bot_status = Config.get_config("group_manager", "DEFAULT_GROUP_BOT_STATUS")
if default_group_bot_status:
default_group_bot_status = True
if not self._data["group_manager"].get(group_id):
self._data["group_manager"][group_id] = {
"level": default_group_level,
"status": default_group_bot_status,
"close_plugins": [],
"group_task_status": {},
}
@init_group
def _set_group_bot_status(self, group_id: Union[int, str], status: bool): def _set_group_bot_status(self, group_id: Union[int, str], status: bool):
""" """
说明: 说明:
@ -360,19 +315,38 @@ class GroupManager(StaticData):
:param group_id: 群号 :param group_id: 群号
:param status: 开关状态 :param status: 开关状态
""" """
group_id = str(group_id) self._data.group_manager[str(group_id)].status = status
if not self._data["group_manager"].get(group_id):
self._init_group(group_id)
self._data["group_manager"][group_id]["status"] = status
self.save() self.save()
def get_super_old_data(self) -> Optional[dict]: def reload(self):
if self.file.exists():
t = self._data.task
self._data = BaseData.parse_file(self.file)
self._data.task = t
def save(self, path: Union[str, Path] = None):
""" """
说明: 说明:
获取旧数据平时使用请不要调用 保存文件
参数:
:param path: 路径文件
""" """
if self._data["super"].get("close_plugins"): path = path or self.file
_x = self._data["super"].get("close_plugins") if isinstance(path, str):
del self._data["super"]["close_plugins"] path = Path(path)
return _x if path:
return None dict_data = self._data.dict()
del dict_data["task"]
with open(path, "w", encoding="utf8") as f:
json.dump(dict_data, f, ensure_ascii=False, indent=4)
# def get_super_old_data(self) -> Optional[dict]:
# """
# 说明:
# 获取旧数据,平时使用请不要调用
# """
# if self._data["super"].get("close_plugins"):
# _x = self._data["super"].get("close_plugins")
# del self._data["super"]["close_plugins"]
# return _x
# return None

95
utils/manager/models.py Normal file
View File

@ -0,0 +1,95 @@
from typing import List, Optional, Dict, Literal, Tuple, Union
from pydantic import BaseModel
from configs.config import Config
class AdminSetting(BaseModel):
"""
管理员设置
"""
level: int
cmd: Optional[List[str]]
class BaseGroup(BaseModel):
"""
基础群聊信息
"""
level: int = Config.get_config("group_manager", "DEFAULT_GROUP_LEVEL") # 群等级
status: bool = Config.get_config(
"group_manager", "DEFAULT_GROUP_BOT_STATUS"
) # 总开关状态
close_plugins: List[str] = [] # 已关闭插件
group_task_status: Dict[str, bool] = {} # 被动状态
class BaseData(BaseModel):
"""
群基本信息
"""
white_group: List[int] = [] # 白名单
group_manager: Dict[str, BaseGroup] = {} # 群组管理
task: Dict[str, str] = {} # 被动任务 【英文:中文】
class PluginBlock(BaseModel):
"""
插件阻断
"""
status: bool # 限制状态
check_type: Literal["private", "group", "all"] # 检查类型
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginCd(BaseModel):
"""
插件阻断
"""
cd: int # cd
status: bool # 限制状态
check_type: Literal["private", "group", "all"] # 检查类型
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginCount(BaseModel):
"""
插件阻断
"""
max_count: int # 次数
status: bool # 限制状态
limit_type: Literal["user", "group"] # 监听对象
rst: Optional[str] # 阻断时回复
class PluginSetting(BaseModel):
"""
插件设置
"""
cmd: List[str] = [] # 命令 或 命令别名
default_status: bool = True # 默认开关状态
level: int = 5 # 功能权限等级
limit_superuser: bool = False # 功能状态是否限制超级用户
plugin_type: Tuple[Union[str, int], ...] = ("normal",) # 插件类型
cost_gold: int = 0 # 需要消费的金币
class Plugin(BaseModel):
"""
插件数据
"""
plugin_name: str # 模块名
status: Optional[bool] = True # 开关状态
error: Optional[bool] = False # 是否加载报错
block_type: Optional[str] = None # 关闭类型
author: Optional[str] = None # 作者
version: Optional[int] = None # 版本

2
utils/manager/none_plugin_count_manager.py Executable file → Normal file
View File

@ -1,4 +1,4 @@
from .data_class import StaticData from utils.manager.data_class import StaticData
from typing import Optional from typing import Optional
from pathlib import Path from pathlib import Path

153
utils/manager/plugins2block_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from services.log import logger from services.log import logger
from utils.utils import UserBlockLimiter from utils.utils import UserBlockLimiter
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginBlock
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2blockManager(StaticData): class Plugins2blockManager(StaticData):
@ -14,53 +15,45 @@ class Plugins2blockManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._block_limiter: Dict[str, UserBlockLimiter] = {} self._block_limiter: Dict[str, UserBlockLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginBlockLimit" in self._data.keys():
self._data = self._data["PluginBlockLimit"] or {}
def add_block_limit( def add_block_limit(
self, self,
plugin: str, plugin: str,
*, *,
status: Optional[bool] = True, status: Optional[bool] = True,
check_type: Optional[str] = "all", check_type: Literal["private", "group", "all"] = "all",
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 block 限制 说明:
:param plugin: 插件模块名称 添加插件调用 block 限制
:param status: 默认开关状态 参数:
:param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部 :param plugin: 插件模块名称
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param status: 默认开关状态
:param rst: 回复的话为空则不回复 :param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
status = status or True
check_type = check_type or "all"
limit_type = limit_type or "user"
if check_type not in ["all", "group", "private"]: if check_type not in ["all", "group", "private"]:
raise ValueError( raise ValueError(
f"{plugin} 添加block限制错误check_type 必须为 'private'/'group'/'all'" f"{plugin} 添加block限制错误check_type 必须为 'private'/'group'/'all'"
) )
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加block限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加block限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginBlock(
"status": status, status=status, check_type=check_type, limit_type=limit_type, rst=rst
"check_type": check_type, )
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_block_data(self, plugin: str) -> Optional[dict]: def get_plugin_block_data(self, plugin: str) -> Optional[PluginBlock]:
""" """
获取插件block数据 说明:
:param plugin: 模块名 获取插件block数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_block_status(plugin): if self.check_plugin_block_status(plugin):
return self._data[plugin] return self._data[plugin]
@ -68,16 +61,20 @@ class Plugins2blockManager(StaticData):
def check_plugin_block_status(self, plugin: str) -> bool: def check_plugin_block_status(self, plugin: str) -> bool:
""" """
检测插件是否有 block 说明:
:param plugin: 模块名 检测插件是否有 block
参数:
:param plugin: 模块名
""" """
return plugin in self._data.keys() and self._data[plugin]["status"] return plugin in self._data.keys() and self._data[plugin].status
def check(self, id_: int, plugin: str) -> bool: def check(self, id_: int, plugin: str) -> bool:
""" """
检查 block 说明:
:param plugin: 模块名 检查 block
:param id_: 限制 id 参数:
:param id_: 限制 id
:param plugin: 模块名
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
return self._block_limiter[plugin].check(id_) return self._block_limiter[plugin].check(id_)
@ -85,26 +82,30 @@ class Plugins2blockManager(StaticData):
def set_true(self, id_: int, plugin: str): def set_true(self, id_: int, plugin: str):
""" """
对插件 block 说明:
:param plugin: 模块名 对插件 block
:param id_: 限制 id 参数:
:param id_: 限制 id
:param plugin: 模块名
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
self._block_limiter[plugin].set_true(id_) self._block_limiter[plugin].set_true(id_)
def set_false(self, id_: int, plugin: str): def set_false(self, id_: int, plugin: str):
""" """
对插件 unblock 说明:
:param plugin: 模块名 对插件 unblock
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._block_limiter.get(plugin): if self._block_limiter.get(plugin):
self._block_limiter[plugin].set_false(id_) self._block_limiter[plugin].set_false(id_)
def reload_block_limit(self): def reload_block_limit(self):
""" """
加载 block 限制器 说明:
:return: 加载 block 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_block_status(plugin): if self.check_plugin_block_status(plugin):
@ -113,10 +114,62 @@ class Plugins2blockManager(StaticData):
def reload(self): def reload(self):
""" """
重载本地数据 说明:
重载本地数据
""" """
self.__load_file()
self.reload_block_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginBlockLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginBlockLimit"].yaml_set_start_comment(
"""# 用户调用阻塞
# 即 当用户调用此功能还未结束时
# 用发送消息阻止用户重复调用此命令直到该命令结束
# key模块名称
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':阻塞用户,'group':阻塞群聊
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginBlock] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = yaml.round_trip_load(f)
self._data = self._data["PluginBlockLimit"] if "PluginBlockLimit" in temp.keys():
self.reload_block_limit() for k, v in temp["PluginBlockLimit"].items():
self._data[k] = PluginBlock.parse_obj(v)

167
utils/manager/plugins2cd_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from utils.utils import FreqLimiter from utils.utils import FreqLimiter
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginCd
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2cdManager(StaticData): class Plugins2cdManager(StaticData):
@ -14,16 +15,9 @@ class Plugins2cdManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._freq_limiter: Dict[str, FreqLimiter] = {} self._freq_limiter: Dict[str, FreqLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginCdLimit" in self._data.keys():
self._data = (
self._data["PluginCdLimit"] if self._data["PluginCdLimit"] else {}
)
def add_cd_limit( def add_cd_limit(
self, self,
@ -31,42 +25,35 @@ class Plugins2cdManager(StaticData):
*, *,
cd: Optional[int] = 5, cd: Optional[int] = 5,
status: Optional[bool] = True, status: Optional[bool] = True,
check_type: Optional[str] = "all", check_type: Literal["private", "group", "all"] = "all",
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 cd 限制 说明:
:param plugin: 插件模块名称 添加插件调用 cd 限制
:param cd: cd 时长 参数:
:param status: 默认开关状态 :param plugin: 插件模块名称
:param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部 :param cd: cd 时长
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param status: 默认开关状态
:param rst: 回复的话为空则不回复 :param check_type: 检查类型 'private'/'group'/'all'限制私聊/群聊/全部
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
cd = cd or 5
status = status or True
check_type = check_type or "all"
limit_type = limit_type or "user"
if check_type not in ["all", "group", "private"]: if check_type not in ["all", "group", "private"]:
raise ValueError( raise ValueError(
f"{plugin} 添加cd限制错误check_type 必须为 'private'/'group'/'all'" f"{plugin} 添加cd限制错误check_type 必须为 'private'/'group'/'all'"
) )
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加cd限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加cd限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginCd(cd=cd, status=status, check_type=check_type, limit_type=limit_type, rst=rst)
"cd": cd,
"status": status,
"check_type": check_type,
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_cd_data(self, plugin: str) -> Optional[dict]: def get_plugin_cd_data(self, plugin: str) -> Optional[PluginCd]:
""" """
获取插件cd数据 说明:
:param plugin: 模块名 获取插件cd数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_cd_status(plugin): if self.check_plugin_cd_status(plugin):
return self._data[plugin] return self._data[plugin]
@ -74,20 +61,24 @@ class Plugins2cdManager(StaticData):
def check_plugin_cd_status(self, plugin: str) -> bool: def check_plugin_cd_status(self, plugin: str) -> bool:
""" """
检测插件是否有 cd 说明:
:param plugin: 模块名 检测插件是否有 cd
参数:
:param plugin: 模块名
""" """
return ( return (
plugin in self._data.keys() plugin in self._data.keys()
and self._data[plugin]["cd"] > 0 and self._data[plugin].cd > 0
and self._data[plugin]["status"] and self._data[plugin].status
) )
def check(self, plugin: str, id_: int) -> bool: def check(self, plugin: str, id_: int) -> bool:
""" """
检查 cd 说明:
:param plugin: 模块名 检查 cd
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._freq_limiter.get(plugin): if self._freq_limiter.get(plugin):
return self._freq_limiter[plugin].check(id_) return self._freq_limiter[plugin].check(id_)
@ -95,42 +86,96 @@ class Plugins2cdManager(StaticData):
def start_cd(self, plugin: str, id_: int, cd: int = 0): def start_cd(self, plugin: str, id_: int, cd: int = 0):
""" """
开始cd 说明:
:param plugin: 模块名 开始cd
:param id_: cd 限制类型 参数:
:param cd: cd 时长 :param plugin: 模块名
:return: :param id_: cd 限制类型
:param cd: cd 时长
""" """
if self._freq_limiter.get(plugin): if self._freq_limiter.get(plugin):
self._freq_limiter[plugin].start_cd(id_, cd) self._freq_limiter[plugin].start_cd(id_, cd)
def get_plugin_data(self, plugin: str) -> dict: def get_plugin_data(self, plugin: str) -> Optional[PluginCd]:
""" """
获取单个模块限制数据 说明:
:param plugin: 模块名 获取单个模块限制数据
参数:
:param plugin: 模块名
""" """
if self._data.get(plugin) is not None: if self._data.get(plugin):
return self._data.get(plugin) return self._data.get(plugin)
return {}
def reload_cd_limit(self): def reload_cd_limit(self):
""" """
加载 cd 限制器 说明:
:return: 加载 cd 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_cd_status(plugin): if self.check_plugin_cd_status(plugin):
self._freq_limiter[plugin] = FreqLimiter( self._freq_limiter[plugin] = FreqLimiter(
self.get_plugin_cd_data(plugin)["cd"] self.get_plugin_cd_data(plugin).cd
) )
logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.") logger.info(f"已成功加载 {len(self._freq_limiter)} 个Cd限制.")
def reload(self): def reload(self):
""" """
重载本地数据 说明:
重载本地数据
""" """
self.__load_file()
self.reload_cd_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginCdLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginCdLimit"].yaml_set_start_comment(
"""# 需要cd的功能
# 自定义的功能需要cd也可以在此配置
# key模块名称
# cdcd 时长(秒)
# status此限制的开关状态
# check_type'private'/'group'/'all',限制私聊/群聊/全部
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user'用户N秒内触发1次'group'群N秒内触发1次
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginCd] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginCdLimit"] if "PluginCdLimit" in temp.keys():
self.reload_cd_limit() for k, v in temp["PluginCdLimit"].items():
self._data[k] = PluginCd.parse_obj(v)

156
utils/manager/plugins2count_manager.py Executable file → Normal file
View File

@ -1,11 +1,12 @@
from typing import Optional, Dict from typing import Optional, Dict, Literal, Union
from .data_class import StaticData from utils.manager.data_class import StaticData
from utils.utils import DailyNumberLimiter from utils.utils import DailyNumberLimiter
from services.log import logger from services.log import logger
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel import yaml
from .models import PluginCount
yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2countManager(StaticData): class Plugins2countManager(StaticData):
@ -14,16 +15,9 @@ class Plugins2countManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None)
self._daily_limiter: Dict[str, DailyNumberLimiter] = {} self._daily_limiter: Dict[str, DailyNumberLimiter] = {}
if file.exists(): self.__load_file()
with open(file, "r", encoding="utf8") as f:
self._data = yaml.load(f)
if "PluginCountLimit" in self._data.keys():
self._data = (
self._data["PluginCountLimit"] if self._data["PluginCountLimit"] else {}
)
def add_count_limit( def add_count_limit(
self, self,
@ -31,64 +25,64 @@ class Plugins2countManager(StaticData):
*, *,
max_count: int = 5, max_count: int = 5,
status: Optional[bool] = True, status: Optional[bool] = True,
limit_type: Optional[str] = "user", limit_type: Literal["user", "group"] = "user",
rst: Optional[str] = None, rst: Optional[str] = None,
**kwargs # 用于接收额外实参
): ):
""" """
添加插件调用 次数 限制 说明:
:param plugin: 插件模块名称 添加插件调用 次数 限制
:param max_count: 最大次数限制 参数:
:param status: 默认开关状态 :param plugin: 插件模块名称
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id :param max_count: 最大次数限制
:param rst: 回复的话为空则不回复 :param status: 默认开关状态
:param limit_type: 限制类型 监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
:param rst: 回复的话为空则不回复
""" """
max_count = max_count or 5
status = status or True
limit_type = limit_type or "user"
if limit_type not in ["user", "group"]: if limit_type not in ["user", "group"]:
raise ValueError(f"{plugin} 添加count限制错误limit_type 必须为 'user'/'group'") raise ValueError(f"{plugin} 添加count限制错误limit_type 必须为 'user'/'group'")
self._data[plugin] = { self._data[plugin] = PluginCount(max_count=max_count, status=status, limit_type=limit_type, rst=rst)
"max_count": max_count,
"status": status,
"limit_type": limit_type,
"rst": rst,
}
def get_plugin_count_data(self, plugin: str) -> Optional[dict]: def get_plugin_count_data(self, plugin: str) -> Optional[PluginCount]:
""" """
获取插件次数数据 说明:
:param plugin: 模块名 获取插件次数数据
参数:
:param plugin: 模块名
""" """
if self.check_plugin_count_status(plugin): if self.check_plugin_count_status(plugin):
return self._data[plugin] return self._data[plugin]
return None return None
def get_plugin_data(self, plugin: str) -> Optional[dict]: def get_plugin_data(self, plugin: str) -> Optional[PluginCount]:
""" """
获取单个模块限制数据 说明:
:param plugin: 模块名 获取单个模块限制数据
参数:
:param plugin: 模块名
""" """
if self._data.get(plugin) is not None: if self._data.get(plugin) is not None:
return self._data.get(plugin) return self._data.get(plugin)
return None
def check_plugin_count_status(self, plugin: str) -> bool: def check_plugin_count_status(self, plugin: str) -> bool:
""" """
检测插件是否有 次数 限制 说明:
:param plugin: 模块名 检测插件是否有 次数 限制
参数:
:param plugin: 模块名
""" """
return ( return (
plugin in self._data.keys() plugin in self._data.keys()
and self._data[plugin]["status"] and self._data[plugin].status
and self._data[plugin]["max_count"] > 0 and self._data[plugin].max_count > 0
) )
def check(self, plugin: str, id_: int) -> bool: def check(self, plugin: str, id_: int) -> bool:
""" """
检查 count 说明:
:param plugin: 模块名 检查 count
:param id_: 限制 id 参数:
:param plugin: 模块名
:param id_: 限制 id
""" """
if self._daily_limiter.get(plugin): if self._daily_limiter.get(plugin):
return self._daily_limiter[plugin].check(id_) return self._daily_limiter[plugin].check(id_)
@ -96,24 +90,25 @@ class Plugins2countManager(StaticData):
def increase(self, plugin: str, id_: int, num: int = 1): def increase(self, plugin: str, id_: int, num: int = 1):
""" """
增加次数 说明:
:param plugin: 模块名 增加次数
:param id_: cd 限制类型 参数:
:param num: 增加次数 :param plugin: 模块名
:return: :param id_: cd 限制类型
:param num: 增加次数
""" """
if self._daily_limiter.get(plugin): if self._daily_limiter.get(plugin):
self._daily_limiter[plugin].increase(id_, num) self._daily_limiter[plugin].increase(id_, num)
def reload_count_limit(self): def reload_count_limit(self):
""" """
加载 cd 限制器 说明:
:return: 加载 cd 限制器
""" """
for plugin in self._data: for plugin in self._data:
if self.check_plugin_count_status(plugin): if self.check_plugin_count_status(plugin):
self._daily_limiter[plugin] = DailyNumberLimiter( self._daily_limiter[plugin] = DailyNumberLimiter(
self.get_plugin_count_data(plugin)["max_count"] self.get_plugin_count_data(plugin).max_count
) )
logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.") logger.info(f"已成功加载 {len(self._daily_limiter)} 个Count限制.")
@ -121,8 +116,59 @@ class Plugins2countManager(StaticData):
""" """
重载本地数据 重载本地数据
""" """
self.__load_file()
self.reload_count_limit()
def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file
if isinstance(path, str):
path = Path(path)
if path:
with open(path, "w", encoding="utf8") as f:
yaml.dump(
{"PluginCountLimit": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginCountLimit"].yaml_set_start_comment(
"""# 命令每日次数限制
# 即 用户/群聊 每日可调用命令的次数 [数据内存存储,重启将会重置]
# 每日调用直到 00:00 刷新
# key模块名称
# max_count: 每日调用上限
# status此限制的开关状态
# limit_type监听对象以user_id或group_id作为键来限制'user'用户id'group'群id
# 示例:'user':用户上限,'group':群聊上限
# rst回复的话可以添加[at][uname][nickname]来对应艾特,用户群名称,昵称系统昵称
# rst 为 "" 或 None 时则不回复
# rst示例"[uname]你冲的太快了,[nickname]先生,请稍后再冲[at]"
# rst回复"老色批你冲的太快了,欧尼酱先生,请稍后再冲@老色批"
# 用户昵称↑ 昵称系统的昵称↑ 艾特用户↑""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def __load_file(self):
"""
说明:
读取配置文件
"""
self._data: Dict[str, PluginCount] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginCountLimit"] if "PluginCountLimit" in temp.keys():
self.reload_count_limit() for k, v in temp["PluginCountLimit"].items():
self._data[k] = PluginCount.parse_obj(v)

143
utils/manager/plugins2settings_manager.py Executable file → Normal file
View File

@ -1,11 +1,11 @@
from typing import List, Optional, Union, Tuple from typing import List, Optional, Union, Tuple, Dict
from .data_class import StaticData from utils.manager.data_class import StaticData
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML
from ruamel import yaml from ruamel import yaml
from .models import PluginSetting
_yaml = YAML(typ="safe") _yaml = yaml.YAML(typ="safe")
class Plugins2settingsManager(StaticData): class Plugins2settingsManager(StaticData):
@ -14,97 +14,120 @@ class Plugins2settingsManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self.file = file super().__init__(file, False)
super().__init__(None) self.__load_file()
if file.exists():
with open(file, "r", encoding="utf8") as f:
self._data = _yaml.load(f)
if self._data:
if "PluginSettings" in self._data.keys():
self._data = (
self._data["PluginSettings"] if self._data["PluginSettings"] else {}
)
for x in self._data.keys():
if self._data[x].get("cost_gold") is None:
self._data[x]["cost_gold"] = 0
def add_plugin_settings( def add_plugin_settings(
self, self,
plugin: str, plugin: str,
cmd: Optional[List[str]] = None, cmd: Optional[List[str]] = None,
default_status: Optional[bool] = True, default_status: bool = True,
level: Optional[int] = 5, level: int = 5,
limit_superuser: Optional[bool] = False, limit_superuser: bool = False,
plugin_type: Tuple[Union[str, int]] = ("normal",), plugin_type: Tuple[Union[str, int]] = ("normal",),
cost_gold: int = 0, cost_gold: int = 0,
): ):
""" """
添加一个插件设置 说明:
:param plugin: 插件模块名称 添加一个插件设置
:param cmd: 命令 命令别名 参数:
:param default_status: 默认开关状态 :param plugin: 插件模块名称
:param level: 功能权限等级 :param cmd: 命令 命令别名
:param limit_superuser: 功能状态是否限制超级用户 :param default_status: 默认开关状态
:param plugin_type: 插件类型 :param level: 功能权限等级
:param cost_gold: 需要消费的金币 :param limit_superuser: 功能状态是否限制超级用户
:param plugin_type: 插件类型
:param cost_gold: 需要消费的金币
""" """
level = level or 5 self._data[plugin] = PluginSetting(
cmd = cmd or [] cmd=cmd,
cost_gold = cost_gold or 0 level=level,
self._data[plugin] = { default_status=default_status,
"level": level if level is not None else 5, limit_superuser=limit_superuser,
"default_status": default_status if default_status is not None else True, plugin_type=plugin_type,
"limit_superuser": ( cost_gold=cost_gold,
limit_superuser )
if limit_superuser is not None
else False
),
"cmd": cmd,
"plugin_type": list(
plugin_type if plugin_type is not None else ("normal",)
),
"cost_gold": cost_gold,
}
def get_plugin_data(self, module: str) -> dict: def get_plugin_data(self, module: str) -> Optional[PluginSetting]:
""" """
通过模块名获取数据 说明:
:param module: 模块名称 通过模块名获取数据
参数:
:param module: 模块名称
""" """
if self._data.get(module) is not None: return self._data.get(module)
return self._data.get(module)
return {}
def get_plugin_module( def get_plugin_module(
self, cmd: str, is_all: bool = False self, cmd: str, is_all: bool = False
) -> Union[str, List[str]]: ) -> Union[str, List[str]]:
""" """
根据 cmd 获取功能 modules 说明:
:param cmd: 命令 根据 cmd 获取功能 modules
:param is_all: 获取全部包含cmd的模块 参数:
:param cmd: 命令
:param is_all: 获取全部包含cmd的模块
""" """
keys = [] keys = []
for key in self._data.keys(): for key in self._data.keys():
if cmd in self._data[key]["cmd"]: if cmd in self._data[key].cmd:
if is_all: if is_all:
keys.append(key) keys.append(key)
else: else:
return key return key
return keys return keys
def reload(self):
"""
说明:
重载本地数据
"""
self.__load_file()
def save(self, path: Union[str, Path] = None): def save(self, path: Union[str, Path] = None):
"""
说明:
保存文件
参数:
:param path: 文件路径
"""
path = path or self.file path = path or self.file
if isinstance(path, str): if isinstance(path, str):
path = Path(path) path = Path(path)
if path: if path:
with open(path, "w", encoding="utf8") as f: with open(path, "w", encoding="utf8") as f:
yaml.dump({"PluginSettings": self._data}, f, indent=2, Dumper=yaml.RoundTripDumper, allow_unicode=True) yaml.dump(
{"PluginSettings": self.dict()},
f,
indent=2,
Dumper=yaml.RoundTripDumper,
allow_unicode=True,
)
_data = yaml.round_trip_load(open(path, encoding="utf8"))
_data["PluginSettings"].yaml_set_start_comment(
"""# 模块与对应命令和对应群权限
# 用于生成帮助图片 和 开关功能
# key模块名称
# level需要的群等级
# default_status加入群时功能的默认开关状态
# limit_superuser: 功能状态是否限制超级用户
# cmd: 关闭[cmd] 都会触发命令 关闭对应功能cmd列表第一个词为统计的功能名称
# plugin_type: 帮助类别 示例:('原神相关',) 或 ('原神相关', 1)1代表帮助命令列向排列否则为横向排列""",
indent=2,
)
with open(path, "w", encoding="utf8") as wf:
yaml.round_trip_dump(
_data, wf, Dumper=yaml.RoundTripDumper, allow_unicode=True
)
def reload(self): def __load_file(self):
""" """
重载本地数据 说明:
读取配置文件
""" """
self._data: Dict[str, PluginSetting] = {}
if self.file.exists(): if self.file.exists():
with open(self.file, "r", encoding="utf8") as f: with open(self.file, "r", encoding="utf8") as f:
self._data: dict = _yaml.load(f) temp = _yaml.load(f)
self._data = self._data["PluginSettings"] if "PluginSettings" in temp.keys():
for k, v in temp["PluginSettings"].items():
self._data[k] = PluginSetting.parse_obj(v)

123
utils/manager/plugins_manager.py Executable file → Normal file
View File

@ -1,7 +1,33 @@
from typing import Optional from typing import Optional, Dict, Callable, Union
from pathlib import Path from pathlib import Path
from .data_class import StaticData from utils.manager.data_class import StaticData
from . import group_manager from utils.manager import group_manager
from .models import Plugin
def init_plugin(func: Callable):
"""
说明:
初始化群数据
参数:
:param func: func
"""
def wrapper(*args, **kwargs):
self = args[0]
module = args[1]
if module not in self._data.keys():
self._data[module] = Plugin(
plugin_name=module,
status=True,
error=False,
block_type=None,
author=None,
version=None,
)
return func(*args, **kwargs)
return wrapper
class PluginsManager(StaticData): class PluginsManager(StaticData):
@ -10,9 +36,10 @@ class PluginsManager(StaticData):
""" """
def __init__(self, file: Path): def __init__(self, file: Path):
self._data: Dict[str, Plugin]
super().__init__(file) super().__init__(file)
if not self._data: for k, v in self._data.items():
self._data = {} self._data[k] = Plugin.parse_obj(v)
def add_plugin_data( def add_plugin_data(
self, self,
@ -26,23 +53,25 @@ class PluginsManager(StaticData):
version: Optional[int] = None, version: Optional[int] = None,
): ):
""" """
添加插件数据 说明:
:param module: 模块名称 添加插件数据
:param plugin_name: 插件名称 参数:
:param status: 插件开关状态 :param module: 模块名称
:param error: 加载状态 :param plugin_name: 插件名称
:param block_type: 限制类型 :param status: 插件开关状态
:param author: 作者 :param error: 加载状态
:param version: 版本 :param block_type: 限制类型
:param author: 作者
:param version: 版本
""" """
self._data[module] = { self._data[module] = Plugin(
"plugin_name": plugin_name, plugin_name=plugin_name,
"status": status, status=status,
"error": error, error=error,
"block_type": block_type, block_type=block_type,
"author": author, author=author,
"version": version, version=version,
} )
def block_plugin( def block_plugin(
self, module: str, group_id: Optional[int] = None, block_type: str = "all" self, module: str, group_id: Optional[int] = None, block_type: str = "all"
@ -67,9 +96,7 @@ class PluginsManager(StaticData):
""" """
self._set_plugin_status(module, "unblock", group_id) self._set_plugin_status(module, "unblock", group_id)
def get_plugin_status( def get_plugin_status(self, module: str, block_type: str = "all") -> bool:
self, module: str, block_type: str = "all"
) -> bool:
""" """
说明: 说明:
获取插件状态 获取插件状态
@ -78,13 +105,12 @@ class PluginsManager(StaticData):
:param block_type: 限制类型 :param block_type: 限制类型
""" """
if module in self._data.keys(): if module in self._data.keys():
if self._data[module]["block_type"] == "all" and block_type == "all": if self._data[module].block_type == "all" and block_type == "all":
return False return False
else: return not self._data[module].block_type == block_type
return not self._data[module]["block_type"] == block_type
return True return True
def get_plugin_block_type(self, module: str) -> str: def get_plugin_block_type(self, module: str) -> Optional[str]:
""" """
说明: 说明:
获取功能限制类型 获取功能限制类型
@ -92,18 +118,19 @@ class PluginsManager(StaticData):
:param module: 模块名称 :param module: 模块名称
""" """
if module in self._data.keys(): if module in self._data.keys():
return self._data[module]["block_type"] return self._data[module].block_type
return ""
@init_plugin
def get_plugin_error_status(self, module: str) -> bool: def get_plugin_error_status(self, module: str) -> bool:
""" """
插件是否成功加载 说明:
:param module: 模块名称 插件是否成功加载
参数:
:param module: 模块名称
""" """
if module not in self._data.keys(): return self._data[module].error
self.init_plugin(module)
return self._data[module]["error"]
@init_plugin
def _set_plugin_status( def _set_plugin_status(
self, self,
module: str, module: str,
@ -120,7 +147,6 @@ class PluginsManager(StaticData):
:param group_id: 群组 :param group_id: 群组
:param block_type: 限制类型 :param block_type: 限制类型
""" """
group_id = str(group_id) if group_id else group_id
if module: if module:
if group_id: if group_id:
if status == "block": if status == "block":
@ -128,28 +154,11 @@ class PluginsManager(StaticData):
else: else:
group_manager.unblock_plugin(f"{module}:super", int(group_id)) group_manager.unblock_plugin(f"{module}:super", int(group_id))
else: else:
if module not in self._data.keys():
self.init_plugin(module)
if status == "block": if status == "block":
self._data[module]["status"] = False self._data[module].status = False
self._data[module]["block_type"] = block_type self._data[module].block_type = block_type
else: else:
if module in self._data.keys(): if module in self._data.keys():
self._data[module]["status"] = True self._data[module].status = True
self._data[module]["block_type"] = None self._data[module].block_type = None
self.save() self.save()
def init_plugin(self, module: str):
"""
初始化插件数据
:param module: 模块名称
"""
if module not in self._data.keys():
self._data[module] = {
"plugin_name": module,
"status": True,
"error": False,
"block_type": None,
"author": None,
"version": None,
}

2
utils/manager/requests_manager.py Executable file → Normal file
View File

@ -1,7 +1,7 @@
from utils.manager.data_class import StaticData from utils.manager.data_class import StaticData
from nonebot.adapters.onebot.v11 import Bot, ActionFailed from nonebot.adapters.onebot.v11 import Bot, ActionFailed
from services.log import logger from services.log import logger
from typing import Optional, Literal from typing import Optional
from utils.image_utils import BuildImage from utils.image_utils import BuildImage
from utils.utils import get_user_avatar from utils.utils import get_user_avatar
from pathlib import Path from pathlib import Path

2
utils/manager/resources_manager.py Executable file → Normal file
View File

@ -1,7 +1,7 @@
from typing import Union, List, Optional from typing import Union, List, Optional
from configs.path_config import IMAGE_PATH, DATA_PATH, RECORD_PATH, TEXT_PATH, FONT_PATH, LOG_PATH from configs.path_config import IMAGE_PATH, DATA_PATH, RECORD_PATH, TEXT_PATH, FONT_PATH, LOG_PATH
from .data_class import StaticData from utils.manager.data_class import StaticData
from pathlib import Path from pathlib import Path
from ruamel.yaml import YAML from ruamel.yaml import YAML
from services.log import logger from services.log import logger

0
utils/manager/withdraw_message_manager.py Executable file → Normal file
View File

View File

@ -450,4 +450,4 @@ def change_img_md5(path_file: Union[str, Path]) -> bool:
return True return True
except Exception as e: except Exception as e:
logger.warning(f"改变图片MD5发生错误 {type(e)}{e} Path{path_file}") logger.warning(f"改变图片MD5发生错误 {type(e)}{e} Path{path_file}")
return False return False