ErisPulse 1.1.8__py3-none-any.whl → 1.1.11__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/adapter.py CHANGED
@@ -47,7 +47,7 @@ class BaseAdapter:
47
47
  # 绑定当前适配器的 Send 实例
48
48
  self.Send = self.__class__.Send(self)
49
49
 
50
- def on(self, event_type: str):
50
+ def on(self, event_type: str = "*"):
51
51
  def decorator(func: Callable):
52
52
  @functools.wraps(func)
53
53
  async def wrapper(*args, **kwargs):
@@ -69,11 +69,32 @@ class BaseAdapter:
69
69
  async def shutdown(self):
70
70
  raise NotImplementedError
71
71
 
72
+ def add_handler(self, *args):
73
+ if len(args) == 1:
74
+ event_type = "*"
75
+ handler = args[0]
76
+ elif len(args) == 2:
77
+ event_type, handler = args
78
+ else:
79
+ raise TypeError("add_handler() 接受 1 个(监听所有事件)或 2 个参数(指定事件类型)")
80
+
81
+ @functools.wraps(handler)
82
+ async def wrapper(*handler_args, **handler_kwargs):
83
+ return await handler(*handler_args, **handler_kwargs)
84
+
85
+ self._handlers[event_type].append(wrapper)
72
86
  async def emit(self, event_type: str, data: Any):
87
+ # 先执行中间件
73
88
  for middleware in self._middlewares:
74
89
  data = await middleware(data)
75
90
 
76
- for handler in self._handlers.get(event_type, []):
91
+ # 触发具体事件类型的处理器
92
+ if event_type in self._handlers:
93
+ for handler in self._handlers[event_type]:
94
+ await handler(data)
95
+
96
+ # 触发通配符 "*" 的处理器
97
+ for handler in self._handlers.get("*", []):
77
98
  await handler(data)
78
99
 
79
100
  async def send(self, target_type: str, target_id: str, message: Any, **kwargs):
@@ -107,6 +128,17 @@ class AdapterManager:
107
128
  self._adapters[platform] = instance
108
129
  self._platform_to_instance[platform] = instance
109
130
 
131
+ if len(platform) <= 10:
132
+ from itertools import product
133
+ combinations = [''.join(c) for c in product(*[(ch.lower(), ch.upper()) for ch in platform])]
134
+ for name in set(combinations):
135
+ setattr(self, name, instance)
136
+ else:
137
+ self.logger.warning(f"平台名 {platform} 过长,如果您是开发者,请考虑使用更短的名称")
138
+ setattr(self, platform.lower(), instance)
139
+ setattr(self, platform.upper(), instance)
140
+ setattr(self, platform.capitalize(), instance)
141
+
110
142
  return True
111
143
 
112
144
  async def startup(self, platforms: List[str] = None):
@@ -131,8 +163,6 @@ class AdapterManager:
131
163
 
132
164
  async def _run_adapter(self, adapter: BaseAdapter, platform: str):
133
165
  from . import sdk
134
- retry_count = 0
135
- max_retry = 3
136
166
 
137
167
  # 加锁防止并发启动
138
168
  if not getattr(adapter, "_starting_lock", None):
@@ -144,34 +174,51 @@ class AdapterManager:
144
174
  sdk.logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已被其他协程启动,跳过")
145
175
  return
146
176
 
147
- while retry_count < max_retry:
177
+ retry_count = 0
178
+ fixed_delay = 3 * 60 * 60
179
+ backoff_intervals = [60, 10 * 60, 30 * 60, 60 * 60]
180
+
181
+ while True:
148
182
  try:
149
183
  await adapter.start()
150
184
  self._started_instances.add(adapter)
151
185
  sdk.logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已启动")
152
- break
186
+ return
153
187
  except Exception as e:
154
188
  retry_count += 1
155
189
  sdk.logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
190
+
156
191
  try:
157
192
  await adapter.shutdown()
158
193
  except Exception as stop_err:
159
194
  sdk.logger.warning(f"停止适配器失败: {stop_err}")
160
195
 
161
- if retry_count >= max_retry:
162
- sdk.logger.critical(f"平台 {platform} 达到最大重试次数,放弃重启")
163
- raise sdk.raiserr.AdapterStartFailedError(f"平台 {platform} 适配器无法重写启动: {e}")
196
+ # 计算等待时间
197
+ if retry_count <= len(backoff_intervals):
198
+ wait_time = backoff_intervals[retry_count - 1]
199
+ else:
200
+ wait_time = fixed_delay
201
+
202
+ sdk.logger.info(f"将在 {wait_time // 60} 分钟后再次尝试重启 {platform}")
203
+ await asyncio.sleep(wait_time)
204
+
164
205
  async def shutdown(self):
165
206
  for adapter in self._adapters.values():
166
207
  await adapter.shutdown()
167
208
 
