Merge pull request #11 from Fairy-Oracle-Sanctuary/plugins

新增插件admin,并在models中新增PluginDataManager类
This commit is contained in:
baby2016
2026-01-02 17:41:39 +08:00
committed by GitHub
5 changed files with 202 additions and 10 deletions

View File

@@ -1,5 +1,6 @@
from .command_manager import matcher from .command_manager import matcher
from .config_loader import global_config from .config_loader import global_config
from .plugin_manager import PluginDataManager
from .ws import WS from .ws import WS
__all__ = ["WS", "matcher", "global_config"] __all__ = ["WS", "matcher", "global_config", "PluginDataManager"]

View File

@@ -3,7 +3,9 @@
负责扫描、加载和管理 `base_plugins` 目录下的所有插件。 负责扫描、加载和管理 `base_plugins` 目录下的所有插件。
""" """
import importlib import importlib
import json
import os import os
import pkgutil import pkgutil
import sys import sys
@@ -18,10 +20,12 @@ def load_all_plugins():
该函数会遍历 `plugins` 目录下的所有模块: 该函数会遍历 `plugins` 目录下的所有模块:
1. 如果模块已加载,则执行 reload 操作(用于热重载)。 1. 如果模块已加载,则执行 reload 操作(用于热重载)。
2. 如果模块未加载,则执行 import 操作。 2. 如果模块未加载,则执行 import 操作。
加载过程中会提取插件元数据 `__plugin_meta__` 并注册到 CommandManager。 加载过程中会提取插件元数据 `__plugin_meta__` 并注册到 CommandManager。
""" """
plugin_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "plugins") plugin_dir = os.path.join(
os.path.dirname(os.path.abspath(__file__)), "..", "plugins"
)
package_name = "plugins" package_name = "plugins"
print(f" 正在从 {package_name} 加载插件...") print(f" 正在从 {package_name} 加载插件...")
@@ -36,13 +40,84 @@ def load_all_plugins():
else: else:
module = importlib.import_module(full_module_name) module = importlib.import_module(full_module_name)
action = "加载" action = "加载"
# 提取插件元数据 # 提取插件元数据
if hasattr(module, "__plugin_meta__"): if hasattr(module, "__plugin_meta__"):
meta = getattr(module, "__plugin_meta__") meta = getattr(module, "__plugin_meta__")
matcher.plugins[full_module_name] = meta matcher.plugins[full_module_name] = meta
type_str = "" if is_pkg else "文件" type_str = "" if is_pkg else "文件"
print(f" [{type_str}] 成功{action}: {module_name}") print(f" [{type_str}] 成功{action}: {module_name}")
except Exception as e: except Exception as e:
print(f" {action if 'action' in locals() else '加载'}插件 {module_name} 失败: {e}") print(
f" {action if 'action' in locals() else '加载'}插件 {module_name} 失败: {e}"
)
class PluginDataManager:
"""
用于管理插件产生的数据文件的类
"""
def __init__(self, plugin_name: str):
"""
初始化插件数据管理器
:param plugin_name: 插件名称
"""
self.plugin_name = plugin_name
self.data_file = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
"..",
"plugins",
"data",
self.plugin_name + ".json",
)
self.data = {}
self.load()
def load(self):
"""读取配置文件"""
if not os.path.exists(self.data_file):
with open(self.data_file, "w", encoding="utf-8") as f:
self.set(self.plugin_name, [])
try:
with open(self.data_file, "r", encoding="utf-8") as f:
self.data = json.load(f)
except json.JSONDecodeError:
self.data = {}
def save(self):
"""保存配置到文件"""
with open(self.data_file, "w", encoding="utf-8") as f:
json.dump(self.data, f, indent=2, ensure_ascii=False)
def get(self, key, default=None):
"""获取配置项"""
return self.data.get(key, default)
def set(self, key, value):
"""设置配置项"""
self.data[key] = value
self.save()
def add(self, key, value):
"""添加配置项"""
if key not in self.data:
self.data[key] = []
self.data[key].append(value)
self.save()
def remove(self, key):
"""删除配置项"""
if key in self.data:
del self.data[key]
self.save()
def clear(self):
"""清空所有配置"""
self.data.clear()
self.save()
def get_all(self):
return self.data.copy()

