ErisPulse 1.1.12__py3-none-any.whl → 1.1.14__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
@@ -1,3 +1,48 @@
1
+ """
2
+ # CLI 入口
3
+
4
+ 提供命令行界面(CLI)用于模块管理、源管理和开发调试。
5
+
6
+ ## 主要功能
7
+ - 模块管理: 安装/卸载/启用/禁用
8
+ - 源管理: 添加/删除/更新源
9
+ - 热重载: 开发时自动重启
10
+ - 彩色终端输出
11
+
12
+ ## 主要命令
13
+ ### 模块管理:
14
+ install: 安装模块
15
+ uninstall: 卸载模块
16
+ enable: 启用模块
17
+ disable: 禁用模块
18
+ list: 列出模块
19
+ update: 更新模块列表
20
+ upgrade: 升级模块
21
+
22
+ ### 源管理:
23
+ origin add: 添加源
24
+ origin del: 删除源
25
+ origin list: 列出源
26
+
27
+ ### 开发调试:
28
+ run: 运行脚本
29
+ --reload: 启用热重载
30
+
31
+ ### 示例用法:
32
+
33
+ ```
34
+ # 安装模块
35
+ epsdk install MyModule
36
+
37
+ # 启用热重载
38
+ epsdk run main.py --reload
39
+
40
+ # 管理源
41
+ epsdk origin add https://example.com/map.json
42
+ ```
43
+
44
+ """
45
+
1
46
  import argparse
2
47
  import os
3
48
  import sys
@@ -9,6 +54,7 @@ import fnmatch
9
54
  import asyncio
10
55
  import subprocess
11
56
  import json
57
+ import json
12
58
  from .db import env
13
59
  from .mods import mods
14
60
  from watchdog.observers import Observer
@@ -37,7 +83,6 @@ class Shell_Printer:
37
83
 
38
84
  @classmethod
39
85
  def _get_color(cls, level):