168
209
  def get(self, platform: str) -> BaseAdapter:
169
- return self._adapters.get(platform)
210
+ platform_lower = platform.lower()
211
+ for registered, instance in self._adapters.items():
212
+ if registered.lower() == platform_lower:
213
+ return instance
214
+ return None
170
215
 
171
216
  def __getattr__(self, platform: str) -> BaseAdapter:
172
- if platform not in self._adapters:
173
- raise AttributeError(f"平台 {platform} 的适配器未注册")
174
- return self._adapters[platform]
217
+ platform_lower = platform.lower()
218
+ for registered, instance in self._adapters.items():
219
+ if registered.lower() == platform_lower:
220
+ return instance
221
+ raise AttributeError(f"平台 {platform} 的适配器未注册")
175
222
 
176
223
  @property
177
224
  def platforms(self) -> list:
ErisPulse/db.py CHANGED
@@ -113,9 +113,12 @@ from ErisPulse import sdk
113
113
  try:
114
114
  with open(env_file, "w", encoding="utf-8") as f:
115
115
  f.write(content)
116
- self.logger.info("已自动生成 env.py 文件")
116
+ return True
117
117
  except Exception as e:
118
- self.logger.error(f"无法创建 env.py 文件: {e}")
118
+ from . import sdk
119
+ sdk.logger.error(f"无法创建 env.py 文件: {e}")
120
+ return False
121
+ return False
119
122
 
120
123
  def __getattr__(self, key):
121
124
  try:
ErisPulse/mods.py CHANGED
@@ -27,6 +27,11 @@ class ModuleManager:
27
27
  def set_module_status(self, module_name: str, status: bool) -> None:
28
28
  self.env.set(f"{self.status_prefix}{module_name}", bool(status))
29
29
 
30
+ module_info = self.get_module(module_name)
31
+ if module_info:
32
+ module_info["status"] = bool(status)
33
+ self.env.set(f"{self.module_prefix}{module_name}", module_info)
34
+
30
35
  def get_module_status(self, module_name: str) -> bool:
31
36
  status = self.env.get(f"{self.status_prefix}{module_name}", True)
32
37
  if isinstance(status, str):
ErisPulse/util.py CHANGED
@@ -25,9 +25,35 @@ def topological_sort(elements, dependencies, error):
25
25
  queue.append(neighbor)
26
26
  if len(sorted_list) != len(elements):
27
27
  from . import sdk
28
- sdk.logger.error(f"Topological sort failed: {sorted_list} vs {elements}")
28
+ sdk.logger.error(f"依赖导入错误: {elements} vs {sorted_list} | 发生了循环依赖")
29
29
  return sorted_list
30
30
 
31
+ def show_topology():
32
+ from . import sdk
33
+ dep_data = sdk.env.get('module_dependencies')
34
+ if not dep_data:
35
+ return "未找到模块依赖关系数据,请先运行sdk.init()"
36
+
37
+ sorted_modules = topological_sort(
38
+ dep_data['modules'],
39
+ dep_data['dependencies'],
40
+ sdk.raiserr.CycleDependencyError
41
+ )
42
+
43
+ tree = {}
44
+ for module in sorted_modules:
45
+ tree[module] = dep_data['dependencies'].get(module, [])
46
+
47
+ result = ["模块拓扑关系表:"]
48
+ for i, module in enumerate(sorted_modules, 1):
49
+ deps = dep_data['dependencies'].get(module, [])
50
+ indent = " " * (len(deps) if deps else 0)
51
+ result.append(f"{i}. {indent}{module}")
52
+ if deps:
53
+ result.append(f" {indent}└─ 依赖: {', '.join(deps)}")
54
+
55
+ return "\n".join(result)
56
+
31
57
  def ExecAsync(async_func, *args, **kwargs):
32
58
  loop = asyncio.get_event_loop()
33
59
  return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
@@ -70,4 +96,4 @@ def retry(max_attempts=3, delay=1):
70
96
  raise
71
97
  time.sleep(delay)
72
98
  return wrapper
73
- return decorator
99
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 1.1.8
3
+ Version: 1.1.11
4
4
  Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
5
5
  Author-email: "艾莉丝·格雷拉特(WSu2059)" <wsu2059@qq.com>, runoneall <runoobsteve@gmail.com>
6
6
  Classifier: Development Status :: 5 - Production/Stable
@@ -18,11 +18,23 @@ Classifier: Operating System :: OS Independent
18
18
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
19
  Requires-Python: >=3.7
20
20
  Description-Content-Type: text/markdown
21
+ License-File: LICENSE
21
22
  Requires-Dist: aiohttp
23
+ Requires-Dist: watchdog
24
+ Dynamic: license-file
22
25
 
23
26
  ![](./.github/assets/erispulse_logo.png)
