ErisPulse 2.3.0__py3-none-any.whl → 2.3.0.dev5__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/_self_config.py +2 -14
- ErisPulse/Core/ux.py +33 -4
- ErisPulse/__init__.py +9 -142
- ErisPulse/utils/__init__.py +0 -2
- ErisPulse/utils/cli.py +82 -72
- ErisPulse/utils/package_manager.py +3 -1
- ErisPulse/utils/reload_handler.py +34 -10
- {erispulse-2.3.0.dist-info → erispulse-2.3.0.dev5.dist-info}/METADATA +1 -1
- {erispulse-2.3.0.dist-info → erispulse-2.3.0.dev5.dist-info}/RECORD +12 -13
- ErisPulse/utils/console.py +0 -53
- {erispulse-2.3.0.dist-info → erispulse-2.3.0.dev5.dist-info}/WHEEL +0 -0
- {erispulse-2.3.0.dist-info → erispulse-2.3.0.dev5.dist-info}/entry_points.txt +0 -0
- {erispulse-2.3.0.dist-info → erispulse-2.3.0.dev5.dist-info}/licenses/LICENSE +0 -0
ErisPulse/Core/_self_config.py
CHANGED
|
@@ -24,10 +24,7 @@ DEFAULT_ERISPULSE_CONFIG = {
|
|
|
24
24
|
"max_snapshot": 20
|
|
25
25
|
},
|
|
26
26
|
"modules": {},
|
|
27
|
-
"adapters": {}
|
|
28
|
-
"framework": {
|
|
29
|
-
"enable_lazy_loading": True
|
|
30
|
-
}
|
|
27
|
+
"adapters": {}
|
|
31
28
|
}
|
|
32
29
|
|
|
33
30
|
def _ensure_erispulse_config_structure(config_dict: Dict[str, Any]) -> Dict[str, Any]:
|
|
@@ -118,13 +115,4 @@ def get_storage_config() -> Dict[str, Any]:
|
|
|
118
115
|
:return: 存储配置字典
|
|
119
116
|
"""
|
|
120
117
|
erispulse_config = get_erispulse_config()
|
|
121
|
-
return erispulse_config["storage"]
|
|
122
|
-
|
|
123
|
-
def get_framework_config() -> Dict[str, Any]:
|
|
124
|
-
"""
|
|
125
|
-
获取框架配置
|
|
126
|
-
|
|
127
|
-
:return: 框架配置字典
|
|
128
|
-
"""
|
|
129
|
-
erispulse_config = get_erispulse_config()
|
|
130
|
-
return erispulse_config["framework"]
|
|
118
|
+
return erispulse_config["storage"]
|
ErisPulse/Core/ux.py
CHANGED
|
@@ -227,7 +227,7 @@ class UXManager:
|
|
|
227
227
|
self.console.print(f"[green]创建项目目录: {project_name}[/green]")
|
|
228
228
|
|
|
229
229
|
# 创建基本目录结构
|
|
230
|
-
dirs = ["config", "logs"]
|
|
230
|
+
dirs = ["modules", "config", "logs"]
|
|
231
231
|
for dir_name in dirs:
|
|
232
232
|
dir_path = project_path / dir_name
|
|
233
233
|
dir_path.mkdir(exist_ok=True)
|
|
@@ -288,11 +288,39 @@ class UXManager:
|
|
|
288
288
|
|
|
289
289
|
self.console.print("[green]创建主程序文件: main.py[/green]")
|
|
290
290
|
|
|
291
|
+
# 创建模块目录和示例模块
|
|
292
|
+
if adapter_list:
|
|
293
|
+
example_file = project_path / "modules" / "example.py"
|
|
294
|
+
if not example_file.exists():
|
|
295
|
+
with open(example_file, "w", encoding="utf-8") as f:
|
|
296
|
+
f.write('"""')
|
|
297
|
+
f.write("\n示例模块\n\n")
|
|
298
|
+
f.write("这是一个示例模块,展示了如何创建基本的消息处理器\n")
|
|
299
|
+
f.write('"""\n\n')
|
|
300
|
+
f.write("from ErisPulse.Core.Event import command, message\n\n")
|
|
301
|
+
f.write("class Main:\n")
|
|
302
|
+
f.write(" def __init__(self, sdk=None):\n")
|
|
303
|
+
f.write(" self.sdk = sdk or globals().get('sdk', __import__('ErisPulse').sdk)\n")
|
|
304
|
+
f.write(" self.logger = self.sdk.logger.get_child(\"Example\")\n")
|
|
305
|
+
f.write(" self.logger.info(\"示例模块已加载\")\n\n")
|
|
306
|
+
f.write(" # 注册命令处理器\n")
|
|
307
|
+
f.write(" @command(\"hello\", help=\"发送问候消息\")\n")
|
|
308
|
+
f.write(" async def hello_command(event):\n")
|
|
309
|
+
f.write(" platform = event[\"platform\"]\n")
|
|
310
|
+
f.write(" user_id = event[\"user_id\"]\n")
|
|
311
|
+
f.write(" \n")
|
|
312
|
+
f.write(" if hasattr(self.sdk.adapter, platform):\n")
|
|
313
|
+
f.write(" adapter_instance = getattr(self.sdk.adapter, platform)\n")
|
|
314
|
+
f.write(" await adapter_instance.Send.To(\"user\", user_id).Text(\"你好!这是一个示例消息。\")\n")
|
|
315
|
+
|
|
316
|
+
self.console.print("[green]创建示例模块: modules/example.py[/green]")
|
|
317
|
+
|
|
291
318
|
self.console.print("\n[bold green]项目 {} 初始化成功![/bold green]".format(project_name))
|
|
292
319
|
self.console.print("\n[cyan]接下来您可以:[/cyan]")
|
|
293
320
|
self.console.print(f"1. 编辑 {project_name}/config.toml 配置适配器")
|
|
294
|
-
self.console.print(f"2.
|
|
295
|
-
self.console.print("\n
|
|
321
|
+
self.console.print(f"2. 在 {project_name}/modules/ 目录下创建自定义模块")
|
|
322
|
+
self.console.print(f"3. 运行 [cyan]cd {project_name} \n ep run[/cyan] 启动项目")
|
|
323
|
+
|
|
296
324
|
return True
|
|
297
325
|
|
|
298
326
|
except Exception as e:
|
|
@@ -382,7 +410,8 @@ class UXManager:
|
|
|
382
410
|
# 显示下一步操作
|
|
383
411
|
self.console.print("\n[cyan]接下来您可以:[/cyan]")
|
|
384
412
|
self.console.print("1. 编辑 {}/config.toml 进一步配置".format(project_name))
|
|
385
|
-
self.console.print("2.
|
|
413
|
+
self.console.print("2. 在 {}/modules/ 目录下创建自定义模块".format(project_name))
|
|
414
|
+
self.console.print("3. 运行 [cyan]cd {} \n ep run[/cyan] 启动项目".format(project_name))
|
|
386
415
|
|
|
387
416
|
return True
|
|
388
417
|
|
ErisPulse/__init__.py
CHANGED
|
@@ -177,88 +177,6 @@ class LazyModule:
|
|
|
177
177
|
logger.error(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 初始化失败: {e}")
|
|
178
178
|
raise e
|
|
179
179
|
|
|
180
|
-
def _initialize_sync(self):
|
|
181
|
-
"""
|
|
182
|
-
同步初始化模块,用于在异步上下文中进行同步调用
|
|
183
|
-
|
|
184
|
-
:raises LazyLoadError: 当模块初始化失败时抛出
|
|
185
|
-
"""
|
|
186
|
-
# 避免重复初始化
|
|
187
|
-
if object.__getattribute__(self, '_initialized'):
|
|
188
|
-
return
|
|
189
|
-
|
|
190
|
-
logger.debug(f"正在同步初始化懒加载模块 {object.__getattribute__(self, '_module_name')}...")
|
|
191
|
-
|
|
192
|
-
try:
|
|
193
|
-
# 获取类的__init__参数信息
|
|
194
|
-
logger.debug(f"正在获取模块 {object.__getattribute__(self, '_module_name')} 的 __init__ 参数信息...")
|
|
195
|
-
init_signature = inspect.signature(object.__getattribute__(self, '_module_class').__init__)
|
|
196
|
-
params = init_signature.parameters
|
|
197
|
-
|
|
198
|
-
# 根据参数决定是否传入sdk
|
|
199
|
-
if 'sdk' in params:
|
|
200
|
-
logger.debug(f"模块 {object.__getattribute__(self, '_module_name')} 需要传入 sdk 参数")
|
|
201
|
-
instance = object.__getattribute__(self, '_module_class')(object.__getattribute__(self, '_sdk_ref'))
|
|
202
|
-
else:
|
|
203
|
-
logger.debug(f"模块 {object.__getattribute__(self, '_module_name')} 不需要传入 sdk 参数")
|
|
204
|
-
instance = object.__getattribute__(self, '_module_class')()
|
|
205
|
-
|
|
206
|
-
logger.debug(f"正在设置模块 {object.__getattribute__(self, '_module_name')} 的 moduleInfo 属性...")
|
|
207
|
-
setattr(instance, "moduleInfo", object.__getattribute__(self, '_module_info'))
|
|
208
|
-
|
|
209
|
-
# 使用object.__setattr__避免触发自定义的__setattr__
|
|
210
|
-
object.__setattr__(self, '_instance', instance)
|
|
211
|
-
object.__setattr__(self, '_initialized', True)
|
|
212
|
-
object.__setattr__(self, '_needs_async_init', False) # 确保清除异步初始化标志
|
|
213
|
-
|
|
214
|
-
# 注意:在同步初始化中,我们不能调用异步的 module.load 和 lifecycle.submit_event
|
|
215
|
-
# 这些将在异步上下文中延迟处理
|
|
216
|
-
|
|
217
|
-
logger.debug(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 同步初始化完成")
|
|
218
|
-
|
|
219
|
-
except Exception as e:
|
|
220
|
-
logger.error(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 同步初始化失败: {e}")
|
|
221
|
-
raise e
|
|
222
|
-
|
|
223
|
-
async def _complete_async_init(self):
|
|
224
|
-
"""
|
|
225
|
-
完成异步初始化部分,用于同步初始化后的异步处理
|
|
226
|
-
|
|
227
|
-
这个方法用于处理 module.load 和事件提交等异步操作
|
|
228
|
-
"""
|
|
229
|
-
if not object.__getattribute__(self, '_initialized'):
|
|
230
|
-
return
|
|
231
|
-
|
|
232
|
-
try:
|
|
233
|
-
# 如果是 BaseModule 子类,在初始化后调用 on_load 方法
|
|
234
|
-
if object.__getattribute__(self, '_is_base_module'):
|
|
235
|
-
logger.debug(f"正在异步调用模块 {object.__getattribute__(self, '_module_name')} 的 on_load 方法...")
|
|
236
|
-
|
|
237
|
-
try:
|
|
238
|
-
await module.load(object.__getattribute__(self, '_module_name'))
|
|
239
|
-
except Exception as e:
|
|
240
|
-
logger.error(f"异步调用模块 {object.__getattribute__(self, '_module_name')} 的 on_load 方法时出错: {e}")
|
|
241
|
-
|
|
242
|
-
await lifecycle.submit_event(
|
|
243
|
-
"module.init",
|
|
244
|
-
msg=f"模块 {object.__getattribute__(self, '_module_name')} 初始化完毕",
|
|
245
|
-
data={
|
|
246
|
-
"module_name": object.__getattribute__(self, '_module_name'),
|
|
247
|
-
"success": True,
|
|
248
|
-
}
|
|
249
|
-
)
|
|
250
|
-
logger.debug(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 异步初始化部分完成")
|
|
251
|
-
except Exception as e:
|
|
252
|
-
await lifecycle.submit_event(
|
|
253
|
-
"module.init",
|
|
254
|
-
msg=f"模块初始化失败: {e}",
|
|
255
|
-
data={
|
|
256
|
-
"module_name": object.__getattribute__(self, '_module_name'),
|
|
257
|
-
"success": False,
|
|
258
|
-
}
|
|
259
|
-
)
|
|
260
|
-
logger.error(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 异步初始化部分失败: {e}")
|
|
261
|
-
|
|
262
180
|
def _ensure_initialized(self) -> None:
|
|
263
181
|
"""
|
|
264
182
|
确保模块已初始化
|
|
@@ -266,32 +184,15 @@ class LazyModule:
|
|
|
266
184
|
:raises LazyLoadError: 当模块未初始化时抛出
|
|
267
185
|
"""
|
|
268
186
|
if not object.__getattribute__(self, '_initialized'):
|
|
269
|
-
#
|
|
187
|
+
# 在异步环境中同步调用异步初始化方法
|
|
270
188
|
try:
|
|
271
189
|
loop = asyncio.get_running_loop()
|
|
272
|
-
#
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
if asyncio.iscoroutinefunction(init_method):
|
|
277
|
-
# 对于需要异步初始化的模块,我们只能设置一个标志,提示需要异步初始化
|
|
278
|
-
object.__setattr__(self, '_needs_async_init', True)
|
|
279
|
-
logger.warning(f"模块 {object.__getattribute__(self, '_module_name')} 需要异步初始化,请在异步上下文中调用")
|
|
280
|
-
return
|
|
281
|
-
else:
|
|
282
|
-
# 对于同步初始化的模块,使用同步初始化方式
|
|
283
|
-
self._initialize_sync()
|
|
284
|
-
|
|
285
|
-
# 异步处理需要在初始化后完成的事件
|
|
286
|
-
if object.__getattribute__(self, '_is_base_module'):
|
|
287
|
-
# 调度异步任务来处理 module.load 和事件提交
|
|
288
|
-
try:
|
|
289
|
-
loop = asyncio.get_running_loop()
|
|
290
|
-
loop.create_task(self._complete_async_init())
|
|
291
|
-
except Exception as e:
|
|
292
|
-
logger.warning(f"无法调度异步初始化任务: {e}")
|
|
190
|
+
# 在已有事件循环中创建任务
|
|
191
|
+
task = loop.create_task(self._initialize())
|
|
192
|
+
# 阻塞等待完成
|
|
193
|
+
loop.run_until_complete(task)
|
|
293
194
|
except RuntimeError:
|
|
294
|
-
#
|
|
195
|
+
# 没有运行中的事件循环
|
|
295
196
|
asyncio.run(self._initialize())
|
|
296
197
|
|
|
297
198
|
def __getattr__(self, name: str) -> Any:
|
|
@@ -303,13 +204,6 @@ class LazyModule:
|
|
|
303
204
|
"""
|
|
304
205
|
logger.debug(f"正在访问懒加载模块 {object.__getattribute__(self, '_module_name')} 的属性 {name}...")
|
|
305
206
|
|
|
306
|
-
# 检查是否需要异步初始化
|
|
307
|
-
if hasattr(self, '_needs_async_init') and object.__getattribute__(self, '_needs_async_init'):
|
|
308
|
-
raise RuntimeError(
|
|
309
|
-
f"模块 {object.__getattribute__(self, '_module_name')} 需要异步初始化,"
|
|
310
|
-
f"请使用 'await sdk.load_module(\"{object.__getattribute__(self, '_module_name')}\")' 来初始化模块"
|
|
311
|
-
)
|
|
312
|
-
|
|
313
207
|
self._ensure_initialized()
|
|
314
208
|
return getattr(object.__getattribute__(self, '_instance'), name)
|
|
315
209
|
|
|
@@ -678,19 +572,6 @@ class ModuleLoader:
|
|
|
678
572
|
|
|
679
573
|
logger.debug(f"检查模块 {module_class.__name__} 是否应该懒加载")
|
|
680
574
|
|
|
681
|
-
# 首先检查全局懒加载配置
|
|
682
|
-
try:
|
|
683
|
-
from .Core._self_config import get_framework_config
|
|
684
|
-
framework_config = get_framework_config()
|
|
685
|
-
global_lazy_loading = framework_config.get("enable_lazy_loading", True)
|
|
686
|
-
|
|
687
|
-
# 如果全局禁用懒加载,则直接返回False
|
|
688
|
-
if not global_lazy_loading:
|
|
689
|
-
logger.debug(f"全局懒加载已禁用,模块 {module_class.__name__} 将立即加载")
|
|
690
|
-
return False
|
|
691
|
-
except Exception as e:
|
|
692
|
-
logger.warning(f"获取框架配置失败: {e},将使用模块默认配置")
|
|
693
|
-
|
|
694
575
|
# 检查模块是否定义了 should_eager_load() 方法
|
|
695
576
|
if hasattr(module_class, "should_eager_load"):
|
|
696
577
|
try:
|
|
@@ -1204,28 +1085,14 @@ async def load_module(module_name: str) -> bool:
|
|
|
1204
1085
|
{!--< tips >!--}
|
|
1205
1086
|
1. 可用于手动触发懒加载模块的初始化
|
|
1206
1087
|
2. 如果模块不存在或已加载会返回False
|
|
1207
|
-
3. 对于需要异步初始化的模块,这是唯一的加载方式
|
|
1208
1088
|
{!--< /tips >!--}
|
|
1209
1089
|
"""
|
|
1210
1090
|
try:
|
|
1211
1091
|
module_instance = getattr(sdk, module_name, None)
|
|
1212
1092
|
if isinstance(module_instance, LazyModule):
|
|
1213
|
-
#
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
await module_instance._initialize()
|
|
1217
|
-
object.__setattr__(module_instance, '_needs_async_init', False) # 清除标志
|
|
1218
|
-
return True
|
|
1219
|
-
# 检查模块是否已经同步初始化但未完成异步部分
|
|
1220
|
-
elif (object.__getattribute__(module_instance, '_initialized') and
|
|
1221
|
-
object.__getattribute__(module_instance, '_is_base_module')):
|
|
1222
|
-
# 如果是BaseModule子类且已同步初始化,只需完成异步部分
|
|
1223
|
-
await module_instance._complete_async_init()
|
|
1224
|
-
return True
|
|
1225
|
-
else:
|
|
1226
|
-
# 触发懒加载模块的完整初始化
|
|
1227
|
-
await module_instance._initialize()
|
|
1228
|
-
return True
|
|
1093
|
+
# 触发懒加载模块的初始化
|
|
1094
|
+
await module_instance._initialize()
|
|
1095
|
+
return True
|
|
1229
1096
|
elif module_instance is not None:
|
|
1230
1097
|
logger.warning(f"模块 {module_name} 已经加载")
|
|
1231
1098
|
return False
|
ErisPulse/utils/__init__.py
CHANGED
ErisPulse/utils/cli.py
CHANGED
|
@@ -8,12 +8,58 @@ from typing import List, Dict, Optional, Any
|
|
|
8
8
|
from watchdog.observers import Observer
|
|
9
9
|
|
|
10
10
|
# Rich console setup
|
|
11
|
+
from rich.console import Console
|
|
11
12
|
from rich.panel import Panel
|
|
12
13
|
from rich.table import Table
|
|
13
14
|
from rich.prompt import Confirm, Prompt
|
|
14
15
|
from rich.box import SIMPLE
|
|
16
|
+
from rich.theme import Theme
|
|
17
|
+
from rich.highlighter import RegexHighlighter
|
|
15
18
|
|
|
16
|
-
|
|
19
|
+
# 确保在Windows上启用颜色
|
|
20
|
+
if sys.platform == "win32":
|
|
21
|
+
from colorama import init
|
|
22
|
+
init()
|
|
23
|
+
|
|
24
|
+
class CommandHighlighter(RegexHighlighter):
|
|
25
|
+
"""
|
|
26
|
+
高亮CLI命令和参数
|
|
27
|
+
|
|
28
|
+
{!--< tips >!--}
|
|
29
|
+
使用正则表达式匹配命令行参数和选项
|
|
30
|
+
{!--< /tips >!--}
|
|
31
|
+
"""
|
|
32
|
+
highlights = [
|
|
33
|
+
r"(?P<switch>\-\-?\w+)",
|
|
34
|
+
r"(?P<option>\[\w+\])",
|
|
35
|
+
r"(?P<command>\b\w+\b)",
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
# 主题配置
|
|
39
|
+
theme = Theme({
|
|
40
|
+
"info": "dim cyan",
|
|
41
|
+
"success": "bold green",
|
|
42
|
+
"warning": "bold yellow",
|
|
43
|
+
"error": "bold red",
|
|
44
|
+
"title": "bold magenta",
|
|
45
|
+
"default": "default",
|
|
46
|
+
"progress": "green",
|
|
47
|
+
"progress.remaining": "white",
|
|
48
|
+
"cmd": "bold blue",
|
|
49
|
+
"param": "italic cyan",
|
|
50
|
+
"switch": "bold yellow",
|
|
51
|
+
"module": "bold green",
|
|
52
|
+
"adapter": "bold yellow",
|
|
53
|
+
"cli": "bold magenta",
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
# 全局控制台实例
|
|
57
|
+
console = Console(
|
|
58
|
+
theme=theme,
|
|
59
|
+
color_system="auto",
|
|
60
|
+
force_terminal=True,
|
|
61
|
+
highlighter=CommandHighlighter()
|
|
62
|
+
)
|
|
17
63
|
|
|
18
64
|
class CLI:
|
|
19
65
|
"""
|
|
@@ -942,8 +988,7 @@ class CLI:
|
|
|
942
988
|
time.sleep(0.5)
|
|
943
989
|
except KeyboardInterrupt:
|
|
944
990
|
console.print("\n[info]正在安全关闭...[/]")
|
|
945
|
-
_cleanup_adapters()
|
|
946
|
-
_cleanup_modules()
|
|
991
|
+
self._cleanup_adapters()
|
|
947
992
|
self._cleanup()
|
|
948
993
|
console.print("[success]已安全退出[/]")
|
|
949
994
|
|
|
@@ -1017,76 +1062,41 @@ class CLI:
|
|
|
1017
1062
|
console.print(traceback.format_exc())
|
|
1018
1063
|
self._cleanup()
|
|
1019
1064
|
sys.exit(1)
|
|
1020
|
-
|
|
1021
|
-
def _cleanup_adapters():
|
|
1022
|
-
"""
|
|
1023
|
-
清理适配器资源
|
|
1024
|
-
"""
|
|
1025
1065
|
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
console.print("[info]正在停止所有适配器...[/]")
|
|
1066
|
+
def _cleanup_adapters(self):
|
|
1067
|
+
"""
|
|
1068
|
+
清理适配器资源
|
|
1069
|
+
"""
|
|
1070
|
+
from ErisPulse import adapter, logger
|
|
1071
|
+
try:
|
|
1072
|
+
import asyncio
|
|
1073
|
+
import threading
|
|
1035
1074
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
if loop.is_running():
|
|
1040
|
-
# 在新线程中运行
|
|
1041
|
-
stop_thread = threading.Thread(
|
|
1042
|
-
target=lambda: asyncio.run(adapter.shutdown())
|
|
1043
|
-
)
|
|
1044
|
-
stop_thread.start()
|
|
1045
|
-
stop_thread.join(timeout=5)
|
|
1046
|
-
else:
|
|
1047
|
-
asyncio.run(adapter.shutdown())
|
|
1048
|
-
except RuntimeError:
|
|
1049
|
-
asyncio.run(adapter.shutdown())
|
|
1050
|
-
else:
|
|
1051
|
-
new_loop = asyncio.new_event_loop()
|
|
1052
|
-
asyncio.set_event_loop(new_loop)
|
|
1053
|
-
new_loop.run_until_complete(adapter.shutdown())
|
|
1075
|
+
# 检查是否有正在运行的适配器
|
|
1076
|
+
if (hasattr(adapter, '_started_instances') and
|
|
1077
|
+
adapter._started_instances):
|
|
1054
1078
|
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
if threading.current_thread() is threading.main_thread():
|
|
1073
|
-
try:
|
|
1074
|
-
loop = asyncio.get_running_loop()
|
|
1075
|
-
if loop.is_running():
|
|
1076
|
-
stop_thread = threading.Thread(
|
|
1077
|
-
target=lambda: asyncio.run(module.unload())
|
|
1078
|
-
)
|
|
1079
|
-
stop_thread.start()
|
|
1080
|
-
stop_thread.join(timeout=5)
|
|
1079
|
+
logger.info("正在停止所有适配器...")
|
|
1080
|
+
|
|
1081
|
+
if threading.current_thread() is threading.main_thread():
|
|
1082
|
+
try:
|
|
1083
|
+
loop = asyncio.get_running_loop()
|
|
1084
|
+
if loop.is_running():
|
|
1085
|
+
# 在新线程中运行
|
|
1086
|
+
stop_thread = threading.Thread(
|
|
1087
|
+
target=lambda: asyncio.run(adapter.shutdown())
|
|
1088
|
+
)
|
|
1089
|
+
stop_thread.start()
|
|
1090
|
+
stop_thread.join(timeout=5)
|
|
1091
|
+
else:
|
|
1092
|
+
asyncio.run(adapter.shutdown())
|
|
1093
|
+
except RuntimeError:
|
|
1094
|
+
asyncio.run(adapter.shutdown())
|
|
1081
1095
|
else:
|
|
1082
|
-
asyncio.
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
console.print("[success]模块已全部卸载[/]")
|
|
1091
|
-
except Exception as e:
|
|
1092
|
-
console.print(f"[error]清理模块资源时出错: {e}[/]")
|
|
1096
|
+
new_loop = asyncio.new_event_loop()
|
|
1097
|
+
asyncio.set_event_loop(new_loop)
|
|
1098
|
+
new_loop.run_until_complete(adapter.shutdown())
|
|
1099
|
+
|
|
1100
|
+
logger.info("适配器已全部停止")
|
|
1101
|
+
except Exception as e:
|
|
1102
|
+
logger.error(f"清理适配器资源时出错: {e}")
|
|
@@ -13,11 +13,13 @@ import sys
|
|
|
13
13
|
import time
|
|
14
14
|
from typing import List, Dict, Tuple, Optional, Any
|
|
15
15
|
|
|
16
|
+
from rich.console import Console
|
|
16
17
|
from rich.panel import Panel
|
|
17
18
|
from rich.progress import Progress, BarColumn, TextColumn
|
|
18
19
|
from rich.prompt import Confirm
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
# 全局控制台实例,从CLI模块导入
|
|
22
|
+
console = Console()
|
|
21
23
|
|
|
22
24
|
class PackageManager:
|
|
23
25
|
"""
|
|
@@ -4,13 +4,18 @@ ErisPulse SDK 热重载处理器
|
|
|
4
4
|
实现热重载功能,监控文件变化并重启进程
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import asyncio
|
|
7
8
|
import os
|
|
8
9
|
import subprocess
|
|
9
10
|
import sys
|
|
11
|
+
import threading
|
|
10
12
|
import time
|
|
11
13
|
from watchdog.events import FileSystemEventHandler
|
|
12
14
|
|
|
13
|
-
from .console import
|
|
15
|
+
from rich.console import Console
|
|
16
|
+
|
|
17
|
+
# 全局控制台实例,从CLI模块导入
|
|
18
|
+
console = Console()
|
|
14
19
|
|
|
15
20
|
|
|
16
21
|
class ReloadHandler(FileSystemEventHandler):
|
|
@@ -96,16 +101,35 @@ class ReloadHandler(FileSystemEventHandler):
|
|
|
96
101
|
:param event: 文件系统事件
|
|
97
102
|
:param reason: 重载原因
|
|
98
103
|
"""
|
|
99
|
-
from ErisPulse.Core import logger
|
|
100
|
-
|
|
104
|
+
from ErisPulse.Core import adapter, logger
|
|
105
|
+
# 在重载前确保所有适配器正确停止
|
|
101
106
|
try:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
107
|
+
# 检查适配器是否正在运行
|
|
108
|
+
if hasattr(adapter, '_started_instances') and adapter._started_instances:
|
|
109
|
+
logger.info("正在停止适配器...")
|
|
110
|
+
# 创建新的事件循环来运行异步停止操作
|
|
111
|
+
|
|
112
|
+
# 如果在主线程中
|
|
113
|
+
if threading.current_thread() is threading.main_thread():
|
|
114
|
+
try:
|
|
115
|
+
# 在新线程中运行适配器停止
|
|
116
|
+
stop_thread = threading.Thread(target=lambda: asyncio.run(adapter.shutdown()))
|
|
117
|
+
stop_thread.start()
|
|
118
|
+
stop_thread.join(timeout=10) # 最多等待10秒
|
|
119
|
+
except RuntimeError:
|
|
120
|
+
# 没有运行中的事件循环
|
|
121
|
+
asyncio.run(adapter.shutdown())
|
|
122
|
+
else:
|
|
123
|
+
# 在非主线程中,创建新的事件循环
|
|
124
|
+
new_loop = asyncio.new_event_loop()
|
|
125
|
+
asyncio.set_event_loop(new_loop)
|
|
126
|
+
new_loop.run_until_complete(adapter.shutdown())
|
|
127
|
+
|
|
128
|
+
logger.info("适配器已停止")
|
|
106
129
|
except Exception as e:
|
|
107
|
-
logger.warning(f"
|
|
130
|
+
logger.warning(f"停止适配器时出错: {e}")
|
|
108
131
|
|
|
109
|
-
|
|
132
|
+
# 原有的重载逻辑
|
|
133
|
+
logger.info(f"检测到文件变更 ({reason}),正在重启...")
|
|
110
134
|
self._terminate_process()
|
|
111
|
-
self.start_process()
|
|
135
|
+
self.start_process()
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
ErisPulse/__init__.py,sha256=
|
|
1
|
+
ErisPulse/__init__.py,sha256=6foVg_ZnQhO9Cg8vwmyHhJSxmnSwLCrzITFE5CP8qLc,42583
|
|
2
2
|
ErisPulse/__main__.py,sha256=x1VV2mbn1B9RVRhG5uumTCrvZCLzJjGWN0wFll-G0H4,471
|
|
3
3
|
ErisPulse/Core/__init__.py,sha256=9RNwUq9Hbe3r6nA8QBvq2pvMJN4QiBfo71N0u_ywiwI,1398
|
|
4
|
-
ErisPulse/Core/_self_config.py,sha256=
|
|
4
|
+
ErisPulse/Core/_self_config.py,sha256=7PdOfJj1_s4fViayUSzqiUWDTb7Tie_1KjdRcIveK8w,3281
|
|
5
5
|
ErisPulse/Core/adapter.py,sha256=9wpaE9B6LixlGTJ0p341wYe4AE3SVuczToMOWd7UkL4,19707
|
|
6
6
|
ErisPulse/Core/config.py,sha256=cV0R2eUWNECIogYLFbhNu1pYl8HStPG-DNbCe3lkY4E,5873
|
|
7
7
|
ErisPulse/Core/exceptions.py,sha256=tTOOs57SD8aSp4HXomuXtVYgHJCJtfP3AS4JIIq1LPk,3920
|
|
@@ -10,7 +10,7 @@ ErisPulse/Core/logger.py,sha256=nktXT-6cxF50NYsUErMsf8J79brzXg2faaJ4Agt2Gro,1259
|
|
|
10
10
|
ErisPulse/Core/module.py,sha256=13rI03GwEzVd66hIhZnZNybiA9wj7ITzQILi1-nCjhQ,12944
|
|
11
11
|
ErisPulse/Core/router.py,sha256=rtvUjbRHVeTTgWBBG-yxK91oEjs5Tw3ReryqCI-rMYc,12411
|
|
12
12
|
ErisPulse/Core/storage.py,sha256=WbREN-GTpzPls8Vx3t8F2U_lzmCKEsI4OcecWWmvaSk,25238
|
|
13
|
-
ErisPulse/Core/ux.py,sha256=
|
|
13
|
+
ErisPulse/Core/ux.py,sha256=DQHzSXJGGI2CHoVQg1Od5qYDDdxXObEJOaqAoGZEegQ,31631
|
|
14
14
|
ErisPulse/Core/Bases/__init__.py,sha256=hHKsI2zQfBdahnEuHlMgzOX2_ygRDOVN8-VqTIrcxP4,230
|
|
15
15
|
ErisPulse/Core/Bases/adapter.py,sha256=aCupQdc8M5Ds7m5dZMCmtoyC-0Zqh5K_6F3uKle8WXE,6490
|
|
16
16
|
ErisPulse/Core/Bases/module.py,sha256=TtzZQ4x4u09S6yDibsIHa9srlGLFPXCHdn2WxZ3nmdo,1154
|
|
@@ -22,13 +22,12 @@ ErisPulse/Core/Event/message.py,sha256=wxg_GJsI1ZvPrV9611xELLxnlk2bcxMJH7EBEkoWw
|
|
|
22
22
|
ErisPulse/Core/Event/meta.py,sha256=0cs0Cg5r58kll3P4lNtnVWAKLQiL6MoXPkbkk6_IEko,3660
|
|
23
23
|
ErisPulse/Core/Event/notice.py,sha256=tU28tc3Ig-FMB2EJUDO2Z9ewfJjzEPh2O2J4lU7GYDk,4557
|
|
24
24
|
ErisPulse/Core/Event/request.py,sha256=rYjFjRJccNRZ6bkY89ig8Q2YntnoytUfg-_PGntJxXg,2956
|
|
25
|
-
ErisPulse/utils/__init__.py,sha256=
|
|
26
|
-
ErisPulse/utils/cli.py,sha256
|
|
27
|
-
ErisPulse/utils/
|
|
28
|
-
ErisPulse/utils/
|
|
29
|
-
|
|
30
|
-
erispulse-2.3.0.dist-info/
|
|
31
|
-
erispulse-2.3.0.dist-info/
|
|
32
|
-
erispulse-2.3.0.dist-info/
|
|
33
|
-
erispulse-2.3.0.dist-info/
|
|
34
|
-
erispulse-2.3.0.dist-info/RECORD,,
|
|
25
|
+
ErisPulse/utils/__init__.py,sha256=GTLeWbAkQSWPJ3NjFDV2DYZaTZ6bx56VumrtqkI8upA,255
|
|
26
|
+
ErisPulse/utils/cli.py,sha256=fwxyGAcIh57rQkZ-YF6TQKou0v2Wrtjg1XUFp-IOcHI,40924
|
|
27
|
+
ErisPulse/utils/package_manager.py,sha256=8auzSigymzff6JBMKVy-6XntPPFGeO7qTUSKoY-vYFE,32767
|
|
28
|
+
ErisPulse/utils/reload_handler.py,sha256=ulVJEK7NsdsTXUkqp40iLf9D5rC8WjFut48UIRj9JyQ,4552
|
|
29
|
+
erispulse-2.3.0.dev5.dist-info/METADATA,sha256=mAAjbybK9-vZPmSMt80JKRBS7YNfDhVhS_J29KEU1pw,7478
|
|
30
|
+
erispulse-2.3.0.dev5.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
31
|
+
erispulse-2.3.0.dev5.dist-info/entry_points.txt,sha256=Jss71M6nEha0TA-DyVZugPYdcL14s9QpiOeIlgWxzOc,182
|
|
32
|
+
erispulse-2.3.0.dev5.dist-info/licenses/LICENSE,sha256=tJjKWuY4OPWNgriiixWLvmFb8Pf8p_-4NMq_zZN3gWg,1858
|
|
33
|
+
erispulse-2.3.0.dev5.dist-info/RECORD,,
|
ErisPulse/utils/console.py
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from rich.console import Console
|
|
3
|
-
from rich.theme import Theme
|
|
4
|
-
from rich.highlighter import RegexHighlighter
|
|
5
|
-
|
|
6
|
-
# 确保在Windows上启用颜色
|
|
7
|
-
if sys.platform == "win32":
|
|
8
|
-
from colorama import init
|
|
9
|
-
init()
|
|
10
|
-
|
|
11
|
-
class CommandHighlighter(RegexHighlighter):
|
|
12
|
-
"""
|
|
13
|
-
高亮CLI命令和参数
|
|
14
|
-
|
|
15
|
-
{!--< tips >!--}
|
|
16
|
-
使用正则表达式匹配命令行参数和选项
|
|
17
|
-
{!--< /tips >!--}
|
|
18
|
-
"""
|
|
19
|
-
highlights = [
|
|
20
|
-
r"(?P<switch>\-\-?\w+)",
|
|
21
|
-
r"(?P<option>\[\w+\])",
|
|
22
|
-
r"(?P<command>\b\w+\b)",
|
|
23
|
-
]
|
|
24
|
-
|
|
25
|
-
# 主题配置
|
|
26
|
-
theme = Theme({
|
|
27
|
-
"info": "dim cyan",
|
|
28
|
-
"success": "bold green",
|
|
29
|
-
"warning": "bold yellow",
|
|
30
|
-
"error": "bold red",
|
|
31
|
-
"title": "bold magenta",
|
|
32
|
-
"default": "default",
|
|
33
|
-
"progress": "green",
|
|
34
|
-
"progress.remaining": "white",
|
|
35
|
-
"cmd": "bold blue",
|
|
36
|
-
"param": "italic cyan",
|
|
37
|
-
"switch": "bold yellow",
|
|
38
|
-
"module": "bold green",
|
|
39
|
-
"adapter": "bold yellow",
|
|
40
|
-
"cli": "bold magenta",
|
|
41
|
-
})
|
|
42
|
-
|
|
43
|
-
# 全局控制台实例
|
|
44
|
-
console = Console(
|
|
45
|
-
theme=theme,
|
|
46
|
-
color_system="auto",
|
|
47
|
-
force_terminal=True,
|
|
48
|
-
highlighter=CommandHighlighter()
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
__all__ = [
|
|
52
|
-
"console",
|
|
53
|
-
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|