ErisPulse 1.1.14.dev1__py3-none-any.whl → 1.1.15__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/__main__.py CHANGED
@@ -549,7 +549,74 @@ def install_pip_dependencies(dependencies):
549
549
  shellprint.panel(f"安装pip依赖失败: {e.stderr}", "错误", "error")
550
550
  return False
551
551
 
552
+ def install_local_module(module_path, force=False):
553
+ """安装本地目录中的模块"""
554
+ module_path = os.path.abspath(module_path)
555
+ if not os.path.exists(module_path):
556
+ shellprint.panel(f"路径不存在: {module_path}", "错误", "error")
557
+ return False
558
+
559
+ # 尝试从目录名获取模块名
560
+ module_name = os.path.basename(module_path.rstrip('/\\'))
561
+
562
+ # 检查是否是有效的模块目录
563
+ init_py = os.path.join(module_path, '__init__.py')
564
+ if not os.path.exists(init_py):
565
+ shellprint.panel(f"目录 {module_path} 不是一个有效的Python模块", "错误", "error")
566
+ return False
567
+
568
+ # 尝试导入模块获取moduleInfo
569
+ try:
570
+ spec = importlib.util.spec_from_file_location(module_name, init_py)
571
+ module = importlib.util.module_from_spec(spec)
572
+ spec.loader.exec_module(module)
573
+ if not hasattr(module, 'moduleInfo'):
574
+ shellprint.panel(f"模块 {module_name} 缺少 moduleInfo 定义", "错误", "error")
575
+ return False
576
+ except Exception as e:
577
+ shellprint.panel(f"导入模块 {module_name} 失败: {e}", "错误", "error")
578
+ return False
579
+
580
+ module_info = mods.get_module(module_name)
581
+ if module_info and not force:
582
+ meta = module_info.get('info', {}).get('meta', {})
583
+ shellprint.panel(
584
+ f"{Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET}\n版本: {meta.get('version', '未知')}\n描述: {meta.get('description', '无描述')}",
585
+ "模块已存在",
586
+ "info"
587
+ )
588
+ if not shellprint.confirm("是否要强制重新安装?", default=False):
589
+ return False
590
+
591
+ # 复制模块到modules目录
592
+ script_dir = os.path.dirname(os.path.abspath(__file__))
593
+ target_dir = os.path.join(script_dir, 'modules', module_name)
594
+
595
+ try:
596
+ if os.path.exists(target_dir):
597
+ shutil.rmtree(target_dir)
598
+ shutil.copytree(module_path, target_dir)
599
+ except Exception as e:
600
+ shellprint.panel(f"复制模块文件失败: {e}", "错误", "error")
601
+ return False
602
+
603
+ # 注册模块信息
604
+ mods.set_module(module_name, {
605
+ 'status': True,
606
+ 'info': {
607
+ 'meta': module.moduleInfo.get('meta', {}),
608
+ 'dependencies': module.moduleInfo.get('dependencies', {})
609
+ }
610
+ })
611
+
612
+ shellprint.panel(f"本地模块 {Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET} 安装成功", "成功", "success")
613
+ return True
614
+
552
615
  def install_module(module_name, force=False):
616
+ # 检查是否是本地路径
617
+ if module_name.startswith('.') or os.path.isabs(module_name):
618
+ return install_local_module(module_name, force)
619
+
553
620
  shellprint.panel(f"准备安装模块: {Shell_Printer.BOLD}{module_name}{Shell_Printer.RESET}", "安装摘要", "info")
554
621
  last_update_time = env.get('last_origin_update_time', None)
555
622
  if last_update_time:
@@ -1147,7 +1214,12 @@ def main():
1147
1214
  else:
1148
1215
  shellprint.panel(f"运行脚本: {Shell_Printer.BOLD}{script_path}{Shell_Printer.RESET}", "执行", "info")
1149
1216
  import runpy
1150
- runpy.run_path(script_path, run_name="__main__")
1217
+
1218
+ # 添加KeyboardInterrupt异常捕捉
1219
+ try:
1220
+ runpy.run_path(script_path, run_name="__main__")
1221
+ except KeyboardInterrupt:
1222
+ shellprint.panel("脚本执行已中断", "中断", "info")
1151
1223
 
1152
1224
  elif args.command == 'origin':
1153
1225
  if args.origin_command == 'add':
