ErisPulse 2.3.4.dev0__py3-none-any.whl → 2.3.4.dev2__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/{utils/cli → CLI}/__init__.py +1 -1
- ErisPulse/{utils/cli → CLI}/__init__.pyi +1 -1
- ErisPulse/{utils/cli/__main__.py → CLI/cli.py} +3 -4
- ErisPulse/{utils/cli/__main__.pyi → CLI/cli.pyi} +2 -3
- ErisPulse/{utils/cli → CLI}/commands/init.py +4 -9
- ErisPulse/{utils/cli → CLI}/commands/init.pyi +2 -14
- ErisPulse/{utils/cli → CLI}/commands/install.py +2 -7
- ErisPulse/{utils/cli → CLI}/commands/install.pyi +2 -14
- ErisPulse/{utils/cli → CLI}/commands/list.py +2 -7
- ErisPulse/{utils/cli → CLI}/commands/list.pyi +2 -14
- ErisPulse/{utils/cli → CLI}/commands/list_remote.py +2 -7
- ErisPulse/{utils/cli → CLI}/commands/list_remote.pyi +2 -14
- ErisPulse/{utils/cli → CLI}/commands/run.py +3 -7
- ErisPulse/{utils/cli → CLI}/commands/run.pyi +2 -11
- ErisPulse/{utils/cli → CLI}/commands/self_update.py +2 -7
- ErisPulse/{utils/cli → CLI}/commands/self_update.pyi +2 -14
- ErisPulse/{utils/cli → CLI}/commands/uninstall.py +1 -6
- ErisPulse/{utils/cli → CLI}/commands/uninstall.pyi +1 -14
- ErisPulse/{utils/cli → CLI}/commands/upgrade.py +1 -7
- ErisPulse/{utils/cli → CLI}/commands/upgrade.pyi +1 -14
- ErisPulse/{utils → CLI/utils}/__init__.py +1 -5
- ErisPulse/{utils → CLI/utils}/__init__.pyi +0 -2
- ErisPulse/{utils → CLI/utils}/package_manager.py +146 -20
- ErisPulse/{utils → CLI/utils}/package_manager.pyi +20 -3
- ErisPulse/{utils → CLI/utils}/reload_handler.py +7 -8
- ErisPulse/{utils → CLI/utils}/reload_handler.pyi +1 -1
- ErisPulse/Core/Bases/manager.py +136 -0
- ErisPulse/Core/Bases/manager.pyi +108 -0
- ErisPulse/Core/Bases/module.py +53 -1
- ErisPulse/Core/Bases/module.pyi +43 -0
- ErisPulse/Core/Event/command.py +6 -1
- ErisPulse/Core/_self_config.py +1 -1
- ErisPulse/Core/adapter.py +70 -10
- ErisPulse/Core/adapter.pyi +18 -1
- ErisPulse/Core/exceptions.py +4 -2
- ErisPulse/Core/lifecycle.py +9 -0
- ErisPulse/Core/logger.py +21 -15
- ErisPulse/Core/logger.pyi +2 -1
- ErisPulse/Core/module.py +57 -9
- ErisPulse/Core/module.pyi +12 -1
- ErisPulse/Core/router.py +13 -5
- ErisPulse/Core/storage.py +94 -256
- ErisPulse/Core/storage.pyi +13 -66
- ErisPulse/__init__.py +35 -1237
- ErisPulse/__init__.pyi +3 -290
- ErisPulse/__main__.py +1 -1
- ErisPulse/__main__.pyi +1 -1
- ErisPulse/loaders/__init__.py +22 -0
- ErisPulse/loaders/__init__.pyi +21 -0
- ErisPulse/loaders/adapter_loader.py +187 -0
- ErisPulse/loaders/adapter_loader.pyi +82 -0
- ErisPulse/loaders/base_loader.py +162 -0
- ErisPulse/loaders/base_loader.pyi +23 -0
- ErisPulse/loaders/initializer.py +150 -0
- ErisPulse/loaders/initializer.pyi +60 -0
- ErisPulse/loaders/module_loader.py +618 -0
- ErisPulse/loaders/module_loader.pyi +179 -0
- ErisPulse/loaders/strategy.py +129 -0
- ErisPulse/loaders/strategy.pyi +90 -0
- ErisPulse/sdk.py +435 -0
- ErisPulse/sdk.pyi +158 -0
- {erispulse-2.3.4.dev0.dist-info → erispulse-2.3.4.dev2.dist-info}/METADATA +1 -1
- erispulse-2.3.4.dev2.dist-info/RECORD +103 -0
- ErisPulse/sdk_protocol.py +0 -143
- ErisPulse/sdk_protocol.pyi +0 -97
- erispulse-2.3.4.dev0.dist-info/RECORD +0 -89
- /ErisPulse/{utils/cli → CLI}/base.py +0 -0
- /ErisPulse/{utils/cli → CLI}/base.pyi +0 -0
- /ErisPulse/{utils/cli → CLI}/commands/__init__.py +0 -0
- /ErisPulse/{utils/cli → CLI}/commands/__init__.pyi +0 -0
- /ErisPulse/{utils → CLI}/console.py +0 -0
- /ErisPulse/{utils → CLI}/console.pyi +0 -0
- /ErisPulse/{utils/cli → CLI}/registry.py +0 -0
- /ErisPulse/{utils/cli → CLI}/registry.pyi +0 -0
- {erispulse-2.3.4.dev0.dist-info → erispulse-2.3.4.dev2.dist-info}/WHEEL +0 -0
- {erispulse-2.3.4.dev0.dist-info → erispulse-2.3.4.dev2.dist-info}/entry_points.txt +0 -0
- {erispulse-2.3.4.dev0.dist-info → erispulse-2.3.4.dev2.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/Bases/module.pyi
CHANGED
|
@@ -10,18 +10,61 @@ ErisPulse 模块基础模块
|
|
|
10
10
|
提供模块基类定义和标准接口
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
from typing import Union, Dict, Any
|
|
14
|
+
from ...loaders.strategy import ModuleLoadStrategy
|
|
15
|
+
|
|
13
16
|
class BaseModule:
|
|
14
17
|
"""
|
|
15
18
|
模块基类
|
|
16
19
|
|
|
17
20
|
提供模块加载和卸载的标准接口
|
|
18
21
|
"""
|
|
22
|
+
def get_load_strategy() -> Union[(ModuleLoadStrategy, Dict[(str, Any)])]:
|
|
23
|
+
"""
|
|
24
|
+
获取模块加载策略
|
|
25
|
+
|
|
26
|
+
支持返回 ModuleLoadStrategy 对象或字典
|
|
27
|
+
所有属性统一处理,没有任何预定义字段
|
|
28
|
+
|
|
29
|
+
:return: 加载策略对象或字典
|
|
30
|
+
|
|
31
|
+
{!--< tips >!--}
|
|
32
|
+
常用配置项:
|
|
33
|
+
- lazy_load: bool, 是否懒加载(默认 True)
|
|
34
|
+
- priority: int, 加载优先级(默认 0,数值越大优先级越高)
|
|
35
|
+
|
|
36
|
+
使用方式:
|
|
37
|
+
>>> class MyModule(BaseModule):
|
|
38
|
+
... @staticmethod
|
|
39
|
+
... def get_load_strategy() -> ModuleLoadStrategy:
|
|
40
|
+
... return ModuleLoadStrategy(
|
|
41
|
+
... lazy_load=False,
|
|
42
|
+
... priority=100
|
|
43
|
+
... )
|
|
44
|
+
|
|
45
|
+
或使用字典:
|
|
46
|
+
>>> class MyModule(BaseModule):
|
|
47
|
+
... @staticmethod
|
|
48
|
+
... def get_load_strategy() -> dict:
|
|
49
|
+
... return {
|
|
50
|
+
... "lazy_load": False,
|
|
51
|
+
... "priority": 100
|
|
52
|
+
... }
|
|
53
|
+
{!--< /tips >!--}
|
|
54
|
+
"""
|
|
55
|
+
...
|
|
19
56
|
def should_eager_load() -> bool:
|
|
20
57
|
"""
|
|
21
58
|
模块是否应该在启动时加载
|
|
22
59
|
默认为False(即懒加载)
|
|
23
60
|
|
|
61
|
+
兼容方法,实际调用 get_load_strategy()
|
|
62
|
+
|
|
24
63
|
:return: 是否应该在启动时加载
|
|
64
|
+
|
|
65
|
+
{!--< tips >!--}
|
|
66
|
+
旧版方法,建议使用 get_load_strategy() 替代
|
|
67
|
+
{!--< /tips >!--}
|
|
25
68
|
"""
|
|
26
69
|
...
|
|
27
70
|
async def on_load(self: object, event: dict) -> bool:
|
ErisPulse/Core/Event/command.py
CHANGED
|
@@ -94,7 +94,7 @@ class CommandHandler:
|
|
|
94
94
|
"main_name": main_name
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
#
|
|
97
|
+
# 注册别名映射(name列表中的额外名称)
|
|
98
98
|
if cmd_name != main_name:
|
|
99
99
|
self.aliases[cmd_name] = main_name
|
|
100
100
|
|
|
@@ -102,6 +102,11 @@ class CommandHandler:
|
|
|
102
102
|
if permission and cmd_name not in self.permissions:
|
|
103
103
|
self.permissions[cmd_name] = permission
|
|
104
104
|
|
|
105
|
+
# 注册aliases参数中的别名
|
|
106
|
+
for alias in alias_list:
|
|
107
|
+
if alias not in self.aliases:
|
|
108
|
+
self.aliases[alias] = main_name
|
|
109
|
+
|
|
105
110
|
# 添加到命令组
|
|
106
111
|
if group:
|
|
107
112
|
if group not in self.groups:
|
ErisPulse/Core/_self_config.py
CHANGED
ErisPulse/Core/adapter.py
CHANGED
|
@@ -14,8 +14,9 @@ from .logger import logger
|
|
|
14
14
|
from .Bases.adapter import BaseAdapter
|
|
15
15
|
from .config import config
|
|
16
16
|
from .lifecycle import lifecycle
|
|
17
|
+
from .Bases.manager import ManagerBase
|
|
17
18
|
|
|
18
|
-
class AdapterManager:
|
|
19
|
+
class AdapterManager(ManagerBase):
|
|
19
20
|
"""
|
|
20
21
|
适配器管理器
|
|
21
22
|
|
|
@@ -269,6 +270,9 @@ class AdapterManager:
|
|
|
269
270
|
from .router import router
|
|
270
271
|
await router.stop()
|
|
271
272
|
|
|
273
|
+
# 清空已启动实例集合
|
|
274
|
+
self._started_instances.clear()
|
|
275
|
+
|
|
272
276
|
# 提交适配器关闭完成事件
|
|
273
277
|
await lifecycle.submit_event(
|
|
274
278
|
"adapter.stopped",
|
|
@@ -301,9 +305,8 @@ class AdapterManager:
|
|
|
301
305
|
:param platform: 平台名称
|
|
302
306
|
:return: [bool] 平台是否存在
|
|
303
307
|
"""
|
|
304
|
-
#
|
|
305
|
-
|
|
306
|
-
return platform in adapter_statuses
|
|
308
|
+
# 检查平台是否已注册(在 _adapters 中)
|
|
309
|
+
return platform in self._adapters
|
|
307
310
|
|
|
308
311
|
def is_enabled(self, platform: str) -> bool:
|
|
309
312
|
"""
|
|
@@ -332,10 +335,11 @@ class AdapterManager:
|
|
|
332
335
|
:param platform: 平台名称
|
|
333
336
|
:return: [bool] 操作是否成功
|
|
334
337
|
"""
|
|
335
|
-
|
|
338
|
+
# 启用平台时自动在配置中注册
|
|
339
|
+
if platform not in self._adapters:
|
|
336
340
|
logger.error(f"平台 {platform} 不存在")
|
|
337
341
|
return False
|
|
338
|
-
|
|
342
|
+
|
|
339
343
|
config.setConfig(f"ErisPulse.adapters.status.{platform}", True)
|
|
340
344
|
logger.info(f"平台 {platform} 已启用")
|
|
341
345
|
return True
|
|
@@ -347,21 +351,77 @@ class AdapterManager:
|
|
|
347
351
|
:param platform: 平台名称
|
|
348
352
|
:return: [bool] 操作是否成功
|
|
349
353
|
"""
|
|
350
|
-
|
|
354
|
+
# 禁用平台时自动在配置中注册
|
|
355
|
+
if platform not in self._adapters:
|
|
351
356
|
logger.error(f"平台 {platform} 不存在")
|
|
352
357
|
return False
|
|
353
|
-
|
|
358
|
+
|
|
354
359
|
config.setConfig(f"ErisPulse.adapters.status.{platform}", False)
|
|
355
360
|
logger.info(f"平台 {platform} 已禁用")
|
|
356
361
|
return True
|
|
357
362
|
|
|
363
|
+
def unregister(self, platform: str) -> bool:
|
|
364
|
+
"""
|
|
365
|
+
取消注册适配器
|
|
366
|
+
|
|
367
|
+
:param platform: 平台名称
|
|
368
|
+
:return: 是否取消成功
|
|
369
|
+
|
|
370
|
+
{!--< internal-use >!--}
|
|
371
|
+
注意:此方法仅取消注册,不关闭已启动的适配器
|
|
372
|
+
{!--< /internal-use >!--}
|
|
373
|
+
"""
|
|
374
|
+
if platform not in self._adapters:
|
|
375
|
+
logger.warning(f"平台 {platform} 未注册")
|
|
376
|
+
return False
|
|
377
|
+
|
|
378
|
+
# 移除适配器实例
|
|
379
|
+
adapter = self._adapters.pop(platform)
|
|
380
|
+
|
|
381
|
+
# 移除平台属性
|
|
382
|
+
if len(platform) <= 10:
|
|
383
|
+
from itertools import product
|
|
384
|
+
combinations = [''.join(c) for c in product(*[(ch.lower(), ch.upper()) for ch in platform])]
|
|
385
|
+
for name in set(combinations):
|
|
386
|
+
if hasattr(self, name):
|
|
387
|
+
delattr(self, name)
|
|
388
|
+
else:
|
|
389
|
+
if hasattr(self, platform.lower()):
|
|
390
|
+
delattr(self, platform.lower())
|
|
391
|
+
if hasattr(self, platform.upper()):
|
|
392
|
+
delattr(self, platform.upper())
|
|
393
|
+
if hasattr(self, platform.capitalize()):
|
|
394
|
+
delattr(self, platform.capitalize())
|
|
395
|
+
|
|
396
|
+
logger.info(f"平台 {platform} 已取消注册")
|
|
397
|
+
return True
|
|
398
|
+
|
|
399
|
+
def list_registered(self) -> List[str]:
|
|
400
|
+
"""
|
|
401
|
+
列出所有已注册的平台
|
|
402
|
+
|
|
403
|
+
:return: 平台名称列表
|
|
404
|
+
"""
|
|
405
|
+
return list(self._adapters.keys())
|
|
406
|
+
|
|
407
|
+
def list_items(self) -> Dict[str, bool]:
|
|
408
|
+
"""
|
|
409
|
+
列出所有平台适配器状态
|
|
410
|
+
|
|
411
|
+
:return: {平台名: 是否启用} 字典
|
|
412
|
+
"""
|
|
413
|
+
return config.getConfig("ErisPulse.adapters.status", {})
|
|
414
|
+
|
|
415
|
+
# 兼容性方法 - 保持向后兼容
|
|
358
416
|
def list_adapters(self) -> Dict[str, bool]:
|
|
359
417
|
"""
|
|
360
418
|
列出所有平台适配器状态
|
|
361
|
-
|
|
419
|
+
|
|
420
|
+
{!--< deprecated >!--} 请使用 list_items() 代替
|
|
421
|
+
|
|
362
422
|
:return: [Dict[str, bool]] 平台适配器状态字典
|
|
363
423
|
"""
|
|
364
|
-
return
|
|
424
|
+
return self.list_items()
|
|
365
425
|
|
|
366
426
|
# ==================== 事件处理与消息发送 ====================
|
|
367
427
|
|
ErisPulse/Core/adapter.pyi
CHANGED
|
@@ -18,8 +18,9 @@ from .logger import logger
|
|
|
18
18
|
from .Bases.adapter import BaseAdapter
|
|
19
19
|
from .config import config
|
|
20
20
|
from .lifecycle import lifecycle
|
|
21
|
+
from .Bases.manager import ManagerBase
|
|
21
22
|
|
|
22
|
-
class AdapterManager:
|
|
23
|
+
class AdapterManager(ManagerBase):
|
|
23
24
|
"""
|
|
24
25
|
适配器管理器
|
|
25
26
|
|
|
@@ -118,10 +119,26 @@ class AdapterManager:
|
|
|
118
119
|
:return: [bool] 操作是否成功
|
|
119
120
|
"""
|
|
120
121
|
...
|
|
122
|
+
def list_registered(self: object) -> List[str]:
|
|
123
|
+
"""
|
|
124
|
+
列出所有已注册的平台
|
|
125
|
+
|
|
126
|
+
:return: 平台名称列表
|
|
127
|
+
"""
|
|
128
|
+
...
|
|
129
|
+
def list_items(self: object) -> Dict[(str, bool)]:
|
|
130
|
+
"""
|
|
131
|
+
列出所有平台适配器状态
|
|
132
|
+
|
|
133
|
+
:return: {平台名: 是否启用} 字典
|
|
134
|
+
"""
|
|
135
|
+
...
|
|
121
136
|
def list_adapters(self: object) -> Dict[(str, bool)]:
|
|
122
137
|
"""
|
|
123
138
|
列出所有平台适配器状态
|
|
124
139
|
|
|
140
|
+
{!--< deprecated >!--} 请使用 list_items() 代替
|
|
141
|
+
|
|
125
142
|
:return: [Dict[str, bool]] 平台适配器状态字典
|
|
126
143
|
"""
|
|
127
144
|
...
|
ErisPulse/Core/exceptions.py
CHANGED
|
@@ -108,6 +108,8 @@ def setup_async_loop(loop: asyncio.AbstractEventLoop = None) -> None: # type:
|
|
|
108
108
|
|
|
109
109
|
sys.excepthook = global_exception_handler
|
|
110
110
|
try:
|
|
111
|
-
asyncio.
|
|
111
|
+
loop = asyncio.get_running_loop()
|
|
112
|
+
loop.set_exception_handler(async_exception_handler)
|
|
112
113
|
except RuntimeError:
|
|
113
|
-
|
|
114
|
+
# 没有运行中的事件循环,这是正常的,在运行时再设置
|
|
115
|
+
pass
|
ErisPulse/Core/lifecycle.py
CHANGED
|
@@ -120,6 +120,15 @@ class LifecycleManager:
|
|
|
120
120
|
:param event: 事件名称
|
|
121
121
|
:param event_data: 事件数据字典
|
|
122
122
|
"""
|
|
123
|
+
# 验证事件类型
|
|
124
|
+
if event_type is None:
|
|
125
|
+
logger.error("事件类型不能为None")
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
if not isinstance(event_type, str) or not event_type:
|
|
129
|
+
logger.error(f"事件类型必须是非空字符串,收到: {event_type}")
|
|
130
|
+
return
|
|
131
|
+
|
|
123
132
|
# 构建完整事件数据
|
|
124
133
|
event_data = {
|
|
125
134
|
"event": event_type,
|
ErisPulse/Core/logger.py
CHANGED
|
@@ -91,11 +91,6 @@ class Logger:
|
|
|
91
91
|
:param level: 日志级别(DEBUG/INFO/WARNING/ERROR/CRITICAL)
|
|
92
92
|
:return: bool 设置是否成功
|
|
93
93
|
"""
|
|
94
|
-
from .module import module
|
|
95
|
-
|
|
96
|
-
if not module.is_enabled(module_name):
|
|
97
|
-
self._logger.warning(f"模块 {module_name} 未启用,无法设置日志等级。")
|
|
98
|
-
return False
|
|
99
94
|
level = level.upper()
|
|
100
95
|
if hasattr(logging, level):
|
|
101
96
|
self._module_levels[module_name] = getattr(logging, level)
|
|
@@ -115,19 +110,21 @@ class Logger:
|
|
|
115
110
|
if self._file_handler:
|
|
116
111
|
self._logger.removeHandler(self._file_handler)
|
|
117
112
|
self._file_handler.close()
|
|
113
|
+
self._file_handler = None
|
|
118
114
|
|
|
119
115
|
if isinstance(path, str):
|
|
120
116
|
path = [path]
|
|
121
117
|
|
|
122
118
|
for p in path:
|
|
123
119
|
try:
|
|
124
|
-
|
|
120
|
+
self._file_handler = logging.FileHandler(p, encoding="utf-8")
|
|
125
121
|
# 使用自定义格式化器去除rich markup标签
|
|
126
|
-
|
|
127
|
-
self._logger.addHandler(
|
|
122
|
+
self._file_handler.setFormatter(logging.Formatter("[%(name)s] %(message)s"))
|
|
123
|
+
self._logger.addHandler(self._file_handler)
|
|
128
124
|
return True
|
|
129
125
|
except Exception as e:
|
|
130
126
|
self._logger.error(f"无法设置日志文件 {p}: {e}")
|
|
127
|
+
self._file_handler = None
|
|
131
128
|
return False
|
|
132
129
|
|
|
133
130
|
self._logger.warning("出现极端错误,无法设置日志文件。")
|
|
@@ -140,9 +137,11 @@ class Logger:
|
|
|
140
137
|
:param path: 日志文件路径 Str/List
|
|
141
138
|
:return: bool 设置是否成功
|
|
142
139
|
"""
|
|
143
|
-
|
|
140
|
+
# 检查是否有日志记录
|
|
141
|
+
if not self._logs or all(len(logs) == 0 for logs in self._logs.values()):
|
|
144
142
|
self._logger.warning("没有log记录可供保存。")
|
|
145
143
|
return False
|
|
144
|
+
|
|
146
145
|
if isinstance(path, str):
|
|
147
146
|
path = [path]
|
|
148
147
|
|
|
@@ -162,16 +161,18 @@ class Logger:
|
|
|
162
161
|
self._logger.warning("出现极端错误,无法保存日志。")
|
|
163
162
|
return False
|
|
164
163
|
|
|
165
|
-
def get_logs(self, module_name: str =
|
|
164
|
+
def get_logs(self, module_name: str = None) -> dict:
|
|
166
165
|
"""
|
|
167
166
|
获取日志内容
|
|
168
167
|
|
|
169
|
-
:param module_name (可选):
|
|
168
|
+
:param module_name (可选): 模块名称,None表示获取所有日志
|
|
170
169
|
:return: dict 日志内容
|
|
171
170
|
"""
|
|
172
|
-
if module_name:
|
|
173
|
-
|
|
174
|
-
|
|
171
|
+
if module_name is None:
|
|
172
|
+
# 返回所有日志
|
|
173
|
+
return {k: v.copy() for k, v in self._logs.items()}
|
|
174
|
+
# 返回指定模块的日志
|
|
175
|
+
return {module_name: self._logs.get(module_name, [])}
|
|
175
176
|
|
|
176
177
|
def _save_in_memory(self, ModuleName, msg):
|
|
177
178
|
if ModuleName not in self._logs:
|
|
@@ -226,13 +227,18 @@ class Logger:
|
|
|
226
227
|
except Exception:
|
|
227
228
|
return "Unknown"
|
|
228
229
|
|
|
229
|
-
def get_child(self, child_name: str = "UnknownChild"):
|
|
230
|
+
def get_child(self, child_name: str = "UnknownChild", *, relative: bool = True):
|
|
230
231
|
"""
|
|
231
232
|
获取子日志记录器
|
|
232
233
|
|
|
233
234
|
:param child_name: 子模块名称(可选)
|
|
235
|
+
:param relative: 是否相对于调用者模块(默认True),False表示使用完整名称
|
|
234
236
|
:return: LoggerChild 子日志记录器实例
|
|
235
237
|
"""
|
|
238
|
+
if child_name and not relative:
|
|
239
|
+
# 使用完整的指定名称,不添加前缀
|
|
240
|
+
return LoggerChild(self, child_name)
|
|
241
|
+
|
|
236
242
|
caller_module = self._get_caller()
|
|
237
243
|
if child_name:
|
|
238
244
|
full_module_name = f"{caller_module}.{child_name}"
|
ErisPulse/Core/logger.pyi
CHANGED
|
@@ -81,7 +81,7 @@ class Logger:
|
|
|
81
81
|
"""
|
|
82
82
|
获取日志内容
|
|
83
83
|
|
|
84
|
-
:param module_name (可选):
|
|
84
|
+
:param module_name (可选): 模块名称,None表示获取所有日志
|
|
85
85
|
:return: dict 日志内容
|
|
86
86
|
"""
|
|
87
87
|
...
|
|
@@ -98,6 +98,7 @@ class Logger:
|
|
|
98
98
|
获取子日志记录器
|
|
99
99
|
|
|
100
100
|
:param child_name: 子模块名称(可选)
|
|
101
|
+
:param relative: 是否相对于调用者模块(默认True),False表示使用完整名称
|
|
101
102
|
:return: LoggerChild 子日志记录器实例
|
|
102
103
|
"""
|
|
103
104
|
...
|
ErisPulse/Core/module.py
CHANGED
|
@@ -5,13 +5,15 @@ ErisPulse 模块系统
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import asyncio
|
|
8
|
+
import warnings
|
|
8
9
|
from typing import Any, Dict, List, Type, Optional
|
|
9
10
|
from .logger import logger
|
|
10
11
|
from .config import config
|
|
11
12
|
from .Bases import BaseModule
|
|
12
13
|
from .lifecycle import lifecycle
|
|
14
|
+
from .Bases.manager import ManagerBase
|
|
13
15
|
|
|
14
|
-
class ModuleManager:
|
|
16
|
+
class ModuleManager(ManagerBase):
|
|
15
17
|
"""
|
|
16
18
|
模块管理器
|
|
17
19
|
|
|
@@ -48,9 +50,16 @@ class ModuleManager:
|
|
|
48
50
|
>>> module.register("MyModule", MyModuleClass)
|
|
49
51
|
"""
|
|
50
52
|
# 严格验证模块类,确保继承自BaseModule
|
|
53
|
+
# 先检查是否为类对象
|
|
54
|
+
if not isinstance(module_class, type):
|
|
55
|
+
error_msg = f"模块 {module_name} 的参数必须是类,而不是 {type(module_class).__name__}"
|
|
56
|
+
logger.error(error_msg)
|
|
57
|
+
raise TypeError(error_msg)
|
|
58
|
+
|
|
51
59
|
if not issubclass(module_class, BaseModule):
|
|
52
60
|
warn_msg = f"模块 {module_name} 的类 {module_class.__name__} 没有继承自BaseModule,但我们仍会继续尝试加载这个模块,但请注意这可能引发其他问题"
|
|
53
61
|
logger.warning(warn_msg)
|
|
62
|
+
warnings.warn(warn_msg, UserWarning)
|
|
54
63
|
# error_msg = f"模块 {module_name} 的类 {module_class.__name__} 必须继承自BaseModule"
|
|
55
64
|
# logger.error(error_msg)
|
|
56
65
|
# raise TypeError(error_msg)
|
|
@@ -63,7 +72,9 @@ class ModuleManager:
|
|
|
63
72
|
|
|
64
73
|
# 检查模块名是否已存在
|
|
65
74
|
if module_name in self._module_classes:
|
|
66
|
-
|
|
75
|
+
warn_msg = f"模块 {module_name} 已存在,将覆盖原模块类"
|
|
76
|
+
logger.warning(warn_msg)
|
|
77
|
+
warnings.warn(warn_msg, UserWarning)
|
|
67
78
|
|
|
68
79
|
self._module_classes[module_name] = module_class
|
|
69
80
|
if module_info:
|
|
@@ -189,14 +200,15 @@ class ModuleManager:
|
|
|
189
200
|
:param module_name: 模块名称
|
|
190
201
|
:return: 是否卸载成功
|
|
191
202
|
"""
|
|
203
|
+
# 模块未加载,返回 True(表示没有需要卸载的模块,这不是错误)
|
|
192
204
|
if module_name not in self._loaded_modules:
|
|
193
205
|
logger.warning(f"模块 {module_name} 未加载")
|
|
194
|
-
return
|
|
206
|
+
return True
|
|
195
207
|
|
|
196
208
|
try:
|
|
197
209
|
# 调用模块的on_unload卸载方法
|
|
198
|
-
instance = self._modules
|
|
199
|
-
if hasattr(instance, 'on_unload'):
|
|
210
|
+
instance = self._modules.get(module_name)
|
|
211
|
+
if instance and hasattr(instance, 'on_unload'):
|
|
200
212
|
try:
|
|
201
213
|
if asyncio.iscoroutinefunction(instance.on_unload):
|
|
202
214
|
await instance.on_unload({"module_name": module_name})
|
|
@@ -204,9 +216,9 @@ class ModuleManager:
|
|
|
204
216
|
instance.on_unload({"module_name": module_name})
|
|
205
217
|
except Exception as e:
|
|
206
218
|
logger.error(f"模块 {module_name} on_unload 方法执行失败: {e}")
|
|
207
|
-
|
|
219
|
+
|
|
208
220
|
# 清理缓存
|
|
209
|
-
del self._modules[module_name]
|
|
221
|
+
del self._modules[module_name]
|
|
210
222
|
self._loaded_modules.discard(module_name)
|
|
211
223
|
|
|
212
224
|
logger.info(f"模块 {module_name} 卸载成功")
|
|
@@ -334,13 +346,49 @@ class ModuleManager:
|
|
|
334
346
|
self._loaded_modules.discard(module_name)
|
|
335
347
|
return True
|
|
336
348
|
|
|
349
|
+
def unregister(self, module_name: str) -> bool:
|
|
350
|
+
"""
|
|
351
|
+
取消注册模块
|
|
352
|
+
|
|
353
|
+
:param module_name: 模块名称
|
|
354
|
+
:return: 是否取消成功
|
|
355
|
+
|
|
356
|
+
{!--< internal-use >!--}
|
|
357
|
+
注意:此方法仅取消注册,不卸载已加载的模块
|
|
358
|
+
{!--< /internal-use >!--}
|
|
359
|
+
"""
|
|
360
|
+
if module_name not in self._module_classes:
|
|
361
|
+
logger.warning(f"模块 {module_name} 未注册")
|
|
362
|
+
return False
|
|
363
|
+
|
|
364
|
+
# 移除模块类
|
|
365
|
+
self._module_classes.pop(module_name)
|
|
366
|
+
|
|
367
|
+
# 移除模块信息
|
|
368
|
+
if module_name in self._module_info:
|
|
369
|
+
self._module_info.pop(module_name)
|
|
370
|
+
|
|
371
|
+
logger.info(f"模块 {module_name} 已取消注册")
|
|
372
|
+
return True
|
|
373
|
+
|
|
374
|
+
def list_items(self) -> Dict[str, bool]:
|
|
375
|
+
"""
|
|
376
|
+
列出所有模块状态
|
|
377
|
+
|
|
378
|
+
:return: {模块名: 是否启用} 字典
|
|
379
|
+
"""
|
|
380
|
+
return config.getConfig("ErisPulse.modules.status", {})
|
|
381
|
+
|
|
382
|
+
# 兼容性方法 - 保持向后兼容
|
|
337
383
|
def list_modules(self) -> Dict[str, bool]:
|
|
338
384
|
"""
|
|
339
385
|
列出所有模块状态
|
|
340
386
|
|
|
387
|
+
{!--< deprecated >!--} 请使用 list_items() 代替
|
|
388
|
+
|
|
341
389
|
:return: [Dict[str, bool]] 模块状态字典
|
|
342
390
|
"""
|
|
343
|
-
return
|
|
391
|
+
return self.list_items()
|
|
344
392
|
|
|
345
393
|
# ==================== 工具方法 ====================
|
|
346
394
|
|
|
@@ -370,4 +418,4 @@ module = ModuleManager()
|
|
|
370
418
|
|
|
371
419
|
__all__ = [
|
|
372
420
|
"module"
|
|
373
|
-
]
|
|
421
|
+
]
|
ErisPulse/Core/module.pyi
CHANGED
|
@@ -11,13 +11,15 @@ ErisPulse 模块系统
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
import asyncio
|
|
14
|
+
import warnings
|
|
14
15
|
from typing import Any, Dict, List, Type, Optional
|
|
15
16
|
from .logger import logger
|
|
16
17
|
from .config import config
|
|
17
18
|
from .Bases import BaseModule
|
|
18
19
|
from .lifecycle import lifecycle
|
|
20
|
+
from .Bases.manager import ManagerBase
|
|
19
21
|
|
|
20
|
-
class ModuleManager:
|
|
22
|
+
class ModuleManager(ManagerBase):
|
|
21
23
|
"""
|
|
22
24
|
模块管理器
|
|
23
25
|
|
|
@@ -152,10 +154,19 @@ class ModuleManager:
|
|
|
152
154
|
:return: [bool] 操作是否成功
|
|
153
155
|
"""
|
|
154
156
|
...
|
|
157
|
+
def list_items(self: object) -> Dict[(str, bool)]:
|
|
158
|
+
"""
|
|
159
|
+
列出所有模块状态
|
|
160
|
+
|
|
161
|
+
:return: {模块名: 是否启用} 字典
|
|
162
|
+
"""
|
|
163
|
+
...
|
|
155
164
|
def list_modules(self: object) -> Dict[(str, bool)]:
|
|
156
165
|
"""
|
|
157
166
|
列出所有模块状态
|
|
158
167
|
|
|
168
|
+
{!--< deprecated >!--} 请使用 list_items() 代替
|
|
169
|
+
|
|
159
170
|
:return: [Dict[str, bool]] 模块状态字典
|
|
160
171
|
"""
|
|
161
172
|
...
|
ErisPulse/Core/router.py
CHANGED
|
@@ -235,13 +235,20 @@ class RouterManager:
|
|
|
235
235
|
try:
|
|
236
236
|
full_path = f"/{module_name}{path}"
|
|
237
237
|
|
|
238
|
-
#
|
|
239
|
-
if full_path in self.
|
|
240
|
-
self.app.remove_api_websocket_route(full_path) # type: ignore || 原因:实际上,FastAPI的API提供了remove_api_websocket_route方法
|
|
238
|
+
# 检查 WebSocket 路由是否存在于我们的内部记录中
|
|
239
|
+
if full_path in self._websocket_routes.get(module_name, {}):
|
|
241
240
|
display_url = self._format_display_url(f"{self.base_url}{full_path}")
|
|
242
241
|
logger.info(f"注销WebSocket: {display_url}")
|
|
243
242
|
del self._websocket_routes[module_name][full_path]
|
|
243
|
+
|
|
244
|
+
# 从 FastAPI 路由列表中移除对应的 WebSocket 路由
|
|
245
|
+
# FastAPI 的 WebSocket 路由有 websocket_endpoint 属性
|
|
246
|
+
self.app.router.routes = [
|
|
247
|
+
route for route in self.app.router.routes
|
|
248
|
+
if not (hasattr(route, 'path') and route.path == full_path)
|
|
249
|
+
]
|
|
244
250
|
return True
|
|
251
|
+
|
|
245
252
|
display_url = self._format_display_url(f"{self.base_url}{full_path}")
|
|
246
253
|
logger.error(f"注销WebSocket失败: 路径 {display_url} 不存在")
|
|
247
254
|
return False
|
|
@@ -339,8 +346,9 @@ class RouterManager:
|
|
|
339
346
|
if "0.0.0.0" in url:
|
|
340
347
|
display_url = url.replace("0.0.0.0", "127.0.0.1")
|
|
341
348
|
return f"{url} (可访问: {display_url})"
|
|
342
|
-
elif "::" in url:
|
|
343
|
-
|
|
349
|
+
elif "[::]" in url:
|
|
350
|
+
# IPv6 回环地址需要替换括号
|
|
351
|
+
display_url = url.replace("[::]", "localhost")
|
|
344
352
|
return f"{url} (可访问: {display_url})"
|
|
345
353
|
return url
|
|
346
354
|
|