115
plugins/admin.py Normal file
View File

@@ -0,0 +1,115 @@
from core import PluginDataManager
from core.bot import Bot
from core.command_manager import matcher
from models import GroupMessageEvent
__plugin_meta__ = {
"name": "admin",
"description": "机器人权限管理插件",
"usage": "/admin",
}
data = PluginDataManager("admin")
@matcher.command("admin")
async def handle_permission(bot: Bot, event: GroupMessageEvent, args: list[str]):
if not args:
await event.reply(
"机器人权限管理插件指令:\n/admin list 列出所有权限\n/admin add member <QQ号> 添加群成员权限\n/admin remove member <QQ号> 删除群成员权限\n/admin add group <群号> 添加群权限\n/admin remove group <群号> 删除群权限\n/admin clear member 清空群成员权限\n/admin clear group 清空群权限\n/admin clear all 清空所有权限"
)
return
if str(event.user_id) not in data.get("members", []):
await event.reply("你没有权限使用此命令。")
return
if str(event.group_id) not in data.get("groups", []):
await event.reply("群聊不在权限中")
return
action = args[0].lower()
# ensure storage keys exist
members = data.get("members", []) or []
groups = data.get("groups", []) or []
if action == "list":
msg_lines = ["当前权限列表:"]
msg_lines.append(
f"群成员权限 ({len(members)}): {', '.join(members) if members else ''}"
)
msg_lines.append(
f"群权限 ({len(groups)}): {', '.join(groups) if groups else ''}"
)
await event.reply("\n".join(msg_lines))
return
if action in ("add", "remove"):
if len(args) < 3:
await event.reply("参数错误,示例:/admin add member 123456")
return
target = args[1].lower()
value = args[2]
if target == "member":
# operate on members list
if action == "add":
if str(value) in members:
await event.reply(f"成员 {value} 已存在,无需重复添加。")
return
members.append(str(value))
data.set("members", members)
await event.reply(f"已添加群成员权限:{value}")
return
else: # remove
if str(value) not in members:
await event.reply(f"成员 {value} 不在权限列表中。")
return
members = [m for m in members if m != str(value)]
data.set("members", members)
await event.reply(f"已移除群成员权限:{value}")
return
if target == "group":
if action == "add":
if str(value) in groups:
await event.reply(f"{value} 已存在,无需重复添加。")
return
groups.append(str(value))
data.set("groups", groups)
await event.reply(f"已添加群权限:{value}")
return
else: # remove
if str(value) not in groups:
await event.reply(f"{value} 不在权限列表中。")
return
groups = [g for g in groups if g != str(value)]
data.set("groups", groups)
await event.reply(f"已移除群权限:{value}")
return
await event.reply("未知目标类型,请使用 member 或 group")
return
if action == "clear":
if len(args) < 2:
await event.reply("参数错误,示例:/admin clear member")
return
target = args[1].lower()
if target == "member":
data.set("members", [])
await event.reply("已清空群成员权限。")
return
if target == "group":
data.set("groups", [])
await event.reply("已清空群权限。")
return
if target == "all":
data.clear()
await event.reply("已清空所有权限。")
return
await event.reply("未知清空目标,请使用 member/group/all")
return
await event.reply("未知指令,使用 /admin 查看帮助")

1
plugins/data/admin.json Normal file
View File

@@ -0,0 +1 @@
{}

View File

@@ -5,16 +5,16 @@ thpic 插件
""" """
from core.bot import Bot
from core.command_manager import matcher
from models import MessageEvent, MessageSegment
__plugin_meta__ = { __plugin_meta__ = {
"name": "thpic", "name": "thpic",
"description": "来看看东方Project的图片吧", "description": "来看看东方Project的图片吧",
"usage": "/thpic", "usage": "/thpic",
} }
from core.bot import Bot
from core.command_manager import matcher
from models import MessageEvent, MessageSegment
@matcher.command("thpic") @matcher.command("thpic")
async def handle_echo(bot: Bot, event: MessageEvent, args: list[str]): async def handle_echo(bot: Bot, event: MessageEvent, args: list[str]):