ErisPulse 1.1.10__py3-none-any.whl → 1.1.12__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/__init__.py +9 -3
- ErisPulse/__main__.py +600 -198
- ErisPulse/adapter.py +29 -13
- ErisPulse/db.py +5 -2
- ErisPulse/mods.py +5 -0
- ErisPulse/util.py +28 -2
- {erispulse-1.1.10.dist-info → erispulse-1.1.12.dist-info}/METADATA +13 -3
- erispulse-1.1.12.dist-info/RECORD +14 -0
- erispulse-1.1.10.dist-info/RECORD +0 -14
- {erispulse-1.1.10.dist-info → erispulse-1.1.12.dist-info}/WHEEL +0 -0
- {erispulse-1.1.10.dist-info → erispulse-1.1.12.dist-info}/entry_points.txt +0 -0
- {erispulse-1.1.10.dist-info → erispulse-1.1.12.dist-info}/licenses/LICENSE +0 -0
- {erispulse-1.1.10.dist-info → erispulse-1.1.12.dist-info}/top_level.txt +0 -0
ErisPulse/adapter.py
CHANGED
|
@@ -36,14 +36,21 @@ class SendDSLBase:
|
|
|
36
36
|
|
|
37
37
|
|
|
38
38
|
class BaseAdapter:
|
|
39
|
+
class Send(SendDSLBase):
|
|
40
|
+
def Text(self, text: str):
|
|
41
|
+
"""基础文本消息发送方法,子类应该重写此方法"""
|
|
42
|
+
return asyncio.create_task(
|
|
43
|
+
self._adapter.call_api(
|
|
44
|
+
endpoint="/send",
|
|
45
|
+
content=text,
|
|
46
|
+
recvId=self._target_id,
|
|
47
|
+
recvType=self._target_type
|
|
48
|
+
)
|
|
49
|
+
)
|
|
50
|
+
|
|
39
51
|
def __init__(self):
|
|
40
52
|
self._handlers = defaultdict(list)
|
|
41
53
|
self._middlewares = []
|
|
42
|
-
|
|
43
|
-
# 检测是否有 Send 子类定义
|
|
44
|
-
if not hasattr(self.__class__, 'Send') or not issubclass(self.__class__.Send, SendDSL):
|
|
45
|
-
raise TypeError(f"{self.__class__.__name__} 必须定义 Send 嵌套类并继承 SendDSL")
|
|
46
|
-
|
|
47
54
|
# 绑定当前适配器的 Send 实例
|
|
48
55
|
self.Send = self.__class__.Send(self)
|
|
49
56
|
|
|
@@ -163,8 +170,6 @@ class AdapterManager:
|
|
|
163
170
|
|
|
164
171
|
async def _run_adapter(self, adapter: BaseAdapter, platform: str):
|
|
165
172
|
from . import sdk
|
|
166
|
-
retry_count = 0
|
|
167
|
-
max_retry = 3
|
|
168
173
|
|
|
169
174
|
# 加锁防止并发启动
|
|
170
175
|
if not getattr(adapter, "_starting_lock", None):
|
|
@@ -176,23 +181,34 @@ class AdapterManager:
|
|
|
176
181
|
sdk.logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已被其他协程启动,跳过")
|
|
177
182
|
return
|
|
178
183
|
|
|
179
|
-
|
|
184
|
+
retry_count = 0
|
|
185
|
+
fixed_delay = 3 * 60 * 60
|
|
186
|
+
backoff_intervals = [60, 10 * 60, 30 * 60, 60 * 60]
|
|
187
|
+
|
|
188
|
+
while True:
|
|
180
189
|
try:
|
|
181
190
|
await adapter.start()
|
|
182
191
|
self._started_instances.add(adapter)
|
|
183
192
|
sdk.logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已启动")
|
|
184
|
-
|
|
193
|
+
return
|
|
185
194
|
except Exception as e:
|
|
186
195
|
retry_count += 1
|
|
187
196
|
sdk.logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
|
|
197
|
+
|
|
188
198
|
try:
|
|
189
199
|
await adapter.shutdown()
|
|
190
200
|
except Exception as stop_err:
|
|
191
201
|
sdk.logger.warning(f"停止适配器失败: {stop_err}")
|
|
192
202
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
203
|
+
# 计算等待时间
|
|
204
|
+
if retry_count <= len(backoff_intervals):
|
|
205
|
+
wait_time = backoff_intervals[retry_count - 1]
|
|
206
|
+
else:
|
|
207
|
+
wait_time = fixed_delay
|
|
208
|
+
|
|
209
|
+
sdk.logger.info(f"将在 {wait_time // 60} 分钟后再次尝试重启 {platform}")
|
|
210
|
+
await asyncio.sleep(wait_time)
|
|
211
|
+
|
|
196
212
|
async def shutdown(self):
|
|
197
213
|
for adapter in self._adapters.values():
|
|
198
214
|
await adapter.shutdown()
|
|
@@ -217,4 +233,4 @@ class AdapterManager:
|
|
|
217
233
|
|
|
218
234
|
|
|
219
235
|
adapter = AdapterManager()
|
|
220
|
-
SendDSL = SendDSLBase
|
|
236
|
+
SendDSL = SendDSLBase
|
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
|
-
|
|
116
|
+
return True
|
|
117
117
|
except Exception as e:
|
|
118
|
-
|
|
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"
|
|
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.
|
|
3
|
+
Version: 1.1.12
|
|
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
|
|
@@ -20,11 +20,21 @@ Requires-Python: >=3.7
|
|
|
20
20
|
Description-Content-Type: text/markdown
|
|
21
21
|
License-File: LICENSE
|
|
22
22
|
Requires-Dist: aiohttp
|
|
23
|
+
Requires-Dist: watchdog
|
|
23
24
|
Dynamic: license-file
|
|
24
25
|
|
|
25
26
|