27
+ **ErisPulse** 是基于 [Framer](https://github.com/FramerOrg/Framer) 构建的异步机器人开发框架。
28
+
29
+ ## 合作伙伴
30
+ [![FramerOrg](https://img.shields.io/badge/合作伙伴-FramerOrg-blue?style=flat-square)](https://github.com/FramerOrg)
31
+
32
+ ### 框架选型指南
33
+ | 需求 | 推荐框架 | 理由 |
34
+ |-------------------|----------------|-----------------------------|
35
+ | 轻量化/底层模块化 | [Framer](https://github.com/FramerOrg/Framer) | 高度解耦的模块化设计 |
36
+ | 全功能机器人开发 | ErisPulse | 开箱即用的完整解决方案 |
24
37
 
25
- 基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
26
38
 
27
39
  ## ✨ 核心特性
28
40
  - ⚡ 完全异步架构设计(async/await)
@@ -48,7 +60,7 @@ from ErisPulse import sdk, logger
48
60
  async def main():
49
61
  sdk.init()
50
62
  logger.info("ErisPulse 已启动")
51
- # 这里可以添加自定义逻辑 | 如模块的 AddHandle,AddTrigger 等
63
+ # 这里可以添加自定义逻辑
52
64
 
53
65
  if __name__ == "__main__":
54
66
  asyncio.run(main())
@@ -0,0 +1,14 @@
1
+ ErisPulse/__init__.py,sha256=tCgjl-0rUeiHV_2rdFlQ-CVTFzbKdjdqXvUApRc6Avk,8095
2
+ ErisPulse/__main__.py,sha256=ZdrOqsZU1C5wJ4CycTge9l7IUldVUDtak17yWRxnxhs,47728
3
+ ErisPulse/adapter.py,sha256=slwStdR8fNPp72o5miut9ffLjwekfljzq0c1qkA1tmg,8625
4
+ ErisPulse/db.py,sha256=DuIc19GbCQMi17BWfLjaDHnthIbdysTSRxaYVFur07w,4424
5
+ ErisPulse/logger.py,sha256=sMA1mUZvwJ8wHwdyCrgIf_VRICv_uBCkx3tmd1stF3E,6094
6
+ ErisPulse/mods.py,sha256=lNiZP2EcfUhYRnOQwROyVnmhsfmk8JAZhmbhxfC2-VQ,3513
7
+ ErisPulse/raiserr.py,sha256=z8BigWkVrBE9dD_dJa5np2YYREwdugyWXKE4_-LEO_Q,2616
8
+ ErisPulse/util.py,sha256=ux3-QRT0_JjabL6S9KChhyR1E_CSRiVYEFYV5txML1M,3406
9
+ erispulse-1.1.11.dist-info/licenses/LICENSE,sha256=plj4EYVfKAzc0ZWoC5T2vsQ86u0yLpu17NdAPeIcgVo,1066
10
+ erispulse-1.1.11.dist-info/METADATA,sha256=6_XH6PEXuF2kNGuorHF1msyRdF6R1iyybLRx0OegrXk,2751
11
+ erispulse-1.1.11.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
12
+ erispulse-1.1.11.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
13
+ erispulse-1.1.11.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
14
+ erispulse-1.1.11.dist-info/RECORD,,
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 ErisPulse
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -1,13 +0,0 @@
1
- ErisPulse/__init__.py,sha256=wNfAnZu0-jFzCLyQhfiXvj7lb0DxSLmRCBUowxUYJW0,7783
2
- ErisPulse/__main__.py,sha256=-UdhsYP_X7EagomCjo73Y_qQdXwtMbDS5KoOSrI-OcU,32181
3
- ErisPulse/adapter.py,sha256=u7XdJxIEHxGRh4RXwTX-vv1R1_oP0M6ZJBehe3rKi0I,6807
4
- ErisPulse/db.py,sha256=OIndsysBOUfSyGMhKs-YVYj9dv5D92YIAltM0ZmwrkA,4379
5
- ErisPulse/logger.py,sha256=sMA1mUZvwJ8wHwdyCrgIf_VRICv_uBCkx3tmd1stF3E,6094
6
- ErisPulse/mods.py,sha256=M9XQWUQYNZ11m845hxbewBAauWXnysy-aOdLwb5xy_M,3312
7
- ErisPulse/raiserr.py,sha256=z8BigWkVrBE9dD_dJa5np2YYREwdugyWXKE4_-LEO_Q,2616
8
- ErisPulse/util.py,sha256=b9TqyRZKkpclN2fkHmWqBl3lnBMnUbucMvKvbqD5Ws8,2541
9
- erispulse-1.1.8.dist-info/METADATA,sha256=UnKdj5QcnPTnmW0zRHWo2mxUME2CjJSM9ffcB1UUQNM,2282
10
- erispulse-1.1.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
- erispulse-1.1.8.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
12
- erispulse-1.1.8.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
13
- erispulse-1.1.8.dist-info/RECORD,,