40
- """根据消息级别返回颜色"""
41
86
  return {
42
87
  "info": cls.CYAN,
43
88
  "success": cls.GREEN,
@@ -49,77 +94,87 @@ class Shell_Printer:
49
94
 
50
95
  @classmethod
51
96
  def panel(cls, msg: str, title: str = None, level: str = "info") -> None:
52
- """带标题和边框的面板,支持颜色编码"""
53
97
  color = cls._get_color(level)
54
- border_char = "═" * 60
98
+ width = 70
99
+ border_char = "─" * width
100
+
101
+ if level == "error":
102
+ border_char = "═" * width
103
+ msg = f"{cls.RED}✗ {msg}{cls.RESET}"
104
+ elif level == "warning":
105
+ border_char = "─" * width
106
+ msg = f"{cls.YELLOW}⚠ {msg}{cls.RESET}"
55
107
 
56
- # 标题行
57
108
  title_line = ""
58
109
  if title:
59
110
  title = f" {title.upper()} "
60
- title_padding = (60 - len(title) - 4) // 2
111
+ title_padding = (width - len(title)) // 2
61
112
  left_pad = " " * title_padding
62
- right_pad = " " * (60 - len(title) - title_padding - 4)
63
- title_line = f"{cls.DIM}{left_pad}{cls.BOLD}{color}{title}{cls.RESET}{cls.DIM}{right_pad}{cls.RESET}\n"
113
+ right_pad = " " * (width - len(title) - title_padding)
114
+ title_line = f"{cls.DIM}{left_pad}{cls.BOLD}{color}{title}{cls.RESET}{cls.DIM}{right_pad}{cls.RESET}\n"
64
115
 
65
- # 内容行
66
116
  lines = []
67
117
  for line in msg.split("\n"):
68
- padding = (60 - len(line) - 4) // 2
69
- left_pad = " " * padding
70
- right_pad = " " * (60 - len(line) - padding - 4)
71
- lines.append(f"{cls.DIM}║{cls.RESET}{left_pad}{line}{right_pad}{cls.DIM}║{cls.RESET}")
118
+ if len(line) > width - 4:
119
+ words = line.split()
120
+ current_line = ""
121
+ for word in words:
122
+ if len(current_line) + len(word) + 1 > width - 4:
123
+ lines.append(f"{cls.DIM}│{cls.RESET} {current_line.ljust(width-4)} {cls.DIM}│{cls.RESET}")
124
+ current_line = word
125
+ else:
126
+ current_line += (" " + word) if current_line else word
127
+ if current_line:
128
+ lines.append(f"{cls.DIM}│{cls.RESET} {current_line.ljust(width-4)} {cls.DIM}│{cls.RESET}")
129
+ else:
130
+ lines.append(f"{cls.DIM}│{cls.RESET} {line.ljust(width-4)} {cls.DIM}│{cls.RESET}")
72
131
 
73
- # 底部边框
74
- bottom_border = f"{cls.DIM}╚{border_char}╝{cls.RESET}"
132
+ if level == "error":
133
+ border_style = ""
134
+ elif level == "warning":
135
+ border_style = "╧"
136
+ else:
137
+ border_style = "└"
138
+ bottom_border = f"{cls.DIM}{border_style}{border_char}┘{cls.RESET}"
75
139
 
76
- # 组合所有部分
77
- panel = f"{title_line}{border_char}\n"
140
+ panel = f"{title_line}"
141
+ panel += f"{cls.DIM}{border_char}┤{cls.RESET}\n"
78
142
  panel += "\n".join(lines) + "\n"
79
- panel += f"{border_char}\n{bottom_border}\n"
143
+ panel += f"{bottom_border}\n"
80
144
 
81
145
  print(panel)
82
146
 
83
147
  @classmethod
84
148
  def table(cls, headers, rows, title=None, level="info") -> None:
85
- """改进的表格输出,带有颜色和分隔线"""
86
149
  color = cls._get_color(level)
87
150
  if title:
88
151
  print(f"{cls.BOLD}{color}== {title} =={cls.RESET}")
89
152
 
90
- # 计算列宽
91
153
  col_widths = [len(h) for h in headers]
92
154
  for row in rows:
93
155
  for i, cell in enumerate(row):
94
156
  col_widths[i] = max(col_widths[i], len(str(cell)))
95
157
 
96
- # 构建标题格式
97
158
  fmt = "│".join(f" {{:<{w}}} " for w in col_widths)
98
159
 
99
- # 顶部边框
100
160
  top_border = "┌" + "┬".join("─" * (w+2) for w in col_widths) + "┐"
101
161
  print(f"{cls.DIM}{top_border}{cls.RESET}")
102
162
 
103
- # 表头
104
163
  header_line = fmt.format(*headers)
105
164
  print(f"{cls.BOLD}{color}│{header_line}│{cls.RESET}")
106
165
 
107
- # 表头分隔线
108
166
  separator = "├" + "┼".join("─" * (w+2) for w in col_widths) + "┤"
109
167
  print(f"{cls.DIM}{separator}{cls.RESET}")
110
168
 
111
- # 表格内容
112
169
  for row in rows:
113
170
  row_line = fmt.format(*row)
114
171
  print(f"│{row_line}│")
115
172
 
116
- # 底部边框
117
173
  bottom_border = "└" + "┴".join("─" * (w+2) for w in col_widths) + "┘"
118
174
  print(f"{cls.DIM}{bottom_border}{cls.RESET}")
119
175
 
120
176
  @classmethod
121
177
  def progress_bar(cls, current, total, prefix="", suffix="", length=50):
122
- """显示进度条"""
123
178
  filled_length = int(length * current // total)
124
179
  percent = min(100.0, 100 * (current / float(total)))
125
180
  bar = f"{cls.GREEN}{'█' * filled_length}{cls.WHITE}{'░' * (length - filled_length)}{cls.RESET}"
@@ -130,7 +185,6 @@ class Shell_Printer:
130
185
 
131
186
  @classmethod
132
187
  def confirm(cls, msg, default=False) -> bool:
133
- """带颜色和默认选择的确认对话框"""
134
188
  yes_options = {'y', 'yes'}
135
189
  no_options = {'n', 'no'}
136
190
  default_str = "Y/n" if default else "y/N"
@@ -148,7 +202,6 @@ class Shell_Printer:
148
202
 
149
203
  @classmethod
150
204
  def ask(cls, msg, choices=None, default=None) -> str | None:
151
- """带颜色和选择的提问"""
152
205
  prompt = f"{cls.BOLD}{msg}{cls.RESET}"
153
206
  if choices:
154
207
  prompt += f" ({cls.CYAN}{'/'.join(choices)}{cls.RESET})"
@@ -166,7 +219,6 @@ class Shell_Printer:
166
219
 
167
220
  @classmethod
168
221
  def status(cls, msg, success=True):
169
- """显示状态指示器"""
170
222
  symbol = f"{cls.GREEN}✓" if success else f"{cls.RED}✗"
171
223
  print(f"\r{symbol}{cls.RESET} {msg}")
172
224
 
@@ -179,10 +231,29 @@ class SourceManager:
179
231
  def _init_sources(self):
180
232
  if not env.get('origins'):
181
233
  env.set('origins', [])
234
+
235
+ primary_source = "https://erisdev.com/map.json"
236
+ secondary_source = "https://raw.githubusercontent.com/ErisPulse/ErisPulse-ModuleRepo/refs/heads/main/map.json"
237
+
238
+ shellprint.status("正在验证主源...")
239
+ validated_url = asyncio.run(self._validate_url(primary_source))
240
+
241
+ if validated_url:
242
+ env.set('origins', [validated_url])
243
+ shellprint.status(f"主源 {validated_url} 已成功添加")
244
+ else:
245
+ if secondary_source not in env.get('origins', []):
246
+ env.set('origins', [secondary_source])
247
+ shellprint.panel(
248
+ f"主源不可用,已添加备用源 {secondary_source}\n\n"
249
+ f"{Shell_Printer.YELLOW}提示:{Shell_Printer.RESET} 建议尽快升级 ErisPulse SDK 版本",
250
+ "源初始化",
251
+ "warning"
252
+ )
182
253
 
183
254
  async def _validate_url(self, url):
184
255
  if not url.startswith(('http://', 'https://')):
185
- protocol = shellprint.confirm("未指定协议,请输入使用的协议", choices=['http', 'https'], default="https")
256
+ protocol = shellprint.ask("未指定协议,请输入使用的协议", choices=['http', 'https'], default="https")
186
257
  url = f"{protocol}://{url}"
187
258
  if not url.endswith('.json'):
188
259
  url = f"{url}/map.json"
@@ -190,10 +261,12 @@ class SourceManager:
190
261
  async with aiohttp.ClientSession() as session:
191
262
  async with session.get(url) as response:
192
263
  response.raise_for_status()
193
- if response.headers.get('Content-Type', '').startswith('application/json'):
264
+ try:
265
+ content = await response.text()
266
+ json.loads(content)
194
267
  return url
195
- else:
196
- shellprint.panel(f"源 {url} 返回的内容不是有效的 JSON 格式", "错误", "error")
268
+ except (ValueError, json.JSONDecodeError) as e:
269
+ shellprint.panel(f"源 {url} 返回的内容不是有效的 JSON 格式: {e}", "错误", "error")
197
270
  return None
198
271
  except Exception as e:
199
272
  shellprint.panel(f"访问源 {url} 失败: {e}", "错误", "error")
@@ -230,8 +303,9 @@ class SourceManager:
230
303
  async with aiohttp.ClientSession() as session:
231
304
  async with session.get(origin) as response:
232
305
  response.raise_for_status()
233
- if response.headers.get('Content-Type', '').startswith('application/json'):
234
- content = await response.json()
306
+ try:
307
+ text = await response.text()
308
+ content = json.loads(text)
235
309
  providers[content["name"]] = content["base"]
236
310
  for module in content["modules"].keys():
237
311
  module_content = content["modules"][module]
@@ -244,8 +318,8 @@ class SourceManager:
244
318
  module,
245
319
  f"{providers[content['name']]}{module_origin_name}"
246
320
  ])