|
|
27
|
+
**ErisPulse** 是基于 [Framer](https://github.com/FramerOrg/Framer) 构建的异步机器人开发框架。
|
|
28
|
+
|
|
29
|
+
## 合作伙伴
|
|
30
|
+
[](https://github.com/FramerOrg)
|
|
31
|
+
|
|
32
|
+
### 框架选型指南
|
|
33
|
+
| 需求 | 推荐框架 | 理由 |
|
|
34
|
+
|-------------------|----------------|-----------------------------|
|
|
35
|
+
| 轻量化/底层模块化 | [Framer](https://github.com/FramerOrg/Framer) | 高度解耦的模块化设计 |
|
|
36
|
+
| 全功能机器人开发 | ErisPulse | 开箱即用的完整解决方案 |
|
|
26
37
|
|
|
27
|
-
基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
|
|
28
38
|
|
|
29
39
|
## ✨ 核心特性
|
|
30
40
|
- ⚡ 完全异步架构设计(async/await)
|
|
@@ -50,7 +60,7 @@ from ErisPulse import sdk, logger
|
|
|
50
60
|
async def main():
|
|
51
61
|
sdk.init()
|
|
52
62
|
logger.info("ErisPulse 已启动")
|
|
53
|
-
# 这里可以添加自定义逻辑
|
|
63
|
+
# 这里可以添加自定义逻辑
|
|
54
64
|
|
|
55
65
|
if __name__ == "__main__":
|
|
56
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=5ntqm5Xrzdi1F6N4kWhqiRzMavSO92Fj9WZ-d3-V2VM,8798
|
|
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.12.dist-info/licenses/LICENSE,sha256=plj4EYVfKAzc0ZWoC5T2vsQ86u0yLpu17NdAPeIcgVo,1066
|
|
10
|
+
erispulse-1.1.12.dist-info/METADATA,sha256=BDRDFwkbWqz7WsebH1cKCbyLaCPBPumDkwFiMG2LJq4,2751
|
|
11
|
+
erispulse-1.1.12.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
+
erispulse-1.1.12.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
|
|
13
|
+
erispulse-1.1.12.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
|
|
14
|
+
erispulse-1.1.12.dist-info/RECORD,,
|
|
@@ -1,14 +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=FEIT9KzLnAJehup_3sa711vlSyecnio3tYMfHQ4i66I,8428
|
|
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.10.dist-info/licenses/LICENSE,sha256=plj4EYVfKAzc0ZWoC5T2vsQ86u0yLpu17NdAPeIcgVo,1066
|
|
10
|
-
erispulse-1.1.10.dist-info/METADATA,sha256=NCiPLZt6jJFy43WCqRmP1Jsge8FbtPRjjioCSmVSzUg,2327
|
|
11
|
-
erispulse-1.1.10.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
12
|
-
erispulse-1.1.10.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
|
|
13
|
-
erispulse-1.1.10.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
|
|
14
|
-
erispulse-1.1.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|