ErisPulse 2.2.0.dev1__py3-none-any.whl → 2.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ErisPulse/Core/Event/__init__.py +10 -7
- ErisPulse/Core/Event/base.py +30 -37
- ErisPulse/Core/Event/command.py +470 -0
- ErisPulse/Core/Event/message.py +43 -12
- ErisPulse/Core/Event/meta.py +42 -11
- ErisPulse/Core/Event/notice.py +51 -11
- ErisPulse/Core/Event/request.py +33 -11
- {erispulse-2.2.0.dev1.dist-info → erispulse-2.2.1.dist-info}/METADATA +31 -52
- {erispulse-2.2.0.dev1.dist-info → erispulse-2.2.1.dist-info}/RECORD +12 -13
- ErisPulse/Core/Event/cmd.py +0 -210
- ErisPulse/Core/Event/manager.py +0 -127
- {erispulse-2.2.0.dev1.dist-info → erispulse-2.2.1.dist-info}/WHEEL +0 -0
- {erispulse-2.2.0.dev1.dist-info → erispulse-2.2.1.dist-info}/entry_points.txt +0 -0
- {erispulse-2.2.0.dev1.dist-info → erispulse-2.2.1.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/Event/__init__.py
CHANGED
|
@@ -2,29 +2,33 @@
|
|
|
2
2
|
ErisPulse 事件处理模块
|
|
3
3
|
|
|
4
4
|
提供统一的事件处理接口,支持命令、消息、通知、请求和元事件处理
|
|
5
|
+
|
|
6
|
+
{!--< tips >!--}
|
|
7
|
+
1. 所有事件处理都基于OneBot12标准事件格式
|
|
8
|
+
2. 通过装饰器方式注册事件处理器
|
|
9
|
+
3. 支持优先级和条件过滤
|
|
10
|
+
{!--< /tips >!--}
|
|
5
11
|
"""
|
|
6
12
|
|
|
7
|
-
from .
|
|
13
|
+
from .command import command
|
|
8
14
|
from .message import message
|
|
9
15
|
from .notice import notice
|
|
10
16
|
from .request import request
|
|
11
17
|
from .meta import meta
|
|
12
|
-
from .manager import event_manager
|
|
13
18
|
from . import exceptions
|
|
14
19
|
from .. import config
|
|
15
20
|
|
|
16
21
|
# 初始化默认配置
|
|
17
22
|
def _setup_default_config():
|
|
18
23
|
"""
|
|
19
|
-
设置默认配置
|
|
20
|
-
|
|
21
24
|
{!--< internal-use >!--}
|
|
22
|
-
|
|
25
|
+
设置默认配置
|
|
23
26
|
"""
|
|
24
27
|
default_config = {
|
|
25
28
|
"command": {
|
|
26
29
|
"prefix": "/",
|
|
27
|
-
"case_sensitive": True
|
|
30
|
+
"case_sensitive": True,
|
|
31
|
+
"allow_space_prefix": False
|
|
28
32
|
},
|
|
29
33
|
"message": {
|
|
30
34
|
"ignore_self": True
|
|
@@ -43,6 +47,5 @@ __all__ = [
|
|
|
43
47
|
"notice",
|
|
44
48
|
"request",
|
|
45
49
|
"meta",
|
|
46
|
-
"event_manager",
|
|
47
50
|
"exceptions"
|
|
48
51
|
]
|
ErisPulse/Core/Event/base.py
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
1
|
"""
|
|
2
2
|
ErisPulse 事件处理基础模块
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
提供事件处理的核心功能,包括事件注册和处理
|
|
5
|
+
|
|
6
|
+
{!--< tips >!--}
|
|
7
|
+
1. 所有事件处理都基于OneBot12标准事件格式
|
|
8
|
+
2. 通过适配器系统进行事件分发和接收
|
|
9
|
+
{!--< /tips >!--}
|
|
5
10
|
"""
|
|
6
11
|
|
|
7
12
|
from .. import adapter, logger
|
|
8
|
-
from typing import Callable, Any, Dict, List, Optional
|
|
13
|
+
from typing import Callable, Any, Dict, List, Optional
|
|
9
14
|
import asyncio
|
|
10
15
|
|
|
11
16
|
class BaseEventHandler:
|
|
12
17
|
"""
|
|
13
18
|
基础事件处理器
|
|
14
19
|
|
|
15
|
-
|
|
20
|
+
提供事件处理的基本功能,包括处理器注册和注销
|
|
16
21
|
"""
|
|
17
22
|
|
|
18
23
|
def __init__(self, event_type: str, module_name: str = None):
|
|
@@ -25,17 +30,8 @@ class BaseEventHandler:
|
|
|
25
30
|
self.event_type = event_type
|
|
26
31
|
self.module_name = module_name
|
|
27
32
|
self.handlers: List[Dict] = []
|
|
28
|
-
self.
|
|
29
|
-
|
|
30
|
-
def middleware(self, func: Callable) -> Callable:
|
|
31
|
-
"""
|
|
32
|
-
添加中间件
|
|
33
|
-
|
|
34
|
-
:param func: 中间件函数
|
|
35
|
-
:return: 中间件函数
|
|
36
|
-
"""
|
|
37
|
-
self.middlewares.append(func)
|
|
38
|
-
return func
|
|
33
|
+
self._handler_map = {} # 用于快速查找处理器
|
|
34
|
+
self._adapter_handler_registered = False # 是否已注册到适配器
|
|
39
35
|
|
|
40
36
|
def register(self, handler: Callable, priority: int = 0, condition: Callable = None):
|
|
41
37
|
"""
|
|
@@ -52,12 +48,28 @@ class BaseEventHandler:
|
|
|
52
48
|
"module": self.module_name
|
|
53
49
|
}
|
|
54
50
|
self.handlers.append(handler_info)
|
|
51
|
+
self._handler_map[id(handler)] = handler_info
|
|
55
52
|
# 按优先级排序
|
|
56
53
|
self.handlers.sort(key=lambda x: x["priority"])
|
|
57
54
|
|
|
58
55
|
# 注册到适配器
|
|
59
|
-
if self.event_type:
|
|
56
|
+
if self.event_type and not self._adapter_handler_registered:
|
|
60
57
|
adapter.on(self.event_type)(self._process_event)
|
|
58
|
+
self._adapter_handler_registered = True
|
|
59
|
+
|
|
60
|
+
def unregister(self, handler: Callable) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
注销事件处理器
|
|
63
|
+
|
|
64
|
+
:param handler: 要注销的事件处理器
|
|
65
|
+
:return: 是否成功注销
|
|
66
|
+
"""
|
|
67
|
+
handler_id = id(handler)
|
|
68
|
+
if handler_id in self._handler_map:
|
|
69
|
+
self.handlers = [h for h in self.handlers if h["func"] != handler]
|
|
70
|
+
del self._handler_map[handler_id]
|
|
71
|
+
return True
|
|
72
|
+
return False
|
|
61
73
|
|
|
62
74
|
def __call__(self, priority: int = 0, condition: Callable = None):
|
|
63
75
|
"""
|
|
@@ -81,37 +93,18 @@ class BaseEventHandler:
|
|
|
81
93
|
|
|
82
94
|
:param event: 事件数据
|
|
83
95
|
"""
|
|
84
|
-
# 执行中间件
|
|
85
|
-
processed_event = event
|
|
86
|
-
for middleware in self.middlewares:
|
|
87
|
-
try:
|
|
88
|
-
if asyncio.iscoroutinefunction(middleware):
|
|
89
|
-
processed_event = await middleware(processed_event)
|
|
90
|
-
else:
|
|
91
|
-
processed_event = middleware(processed_event)
|
|
92
|
-
except Exception as e:
|
|
93
|
-
logger.error(f"中间件执行错误: {e}")
|
|
94
|
-
|
|
95
96
|
# 执行处理器
|
|
96
97
|
for handler_info in self.handlers:
|
|
97
98
|
condition = handler_info.get("condition")
|
|
98
99
|
# 检查条件
|
|
99
|
-
if condition and not condition(
|
|
100
|
+
if condition and not condition(event):
|
|
100
101
|
continue
|
|
101
102
|
|
|
102
103
|
handler = handler_info["func"]
|
|
103
104
|
try:
|
|
104
105
|
if asyncio.iscoroutinefunction(handler):
|
|
105
|
-
await handler(
|
|
106
|
+
await handler(event)
|
|
106
107
|
else:
|
|
107
|
-
handler(
|
|
108
|
+
handler(event)
|
|
108
109
|
except Exception as e:
|
|
109
110
|
logger.error(f"事件处理器执行错误: {e}")
|
|
110
|
-
|
|
111
|
-
def unregister(self, handler: Callable):
|
|
112
|
-
"""
|
|
113
|
-
注销事件处理器
|
|
114
|
-
|
|
115
|
-
:param handler: 要注销的事件处理器
|
|
116
|
-
"""
|
|
117
|
-
self.handlers = [h for h in self.handlers if h["func"] != handler]
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
"""
|
|
2
|
+
ErisPulse 命令处理模块
|
|
3
|
+
|
|
4
|
+
提供基于装饰器的命令注册和处理功能
|
|
5
|
+
|
|
6
|
+
{!--< tips >!--}
|
|
7
|
+
1. 支持命令别名和命令组
|
|
8
|
+
2. 支持命令权限控制
|
|
9
|
+
3. 支持命令帮助系统
|
|
10
|
+
4. 支持等待用户回复交互
|
|
11
|
+
{!--< /tips >!--}
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .base import BaseEventHandler
|
|
15
|
+
from .. import adapter, config, logger
|
|
16
|
+
from typing import Callable, Union, List, Dict, Any, Optional, Awaitable
|
|
17
|
+
import asyncio
|
|
18
|
+
import re
|
|
19
|
+
from collections import defaultdict
|
|
20
|
+
|
|
21
|
+
class CommandHandler:
|
|
22
|
+
def __init__(self):
|
|
23
|
+
self.commands: Dict[str, Dict] = {}
|
|
24
|
+
self.aliases: Dict[str, str] = {} # 别名映射
|
|
25
|
+
self.groups: Dict[str, List[str]] = {} # 命令组
|
|
26
|
+
self.permissions: Dict[str, Callable] = {} # 权限检查函数
|
|
27
|
+
self.prefix = config.getConfig("ErisPulse.event.command.prefix", "/")
|
|
28
|
+
self.case_sensitive = config.getConfig("ErisPulse.event.command.case_sensitive", True)
|
|
29
|
+
self.allow_space_prefix = config.getConfig("ErisPulse.event.command.allow_space_prefix", False)
|
|
30
|
+
|
|
31
|
+
# 等待回复相关
|
|
32
|
+
self._waiting_replies = {} # 存储等待回复的用户信息
|
|
33
|
+
|
|
34
|
+
# 创建消息事件处理器
|
|
35
|
+
self.handler = BaseEventHandler("message", "command")
|
|
36
|
+
|
|
37
|
+
# 注册消息处理器
|
|
38
|
+
if not hasattr(self.handler, '_command_handler_registered') or not self.handler._command_handler_registered:
|
|
39
|
+
self.handler.register(self._handle_message)
|
|
40
|
+
self.handler._command_handler_registered = True
|
|
41
|
+
|
|
42
|
+
def __call__(self,
|
|
43
|
+
name: Union[str, List[str]] = None,
|
|
44
|
+
aliases: List[str] = None,
|
|
45
|
+
group: str = None,
|
|
46
|
+
priority: int = 0,
|
|
47
|
+
permission: Callable = None,
|
|
48
|
+
help: str = None,
|
|
49
|
+
usage: str = None,
|
|
50
|
+
hidden: bool = False):
|
|
51
|
+
"""
|
|
52
|
+
命令装饰器
|
|
53
|
+
|
|
54
|
+
:param name: 命令名称,可以是字符串或字符串列表
|
|
55
|
+
:param aliases: 命令别名列表
|
|
56
|
+
:param group: 命令组名称
|
|
57
|
+
:param priority: 处理器优先级
|
|
58
|
+
:param permission: 权限检查函数,返回True时允许执行命令
|
|
59
|
+
:param help: 命令帮助信息
|
|
60
|
+
:param usage: 命令使用方法
|
|
61
|
+
:param hidden: 是否在帮助中隐藏命令
|
|
62
|
+
:return: 装饰器函数
|
|
63
|
+
"""
|
|
64
|
+
def decorator(func: Callable):
|
|
65
|
+
cmd_names = []
|
|
66
|
+
if isinstance(name, str):
|
|
67
|
+
cmd_names = [name]
|
|
68
|
+
elif isinstance(name, list):
|
|
69
|
+
cmd_names = name
|
|
70
|
+
else:
|
|
71
|
+
# 使用函数名作为命令名
|
|
72
|
+
cmd_names = [func.__name__]
|
|
73
|
+
|
|
74
|
+
main_name = cmd_names[0]
|
|
75
|
+
|
|
76
|
+
# 添加别名
|
|
77
|
+
alias_list = aliases or []
|
|
78
|
+
if len(cmd_names) > 1:
|
|
79
|
+
alias_list.extend(cmd_names[1:])
|
|
80
|
+
|
|
81
|
+
# 注册命令
|
|
82
|
+
for cmd_name in cmd_names:
|
|
83
|
+
self.commands[cmd_name] = {
|
|
84
|
+
"func": func,
|
|
85
|
+
"help": help,
|
|
86
|
+
"usage": usage,
|
|
87
|
+
"group": group,
|
|
88
|
+
"permission": permission,
|
|
89
|
+
"hidden": hidden,
|
|
90
|
+
"main_name": main_name
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
# 注册别名映射
|
|
94
|
+
if cmd_name != main_name:
|
|
95
|
+
self.aliases[cmd_name] = main_name
|
|
96
|
+
|
|
97
|
+
# 注册权限检查函数
|
|
98
|
+
if permission and cmd_name not in self.permissions:
|
|
99
|
+
self.permissions[cmd_name] = permission
|
|
100
|
+
|
|
101
|
+
# 添加到命令组
|
|
102
|
+
if group:
|
|
103
|
+
if group not in self.groups:
|
|
104
|
+
self.groups[group] = []
|
|
105
|
+
for cmd_name in cmd_names:
|
|
106
|
+
if cmd_name not in self.groups[group]:
|
|
107
|
+
self.groups[group].append(cmd_name)
|
|
108
|
+
|
|
109
|
+
return func
|
|
110
|
+
return decorator
|
|
111
|
+
|
|
112
|
+
def unregister(self, handler: Callable) -> bool:
|
|
113
|
+
"""
|
|
114
|
+
注销命令处理器
|
|
115
|
+
|
|
116
|
+
:param handler: 要注销的命令处理器
|
|
117
|
+
:return: 是否成功注销
|
|
118
|
+
"""
|
|
119
|
+
# 从基础处理器中移除
|
|
120
|
+
result = self.handler.unregister(handler)
|
|
121
|
+
|
|
122
|
+
# 从命令映射中移除
|
|
123
|
+
commands_to_remove = []
|
|
124
|
+
for cmd_name, cmd_info in self.commands.items():
|
|
125
|
+
if cmd_info["func"] == handler:
|
|
126
|
+
commands_to_remove.append(cmd_name)
|
|
127
|
+
|
|
128
|
+
for cmd_name in commands_to_remove:
|
|
129
|
+
# 移除命令别名映射
|
|
130
|
+
main_name = self.commands[cmd_name]["main_name"]
|
|
131
|
+
aliases_to_remove = [alias for alias, name in self.aliases.items() if name == main_name]
|
|
132
|
+
for alias in aliases_to_remove:
|
|
133
|
+
del self.aliases[alias]
|
|
134
|
+
|
|
135
|
+
# 从命令组中移除
|
|
136
|
+
for group_name, group_commands in self.groups.items():
|
|
137
|
+
if cmd_name in group_commands:
|
|
138
|
+
group_commands.remove(cmd_name)
|
|
139
|
+
|
|
140
|
+
# 移除权限检查函数
|
|
141
|
+
if cmd_name in self.permissions:
|
|
142
|
+
del self.permissions[cmd_name]
|
|
143
|
+
|
|
144
|
+
# 最后移除命令本身
|
|
145
|
+
del self.commands[cmd_name]
|
|
146
|
+
|
|
147
|
+
return result
|
|
148
|
+
|
|
149
|
+
async def wait_reply(self,
|
|
150
|
+
event: Dict[str, Any],
|
|
151
|
+
prompt: str = None,
|
|
152
|
+
timeout: float = 60.0,
|
|
153
|
+
callback: Callable[[Dict[str, Any]], Awaitable[Any]] = None,
|
|
154
|
+
validator: Callable[[Dict[str, Any]], bool] = None) -> Optional[Dict[str, Any]]:
|
|
155
|
+
"""
|
|
156
|
+
等待用户回复
|
|
157
|
+
|
|
158
|
+
:param event: 原始事件数据
|
|
159
|
+
:param prompt: 提示消息,如果提供会发送给用户
|
|
160
|
+
:param timeout: 等待超时时间(秒)
|
|
161
|
+
:param callback: 回调函数,当收到回复时执行
|
|
162
|
+
:param validator: 验证函数,用于验证回复是否有效
|
|
163
|
+
:return: 用户回复的事件数据,如果超时则返回None
|
|
164
|
+
"""
|
|
165
|
+
platform = event.get("platform")
|
|
166
|
+
user_id = event.get("user_id")
|
|
167
|
+
group_id = event.get("group_id")
|
|
168
|
+
detail_type = "group" if group_id else "private"
|
|
169
|
+
target_id = group_id or user_id
|
|
170
|
+
|
|
171
|
+
# 发送提示消息(如果提供)
|
|
172
|
+
if prompt and platform:
|
|
173
|
+
try:
|
|
174
|
+
adapter_instance = getattr(adapter, platform)
|
|
175
|
+
await adapter_instance.Send.To(detail_type, target_id).Text(prompt)
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.warning(f"发送提示消息失败: {e}")
|
|
178
|
+
|
|
179
|
+
# 创建等待 future
|
|
180
|
+
future = asyncio.get_event_loop().create_future()
|
|
181
|
+
|
|
182
|
+
# 存储等待信息
|
|
183
|
+
wait_key = f"{platform}:{user_id}:{target_id}"
|
|
184
|
+
self._waiting_replies[wait_key] = {
|
|
185
|
+
"future": future,
|
|
186
|
+
"callback": callback,
|
|
187
|
+
"validator": validator,
|
|
188
|
+
"timestamp": asyncio.get_event_loop().time()
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
# 等待回复或超时
|
|
193
|
+
result = await asyncio.wait_for(future, timeout=timeout)
|
|
194
|
+
|
|
195
|
+
# 如果提供了回调函数,则执行
|
|
196
|
+
if callback:
|
|
197
|
+
if asyncio.iscoroutinefunction(callback):
|
|
198
|
+
await callback(result)
|
|
199
|
+
else:
|
|
200
|
+
callback(result)
|
|
201
|
+
|
|
202
|
+
return result
|
|
203
|
+
except asyncio.TimeoutError:
|
|
204
|
+
# 清理超时的等待
|
|
205
|
+
if wait_key in self._waiting_replies:
|
|
206
|
+
del self._waiting_replies[wait_key]
|
|
207
|
+
return None
|
|
208
|
+
except Exception as e:
|
|
209
|
+
# 清理异常情况
|
|
210
|
+
if wait_key in self._waiting_replies:
|
|
211
|
+
del self._waiting_replies[wait_key]
|
|
212
|
+
logger.error(f"等待回复时发生错误: {e}")
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
async def _handle_message(self, event: Dict[str, Any]):
|
|
216
|
+
"""
|
|
217
|
+
处理消息事件中的命令
|
|
218
|
+
|
|
219
|
+
{!--< internal-use >!--}
|
|
220
|
+
内部使用的方法,用于从消息中解析并执行命令
|
|
221
|
+
|
|
222
|
+
:param event: 消息事件数据
|
|
223
|
+
"""
|
|
224
|
+
# 检查是否是系统消息或自身消息
|
|
225
|
+
if event.get("self", {}).get("user_id") == event.get("user_id"):
|
|
226
|
+
# 根据配置决定是否忽略自身消息
|
|
227
|
+
ignore_self = config.getConfig("ErisPulse.event.message.ignore_self", True)
|
|
228
|
+
if ignore_self:
|
|
229
|
+
return
|
|
230
|
+
|
|
231
|
+
# 检查是否已经被其他处理器标记为已处理
|
|
232
|
+
if event.get("_processed"):
|
|
233
|
+
return
|
|
234
|
+
|
|
235
|
+
# 检查是否为文本消息
|
|
236
|
+
if event.get("type") != "message":
|
|
237
|
+
return
|
|
238
|
+
|
|
239
|
+
message_segments = event.get("message", [])
|
|
240
|
+
text_content = ""
|
|
241
|
+
for segment in message_segments:
|
|
242
|
+
if segment.get("type") == "text":
|
|
243
|
+
text_content = segment.get("data", {}).get("text", "")
|
|
244
|
+
break
|
|
245
|
+
|
|
246
|
+
if not text_content:
|
|
247
|
+
return
|
|
248
|
+
|
|
249
|
+
# 处理大小写敏感性
|
|
250
|
+
check_text = text_content if self.case_sensitive else text_content.lower()
|
|
251
|
+
prefix = self.prefix if self.case_sensitive else self.prefix.lower()
|
|
252
|
+
|
|
253
|
+
# 检查前缀
|
|
254
|
+
if not check_text.startswith(prefix):
|
|
255
|
+
# 检查是否允许空格前缀 (例如: "/ command")
|
|
256
|
+
if self.allow_space_prefix and check_text.startswith(prefix + " "):
|
|
257
|
+
pass
|
|
258
|
+
else:
|
|
259
|
+
# 检查是否是等待回复的消息
|
|
260
|
+
await self._check_pending_reply(event)
|
|
261
|
+
return
|
|
262
|
+
|
|
263
|
+
# 解析命令和参数
|
|
264
|
+
command_text = check_text[len(prefix):].strip()
|
|
265
|
+
parts = command_text.split()
|
|
266
|
+
if not parts:
|
|
267
|
+
return
|
|
268
|
+
|
|
269
|
+
cmd_name = parts[0]
|
|
270
|
+
args = parts[1:] if len(parts) > 1 else []
|
|
271
|
+
|
|
272
|
+
# 处理大小写敏感性
|
|
273
|
+
if not self.case_sensitive:
|
|
274
|
+
cmd_name = cmd_name.lower()
|
|
275
|
+
|
|
276
|
+
# 处理别名
|
|
277
|
+
actual_cmd_name = self.aliases.get(cmd_name, cmd_name)
|
|
278
|
+
|
|
279
|
+
# 查找命令处理器
|
|
280
|
+
if actual_cmd_name in self.commands:
|
|
281
|
+
cmd_info = self.commands[actual_cmd_name]
|
|
282
|
+
handler = cmd_info["func"]
|
|
283
|
+
|
|
284
|
+
# 检查权限
|
|
285
|
+
permission_func = cmd_info.get("permission") or self.permissions.get(actual_cmd_name)
|
|
286
|
+
if permission_func:
|
|
287
|
+
try:
|
|
288
|
+
has_permission = permission_func(event) if not asyncio.iscoroutinefunction(permission_func) \
|
|
289
|
+
else await permission_func(event)
|
|
290
|
+
if not has_permission:
|
|
291
|
+
await self._send_permission_denied(event)
|
|
292
|
+
return
|
|
293
|
+
except Exception as e:
|
|
294
|
+
logger.error(f"权限检查错误: {e}")
|
|
295
|
+
await self._send_permission_denied(event)
|
|
296
|
+
return
|
|
297
|
+
|
|
298
|
+
# 添加命令相关信息到事件
|
|
299
|
+
command_info = {
|
|
300
|
+
"name": actual_cmd_name,
|
|
301
|
+
"main_name": cmd_info["main_name"],
|
|
302
|
+
"args": args,
|
|
303
|
+
"raw": command_text,
|
|
304
|
+
"help": cmd_info["help"],
|
|
305
|
+
"usage": cmd_info["usage"],
|
|
306
|
+
"group": cmd_info["group"]
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
event["command"] = command_info
|
|
310
|
+
|
|
311
|
+
# 标记事件已被处理
|
|
312
|
+
event["_processed"] = True
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
if asyncio.iscoroutinefunction(handler):
|
|
316
|
+
await handler(event)
|
|
317
|
+
else:
|
|
318
|
+
handler(event)
|
|
319
|
+
except Exception as e:
|
|
320
|
+
logger.error(f"命令执行错误: {e}")
|
|
321
|
+
await self._send_command_error(event, str(e))
|
|
322
|
+
|
|
323
|
+
async def _check_pending_reply(self, event: Dict[str, Any]):
|
|
324
|
+
"""
|
|
325
|
+
检查是否是等待回复的消息
|
|
326
|
+
|
|
327
|
+
:param event: 消息事件数据
|
|
328
|
+
"""
|
|
329
|
+
platform = event.get("platform")
|
|
330
|
+
user_id = event.get("user_id")
|
|
331
|
+
group_id = event.get("group_id")
|
|
332
|
+
target_id = group_id or user_id
|
|
333
|
+
|
|
334
|
+
wait_key = f"{platform}:{user_id}:{target_id}"
|
|
335
|
+
|
|
336
|
+
# 检查是否有等待的处理器
|
|
337
|
+
if wait_key in self._waiting_replies:
|
|
338
|
+
wait_info = self._waiting_replies[wait_key]
|
|
339
|
+
validator = wait_info.get("validator")
|
|
340
|
+
|
|
341
|
+
# 如果有验证器,验证回复是否有效
|
|
342
|
+
if validator:
|
|
343
|
+
if not validator(event):
|
|
344
|
+
# 验证失败,不处理此回复,继续等待
|
|
345
|
+
return
|
|
346
|
+
|
|
347
|
+
# 设置 future 结果
|
|
348
|
+
if not wait_info["future"].done():
|
|
349
|
+
wait_info["future"].set_result(event)
|
|
350
|
+
|
|
351
|
+
# 清理等待信息
|
|
352
|
+
del self._waiting_replies[wait_key]
|
|
353
|
+
|
|
354
|
+
# 标记事件已被处理
|
|
355
|
+
event["_processed"] = True
|
|
356
|
+
|
|
357
|
+
async def _send_permission_denied(self, event: Dict[str, Any]):
|
|
358
|
+
"""
|
|
359
|
+
发送权限拒绝消息
|
|
360
|
+
|
|
361
|
+
{!--< internal-use >!--}
|
|
362
|
+
内部使用的方法
|
|
363
|
+
|
|
364
|
+
:param event: 事件数据
|
|
365
|
+
"""
|
|
366
|
+
try:
|
|
367
|
+
platform = event.get("platform")
|
|
368
|
+
user_id = event.get("user_id")
|
|
369
|
+
group_id = event.get("group_id")
|
|
370
|
+
detail_type = "group" if group_id else "private"
|
|
371
|
+
target_id = group_id or user_id
|
|
372
|
+
|
|
373
|
+
if platform and hasattr(adapter, platform):
|
|
374
|
+
adapter_instance = getattr(adapter, platform)
|
|
375
|
+
await adapter_instance.Send.To(detail_type, target_id).Text("权限不足,无法执行该命令")
|
|
376
|
+
except Exception as e:
|
|
377
|
+
logger.error(f"发送权限拒绝消息失败: {e}")
|
|
378
|
+
|
|
379
|
+
async def _send_command_error(self, event: Dict[str, Any], error: str):
|
|
380
|
+
"""
|
|
381
|
+
发送命令错误消息
|
|
382
|
+
|
|
383
|
+
{!--< internal-use >!--}
|
|
384
|
+
内部使用的方法
|
|
385
|
+
|
|
386
|
+
:param event: 事件数据
|
|
387
|
+
:param error: 错误信息
|
|
388
|
+
"""
|
|
389
|
+
try:
|
|
390
|
+
platform = event.get("platform")
|
|
391
|
+
user_id = event.get("user_id")
|
|
392
|
+
group_id = event.get("group_id")
|
|
393
|
+
detail_type = "group" if group_id else "private"
|
|
394
|
+
target_id = group_id or user_id
|
|
395
|
+
|
|
396
|
+
if platform and hasattr(adapter, platform):
|
|
397
|
+
adapter_instance = getattr(adapter, platform)
|
|
398
|
+
await adapter_instance.Send.To(detail_type, target_id).Text(f"命令执行出错: {error}")
|
|
399
|
+
except Exception as e:
|
|
400
|
+
logger.error(f"发送命令错误消息失败: {e}")
|
|
401
|
+
|
|
402
|
+
def get_command(self, name: str) -> Optional[Dict]:
|
|
403
|
+
"""
|
|
404
|
+
获取命令信息
|
|
405
|
+
|
|
406
|
+
:param name: 命令名称
|
|
407
|
+
:return: 命令信息字典,如果不存在则返回None
|
|
408
|
+
"""
|
|
409
|
+
actual_name = self.aliases.get(name, name)
|
|
410
|
+
return self.commands.get(actual_name)
|
|
411
|
+
|
|
412
|
+
def get_commands(self) -> Dict[str, Dict]:
|
|
413
|
+
"""
|
|
414
|
+
获取所有命令
|
|
415
|
+
|
|
416
|
+
:return: 命令信息字典
|
|
417
|
+
"""
|
|
418
|
+
return self.commands
|
|
419
|
+
|
|
420
|
+
def get_group_commands(self, group: str) -> List[str]:
|
|
421
|
+
"""
|
|
422
|
+
获取命令组中的命令
|
|
423
|
+
|
|
424
|
+
:param group: 命令组名称
|
|
425
|
+
:return: 命令名称列表
|
|
426
|
+
"""
|
|
427
|
+
return self.groups.get(group, [])
|
|
428
|
+
|
|
429
|
+
def get_visible_commands(self) -> Dict[str, Dict]:
|
|
430
|
+
"""
|
|
431
|
+
获取所有可见命令(非隐藏命令)
|
|
432
|
+
|
|
433
|
+
:return: 可见命令信息字典
|
|
434
|
+
"""
|
|
435
|
+
return {name: info for name, info in self.commands.items()
|
|
436
|
+
if not info.get("hidden", False) and name == info["main_name"]}
|
|
437
|
+
|
|
438
|
+
def help(self, command_name: str = None, show_hidden: bool = False) -> str:
|
|
439
|
+
"""
|
|
440
|
+
生成帮助信息
|
|
441
|
+
|
|
442
|
+
:param command_name: 命令名称,如果为None则生成所有命令的帮助
|
|
443
|
+
:param show_hidden: 是否显示隐藏命令
|
|
444
|
+
:return: 帮助信息字符串
|
|
445
|
+
"""
|
|
446
|
+
if command_name:
|
|
447
|
+
cmd_info = self.get_command(command_name)
|
|
448
|
+
if cmd_info:
|
|
449
|
+
help_text = cmd_info.get("help", "无帮助信息")
|
|
450
|
+
usage = cmd_info.get("usage", f"{self.prefix}{command_name}")
|
|
451
|
+
return f"命令: {command_name}\n用法: {usage}\n说明: {help_text}"
|
|
452
|
+
else:
|
|
453
|
+
return f"未找到命令: {command_name}"
|
|
454
|
+
else:
|
|
455
|
+
# 生成所有命令的帮助
|
|
456
|
+
commands_to_show = self.get_visible_commands() if not show_hidden else {
|
|
457
|
+
name: info for name, info in self.commands.items()
|
|
458
|
+
if name == info["main_name"]
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if not commands_to_show:
|
|
462
|
+
return "暂无可用命令"
|
|
463
|
+
|
|
464
|
+
help_lines = ["可用命令:"]
|
|
465
|
+
for cmd_name, cmd_info in commands_to_show.items():
|
|
466
|
+
help_text = cmd_info.get("help", "无说明")
|
|
467
|
+
help_lines.append(f" {self.prefix}{cmd_name} - {help_text}")
|
|
468
|
+
return "\n".join(help_lines)
|
|
469
|
+
|
|
470
|
+
command = CommandHandler()
|