247
- else:
248
- shellprint.panel(f"源 {origin} 返回的内容不是有效的 JSON 格式", "错误", "error")
321
+ except (ValueError, json.JSONDecodeError) as e:
322
+ shellprint.panel(f"源 {origin} 返回的内容不是有效的 JSON 格式: {e}", "错误", "error")
249
323
  except Exception as e:
250
324
  shellprint.panel(f"获取 {origin} 时出错: {e}", "错误", "error")
251
325
 
@@ -1073,7 +1147,12 @@ def main():
1073
1147
  else:
1074
1148
  shellprint.panel(f"运行脚本: {Shell_Printer.BOLD}{script_path}{Shell_Printer.RESET}", "执行", "info")
1075
1149
  import runpy
1076
- runpy.run_path(script_path, run_name="__main__")
1150
+
1151
+ # 添加KeyboardInterrupt异常捕捉
1152
+ try:
1153
+ runpy.run_path(script_path, run_name="__main__")
1154
+ except KeyboardInterrupt:
1155
+ shellprint.panel("脚本执行已中断", "中断", "info")
1077
1156
 
1078
1157
  elif args.command == 'origin':
1079
1158
  if args.origin_command == 'add':
@@ -1090,7 +1169,6 @@ def main():
1090
1169
  else:
1091
1170
  origin_parser.print_help()
1092
1171
  else:
1093
- # 如果没有提供命令,显示帮助信息
1094
1172
  parser.print_help()
1095
1173
 
1096
1174
  if __name__ == "__main__":
ErisPulse/adapter.py CHANGED
@@ -1,3 +1,354 @@
1
+ """
2
+ # 适配器系统
3
+
4
+ 提供平台适配器基类、消息发送DSL和适配器管理功能。支持多平台消息处理、事件驱动和生命周期管理。
5
+
6
+ ## 核心功能
7
+ 1. 适配器基类定义
8
+ 2. 链式消息发送DSL
9
+ 3. 适配器注册和管理
10
+ 4. 事件处理系统
11
+ 5. 中间件支持
12
+
13
+ ## API 文档
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}")
37
+ ```
38
+
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
+ ```
73
+
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
+ ```
139
+
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
+ # 启动所有适配器
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)
323
+ ```
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
+ - 注意资源泄漏问题
350
+ """
351
+
1
352
  import functools
2
353
  import asyncio
3
354
  from typing import Callable, Any, Dict, List, Type, Optional, Set