ErisPulse/adapter.py CHANGED
@@ -1,48 +1,352 @@
1
1
  """
2
2
  # 适配器系统
3
3
 
4
- 提供平台适配器基类、消息发送DSL和适配器管理功能。
4
+ 提供平台适配器基类、消息发送DSL和适配器管理功能。支持多平台消息处理、事件驱动和生命周期管理。
5
5
 
6
- ## 主要功能
7
- - BaseAdapter: 适配器基类
8
- - SendDSL: 链式消息发送接口
9
- - AdapterManager: 适配器管理
10
- - 适配器注册和生命周期管理
6
+ ## 核心功能
7
+ 1. 适配器基类定义
8
+ 2. 链式消息发送DSL
9
+ 3. 适配器注册和管理
10
+ 4. 事件处理系统
11
+ 5. 中间件支持
11
12
 
12
13
  ## API 文档
13
- ### 适配器基类 (BaseAdapter):
14
- - call_api(): 必须实现的API调用方法
15
- - start(): 启动适配器
16
- - shutdown(): 关闭适配器
17
- - on(): 事件监听装饰器
18
- - emit(): 触发事件
19
-
20
- ### 消息发送DSL (SendDSL):
21
- - To(): 设置消息目标
22
- - Text(): 发送文本消息
23
- - 可扩展其他消息类型
24
-
25
- ### 适配器管理 (AdapterManager):
26
- - register(): 注册适配器
27
- - startup(): 启动适配器
28
- - shutdown(): 关闭所有适配器
29
- - get(): 获取适配器实例
30
-
31
- ### 示例用法:
32
14
 
15
+ ### 适配器基类 (BaseAdapter)
16
+ 适配器基类提供了与外部平台交互的标准接口。
17
+
18
+ #### call_api(endpoint: str, **params) -> Any
19
+ 调用平台API的抽象方法。
20
+ - 参数:
21
+ - endpoint: API端点
22
+ - **params: API参数
23
+ - 返回:
24
+ - Any: API调用结果
25
+ - 说明:
26
+ - 必须由子类实现
27
+ - 处理与平台的实际通信
28
+ - 示例:
29
+ ```python
30
+ class MyPlatformAdapter(BaseAdapter):
31
+ async def call_api(self, endpoint: str, **params):
32
+ if endpoint == "/send":
33
+ return await self._send_message(params)
34
+ elif endpoint == "/upload":
35
+ return await self._upload_file(params)
36
+ raise NotImplementedError(f"未实现的端点: {endpoint}")
33
37
  ```
34
- from ErisPulse import sdk
35
38
 
36
- # 注册适配器
37
- sdk.adapter.register("MyPlatform", MyAdapter)
39
+ #### start() -> None
40
+ 启动适配器的抽象方法。
41
+ - 参数: 无
42
+ - 返回:
43
+ - None
44
+ - 说明:
45
+ - 必须由子类实现
46
+ - 处理适配器的初始化和启动逻辑
47
+ - 示例:
48
+ ```python
49
+ class MyPlatformAdapter(BaseAdapter):
50
+ async def start(self):
51
+ self.client = await self._create_client()
52
+ self.ws = await self.client.create_websocket()
53
+ self._start_heartbeat()
54
+ ```
55
+
56
+ #### shutdown() -> None
57
+ 关闭适配器的抽象方法。
58
+ - 参数: 无
59
+ - 返回:
60
+ - None
61
+ - 说明:
62
+ - 必须由子类实现
63
+ - 处理资源清理和关闭逻辑
64
+ - 示例:
65
+ ```python
66
+ class MyPlatformAdapter(BaseAdapter):
67
+ async def shutdown(self):
68
+ if self.ws:
69
+ await self.ws.close()
70
+ if self.client:
71
+ await self.client.close()
72
+ ```
38
73
 
39
- # 发送消息
40
- sdk.adapter.MyPlatform.Send.To("user", "123").Text("Hello")
74
+ #### on(event_type: str = "*") -> Callable
75
+ 事件监听装饰器。
76
+ - 参数:
77
+ - event_type: 事件类型,默认"*"表示所有事件
78
+ - 返回:
79
+ - Callable: 装饰器函数
80
+ - 示例:
81
+ ```python
82
+ adapter = MyPlatformAdapter()
83
+
84
+ @adapter.on("message")
85
+ async def handle_message(data):
86
+ print(f"收到消息: {data}")
87
+
88
+ @adapter.on("error")
89
+ async def handle_error(error):
90
+ print(f"发生错误: {error}")
91
+
92
+ # 处理所有事件
93
+ @adapter.on()
94
+ async def handle_all(event):
95
+ print(f"事件: {event}")
96
+ ```
97
+
98
+ #### emit(event_type: str, data: Any) -> None
99
+ 触发事件。
100
+ - 参数:
101
+ - event_type: 事件类型
102
+ - data: 事件数据
103
+ - 返回:
104
+ - None
105
+ - 示例:
106
+ ```python
107
+ class MyPlatformAdapter(BaseAdapter):
108
+ async def _handle_websocket_message(self, message):
109
+ # 处理消息并触发相应事件
110
+ if message.type == "chat":
111
+ await self.emit("message", {
112
+ "type": "chat",
113
+ "content": message.content,
114
+ "sender": message.sender
115
+ })
116
+ ```
117
+
118
+ #### middleware(func: Callable) -> Callable
119
+ 添加中间件处理器。
120
+ - 参数:
121
+ - func: 中间件函数
122
+ - 返回:
123
+ - Callable: 中间件函数
124
+ - 示例:
125
+ ```python
126
+ adapter = MyPlatformAdapter()
127
+
128
+ @adapter.middleware
129
+ async def log_middleware(data):
130
+ print(f"处理数据: {data}")
131
+ return data
132
+
133
+ @adapter.middleware
134
+ async def filter_middleware(data):
135
+ if "spam" in data.get("content", ""):
136
+ return None
137
+ return data
138
+ ```
41
139
 
42
- # 启动适配器
140
+ ### 消息发送DSL (SendDSL)
141
+ 提供链式调用风格的消息发送接口。
142
+
143
+ #### To(target_type: str = None, target_id: str = None) -> 'SendDSL'
144
+ 设置消息目标。
145
+ - 参数:
146
+ - target_type: 目标类型(可选)
147
+ - target_id: 目标ID
148
+ - 返回:
149
+ - SendDSL: 发送器实例
150
+ - 示例:
151
+ ```python
152
+ # 发送到用户
153
+ sdk.adapter.Platform.Send.To("user", "123").Text("Hello")
154
+
155
+ # 发送到群组
156
+ sdk.adapter.Platform.Send.To("group", "456").Text("Hello Group")
157
+
158
+ # 简化形式(只有ID)
159
+ sdk.adapter.Platform.Send.To("123").Text("Hello")
160
+ ```
161
+
162
+ #### Text(text: str) -> Task
163
+ 发送文本消息。
164
+ - 参数:
165
+ - text: 文本内容
166
+ - 返回:
167
+ - Task: 异步任务
168
+ - 示例:
169
+ ```python
170
+ # 发送简单文本
171
+ await sdk.adapter.Platform.Send.To("user", "123").Text("Hello")
172
+
173
+ # 发送格式化文本
174
+ name = "Alice"
175
+ await sdk.adapter.Platform.Send.To("123").Text(f"Hello {name}")
176
+ ```
177
+
178
+ ### 适配器管理 (AdapterManager)
179
+ 管理多个平台适配器的注册、启动和关闭。
180
+
181
+ #### register(platform: str, adapter_class: Type[BaseAdapter]) -> bool
182
+ 注册新的适配器类。
183
+ - 参数:
184
+ - platform: 平台名称
185
+ - adapter_class: 适配器类
186
+ - 返回:
187
+ - bool: 注册是否成功
188
+ - 示例:
189
+ ```python
190
+ # 注册适配器
191
+ sdk.adapter.register("MyPlatform", MyPlatformAdapter)
192
+
193
+ # 注册多个适配器
194
+ adapters = {
195
+ "Platform1": Platform1Adapter,
196
+ "Platform2": Platform2Adapter
197
+ }
198
+ for name, adapter in adapters.items():
199
+ sdk.adapter.register(name, adapter)
200
+ ```
201
+
202
+ #### startup(platforms: List[str] = None) -> None
203
+ 启动指定的适配器。
204
+ - 参数:
205
+ - platforms: 要启动的平台列表,None表示所有平台
206
+ - 返回:
207
+ - None
208
+ - 示例:
209
+ ```python
210
+ # 启动所有适配器
43
211
  await sdk.adapter.startup()
212
+
213
+ # 启动指定适配器
214
+ await sdk.adapter.startup(["Platform1", "Platform2"])
215
+ ```
216
+
217
+ #### shutdown() -> None
218
+ 关闭所有适配器。
219
+ - 参数: 无
220
+ - 返回:
221
+ - None
222
+ - 示例:
223
+ ```python
224
+ # 关闭所有适配器
225
+ await sdk.adapter.shutdown()
226
+
227
+ # 在程序退出时关闭
228
+ import atexit
229
+ atexit.register(lambda: asyncio.run(sdk.adapter.shutdown()))
230
+ ```
231
+
232
+ ## 最佳实践
233
+
234
+ 1. 适配器实现
235
+ ```python
236
+ class MyPlatformAdapter(sdk.BaseAdapter):
237
+ class Send(sdk.BaseAdapter.Send):
238
+ # 实现基本消息类型
239
+ def Text(self, text: str):
240
+ return asyncio.create_task(
241
+ self._adapter.call_api(
242
+ endpoint="/send",
243
+ content=text,
244
+ recvId=self._target_id,
245
+ recvType=self._target_type
246
+ )
247
+ )
248
+
249
+ # 添加自定义消息类型
250
+ def Image(self, file: bytes):
251
+ return asyncio.create_task(
252
+ self._adapter.call_api(
253
+ endpoint="/send_image",
254
+ file=file,
255
+ recvId=self._target_id,
256
+ recvType=self._target_type
257
+ )
258
+ )
259
+
260
+ async def call_api(self, endpoint: str, **params):
261
+ # 实现API调用逻辑
262
+ async with aiohttp.ClientSession() as session:
263
+ async with session.post(
264
+ f"{self.api_base}{endpoint}",
265
+ json=params
266
+ ) as response:
267
+ return await response.json()
268
+
269
+ async def start(self):
270
+ # 初始化连接
271
+ self.client = await self._create_client()
272
+ # 启动事件监听
273
+ asyncio.create_task(self._listen_events())
274
+
275
+ async def shutdown(self):
276
+ # 清理资源
277
+ if self.client:
278
+ await self.client.close()
279
+ ```
280
+
281
+ 2. 事件处理
282
+ ```python
283
+ # 注册事件处理器
284
+ adapter = MyPlatformAdapter()
285
+
286
+ @adapter.on("message")
287
+ async def handle_message(data):
288
+ # 消息处理逻辑
289
+ if data["type"] == "text":
290
+ await process_text_message(data)
291
+ elif data["type"] == "image":
292
+ await process_image_message(data)
293
+
294
+ # 使用中间件
295
+ @adapter.middleware
296
+ async def auth_middleware(data):
297
+ if not verify_token(data.get("token")):
298
+ return None
299
+ return data
300
+
301
+ @adapter.middleware
302
+ async def log_middleware(data):
303
+ sdk.logger.info(f"处理事件: {data}")
304
+ return data
305
+ ```
306
+
307
+ 3. 消息发送
308
+ ```python
309
+ # 基本消息发送
310
+ async def send_welcome(user_id: str):
311
+ await sdk.adapter.Platform.Send.To("user", user_id).Text("欢迎!")
312
+
313
+ # 复杂消息处理
314
+ async def process_group_notification(group_id: str, event: dict):
315
+ # 发送格式化消息
316
+ message = format_notification(event)
317
+ await sdk.adapter.Platform.Send.To("group", group_id).Text(message)
318
+
319
+ # 发送附加文件
320
+ if event.get("has_attachment"):
321
+ file_data = await get_attachment(event["attachment_id"])
322
+ await sdk.adapter.Platform.Send.To("group", group_id).File(file_data)
44
323
  ```
45
324
 
325
+ ## 注意事项
326
+
327
+ 1. 适配器实现
328
+ - 确保正确实现所有抽象方法
329
+ - 处理所有可能的异常情况
330
+ - 实现适当的重试机制
331
+ - 注意资源的正确释放
332
+
333
+ 2. 事件处理
334
+ - 避免在事件处理器中执行长时间操作
335
+ - 使用适当的错误处理
336
+ - 考虑事件处理的顺序性
337
+ - 合理使用中间件过滤机制
338
+
339
+ 3. 消息发送
340
+ - 实现消息发送的限流机制
341
+ - 处理发送失败的情况
342
+ - 注意消息格式的平台兼容性
343
+ - 大文件传输时考虑分片
344
+
345
+ 4. 生命周期管理
346
+ - 确保适配器正确启动和关闭
347
+ - 处理意外断开的情况
348
+ - 实现自动重连机制
349
+ - 注意资源泄漏问题
46
350
  """
47
351
 
48
352
  import functools