ErisPulse 2.3.4.dev2__py3-none-any.whl → 2.3.4.dev114514__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/Bases/module.py +1 -53
- ErisPulse/Core/Bases/module.pyi +0 -43
- ErisPulse/Core/Event/command.py +1 -6
- ErisPulse/Core/_self_config.py +1 -1
- ErisPulse/Core/adapter.py +10 -70
- ErisPulse/Core/adapter.pyi +1 -18
- ErisPulse/Core/exceptions.py +2 -4
- ErisPulse/Core/lifecycle.py +0 -9
- ErisPulse/Core/logger.py +15 -21
- ErisPulse/Core/logger.pyi +1 -2
- ErisPulse/Core/module.py +9 -57
- ErisPulse/Core/module.pyi +1 -12
- ErisPulse/Core/router.py +5 -13
- ErisPulse/Core/storage.py +256 -94
- ErisPulse/Core/storage.pyi +66 -13
- ErisPulse/__init__.py +1237 -35
- ErisPulse/__init__.pyi +290 -3
- ErisPulse/sdk_protocol.py +143 -0
- ErisPulse/sdk_protocol.pyi +97 -0
- {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/METADATA +1 -1
- {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/RECORD +24 -38
- ErisPulse/Core/Bases/manager.py +0 -136
- ErisPulse/Core/Bases/manager.pyi +0 -108
- ErisPulse/loaders/__init__.py +0 -22
- ErisPulse/loaders/__init__.pyi +0 -21
- ErisPulse/loaders/adapter_loader.py +0 -187
- ErisPulse/loaders/adapter_loader.pyi +0 -82
- ErisPulse/loaders/base_loader.py +0 -162
- ErisPulse/loaders/base_loader.pyi +0 -23
- ErisPulse/loaders/initializer.py +0 -150
- ErisPulse/loaders/initializer.pyi +0 -60
- ErisPulse/loaders/module_loader.py +0 -618
- ErisPulse/loaders/module_loader.pyi +0 -179
- ErisPulse/loaders/strategy.py +0 -129
- ErisPulse/loaders/strategy.pyi +0 -90
- ErisPulse/sdk.py +0 -435
- ErisPulse/sdk.pyi +0 -158
- {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/WHEEL +0 -0
- {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/entry_points.txt +0 -0
- {erispulse-2.3.4.dev2.dist-info → erispulse-2.3.4.dev114514.dist-info}/licenses/LICENSE +0 -0
ErisPulse/__init__.py
CHANGED
|
@@ -10,46 +10,1248 @@ ErisPulse SDK 主模块
|
|
|
10
10
|
{!--< /tips >!--}
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
|
+
import os
|
|
14
|
+
import sys
|
|
15
|
+
import types
|
|
16
|
+
import importlib
|
|
17
|
+
import asyncio
|
|
18
|
+
import inspect
|
|
13
19
|
import importlib.metadata
|
|
20
|
+
from typing import Dict, List, Tuple, Type, Any, TYPE_CHECKING
|
|
21
|
+
from pathlib import Path
|
|
14
22
|
|
|
15
|
-
#
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
#
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
# 导入懒加载模块类
|
|
37
|
-
from .loaders.module_loader import LazyModule
|
|
38
|
-
|
|
39
|
-
# 版本信息
|
|
40
|
-
__version__ = "UnknownVersion"
|
|
41
|
-
__author__ = "ErisPulse"
|
|
23
|
+
# 类型检查时导入 Protocol,避免运行时循环导入
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from .sdk_protocol import SDKProtocol
|
|
26
|
+
|
|
27
|
+
# BaseModules: SDK核心模块
|
|
28
|
+
# 事件处理模块
|
|
29
|
+
from .Core import Event
|
|
30
|
+
# 基础设施
|
|
31
|
+
from .Core import lifecycle, logger, exceptions
|
|
32
|
+
# 存储和配置相关
|
|
33
|
+
from .Core import storage, env, config
|
|
34
|
+
# 适配器相关
|
|
35
|
+
from .Core import adapter, AdapterFather, BaseAdapter, SendDSL
|
|
36
|
+
# 模块相关
|
|
37
|
+
from .Core import module
|
|
38
|
+
# 路由相关
|
|
39
|
+
from .Core import router, adapter_server
|
|
40
|
+
|
|
41
|
+
# SDK统一对外接口
|
|
42
|
+
sdk: 'SDKProtocol' = types.ModuleType('sdk') # type: ignore[assignment]
|
|
42
43
|
|
|
43
44
|
try:
|
|
44
45
|
__version__ = importlib.metadata.version('ErisPulse')
|
|
45
46
|
except importlib.metadata.PackageNotFoundError:
|
|
46
|
-
|
|
47
|
+
logger.critical("未找到ErisPulse版本信息,请检查是否正确安装ErisPulse")
|
|
48
|
+
__author__ = "ErisPulse"
|
|
49
|
+
|
|
50
|
+
logger.debug("ErisPulse 正在挂载SDK核心模块...")
|
|
51
|
+
|
|
52
|
+
BaseModules = {
|
|
53
|
+
"Event" : Event,
|
|
54
|
+
|
|
55
|
+
"lifecycle" : lifecycle,
|
|
56
|
+
"logger" : logger,
|
|
57
|
+
"exceptions" : exceptions,
|
|
58
|
+
|
|
59
|
+
"storage" : storage,
|
|
60
|
+
"env" : env,
|
|
61
|
+
"config" : config,
|
|
62
|
+
|
|
63
|
+
"adapter" : adapter,
|
|
64
|
+
"AdapterFather" : AdapterFather,
|
|
65
|
+
"BaseAdapter" : BaseAdapter,
|
|
66
|
+
"SendDSL" : SendDSL,
|
|
67
|
+
|
|
68
|
+
"module" : module,
|
|
69
|
+
|
|
70
|
+
"router": router,
|
|
71
|
+
"adapter_server": adapter_server,
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
for module_name, moduleObj in BaseModules.items():
|
|
75
|
+
setattr(sdk, module_name, moduleObj)
|
|
76
|
+
|
|
77
|
+
logger.debug("ErisPulse 正在挂载loop循环器...")
|
|
78
|
+
|
|
79
|
+
# 设置默认loop循环捕捉器
|
|
80
|
+
asyncio_loop = asyncio.get_event_loop()
|
|
81
|
+
exceptions.setup_async_loop(asyncio_loop)
|
|
82
|
+
|
|
83
|
+
logger.debug("SDK核心模块挂载完毕")
|
|
84
|
+
|
|
85
|
+
class LazyModule:
|
|
86
|
+
"""
|
|
87
|
+
懒加载模块包装器
|
|
88
|
+
|
|
89
|
+
当模块第一次被访问时才进行实例化
|
|
90
|
+
|
|
91
|
+
{!--< tips >!--}
|
|
92
|
+
1. 模块的实际实例化会在第一次属性访问时进行
|
|
93
|
+
2. 依赖模块会在被使用时自动初始化
|
|
94
|
+
3. 对于继承自 BaseModule 的模块,会自动调用生命周期方法
|
|
95
|
+
{!--< /tips >!--}
|
|
96
|
+
"""
|
|
97
|
+
|
|
98
|
+
def __init__(self, module_name: str, module_class: Type, sdk_ref: Any, module_info: Dict[str, Any]) -> None:
|
|
99
|
+
"""
|
|
100
|
+
初始化懒加载包装器
|
|
101
|
+
|
|
102
|
+
:param module_name: str 模块名称
|
|
103
|
+
:param module_class: Type 模块类
|
|
104
|
+
:param sdk_ref: Any SDK引用
|
|
105
|
+
:param module_info: Dict[str, Any] 模块信息字典
|
|
106
|
+
"""
|
|
107
|
+
# 使用object.__setattr__避免触发自定义的__setattr__
|
|
108
|
+
object.__setattr__(self, '_module_name', module_name)
|
|
109
|
+
object.__setattr__(self, '_module_class', module_class)
|
|
110
|
+
object.__setattr__(self, '_sdk_ref', sdk_ref)
|
|
111
|
+
object.__setattr__(self, '_module_info', module_info)
|
|
112
|
+
object.__setattr__(self, '_instance', None)
|
|
113
|
+
object.__setattr__(self, '_initialized', False)
|
|
114
|
+
object.__setattr__(self, '_is_base_module', module_info.get("meta", {}).get("is_base_module", False))
|
|
115
|
+
|
|
116
|
+
async def _initialize(self):
|
|
117
|
+
"""
|
|
118
|
+
实际初始化模块
|
|
119
|
+
|
|
120
|
+
:raises LazyLoadError: 当模块初始化失败时抛出
|
|
121
|
+
"""
|
|
122
|
+
# 避免重复初始化
|
|
123
|
+
if object.__getattribute__(self, '_initialized'):
|
|
124
|
+
return
|
|
125
|
+
|
|
126
|
+
logger.debug(f"正在初始化懒加载模块 {object.__getattribute__(self, '_module_name')}...")
|
|
127
|
+
|
|
128
|
+
try:
|
|
129
|
+
# 获取类的__init__参数信息
|
|
130
|
+
logger.debug(f"正在获取模块 {object.__getattribute__(self, '_module_name')} 的 __init__ 参数信息...")
|
|
131
|
+
init_signature = inspect.signature(object.__getattribute__(self, '_module_class').__init__)
|
|
132
|
+
params = init_signature.parameters
|
|
133
|
+
|
|
134
|
+
# 根据参数决定是否传入sdk
|
|
135
|
+
if 'sdk' in params:
|
|
136
|
+
logger.debug(f"模块 {object.__getattribute__(self, '_module_name')} 需要传入 sdk 参数")
|
|
137
|
+
instance = object.__getattribute__(self, '_module_class')(object.__getattribute__(self, '_sdk_ref'))
|
|
138
|
+
else:
|
|
139
|
+
logger.debug(f"模块 {object.__getattribute__(self, '_module_name')} 不需要传入 sdk 参数")
|
|
140
|
+
instance = object.__getattribute__(self, '_module_class')()
|
|
141
|
+
|
|
142
|
+
logger.debug(f"正在设置模块 {object.__getattribute__(self, '_module_name')} 的 moduleInfo 属性...")
|
|
143
|
+
setattr(instance, "moduleInfo", object.__getattribute__(self, '_module_info'))
|
|
144
|
+
|
|
145
|
+
# 使用object.__setattr__避免触发自定义的__setattr__
|
|
146
|
+
object.__setattr__(self, '_instance', instance)
|
|
147
|
+
object.__setattr__(self, '_initialized', True)
|
|
148
|
+
|
|
149
|
+
# 如果是 BaseModule 子类,在初始化后调用 on_load 方法
|
|
150
|
+
if object.__getattribute__(self, '_is_base_module'):
|
|
151
|
+
logger.debug(f"正在调用模块 {object.__getattribute__(self, '_module_name')} 的 on_load 方法...")
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
await module.load(object.__getattribute__(self, '_module_name'))
|
|
155
|
+
except Exception as e:
|
|
156
|
+
logger.error(f"调用模块 {object.__getattribute__(self, '_module_name')} 的 on_load 方法时出错: {e}")
|
|
157
|
+
|
|
158
|
+
await lifecycle.submit_event(
|
|
159
|
+
"module.init",
|
|
160
|
+
msg=f"模块 {object.__getattribute__(self, '_module_name')} 初始化完毕",
|
|
161
|
+
data={
|
|
162
|
+
"module_name": object.__getattribute__(self, '_module_name'),
|
|
163
|
+
"success": True,
|
|
164
|
+
}
|
|
165
|
+
)
|
|
166
|
+
logger.debug(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 初始化完成")
|
|
167
|
+
|
|
168
|
+
except Exception as e:
|
|
169
|
+
await lifecycle.submit_event(
|
|
170
|
+
"module.init",
|
|
171
|
+
msg=f"模块初始化失败: {e}",
|
|
172
|
+
data={
|
|
173
|
+
"module_name": object.__getattribute__(self, '_module_name'),
|
|
174
|
+
"success": False,
|
|
175
|
+
}
|
|
176
|
+
)
|
|
177
|
+
logger.error(f"懒加载模块 {object.__getattribute__(self, '_module_name')} 初始化失败: {e}")
|
|
178
|
+
raise e
|
|
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
|
+
def _ensure_initialized(self) -> None:
|
|
263
|
+
"""
|
|
264
|
+
确保模块已初始化
|
|
265
|
+
|
|
266
|
+
:raises LazyLoadError: 当模块未初始化时抛出
|
|
267
|
+
"""
|
|
268
|
+
if not object.__getattribute__(self, '_initialized'):
|
|
269
|
+
# 检查当前是否在异步上下文中
|
|
270
|
+
try:
|
|
271
|
+
loop = asyncio.get_running_loop()
|
|
272
|
+
# 如果在异步上下文中,我们需要检查模块初始化方法是否需要异步
|
|
273
|
+
init_method = getattr(object.__getattribute__(self, '_module_class'), '__init__', None)
|
|
274
|
+
|
|
275
|
+
# 检查__init__方法是否是协程函数
|
|
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}")
|
|
293
|
+
except RuntimeError:
|
|
294
|
+
# 没有运行中的事件循环,可以安全地创建新的事件循环
|
|
295
|
+
asyncio.run(self._initialize())
|
|
296
|
+
|
|
297
|
+
def __getattr__(self, name: str) -> Any:
|
|
298
|
+
"""
|
|
299
|
+
属性访问时触发初始化
|
|
300
|
+
|
|
301
|
+
:param name: str 属性名
|
|
302
|
+
:return: Any 属性值
|
|
303
|
+
"""
|
|
304
|
+
logger.debug(f"正在访问懒加载模块 {object.__getattribute__(self, '_module_name')} 的属性 {name}...")
|
|
305
|
+
|
|
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
|
+
self._ensure_initialized()
|
|
314
|
+
return getattr(object.__getattribute__(self, '_instance'), name)
|
|
315
|
+
|
|
316
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
317
|
+
"""
|
|
318
|
+
属性设置
|
|
319
|
+
|
|
320
|
+
:param name: str 属性名
|
|
321
|
+
:param value: Any 属性值
|
|
322
|
+
"""
|
|
323
|
+
logger.debug(f"正在设置懒加载模块 {object.__getattribute__(self, '_module_name')} 的属性 {name}...")
|
|
324
|
+
|
|
325
|
+
# 特殊属性直接设置到包装器上
|
|
326
|
+
if name.startswith('_') or name in ('moduleInfo',):
|
|
327
|
+
object.__setattr__(self, name, value)
|
|
328
|
+
else:
|
|
329
|
+
# 其他属性在初始化前设置到包装器上,初始化后设置到实际模块实例上
|
|
330
|
+
if name == '_instance' or not hasattr(self, '_initialized') or not object.__getattribute__(self, '_initialized'):
|
|
331
|
+
object.__setattr__(self, name, value)
|
|
332
|
+
else:
|
|
333
|
+
setattr(object.__getattribute__(self, '_instance'), name, value)
|
|
334
|
+
|
|
335
|
+
def __delattr__(self, name: str) -> None:
|
|
336
|
+
"""
|
|
337
|
+
属性删除
|
|
338
|
+
|
|
339
|
+
:param name: str 属性名
|
|
340
|
+
"""
|
|
341
|
+
logger.debug(f"正在删除懒加载模块 {object.__getattribute__(self, '_module_name')} 的属性 {name}...")
|
|
342
|
+
|
|
343
|
+
self._ensure_initialized()
|
|
344
|
+
delattr(object.__getattribute__(self, '_instance'), name)
|
|
345
|
+
|
|
346
|
+
def __getattribute__(self, name: str) -> Any:
|
|
347
|
+
"""
|
|
348
|
+
属性访问,初始化后直接委托给实际实例
|
|
349
|
+
|
|
350
|
+
:param name: str 属性名
|
|
351
|
+
:return: Any 属性值
|
|
352
|
+
"""
|
|
353
|
+
# 特殊属性直接从包装器获取
|
|
354
|
+
if name.startswith('_') or name in ('moduleInfo',):
|
|
355
|
+
return object.__getattribute__(self, name)
|
|
356
|
+
|
|
357
|
+
# 检查是否已初始化
|
|
358
|
+
try:
|
|
359
|
+
initialized = object.__getattribute__(self, '_initialized')
|
|
360
|
+
except AttributeError:
|
|
361
|
+
# 避免在初始化过程中访问_initialized时出现递归
|
|
362
|
+
return object.__getattribute__(self, name)
|
|
363
|
+
|
|
364
|
+
if not initialized:
|
|
365
|
+
# 确保初始化
|
|
366
|
+
self._ensure_initialized()
|
|
367
|
+
# 重新获取initialized状态
|
|
368
|
+
initialized = object.__getattribute__(self, '_initialized')
|
|
369
|
+
|
|
370
|
+
# 初始化后直接委托给实际实例
|
|
371
|
+
if initialized:
|
|
372
|
+
instance = object.__getattribute__(self, '_instance')
|
|
373
|
+
return getattr(instance, name)
|
|
374
|
+
else:
|
|
375
|
+
return object.__getattribute__(self, name)
|
|
376
|
+
|
|
377
|
+
def __dir__(self) -> List[str]:
|
|
378
|
+
"""
|
|
379
|
+
返回模块属性列表
|
|
380
|
+
|
|
381
|
+
:return: List[str] 属性列表
|
|
382
|
+
"""
|
|
383
|
+
logger.debug(f"正在获取懒加载模块 {object.__getattribute__(self, '_module_name')} 的属性列表...")
|
|
384
|
+
|
|
385
|
+
self._ensure_initialized()
|
|
386
|
+
return dir(object.__getattribute__(self, '_instance'))
|
|
387
|
+
|
|
388
|
+
def __repr__(self) -> str:
|
|
389
|
+
"""
|
|
390
|
+
返回模块表示字符串
|
|
391
|
+
|
|
392
|
+
:return: str 表示字符串
|
|
393
|
+
"""
|
|
394
|
+
logger.debug(f"正在获取懒加载模块 {object.__getattribute__(self, '_module_name')} 的表示字符串...")
|
|
395
|
+
|
|
396
|
+
if object.__getattribute__(self, '_initialized'):
|
|
397
|
+
return repr(object.__getattribute__(self, '_instance'))
|
|
398
|
+
return f"<LazyModule {object.__getattribute__(self, '_module_name')} (not initialized)>"
|
|
399
|
+
|
|
400
|
+
# 代理所有其他魔术方法到实际模块实例
|
|
401
|
+
def __call__(self, *args, **kwargs):
|
|
402
|
+
"""代理函数调用"""
|
|
403
|
+
self._ensure_initialized()
|
|
404
|
+
return object.__getattribute__(self, '_instance')(*args, **kwargs)
|
|
405
|
+
|
|
406
|
+
|
|
407
|
+
class AdapterLoader:
|
|
408
|
+
"""
|
|
409
|
+
适配器加载器
|
|
410
|
+
|
|
411
|
+
专门用于从PyPI包加载和初始化适配器
|
|
412
|
+
|
|
413
|
+
{!--< tips >!--}
|
|
414
|
+
1. 适配器必须通过entry-points机制注册到erispulse.adapter组
|
|
415
|
+
2. 适配器类必须继承BaseAdapter
|
|
416
|
+
3. 适配器不适用懒加载
|
|
417
|
+
{!--< /tips >!--}
|
|
418
|
+
"""
|
|
419
|
+
|
|
420
|
+
@staticmethod
|
|
421
|
+
async def load() -> Tuple[Dict[str, object], List[str], List[str]]:
|
|
422
|
+
"""
|
|
423
|
+
从PyPI包entry-points加载适配器
|
|
424
|
+
|
|
425
|
+
:return:
|
|
426
|
+
Dict[str, object]: 适配器对象字典 {适配器名: 模块对象}
|
|
427
|
+
List[str]: 启用的适配器名称列表
|
|
428
|
+
List[str]: 停用的适配器名称列表
|
|
429
|
+
|
|
430
|
+
:raises ImportError: 当无法加载适配器时抛出
|
|
431
|
+
"""
|
|
432
|
+
adapter_objs = {}
|
|
433
|
+
enabled_adapters = []
|
|
434
|
+
disabled_adapters = []
|
|
435
|
+
|
|
436
|
+
logger.info("正在加载适配器entry-points...")
|
|
437
|
+
|
|
438
|
+
try:
|
|
439
|
+
# 加载适配器entry-points
|
|
440
|
+
logger.debug("正在获取适配器entry-points...")
|
|
441
|
+
entry_points = importlib.metadata.entry_points()
|
|
442
|
+
if hasattr(entry_points, 'select'):
|
|
443
|
+
adapter_entries = entry_points.select(group='erispulse.adapter')
|
|
444
|
+
else:
|
|
445
|
+
adapter_entries = entry_points.get('erispulse.adapter', []) # type: ignore[attr-defined] || 原因: 3.10.0后entry_points不再支持select方法
|
|
446
|
+
|
|
447
|
+
# 处理适配器
|
|
448
|
+
logger.debug("正在处理适配器entry-points...")
|
|
449
|
+
for entry_point in adapter_entries:
|
|
450
|
+
adapter_objs, enabled_adapters, disabled_adapters = await AdapterLoader._process_adapter(
|
|
451
|
+
entry_point, adapter_objs, enabled_adapters, disabled_adapters)
|
|
452
|
+
|
|
453
|
+
logger.info("适配器加载完成")
|
|
454
|
+
|
|
455
|
+
except Exception as e:
|
|
456
|
+
logger.error(f"加载适配器entry-points失败: {e}")
|
|
457
|
+
raise ImportError(f"无法加载适配器: {e}")
|
|
458
|
+
|
|
459
|
+
return adapter_objs, enabled_adapters, disabled_adapters
|
|
460
|
+
|
|
461
|
+
@staticmethod
|
|
462
|
+
async def _process_adapter(
|
|
463
|
+
entry_point: Any,
|
|
464
|
+
adapter_objs: Dict[str, object],
|
|
465
|
+
enabled_adapters: List[str],
|
|
466
|
+
disabled_adapters: List[str]
|
|
467
|
+
) -> Tuple[Dict[str, object], List[str], List[str]]:
|
|
468
|
+
"""
|
|
469
|
+
{!--< internal-use >!--}
|
|
470
|
+
处理单个适配器entry-point
|
|
471
|
+
|
|
472
|
+
:param entry_point: entry-point对象
|
|
473
|
+
:param adapter_objs: 适配器对象字典
|
|
474
|
+
:param enabled_adapters: 启用的适配器列表
|
|
475
|
+
:param disabled_adapters: 停用的适配器列表
|
|
476
|
+
|
|
477
|
+
:return:
|
|
478
|
+
Dict[str, object]: 更新后的适配器对象字典
|
|
479
|
+
List[str]: 更新后的启用适配器列表
|
|
480
|
+
List[str]: 更新后的禁用适配器列表
|
|
481
|
+
|
|
482
|
+
:raises ImportError: 当适配器加载失败时抛出
|
|
483
|
+
"""
|
|
484
|
+
meta_name = entry_point.name
|
|
485
|
+
|
|
486
|
+
# # 检查适配器是否已经注册,如果未注册则进行注册(默认禁用)
|
|
487
|
+
# if not sdk.adapter.exists(meta_name):
|
|
488
|
+
# sdk.adapter._config_register(meta_name, False)
|
|
489
|
+
# logger.info(f"发现新适配器 {meta_name},默认已禁用,请在配置文件中配置适配器并决定是否启用")
|
|
490
|
+
if not sdk.adapter.exists(meta_name):
|
|
491
|
+
sdk.adapter._config_register(meta_name, True)
|
|
492
|
+
logger.info(f"发现新适配器 {meta_name},默认已启用")
|
|
493
|
+
|
|
494
|
+
# 获取适配器当前状态
|
|
495
|
+
adapter_status = sdk.adapter.is_enabled(meta_name)
|
|
496
|
+
logger.debug(f"适配器 {meta_name} 状态: {adapter_status}")
|
|
497
|
+
|
|
498
|
+
if not adapter_status:
|
|
499
|
+
disabled_adapters.append(meta_name)
|
|
500
|
+
logger.debug(f"适配器 {meta_name} 已禁用, 跳过...")
|
|
501
|
+
return adapter_objs, enabled_adapters, disabled_adapters
|
|
502
|
+
|
|
503
|
+
try:
|
|
504
|
+
loaded_class = entry_point.load()
|
|
505
|
+
adapter_obj = sys.modules[loaded_class.__module__]
|
|
506
|
+
dist = importlib.metadata.distribution(entry_point.dist.name)
|
|
507
|
+
|
|
508
|
+
adapter_info = {
|
|
509
|
+
"meta": {
|
|
510
|
+
"name": meta_name,
|
|
511
|
+
"version": getattr(adapter_obj, "__version__", dist.version if dist else "1.0.0"),
|
|
512
|
+
"description": getattr(adapter_obj, "__description__", ""),
|
|
513
|
+
"author": getattr(adapter_obj, "__author__", ""),
|
|
514
|
+
"license": getattr(adapter_obj, "__license__", ""),
|
|
515
|
+
"package": entry_point.dist.name
|
|
516
|
+
},
|
|
517
|
+
"adapter_class": loaded_class
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if not hasattr(adapter_obj, 'adapterInfo'):
|
|
521
|
+
setattr(adapter_obj, 'adapterInfo', {})
|
|
522
|
+
|
|
523
|
+
adapter_obj.adapterInfo[meta_name] = adapter_info
|
|
524
|
+
|
|
525
|
+
adapter_objs[meta_name] = adapter_obj
|
|
526
|
+
enabled_adapters.append(meta_name)
|
|
527
|
+
logger.debug(f"从PyPI包发现适配器: {meta_name}")
|
|
528
|
+
|
|
529
|
+
except Exception as e:
|
|
530
|
+
logger.warning(f"从entry-point加载适配器 {meta_name} 失败: {e}")
|
|
531
|
+
raise ImportError(f"无法加载适配器 {meta_name}: {e}")
|
|
532
|
+
|
|
533
|
+
return adapter_objs, enabled_adapters, disabled_adapters
|
|
534
|
+
|
|
535
|
+
class ModuleLoader:
|
|
536
|
+
"""
|
|
537
|
+
模块加载器
|
|
538
|
+
|
|
539
|
+
专门用于从PyPI包加载和初始化普通模块
|
|
540
|
+
|
|
541
|
+
{!--< tips >!--}
|
|
542
|
+
1. 模块必须通过entry-points机制注册到erispulse.module组
|
|
543
|
+
2. 模块类名应与entry-point名称一致
|
|
544
|
+
{!--< /tips >!--}
|
|
545
|
+
"""
|
|
546
|
+
|
|
547
|
+
@staticmethod
|
|
548
|
+
async def load() -> Tuple[Dict[str, object], List[str], List[str]]:
|
|
549
|
+
"""
|
|
550
|
+
从PyPI包entry-points加载模块
|
|
551
|
+
|
|
552
|
+
:return:
|
|
553
|
+
Dict[str, object]: 模块对象字典 {模块名: 模块对象}
|
|
554
|
+
List[str]: 启用的模块名称列表
|
|
555
|
+
List[str]: 停用的模块名称列表
|
|
556
|
+
|
|
557
|
+
:raises ImportError: 当无法加载模块时抛出
|
|
558
|
+
"""
|
|
559
|
+
module_objs = {}
|
|
560
|
+
enabled_modules = []
|
|
561
|
+
disabled_modules = []
|
|
562
|
+
|
|
563
|
+
logger.info("正在加载模块entry-points...")
|
|
564
|
+
|
|
565
|
+
try:
|
|
566
|
+
# 加载模块entry-points
|
|
567
|
+
entry_points = importlib.metadata.entry_points()
|
|
568
|
+
if hasattr(entry_points, 'select'):
|
|
569
|
+
module_entries = entry_points.select(group='erispulse.module')
|
|
570
|
+
else:
|
|
571
|
+
module_entries = entry_points.get('erispulse.module', []) # type: ignore[attr-defined] || 原因: 3.10.0后entry_points不再支持select方法
|
|
572
|
+
|
|
573
|
+
# 处理模块
|
|
574
|
+
for entry_point in module_entries:
|
|
575
|
+
module_objs, enabled_modules, disabled_modules = await ModuleLoader._process_module(
|
|
576
|
+
entry_point, module_objs, enabled_modules, disabled_modules)
|
|
577
|
+
|
|
578
|
+
logger.info("模块加载完成")
|
|
579
|
+
|
|
580
|
+
except Exception as e:
|
|
581
|
+
logger.error(f"加载模块entry-points失败: {e}")
|
|
582
|
+
raise ImportError(f"无法加载模块: {e}")
|
|
583
|
+
|
|
584
|
+
return module_objs, enabled_modules, disabled_modules
|
|
585
|
+
|
|
586
|
+
@staticmethod
|
|
587
|
+
async def _process_module(
|
|
588
|
+
entry_point: Any,
|
|
589
|
+
module_objs: Dict[str, object],
|
|
590
|
+
enabled_modules: List[str],
|
|
591
|
+
disabled_modules: List[str]
|
|
592
|
+
) -> Tuple[Dict[str, object], List[str], List[str]]:
|
|
593
|
+
"""
|
|
594
|
+
{!--< internal-use >!--}
|
|
595
|
+
处理单个模块entry-point
|
|
596
|
+
|
|
597
|
+
:param entry_point: entry-point对象
|
|
598
|
+
:param module_objs: 模块对象字典
|
|
599
|
+
:param enabled_modules: 启用的模块列表
|
|
600
|
+
:param disabled_modules: 停用的模块列表
|
|
601
|
+
|
|
602
|
+
:return:
|
|
603
|
+
Dict[str, object]: 更新后的模块对象字典
|
|
604
|
+
List[str]: 更新后的启用模块列表
|
|
605
|
+
List[str]: 更新后的禁用模块列表
|
|
606
|
+
|
|
607
|
+
:raises ImportError: 当模块加载失败时抛出
|
|
608
|
+
"""
|
|
609
|
+
meta_name = entry_point.name
|
|
610
|
+
|
|
611
|
+
logger.debug(f"正在处理模块: {meta_name}")
|
|
612
|
+
# # 检查模块是否已经注册,如果未注册则进行注册(默认禁用)
|
|
613
|
+
# if not sdk.module.exists(meta_name):
|
|
614
|
+
# sdk.module._config_register(meta_name, False) # 默认禁用
|
|
615
|
+
# logger.info(f"发现新模块 {meta_name},默认已禁用,请在配置文件中手动启用")
|
|
616
|
+
|
|
617
|
+
if not sdk.module.exists(meta_name):
|
|
618
|
+
sdk.module._config_register(meta_name, True) # 默认启用
|
|
619
|
+
logger.info(f"发现新模块 {meta_name},默认已启用。如需禁用,请在配置文件中设置 ErisPulse.modules.status.{meta_name} = false")
|
|
620
|
+
|
|
621
|
+
# 获取模块当前状态
|
|
622
|
+
module_status = sdk.module.is_enabled(meta_name)
|
|
623
|
+
logger.debug(f"模块 {meta_name} 状态: {module_status}")
|
|
624
|
+
|
|
625
|
+
if not module_status:
|
|
626
|
+
disabled_modules.append(meta_name)
|
|
627
|
+
return module_objs, enabled_modules, disabled_modules
|
|
628
|
+
|
|
629
|
+
try:
|
|
630
|
+
loaded_obj = entry_point.load()
|
|
631
|
+
module_obj = sys.modules[loaded_obj.__module__]
|
|
632
|
+
dist = importlib.metadata.distribution(entry_point.dist.name)
|
|
633
|
+
|
|
634
|
+
# 检查模块是否继承自 BaseModule
|
|
635
|
+
from .Core.Bases.module import BaseModule
|
|
636
|
+
is_base_module = inspect.isclass(loaded_obj) and issubclass(loaded_obj, BaseModule)
|
|
637
|
+
|
|
638
|
+
if not is_base_module:
|
|
639
|
+
logger.warning(f"模块 {meta_name} 未继承自 BaseModule,"\
|
|
640
|
+
"如果你是这个模块的作者,请检查 ErisPulse 的文档更新 并尽快迁移!")
|
|
641
|
+
|
|
642
|
+
lazy_load = ModuleLoader._should_lazy_load(loaded_obj)
|
|
643
|
+
|
|
644
|
+
module_info = {
|
|
645
|
+
"meta": {
|
|
646
|
+
"name": meta_name,
|
|
647
|
+
"version": getattr(module_obj, "__version__", dist.version if dist else "1.0.0"),
|
|
648
|
+
"description": getattr(module_obj, "__description__", ""),
|
|
649
|
+
"author": getattr(module_obj, "__author__", ""),
|
|
650
|
+
"license": getattr(module_obj, "__license__", ""),
|
|
651
|
+
"package": entry_point.dist.name,
|
|
652
|
+
"lazy_load": lazy_load,
|
|
653
|
+
"is_base_module": is_base_module
|
|
654
|
+
},
|
|
655
|
+
"module_class": loaded_obj
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
setattr(module_obj, "moduleInfo", module_info)
|
|
659
|
+
|
|
660
|
+
module_objs[meta_name] = module_obj
|
|
661
|
+
enabled_modules.append(meta_name)
|
|
662
|
+
logger.debug(f"从PyPI包加载模块: {meta_name}")
|
|
663
|
+
|
|
664
|
+
except Exception as e:
|
|
665
|
+
logger.warning(f"从entry-point加载模块 {meta_name} 失败: {e}")
|
|
666
|
+
raise ImportError(f"无法加载模块 {meta_name}: {e}")
|
|
667
|
+
|
|
668
|
+
return module_objs, enabled_modules, disabled_modules
|
|
669
|
+
|
|
670
|
+
@staticmethod
|
|
671
|
+
def _should_lazy_load(module_class: Type) -> bool:
|
|
672
|
+
"""
|
|
673
|
+
检查模块是否应该懒加载
|
|
674
|
+
|
|
675
|
+
:param module_class: Type 模块类
|
|
676
|
+
:return: bool 如果返回 False,则立即加载;否则懒加载
|
|
677
|
+
"""
|
|
678
|
+
|
|
679
|
+
logger.debug(f"检查模块 {module_class.__name__} 是否应该懒加载")
|
|
680
|
+
|
|
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
|
+
# 检查模块是否定义了 should_eager_load() 方法
|
|
695
|
+
if hasattr(module_class, "should_eager_load"):
|
|
696
|
+
try:
|
|
697
|
+
# 调用静态方法,如果返回 True,则禁用懒加载(立即加载)
|
|
698
|
+
return not module_class.should_eager_load()
|
|
699
|
+
except Exception as e:
|
|
700
|
+
logger.warning(f"调用模块 {module_class.__name__} 的 should_eager_load() 失败: {e}")
|
|
701
|
+
|
|
702
|
+
# 默认启用懒加载
|
|
703
|
+
return True
|
|
704
|
+
|
|
705
|
+
class ModuleInitializer:
|
|
706
|
+
"""
|
|
707
|
+
模块初始化器(注意:适配器是一个特殊的模块)
|
|
708
|
+
|
|
709
|
+
负责协调适配器和模块的初始化流程
|
|
710
|
+
|
|
711
|
+
{!--< tips >!--}
|
|
712
|
+
1. 初始化顺序:适配器 → 模块
|
|
713
|
+
2. 模块初始化采用懒加载机制
|
|
714
|
+
{!--< /tips >!--}
|
|
715
|
+
"""
|
|
716
|
+
|
|
717
|
+
@staticmethod
|
|
718
|
+
async def init() -> bool:
|
|
719
|
+
"""
|
|
720
|
+
初始化所有模块和适配器
|
|
721
|
+
|
|
722
|
+
执行步骤:
|
|
723
|
+
1. 从PyPI包加载适配器
|
|
724
|
+
2. 从PyPI包加载模块
|
|
725
|
+
3. 预记录所有模块信息
|
|
726
|
+
4. 注册适配器
|
|
727
|
+
5. 初始化各模块
|
|
728
|
+
|
|
729
|
+
:return: bool 初始化是否成功
|
|
730
|
+
:raises InitError: 当初始化失败时抛出
|
|
731
|
+
"""
|
|
732
|
+
logger.info("[Init] SDK 正在初始化...")
|
|
733
|
+
|
|
734
|
+
try:
|
|
735
|
+
# 1. 并行加载适配器和模块
|
|
736
|
+
(adapter_result, module_result) = await asyncio.gather(
|
|
737
|
+
AdapterLoader.load(),
|
|
738
|
+
ModuleLoader.load(),
|
|
739
|
+
return_exceptions=True
|
|
740
|
+
)
|
|
741
|
+
|
|
742
|
+
# 检查是否有异常
|
|
743
|
+
if isinstance(adapter_result, Exception):
|
|
744
|
+
logger.error(f"[Init] 适配器加载失败: {adapter_result}")
|
|
745
|
+
return False
|
|
746
|
+
|
|
747
|
+
if isinstance(module_result, Exception):
|
|
748
|
+
logger.error(f"[Init] 模块加载失败: {module_result}")
|
|
749
|
+
return False
|
|
750
|
+
|
|
751
|
+
# 解包结果
|
|
752
|
+
if not isinstance(adapter_result, Exception):
|
|
753
|
+
adapter_objs, enabled_adapters, disabled_adapters = adapter_result # type: ignore[assignment] || 原因: 已经在方法中进行了类型检查
|
|
754
|
+
else:
|
|
755
|
+
return False
|
|
756
|
+
|
|
757
|
+
if not isinstance(module_result, Exception):
|
|
758
|
+
module_objs, enabled_modules, disabled_modules = module_result # type: ignore[assignment] || 原因: 已经在方法中进行了类型检查
|
|
759
|
+
else:
|
|
760
|
+
return False
|
|
761
|
+
|
|
762
|
+
logger.info(f"[Init] 加载了 {len(enabled_adapters)} 个适配器, {len(disabled_adapters)} 个适配器被禁用")
|
|
763
|
+
logger.info(f"[Init] 加载了 {len(enabled_modules)} 个模块, {len(disabled_modules)} 个模块被禁用")
|
|
764
|
+
|
|
765
|
+
modules_dir = os.path.join(os.path.dirname(__file__), "modules")
|
|
766
|
+
if os.path.exists(modules_dir) and os.listdir(modules_dir):
|
|
767
|
+
logger.warning("[Warning] 你的项目使用了已经弃用的模块加载方式, 请尽快使用 PyPI 模块加载方式代替")
|
|
768
|
+
|
|
769
|
+
if not enabled_modules and not enabled_adapters:
|
|
770
|
+
logger.warning("[Init] 没有找到可用的模块和适配器")
|
|
771
|
+
return True
|
|
772
|
+
|
|
773
|
+
# 3. 注册适配器
|
|
774
|
+
logger.debug("[Init] 正在注册适配器...")
|
|
775
|
+
if not await ModuleInitializer._register_adapters(enabled_adapters, adapter_objs):
|
|
776
|
+
return False
|
|
777
|
+
|
|
778
|
+
# 4. 初始化模块
|
|
779
|
+
logger.debug("[Init] 正在初始化模块...")
|
|
780
|
+
success = await ModuleInitializer._initialize_modules(enabled_modules, module_objs)
|
|
781
|
+
|
|
782
|
+
if success:
|
|
783
|
+
logger.info("[Init] SDK初始化成功")
|
|
784
|
+
else:
|
|
785
|
+
logger.error("[Init] SDK初始化失败")
|
|
786
|
+
|
|
787
|
+
load_duration = lifecycle.stop_timer("core.init")
|
|
788
|
+
await lifecycle.submit_event(
|
|
789
|
+
"core.init.complete",
|
|
790
|
+
msg="模块初始化完成" if success else "模块初始化失败",
|
|
791
|
+
data={
|
|
792
|
+
"duration": load_duration,
|
|
793
|
+
"success": success
|
|
794
|
+
}
|
|
795
|
+
)
|
|
796
|
+
return success
|
|
797
|
+
|
|
798
|
+
except Exception as e:
|
|
799
|
+
load_duration = lifecycle.stop_timer("core.init")
|
|
800
|
+
await lifecycle.submit_event(
|
|
801
|
+
"core.init.complete",
|
|
802
|
+
msg="模块初始化失败",
|
|
803
|
+
data={
|
|
804
|
+
"duration": load_duration,
|
|
805
|
+
"success": False
|
|
806
|
+
}
|
|
807
|
+
)
|
|
808
|
+
logger.critical(f"SDK初始化严重错误: {e}")
|
|
809
|
+
return False
|
|
810
|
+
@staticmethod
|
|
811
|
+
async def _initialize_modules(modules: List[str], module_objs: Dict[str, Any]) -> bool:
|
|
812
|
+
"""
|
|
813
|
+
{!--< internal-use >!--}
|
|
814
|
+
初始化模块
|
|
815
|
+
|
|
816
|
+
:param modules: List[str] 模块名称列表
|
|
817
|
+
:param module_objs: Dict[str, Any] 模块对象字典
|
|
818
|
+
|
|
819
|
+
:return: bool 模块初始化是否成功
|
|
820
|
+
"""
|
|
821
|
+
# 并行注册所有模块类
|
|
822
|
+
register_tasks = []
|
|
823
|
+
for module_name in modules:
|
|
824
|
+
module_obj = module_objs[module_name]
|
|
825
|
+
meta_name = module_obj.moduleInfo["meta"]["name"]
|
|
826
|
+
|
|
827
|
+
async def register_module(name, obj):
|
|
828
|
+
try:
|
|
829
|
+
entry_points = importlib.metadata.entry_points()
|
|
830
|
+
if hasattr(entry_points, 'select'):
|
|
831
|
+
module_entries = entry_points.select(group='erispulse.module')
|
|
832
|
+
module_entry_map = {entry.name: entry for entry in module_entries}
|
|
833
|
+
else:
|
|
834
|
+
module_entries = entry_points.get('erispulse.module', []) # type: ignore[assignment] || 原因: 已经在方法中进行了类型检查,这是一个兼容性的写法
|
|
835
|
+
module_entry_map = {entry.name: entry for entry in module_entries}
|
|
836
|
+
|
|
837
|
+
entry_point = module_entry_map.get(name)
|
|
838
|
+
if entry_point:
|
|
839
|
+
module_class = entry_point.load()
|
|
840
|
+
|
|
841
|
+
module.register(name, module_class, obj.moduleInfo)
|
|
842
|
+
logger.debug(f"注册模块类: {name}")
|
|
843
|
+
return True
|
|
844
|
+
return False
|
|
845
|
+
except Exception as e:
|
|
846
|
+
logger.error(f"注册模块 {name} 失败: {e}")
|
|
847
|
+
return False
|
|
848
|
+
|
|
849
|
+
register_tasks.append(register_module(meta_name, module_obj))
|
|
850
|
+
|
|
851
|
+
# 等待所有注册任务完成
|
|
852
|
+
register_results = await asyncio.gather(*register_tasks, return_exceptions=True)
|
|
853
|
+
|
|
854
|
+
# 检查是否有注册失败的情况
|
|
855
|
+
if any(isinstance(result, Exception) or result is False for result in register_results):
|
|
856
|
+
return False
|
|
857
|
+
|
|
858
|
+
# 将所有模块挂载到sdk对象上
|
|
859
|
+
for module_name in modules:
|
|
860
|
+
module_obj = module_objs[module_name]
|
|
861
|
+
meta_name = module_obj.moduleInfo["meta"]["name"]
|
|
862
|
+
lazy_load = module_obj.moduleInfo["meta"].get("lazy_load", True)
|
|
863
|
+
|
|
864
|
+
if lazy_load:
|
|
865
|
+
# 使用懒加载方式挂载
|
|
866
|
+
lazy_module = LazyModule(
|
|
867
|
+
meta_name,
|
|
868
|
+
module_obj.moduleInfo["module_class"],
|
|
869
|
+
sdk,
|
|
870
|
+
module_obj.moduleInfo
|
|
871
|
+
)
|
|
872
|
+
setattr(sdk, meta_name, lazy_module)
|
|
873
|
+
logger.debug(f"挂载懒加载模块到sdk: {meta_name}")
|
|
874
|
+
else:
|
|
875
|
+
# 立即加载的模块暂时挂载为None,稍后会加载
|
|
876
|
+
setattr(sdk, meta_name, None)
|
|
877
|
+
logger.debug(f"预挂载立即加载模块到sdk: {meta_name}")
|
|
878
|
+
|
|
879
|
+
# 并行初始化需要立即加载的模块
|
|
880
|
+
eager_load_tasks = []
|
|
881
|
+
for module_name in modules:
|
|
882
|
+
module_obj = module_objs[module_name]
|
|
883
|
+
meta_name = module_obj.moduleInfo["meta"]["name"]
|
|
884
|
+
|
|
885
|
+
async def load_module_if_eager(name, obj):
|
|
886
|
+
try:
|
|
887
|
+
# 检查是否需要立即加载
|
|
888
|
+
entry_points = importlib.metadata.entry_points()
|
|
889
|
+
if hasattr(entry_points, 'select'):
|
|
890
|
+
module_entries = entry_points.select(group='erispulse.module')
|
|
891
|
+
module_entry_map = {entry.name: entry for entry in module_entries}
|
|
892
|
+
else:
|
|
893
|
+
module_entries = entry_points.get('erispulse.module', []) # type: ignore[assignment] || 原因: 已经在方法中进行了类型检查,这是一个兼容性的写法
|
|
894
|
+
module_entry_map = {entry.name: entry for entry in module_entries}
|
|
895
|
+
|
|
896
|
+
entry_point = module_entry_map.get(name)
|
|
897
|
+
if entry_point:
|
|
898
|
+
module_class = entry_point.load()
|
|
899
|
+
|
|
900
|
+
# 检查是否需要立即加载
|
|
901
|
+
lazy_load = ModuleLoader._should_lazy_load(module_class)
|
|
902
|
+
if not lazy_load:
|
|
903
|
+
# 立即加载模块
|
|
904
|
+
result = await module.load(name)
|
|
905
|
+
if not result:
|
|
906
|
+
logger.error(f"加载模块 {name} 失败")
|
|
907
|
+
else:
|
|
908
|
+
logger.debug(f"立即加载模块: {name}")
|
|
909
|
+
# 更新sdk上的引用
|
|
910
|
+
setattr(sdk, name, module.get(name))
|
|
911
|
+
return result
|
|
912
|
+
return True # 不需要立即加载的模块返回True
|
|
913
|
+
except Exception as e:
|
|
914
|
+
logger.error(f"初始化模块 {name} 失败: {e}")
|
|
915
|
+
return False
|
|
916
|
+
|
|
917
|
+
eager_load_tasks.append(load_module_if_eager(meta_name, module_obj))
|
|
918
|
+
|
|
919
|
+
# 等待所有立即加载任务完成
|
|
920
|
+
load_results = await asyncio.gather(*eager_load_tasks, return_exceptions=True)
|
|
921
|
+
|
|
922
|
+
# 检查是否有加载失败的情况
|
|
923
|
+
return not any(isinstance(result, Exception) or result is False for result in load_results)
|
|
924
|
+
|
|
925
|
+
@staticmethod
|
|
926
|
+
async def _register_adapters(adapters: List[str], adapter_objs: Dict[str, Any]) -> bool:
|
|
927
|
+
"""
|
|
928
|
+
{!--< internal-use >!--}
|
|
929
|
+
注册适配器
|
|
930
|
+
|
|
931
|
+
:param adapters: List[str] 适配器名称列表
|
|
932
|
+
:param adapter_objs: Dict[str, Any] 适配器对象字典
|
|
933
|
+
|
|
934
|
+
:return: bool 适配器注册是否成功
|
|
935
|
+
"""
|
|
936
|
+
# 并行注册所有适配器
|
|
937
|
+
register_tasks = []
|
|
938
|
+
|
|
939
|
+
for adapter_name in adapters:
|
|
940
|
+
adapter_obj = adapter_objs[adapter_name]
|
|
941
|
+
|
|
942
|
+
async def register_single_adapter(name, obj):
|
|
943
|
+
try:
|
|
944
|
+
success = True
|
|
945
|
+
if hasattr(obj, "adapterInfo") and isinstance(obj.adapterInfo, dict):
|
|
946
|
+
for platform, adapter_info in obj.adapterInfo.items():
|
|
947
|
+
if platform in adapter._adapters:
|
|
948
|
+
continue
|
|
949
|
+
|
|
950
|
+
adapter_class = adapter_info["adapter_class"]
|
|
951
|
+
|
|
952
|
+
adapter.register(platform, adapter_class, adapter_info)
|
|
953
|
+
logger.info(f"注册适配器: {platform} ({adapter_class.__name__})")
|
|
954
|
+
|
|
955
|
+
# 提交适配器加载完成事件
|
|
956
|
+
await lifecycle.submit_event(
|
|
957
|
+
"adapter.load",
|
|
958
|
+
msg=f"适配器 {platform} 加载完成",
|
|
959
|
+
data={
|
|
960
|
+
"platform": platform,
|
|
961
|
+
"success": True
|
|
962
|
+
}
|
|
963
|
+
)
|
|
964
|
+
return success
|
|
965
|
+
except Exception as e:
|
|
966
|
+
logger.error(f"适配器 {name} 注册失败: {e}")
|
|
967
|
+
# 提交适配器加载失败事件
|
|
968
|
+
await lifecycle.submit_event(
|
|
969
|
+
"adapter.load",
|
|
970
|
+
msg=f"适配器 {name} 加载失败: {e}",
|
|
971
|
+
data={
|
|
972
|
+
"platform": name,
|
|
973
|
+
"success": False
|
|
974
|
+
}
|
|
975
|
+
)
|
|
976
|
+
return False
|
|
977
|
+
|
|
978
|
+
register_tasks.append(register_single_adapter(adapter_name, adapter_obj))
|
|
979
|
+
|
|
980
|
+
# 等待所有注册任务完成
|
|
981
|
+
register_results = await asyncio.gather(*register_tasks, return_exceptions=True)
|
|
982
|
+
|
|
983
|
+
# 检查是否有注册失败的情况
|
|
984
|
+
return not any(isinstance(result, Exception) or result is False for result in register_results)
|
|
985
|
+
|
|
986
|
+
async def init_progress() -> bool:
|
|
987
|
+
"""
|
|
988
|
+
初始化项目环境文件
|
|
989
|
+
|
|
990
|
+
1. 检查并创建main.py入口文件
|
|
991
|
+
2. 确保基础目录结构存在
|
|
992
|
+
|
|
993
|
+
:return: bool 是否创建了新的main.py文件
|
|
994
|
+
|
|
995
|
+
{!--< tips >!--}
|
|
996
|
+
1. 如果main.py已存在则不会覆盖
|
|
997
|
+
2. 此方法通常由SDK内部调用
|
|
998
|
+
{!--< /tips >!--}
|
|
999
|
+
"""
|
|
1000
|
+
main_file = Path("main.py")
|
|
1001
|
+
main_init = False
|
|
1002
|
+
|
|
1003
|
+
try:
|
|
1004
|
+
if not main_file.exists():
|
|
1005
|
+
main_content = '''# main.py
|
|
1006
|
+
# ErisPulse 主程序文件
|
|
1007
|
+
# 本文件由 SDK 自动创建,您可随意修改
|
|
1008
|
+
import asyncio
|
|
1009
|
+
from ErisPulse import sdk
|
|
1010
|
+
|
|
1011
|
+
async def main():
|
|
1012
|
+
try:
|
|
1013
|
+
isInit = await sdk.init()
|
|
1014
|
+
|
|
1015
|
+
if not isInit:
|
|
1016
|
+
sdk.logger.error("ErisPulse 初始化失败,请检查日志")
|
|
1017
|
+
return
|
|
1018
|
+
|
|
1019
|
+
await sdk.adapter.startup()
|
|
1020
|
+
|
|
1021
|
+
# 保持程序运行(不建议修改)
|
|
1022
|
+
await asyncio.Event().wait()
|
|
1023
|
+
except Exception as e:
|
|
1024
|
+
sdk.logger.error(e)
|
|
1025
|
+
except KeyboardInterrupt:
|
|
1026
|
+
sdk.logger.info("正在停止程序")
|
|
1027
|
+
finally:
|
|
1028
|
+
await sdk.adapter.shutdown()
|
|
1029
|
+
|
|
1030
|
+
if __name__ == "__main__":
|
|
1031
|
+
asyncio.run(main())
|
|
1032
|
+
'''
|
|
1033
|
+
with open(main_file, "w", encoding="utf-8") as f:
|
|
1034
|
+
f.write(main_content)
|
|
1035
|
+
main_init = True
|
|
1036
|
+
|
|
1037
|
+
return main_init
|
|
1038
|
+
except Exception as e:
|
|
1039
|
+
logger.error(f"无法初始化项目环境: {e}")
|
|
1040
|
+
return False
|
|
1041
|
+
|
|
1042
|
+
async def _prepare_environment() -> bool:
|
|
1043
|
+
"""
|
|
1044
|
+
{!--< internal-use >!--}
|
|
1045
|
+
准备运行环境
|
|
1046
|
+
|
|
1047
|
+
初始化项目环境文件
|
|
1048
|
+
|
|
1049
|
+
:return: bool 环境准备是否成功
|
|
1050
|
+
"""
|
|
1051
|
+
await lifecycle.submit_event(
|
|
1052
|
+
"core.init.start",
|
|
1053
|
+
msg="开始初始化"
|
|
1054
|
+
)
|
|
1055
|
+
lifecycle.start_timer("core.init")
|
|
1056
|
+
|
|
1057
|
+
logger.info("[Init] 准备初始化环境...")
|
|
1058
|
+
try:
|
|
1059
|
+
from .Core._self_config import get_erispulse_config
|
|
1060
|
+
get_erispulse_config()
|
|
1061
|
+
logger.info("[Init] 配置文件已加载")
|
|
1062
|
+
|
|
1063
|
+
main_init = await init_progress()
|
|
1064
|
+
if main_init:
|
|
1065
|
+
logger.info("[Init] 项目入口已生成, 你可以在 main.py 中编写一些代码")
|
|
1066
|
+
return True
|
|
1067
|
+
except Exception as e:
|
|
1068
|
+
load_duration = lifecycle.stop_timer("core.init")
|
|
1069
|
+
await lifecycle.submit_event(
|
|
1070
|
+
"core.init.complete",
|
|
1071
|
+
msg="模块初始化失败",
|
|
1072
|
+
data={
|
|
1073
|
+
"duration": load_duration,
|
|
1074
|
+
"success": False
|
|
1075
|
+
}
|
|
1076
|
+
)
|
|
1077
|
+
logger.error(f"环境准备失败: {e}")
|
|
1078
|
+
return False
|
|
1079
|
+
|
|
1080
|
+
async def init() -> bool:
|
|
1081
|
+
"""
|
|
1082
|
+
SDK初始化入口
|
|
1083
|
+
|
|
1084
|
+
:return: bool SDK初始化是否成功
|
|
1085
|
+
"""
|
|
1086
|
+
if not await _prepare_environment():
|
|
1087
|
+
return False
|
|
1088
|
+
|
|
1089
|
+
return await ModuleInitializer.init()
|
|
1090
|
+
|
|
1091
|
+
def init_sync() -> bool:
|
|
1092
|
+
"""
|
|
1093
|
+
SDK初始化入口(同步版本)
|
|
1094
|
+
|
|
1095
|
+
用于命令行直接调用,自动在事件循环中运行异步初始化
|
|
1096
|
+
|
|
1097
|
+
:return: bool SDK初始化是否成功
|
|
1098
|
+
"""
|
|
1099
|
+
return asyncio.run(init())
|
|
1100
|
+
|
|
1101
|
+
def init_task() -> asyncio.Task:
|
|
1102
|
+
"""
|
|
1103
|
+
SDK初始化入口,返回Task对象
|
|
1104
|
+
|
|
1105
|
+
:return: asyncio.Task 初始化任务
|
|
1106
|
+
"""
|
|
1107
|
+
async def _async_init():
|
|
1108
|
+
if not await _prepare_environment():
|
|
1109
|
+
return False
|
|
1110
|
+
return await ModuleInitializer.init()
|
|
1111
|
+
|
|
1112
|
+
try:
|
|
1113
|
+
return asyncio.create_task(_async_init())
|
|
1114
|
+
except RuntimeError:
|
|
1115
|
+
loop = asyncio.new_event_loop()
|
|
1116
|
+
asyncio.set_event_loop(loop)
|
|
1117
|
+
return loop.create_task(_async_init())
|
|
1118
|
+
|
|
1119
|
+
async def uninit() -> bool:
|
|
1120
|
+
"""
|
|
1121
|
+
SDK反初始化
|
|
1122
|
+
|
|
1123
|
+
执行以下操作:
|
|
1124
|
+
1. 关闭所有适配器
|
|
1125
|
+
2. 卸载所有模块
|
|
1126
|
+
3. 清理所有事件处理器
|
|
1127
|
+
4. 清理僵尸线程
|
|
1128
|
+
|
|
1129
|
+
:return: bool 反初始化是否成功
|
|
1130
|
+
"""
|
|
1131
|
+
try:
|
|
1132
|
+
logger.info("[Uninit] 开始反初始化SDK...")
|
|
1133
|
+
|
|
1134
|
+
# 1. 关闭所有适配器
|
|
1135
|
+
logger.debug("[Uninit] 正在关闭适配器...")
|
|
1136
|
+
await adapter.shutdown()
|
|
1137
|
+
|
|
1138
|
+
# 2. 卸载所有模块
|
|
1139
|
+
logger.debug("[Uninit] 正在卸载模块...")
|
|
1140
|
+
await module.unload()
|
|
1141
|
+
|
|
1142
|
+
# 3. 清理Event模块中的所有事件处理器
|
|
1143
|
+
Event._clear_all_handlers()
|
|
1144
|
+
|
|
1145
|
+
# 4. 清理僵尸线程
|
|
1146
|
+
logger.debug("[Uninit] 正在清理线程...")
|
|
1147
|
+
# SDK本身不创建线程,但可以记录可能的线程泄漏
|
|
1148
|
+
current_task = asyncio.current_task()
|
|
1149
|
+
logger.debug(f"[Uninit] 当前任务: {current_task}")
|
|
1150
|
+
|
|
1151
|
+
logger.info("[Uninit] SDK反初始化完成")
|
|
1152
|
+
return True
|
|
1153
|
+
|
|
1154
|
+
except Exception as e:
|
|
1155
|
+
logger.error(f"[Uninit] SDK反初始化失败: {e}")
|
|
1156
|
+
return False
|
|
1157
|
+
|
|
1158
|
+
async def restart() -> bool:
|
|
1159
|
+
"""
|
|
1160
|
+
SDK重新启动
|
|
1161
|
+
|
|
1162
|
+
执行完整的反初始化后再初始化过程
|
|
1163
|
+
|
|
1164
|
+
:return: bool 重新加载是否成功
|
|
1165
|
+
"""
|
|
1166
|
+
logger.info("[Reload] 开始重新加载SDK...")
|
|
1167
|
+
|
|
1168
|
+
# 先执行反初始化
|
|
1169
|
+
if not await uninit():
|
|
1170
|
+
logger.error("[Reload] 反初始化失败,无法继续重新加载")
|
|
1171
|
+
return False
|
|
1172
|
+
|
|
1173
|
+
# 再执行初始化
|
|
1174
|
+
logger.info("[Reload] 开始重新初始化SDK...")
|
|
1175
|
+
if not await init():
|
|
1176
|
+
logger.error("[Reload] 初始化失败,请检查日志")
|
|
1177
|
+
return False
|
|
1178
|
+
|
|
1179
|
+
logger.info("[Reload] 正在启动适配器...")
|
|
1180
|
+
await adapter.startup()
|
|
1181
|
+
|
|
1182
|
+
logger.info("[Reload] 重新加载完成")
|
|
1183
|
+
return True
|
|
47
1184
|
|
|
1185
|
+
async def run(keep_running: bool = True) -> None:
|
|
1186
|
+
"""
|
|
1187
|
+
无头模式运行ErisPulse
|
|
1188
|
+
|
|
1189
|
+
此方法提供了一种无需入口启动的方式,适用于与其它框架集成的场景
|
|
1190
|
+
"""
|
|
1191
|
+
try:
|
|
1192
|
+
isInit = await init()
|
|
1193
|
+
|
|
1194
|
+
if not isInit:
|
|
1195
|
+
logger.error("ErisPulse 初始化失败,请检查日志")
|
|
1196
|
+
return
|
|
1197
|
+
|
|
1198
|
+
await adapter.startup()
|
|
1199
|
+
|
|
1200
|
+
if keep_running:
|
|
1201
|
+
# 保持程序运行
|
|
1202
|
+
await asyncio.Event().wait()
|
|
1203
|
+
except Exception as e:
|
|
1204
|
+
logger.error(e)
|
|
1205
|
+
finally:
|
|
1206
|
+
await module.unload()
|
|
1207
|
+
await adapter.shutdown()
|
|
48
1208
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
1209
|
+
async def load_module(module_name: str) -> bool:
|
|
1210
|
+
"""
|
|
1211
|
+
手动加载指定模块
|
|
1212
|
+
|
|
1213
|
+
:param module_name: str 要加载的模块名称
|
|
1214
|
+
:return: bool 加载是否成功
|
|
1215
|
+
|
|
1216
|
+
{!--< tips >!--}
|
|
1217
|
+
1. 可用于手动触发懒加载模块的初始化
|
|
1218
|
+
2. 如果模块不存在或已加载会返回False
|
|
1219
|
+
3. 对于需要异步初始化的模块,这是唯一的加载方式
|
|
1220
|
+
{!--< /tips >!--}
|
|
1221
|
+
"""
|
|
1222
|
+
try:
|
|
1223
|
+
module_instance = getattr(sdk, module_name, None)
|
|
1224
|
+
if isinstance(module_instance, LazyModule):
|
|
1225
|
+
# 检查模块是否需要异步初始化
|
|
1226
|
+
if hasattr(module_instance, '_needs_async_init') and object.__getattribute__(module_instance, '_needs_async_init'):
|
|
1227
|
+
# 对于需要异步初始化的模块,执行完整异步初始化
|
|
1228
|
+
await module_instance._initialize()
|
|
1229
|
+
object.__setattr__(module_instance, '_needs_async_init', False) # 清除标志
|
|
1230
|
+
return True
|
|
1231
|
+
# 检查模块是否已经同步初始化但未完成异步部分
|
|
1232
|
+
elif (object.__getattribute__(module_instance, '_initialized') and
|
|
1233
|
+
object.__getattribute__(module_instance, '_is_base_module')):
|
|
1234
|
+
# 如果是BaseModule子类且已同步初始化,只需完成异步部分
|
|
1235
|
+
await module_instance._complete_async_init()
|
|
1236
|
+
return True
|
|
1237
|
+
else:
|
|
1238
|
+
# 触发懒加载模块的完整初始化
|
|
1239
|
+
await module_instance._initialize()
|
|
1240
|
+
return True
|
|
1241
|
+
elif module_instance is not None:
|
|
1242
|
+
logger.warning(f"模块 {module_name} 已经加载")
|
|
1243
|
+
return False
|
|
1244
|
+
else:
|
|
1245
|
+
logger.error(f"模块 {module_name} 不存在")
|
|
1246
|
+
return False
|
|
1247
|
+
except Exception as e:
|
|
1248
|
+
logger.error(f"加载模块 {module_name} 失败: {e}")
|
|
1249
|
+
return False
|
|
1250
|
+
|
|
1251
|
+
logger.debug("ErisPulse 正在挂载必要的入口方法")
|
|
1252
|
+
setattr(sdk, "init", init)
|
|
1253
|
+
setattr(sdk, "init_task", init_task)
|
|
1254
|
+
setattr(sdk, "load_module", load_module)
|
|
1255
|
+
setattr(sdk, "run", run)
|
|
1256
|
+
setattr(sdk, "restart", restart)
|
|
1257
|
+
setattr(sdk, "uninit", uninit)
|