ErisPulse 1.0.11__tar.gz → 1.0.13__tar.gz
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-1.0.11 → erispulse-1.0.13}/ErisPulse/__init__.py +19 -21
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse/__main__.py +246 -38
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse/envManager.py +53 -39
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse/logger.py +1 -13
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse/util.py +2 -1
- erispulse-1.0.13/ErisPulse.egg-info/PKG-INFO +96 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse.egg-info/SOURCES.txt +0 -2
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse.egg-info/entry_points.txt +2 -0
- erispulse-1.0.13/PKG-INFO +96 -0
- erispulse-1.0.13/README.md +55 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/setup.py +4 -2
- erispulse-1.0.11/ErisPulse/origin.py +0 -114
- erispulse-1.0.11/ErisPulse/sdk.py +0 -3
- erispulse-1.0.11/ErisPulse.egg-info/PKG-INFO +0 -74
- erispulse-1.0.11/PKG-INFO +0 -74
- erispulse-1.0.11/README.md +0 -33
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse/errors.py +0 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse.egg-info/dependency_links.txt +0 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse.egg-info/requires.txt +0 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/ErisPulse.egg-info/top_level.txt +0 -0
- {erispulse-1.0.11 → erispulse-1.0.13}/setup.cfg +0 -0
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
|
-
|
|
3
|
+
import types
|
|
4
4
|
from . import util
|
|
5
5
|
from . import errors
|
|
6
6
|
from . import logger
|
|
7
7
|
from .envManager import env
|
|
8
8
|
|
|
9
|
+
sdk = types.SimpleNamespace()
|
|
9
10
|
setattr(sdk, "env", env)
|
|
10
11
|
setattr(sdk, "logger", logger)
|
|
11
12
|
setattr(sdk, "util", util)
|
|
12
13
|
|
|
13
14
|
env.load_env_file()
|
|
14
15
|
|
|
15
|
-
def init(
|
|
16
|
+
def init():
|
|
16
17
|
try:
|
|
17
|
-
|
|
18
|
-
sdkModulePath = os.path.join(os.getcwd(), "modules")
|
|
19
|
-
else:
|
|
20
|
-
sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
|
|
18
|
+
sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
|
|
21
19
|
|
|
22
20
|
if not os.path.exists(sdkModulePath):
|
|
23
21
|
os.makedirs(sdkModulePath)
|
|
@@ -38,35 +36,35 @@ def init(dev_mode=False):
|
|
|
38
36
|
if not hasattr(moduleObj, "moduleInfo") or not isinstance(moduleObj.moduleInfo, dict):
|
|
39
37
|
logger.warning(f"模块 {module_name} 缺少有效的 'moduleInfo' 字典.")
|
|
40
38
|
continue
|
|
41
|
-
if "name" not in moduleObj.moduleInfo:
|
|
39
|
+
if "name" not in moduleObj.moduleInfo.get("meta", {}):
|
|
42
40
|
logger.warning(f"模块 {module_name} 的 'moduleInfo' 字典 缺少必要 'name' 键.")
|
|
43
41
|
continue
|
|
44
42
|
if not hasattr(moduleObj, "Main"):
|
|
45
43
|
logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
|
|
46
44
|
continue
|
|
47
45
|
|
|
48
|
-
module_info = env.get_module(moduleObj.moduleInfo
|
|
46
|
+
module_info = env.get_module(moduleObj.moduleInfo.get("meta", {}).get("name", None))
|
|
49
47
|
if module_info is None:
|
|
50
48
|
module_info = {
|
|
51
49
|
"status": True,
|
|
52
50
|
"info": moduleObj.moduleInfo
|
|
53
51
|
}
|
|
54
|
-
env.set_module(moduleObj.moduleInfo
|
|
55
|
-
logger.info(f"模块 {moduleObj.moduleInfo
|
|
52
|
+
env.set_module(moduleObj.moduleInfo.get("meta", {}).get("name", None), module_info)
|
|
53
|
+
logger.info(f"模块 {moduleObj.moduleInfo.get("meta", {}).get("name", None)} 信息已初始化并存储到数据库")
|
|
56
54
|
|
|
57
55
|
if not module_info.get('status', True):
|
|
58
56
|
disabledModules.append(module_name)
|
|
59
|
-
logger.warning(f"模块 {moduleObj.moduleInfo
|
|
57
|
+
logger.warning(f"模块 {moduleObj.moduleInfo.get("meta", {}).get("name", None)} 已禁用,跳过加载")
|
|
60
58
|
continue
|
|
61
59
|
|
|
62
|
-
required_deps = moduleObj.moduleInfo.get("dependencies", [])
|
|
60
|
+
required_deps = moduleObj.moduleInfo.get("dependencies", []).get("requires", [])
|
|
63
61
|
missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
|
|
64
62
|
if missing_required_deps:
|
|
65
63
|
logger.error(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
|
|
66
64
|
raise errors.MissingDependencyError(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
|
|
67
65
|
|
|
68
66
|
# 检查可选依赖部分
|
|
69
|
-
optional_deps = moduleObj.moduleInfo.get("
|
|
67
|
+
optional_deps = moduleObj.moduleInfo.get("dependencies", []).get("optional", [])
|
|
70
68
|
if optional_deps:
|
|
71
69
|
available_optional_deps = []
|
|
72
70
|
for dep in optional_deps:
|
|
@@ -90,9 +88,9 @@ def init(dev_mode=False):
|
|
|
90
88
|
sdkModuleDependencies = {}
|
|
91
89
|
for module_name in sdkInstalledModuleNames:
|
|
92
90
|
moduleObj = __import__(module_name)
|
|
93
|
-
moduleDependecies: list[str] = moduleObj.moduleInfo.get("dependencies", [])
|
|
91
|
+
moduleDependecies: list[str] = moduleObj.moduleInfo.get("dependencies", []).get("requires", [])
|
|
94
92
|
|
|
95
|
-
optional_deps = moduleObj.moduleInfo.get("
|
|
93
|
+
optional_deps = moduleObj.moduleInfo.get("dependencies", []).get("optional", [])
|
|
96
94
|
available_optional_deps = [dep for dep in optional_deps if dep in sdkInstalledModuleNames]
|
|
97
95
|
moduleDependecies.extend(available_optional_deps)
|
|
98
96
|
|
|
@@ -116,8 +114,8 @@ def init(dev_mode=False):
|
|
|
116
114
|
moduleObj = __import__(module_name)
|
|
117
115
|
moduleInfo: dict = moduleObj.moduleInfo
|
|
118
116
|
|
|
119
|
-
module_info = env.get_module(moduleInfo
|
|
120
|
-
env.set_module(moduleInfo
|
|
117
|
+
module_info = env.get_module(moduleInfo.get("meta", {}).get("name", None))
|
|
118
|
+
env.set_module(moduleInfo.get("meta", {}).get("name", None), {
|
|
121
119
|
"status": True,
|
|
122
120
|
"info": moduleInfo
|
|
123
121
|
})
|
|
@@ -126,14 +124,14 @@ def init(dev_mode=False):
|
|
|
126
124
|
for module_name in sdkInstalledModuleNames:
|
|
127
125
|
moduleObj = __import__(module_name)
|
|
128
126
|
moduleInfo = moduleObj.moduleInfo
|
|
129
|
-
module_status = env.get_module_status(moduleInfo
|
|
127
|
+
module_status = env.get_module_status(moduleInfo.get("meta", {}).get("name", None))
|
|
130
128
|
if not module_status:
|
|
131
129
|
continue
|
|
132
130
|
|
|
133
|
-
moduleMain = moduleObj.Main(sdk
|
|
131
|
+
moduleMain = moduleObj.Main(sdk)
|
|
134
132
|
setattr(moduleMain, "moduleInfo", moduleInfo)
|
|
135
|
-
setattr(sdk, moduleInfo
|
|
136
|
-
logger.debug(f"模块 {moduleInfo
|
|
133
|
+
setattr(sdk, moduleInfo.get("meta", {}).get("name", None), moduleMain)
|
|
134
|
+
logger.debug(f"模块 {moduleInfo.get("meta", {}).get("name", None)} 正在初始化")
|
|
137
135
|
except Exception as e:
|
|
138
136
|
logger.error(f"初始化失败: {e}")
|
|
139
137
|
raise e
|
|
@@ -17,10 +17,171 @@ from prompt_toolkit import PromptSession
|
|
|
17
17
|
from prompt_toolkit.completion import WordCompleter
|
|
18
18
|
from prompt_toolkit.formatted_text import HTML
|
|
19
19
|
from .envManager import env
|
|
20
|
-
from .origin import origin_manager
|
|
21
20
|
|
|
22
21
|
console = Console()
|
|
22
|
+
class SourceManager:
|
|
23
|
+
def __init__(self):
|
|
24
|
+
self._init_sources()
|
|
25
|
+
|
|
26
|
+
def _init_sources(self):
|
|
27
|
+
if not env.get('origins'):
|
|
28
|
+
env.set('origins', [])
|
|
29
|
+
|
|
30
|
+
async def _validate_url(self, url):
|
|
31
|
+
if not url.startswith(('http://', 'https://')):
|
|
32
|
+
protocol = Prompt.ask("未指定协议,请输入使用的协议",
|
|
33
|
+
choices=['http', 'https'],
|
|
34
|
+
default="https")
|
|
35
|
+
url = f"{protocol}://{url}"
|
|
36
|
+
|
|
37
|
+
if not url.endswith('.json'):
|
|
38
|
+
url = f"{url}/map.json"
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
async with aiohttp.ClientSession() as session:
|
|
42
|
+
async with session.get(url) as response:
|
|
43
|
+
response.raise_for_status()
|
|
44
|
+
if response.headers.get('Content-Type', '').startswith('application/json'):
|
|
45
|
+
return url
|
|
46
|
+
else:
|
|
47
|
+
console.print(Panel(
|
|
48
|
+
f"[red]源 {url} 返回的内容不是有效的 JSON 格式[/red]",
|
|
49
|
+
title="错误",
|
|
50
|
+
border_style="red"
|
|
51
|
+
))
|
|
52
|
+
return None
|
|
53
|
+
except Exception as e:
|
|
54
|
+
console.print(Panel(
|
|
55
|
+
f"[red]访问源 {url} 失败: {e}[/red]",
|
|
56
|
+
title="错误",
|
|
57
|
+
border_style="red"
|
|
58
|
+
))
|
|
59
|
+
return None
|
|
60
|
+
|
|
61
|
+
def add_source(self, value):
|
|
62
|
+
validated_url = asyncio.run(self._validate_url(value))
|
|
63
|
+
if not validated_url:
|
|
64
|
+
console.print(Panel(
|
|
65
|
+
"[red]提供的源不是一个有效源,请检查后重试[/red]",
|
|
66
|
+
title="错误",
|
|
67
|
+
border_style="red"
|
|
68
|
+
))
|
|
69
|
+
return False
|
|
23
70
|
|
|
71
|
+
origins = env.get('origins')
|
|
72
|
+
if validated_url not in origins:
|
|
73
|
+
origins.append(validated_url)
|
|
74
|
+
env.set('origins', origins)
|
|
75
|
+
console.print(Panel(
|
|
76
|
+
f"[green]源 {validated_url} 已成功添加[/green]",
|
|
77
|
+
border_style="green"
|
|
78
|
+
))
|
|
79
|
+
return True
|
|
80
|
+
else:
|
|
81
|
+
console.print(Panel(
|
|
82
|
+
f"[yellow]源 {validated_url} 已存在,无需重复添加[/yellow]",
|
|
83
|
+
border_style="yellow"
|
|
84
|
+
))
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
def update_sources(self):
|
|
88
|
+
origins = env.get('origins')
|
|
89
|
+
providers = {}
|
|
90
|
+
modules = {}
|
|
91
|
+
module_alias = {}
|
|
92
|
+
|
|
93
|
+
table = Table(
|
|
94
|
+
title="源更新状态",
|
|
95
|
+
show_header=True,
|
|
96
|
+
header_style="bold magenta",
|
|
97
|
+
box=box.ROUNDED
|
|
98
|
+
)
|
|
99
|
+
table.add_column("源", style="cyan")
|
|
100
|
+
table.add_column("模块", style="green")
|
|
101
|
+
table.add_column("地址", style="blue")
|
|
102
|
+
|
|
103
|
+
async def fetch_source_data():
|
|
104
|
+
async with aiohttp.ClientSession() as session:
|
|
105
|
+
for origin in origins:
|
|
106
|
+
console.print(f"[cyan]正在获取 {origin}...[/cyan]")
|
|
107
|
+
try:
|
|
108
|
+
async with session.get(origin) as response:
|
|
109
|
+
response.raise_for_status()
|
|
110
|
+
if response.headers.get('Content-Type', '').startswith('application/json'):
|
|
111
|
+
content = await response.json()
|
|
112
|
+
providers[content["name"]] = content["base"]
|
|
113
|
+
|
|
114
|
+
for module in content["modules"].keys():
|
|
115
|
+
module_content = content["modules"][module]
|
|
116
|
+
modules[f'{module}@{content["name"]}'] = module_content
|
|
117
|
+
module_origin_name = module_content["path"]
|
|
118
|
+
module_alias_name = module
|
|
119
|
+
module_alias[f'{module_origin_name}@{content["name"]}'] = module_alias_name
|
|
120
|
+
|
|
121
|
+
table.add_row(
|
|
122
|
+
content['name'],
|
|
123
|
+
module,
|
|
124
|
+
f"{providers[content['name']]}{module_origin_name}"
|
|
125
|
+
)
|
|
126
|
+
else:
|
|
127
|
+
console.print(Panel(
|
|
128
|
+
f"[red]源 {origin} 返回的内容不是有效的 JSON 格式[/red]",
|
|
129
|
+
title="错误",
|
|
130
|
+
border_style="red"
|
|
131
|
+
))
|
|
132
|
+
except Exception as e:
|
|
133
|
+
console.print(Panel(
|
|
134
|
+
f"[red]获取 {origin} 时出错: {e}[/red]",
|
|
135
|
+
title="错误",
|
|
136
|
+
border_style="red"
|
|
137
|
+
))
|
|
138
|
+
|
|
139
|
+
asyncio.run(fetch_source_data())
|
|
140
|
+
console.print(table)
|
|
141
|
+
from datetime import datetime
|
|
142
|
+
env.set('providers', providers)
|
|
143
|
+
env.set('modules', modules)
|
|
144
|
+
env.set('module_alias', module_alias)
|
|
145
|
+
env.set('last_origin_update_time', datetime.now().isoformat())
|
|
146
|
+
|
|
147
|
+
console.print(Panel(
|
|
148
|
+
"[green]源更新完成[/green]",
|
|
149
|
+
border_style="green"
|
|
150
|
+
))
|
|
151
|
+
|
|
152
|
+
def list_sources(self):
|
|
153
|
+
origins = env.get('origins')
|
|
154
|
+
if not origins:
|
|
155
|
+
console.print(Panel(
|
|
156
|
+
"[yellow]当前没有配置任何源[/yellow]",
|
|
157
|
+
border_style="yellow"
|
|
158
|
+
))
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
table = Table(title="已配置的源", show_header=True, header_style="bold magenta")
|
|
162
|
+
table.add_column("序号", style="cyan", justify="center")
|
|
163
|
+
table.add_column("源地址", style="green")
|
|
164
|
+
|
|
165
|
+
for idx, origin in enumerate(origins, 1):
|
|
166
|
+
table.add_row(str(idx), origin)
|
|
167
|
+
|
|
168
|
+
console.print(table)
|
|
169
|
+
|
|
170
|
+
def del_source(self, value):
|
|
171
|
+
origins = env.get('origins')
|
|
172
|
+
if value in origins:
|
|
173
|
+
origins.remove(value)
|
|
174
|
+
env.set('origins', origins)
|
|
175
|
+
console.print(Panel(
|
|
176
|
+
f"[green]源 {value} 已成功删除[/green]",
|
|
177
|
+
border_style="green"
|
|
178
|
+
))
|
|
179
|
+
else:
|
|
180
|
+
console.print(Panel(
|
|
181
|
+
f"[red]源 {value} 不存在[/red]",
|
|
182
|
+
title="错误",
|
|
183
|
+
border_style="red"
|
|
184
|
+
))
|
|
24
185
|
def enable_module(module_name):
|
|
25
186
|
module_info = env.get_module(module_name)
|
|
26
187
|
if module_info:
|
|
@@ -157,16 +318,17 @@ def install_module(module_name, force=False):
|
|
|
157
318
|
)
|
|
158
319
|
if update_confirmation:
|
|
159
320
|
with console.status("[cyan]正在更新源...[/cyan]"):
|
|
160
|
-
|
|
321
|
+
SourceManager().update_sources()
|
|
161
322
|
env.set('last_origin_update_time', datetime.now().isoformat())
|
|
162
323
|
console.print("[green]✓ 源更新完成[/green]")
|
|
163
324
|
|
|
164
325
|
module_info = env.get_module(module_name)
|
|
165
326
|
if module_info and not force:
|
|
327
|
+
meta = module_info.get('info', {}).get('meta', {})
|
|
166
328
|
console.print(Panel(
|
|
167
329
|
f"[yellow]模块 {module_name} 已存在[/yellow]\n"
|
|
168
|
-
f"版本: {
|
|
169
|
-
f"描述: {
|
|
330
|
+
f"版本: {meta.get('version', '未知')}\n"
|
|
331
|
+
f"描述: {meta.get('description', '无描述')}",
|
|
170
332
|
title="模块已存在",
|
|
171
333
|
border_style="yellow"
|
|
172
334
|
))
|
|
@@ -186,16 +348,21 @@ def install_module(module_name, force=False):
|
|
|
186
348
|
|
|
187
349
|
if module_key in modules_data:
|
|
188
350
|
module_data = modules_data[module_key]
|
|
351
|
+
console.print(f"[cyan]正在处理模块 {module_name} 源: {provider}...[/cyan]")
|
|
352
|
+
console.print(f"[cyan]源地址: {url}[/cyan] | 信息: {module_data}")
|
|
353
|
+
meta = module_data.get("meta", {})
|
|
354
|
+
depsinfo = module_data.get("dependencies", {})
|
|
355
|
+
|
|
189
356
|
module_info.append({
|
|
190
357
|
'provider': provider,
|
|
191
358
|
'url': url,
|
|
192
359
|
'path': module_data.get('path', ''),
|
|
193
|
-
'version':
|
|
194
|
-
'description':
|
|
195
|
-
'author':
|
|
196
|
-
'dependencies':
|
|
197
|
-
'optional_dependencies':
|
|
198
|
-
'pip_dependencies':
|
|
360
|
+
'version': meta.get('version', '未知'),
|
|
361
|
+
'description': meta.get('description', '无描述'),
|
|
362
|
+
'author': meta.get('author', '未知'),
|
|
363
|
+
'dependencies': depsinfo.get("requires", []),
|
|
364
|
+
'optional_dependencies': depsinfo.get("optional", []),
|
|
365
|
+
'pip_dependencies': depsinfo.get("pip", [])
|
|
199
366
|
})
|
|
200
367
|
|
|
201
368
|
if not module_info:
|
|
@@ -219,7 +386,8 @@ def install_module(module_name, force=False):
|
|
|
219
386
|
table.add_column("描述", style="white")
|
|
220
387
|
table.add_column("作者", style="yellow")
|
|
221
388
|
for i, info in enumerate(module_info):
|
|
222
|
-
|
|
389
|
+
console.print(info)
|
|
390
|
+
table.add_row(str(i+1), info['provider'], info.get('meta', {}).get('version', '未知'), info.get('description', {}).get('requires'), info.get('meta', {}).get('author', '未知'))
|
|
223
391
|
console.print(table)
|
|
224
392
|
|
|
225
393
|
while True:
|
|
@@ -259,12 +427,17 @@ def install_module(module_name, force=False):
|
|
|
259
427
|
env.set_module(module_name, {
|
|
260
428
|
'status': True,
|
|
261
429
|
'info': {
|
|
262
|
-
'
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
430
|
+
'meta': {
|
|
431
|
+
'version': selected_module['version'],
|
|
432
|
+
'description': selected_module['description'],
|
|
433
|
+
'author': selected_module['author'],
|
|
434
|
+
'pip_dependencies': selected_module['pip_dependencies']
|
|
435
|
+
},
|
|
436
|
+
'dependencies': {
|
|
437
|
+
'requires': selected_module['dependencies'],
|
|
438
|
+
'optional': selected_module['optional_dependencies'],
|
|
439
|
+
'pip': selected_module['pip_dependencies']
|
|
440
|
+
}
|
|
268
441
|
}
|
|
269
442
|
})
|
|
270
443
|
console.print(f"[green]模块 {module_name} 安装成功[/green]")
|
|
@@ -285,12 +458,14 @@ def uninstall_module(module_name):
|
|
|
285
458
|
border_style="red"
|
|
286
459
|
))
|
|
287
460
|
return
|
|
288
|
-
|
|
461
|
+
meta = module_info.get('info', {}).get('meta', {})
|
|
462
|
+
depsinfo = module_info.get('info', {}).get('dependencies', {})
|
|
463
|
+
|
|
289
464
|
# 显示模块信息
|
|
290
465
|
console.print(Panel(
|
|
291
|
-
f"版本: {
|
|
292
|
-
f"描述: {
|
|
293
|
-
f"pip依赖: {', '.join(
|
|
466
|
+
f"版本: {meta.get('version', '未知')}\n"
|
|
467
|
+
f"描述: {meta.get('description', '无描述')}\n"
|
|
468
|
+
f"pip依赖: {', '.join(depsinfo.get('pip', [])) or '无'}",
|
|
294
469
|
title="模块信息",
|
|
295
470
|
border_style="green"
|
|
296
471
|
))
|
|
@@ -330,8 +505,8 @@ def uninstall_module(module_name):
|
|
|
330
505
|
border_style="red"
|
|
331
506
|
))
|
|
332
507
|
return
|
|
333
|
-
|
|
334
|
-
pip_dependencies =
|
|
508
|
+
|
|
509
|
+
pip_dependencies = depsinfo.get('pip', [])
|
|
335
510
|
if pip_dependencies:
|
|
336
511
|
all_modules = env.get_all_modules()
|
|
337
512
|
unused_pip_dependencies = []
|
|
@@ -345,7 +520,7 @@ def uninstall_module(module_name):
|
|
|
345
520
|
|
|
346
521
|
is_dependency_used = False
|
|
347
522
|
for name, info in all_modules.items():
|
|
348
|
-
if name != module_name and dep in info.get('info', {}).get('
|
|
523
|
+
if name != module_name and dep in info.get('info', {}).get('dependencies', {}).get('pip', []):
|
|
349
524
|
is_dependency_used = True
|
|
350
525
|
break
|
|
351
526
|
if not is_dependency_used:
|
|
@@ -405,12 +580,12 @@ def upgrade_all_modules(force=False):
|
|
|
405
580
|
|
|
406
581
|
updates_available = []
|
|
407
582
|
for module_name, module_info in all_modules.items():
|
|
408
|
-
local_version = module_info
|
|
583
|
+
local_version = module_info.get('info', []).get('meta', []).get('version', '0.0.0')
|
|
409
584
|
for provider, url in providers.items():
|
|
410
585
|
module_key = f"{module_name}@{provider}"
|
|
411
586
|
if module_key in modules_data:
|
|
412
587
|
remote_module = modules_data[module_key]
|
|
413
|
-
remote_version = remote_module.get('version', '
|
|
588
|
+
remote_version = remote_module.get('meta', {}).get('version', '1.14.514')
|
|
414
589
|
if remote_version > local_version:
|
|
415
590
|
updates_available.append({
|
|
416
591
|
'name': module_name,
|
|
@@ -502,15 +677,44 @@ def list_modules(module_name=None):
|
|
|
502
677
|
|
|
503
678
|
for name, info in all_modules.items():
|
|
504
679
|
status = "[green]✓[/green]" if info.get("status", True) else "[red]✗[/red]"
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
680
|
+
meta = info.get('info', {}).get('meta', {})
|
|
681
|
+
depsinfo = info.get('info', {}).get('dependencies', {})
|
|
682
|
+
optional_deps = depsinfo.get('optional', [])
|
|
683
|
+
available_optional_deps = []
|
|
684
|
+
missing_optional_deps = []
|
|
685
|
+
|
|
686
|
+
if optional_deps:
|
|
687
|
+
for dep in optional_deps:
|
|
688
|
+
if isinstance(dep, list):
|
|
689
|
+
# 处理嵌套列表
|
|
690
|
+
available_deps = [d for d in dep if d in all_modules]
|
|
691
|
+
if available_deps:
|
|
692
|
+
available_optional_deps.extend(available_deps)
|
|
693
|
+
else:
|
|
694
|
+
missing_optional_deps.extend(dep)
|
|
695
|
+
elif dep in all_modules:
|
|
696
|
+
# 单个字符串依赖
|
|
697
|
+
available_optional_deps.append(dep)
|
|
698
|
+
else:
|
|
699
|
+
missing_optional_deps.append(dep)
|
|
700
|
+
|
|
701
|
+
optional_dependencies = (
|
|
702
|
+
f"[green]可用: {', '.join(available_optional_deps)}[/green]\n"
|
|
703
|
+
f"[red]缺失: {', '.join(missing_optional_deps)}[/red]"
|
|
704
|
+
if missing_optional_deps
|
|
705
|
+
else ', '.join(available_optional_deps) or '无'
|
|
706
|
+
)
|
|
707
|
+
else:
|
|
708
|
+
optional_dependencies = '无'
|
|
709
|
+
|
|
710
|
+
dependencies = '\n'.join(depsinfo.get('requires', [])) or '无'
|
|
711
|
+
pip_dependencies = '\n'.join(depsinfo.get('pip', [])) or '无'
|
|
712
|
+
|
|
509
713
|
table.add_row(
|
|
510
714
|
f"[bold]{name}[/bold]",
|
|
511
715
|
status,
|
|
512
|
-
|
|
513
|
-
|
|
716
|
+
meta.get('version', '未知'),
|
|
717
|
+
meta.get('description', '无描述'),
|
|
514
718
|
dependencies,
|
|
515
719
|
optional_dependencies,
|
|
516
720
|
pip_dependencies
|
|
@@ -571,6 +775,7 @@ def main():
|
|
|
571
775
|
del_origin_parser.add_argument('url', type=str, help='要删除的模块源URL')
|
|
572
776
|
|
|
573
777
|
args = parser.parse_args()
|
|
778
|
+
source_manager = SourceManager()
|
|
574
779
|
|
|
575
780
|
# 初始化模块数据库
|
|
576
781
|
if hasattr(args, 'init') and args.init:
|
|
@@ -700,20 +905,23 @@ def main():
|
|
|
700
905
|
else:
|
|
701
906
|
install_module(module_name, args.force)
|
|
702
907
|
elif args.command == 'update':
|
|
703
|
-
|
|
908
|
+
SourceManager().update_sources()
|
|
704
909
|
elif args.command == 'upgrade':
|
|
705
910
|
upgrade_all_modules(args.force)
|
|
706
911
|
elif args.command == 'origin':
|
|
707
912
|
if args.origin_command == 'add':
|
|
708
|
-
success =
|
|
913
|
+
success = source_manager.add_source(args.url)
|
|
709
914
|
if success:
|
|
710
|
-
update_confirmation = Confirm.ask(
|
|
915
|
+
update_confirmation = Confirm.ask(
|
|
916
|
+
"[yellow]源已添加,是否立即更新源以获取最新模块信息?[/yellow]",
|
|
917
|
+
default=True
|
|
918
|
+
)
|
|
711
919
|
if update_confirmation:
|
|
712
|
-
|
|
920
|
+
source_manager.update_sources()
|
|
713
921
|
elif args.origin_command == 'list':
|
|
714
|
-
|
|
922
|
+
source_manager.list_sources()
|
|
715
923
|
elif args.origin_command == 'del':
|
|
716
|
-
|
|
924
|
+
source_manager.del_source(args.url)
|
|
717
925
|
else:
|
|
718
926
|
origin_parser.print_help()
|
|
719
927
|
else:
|
|
@@ -111,11 +111,13 @@ class EnvManager:
|
|
|
111
111
|
""", (module_name,))
|
|
112
112
|
result = cursor.fetchone()
|
|
113
113
|
return bool(result[0]) if result else True
|
|
114
|
-
|
|
114
|
+
|
|
115
115
|
def set_all_modules(self, modules_info):
|
|
116
116
|
with sqlite3.connect(self.db_path) as conn:
|
|
117
117
|
cursor = conn.cursor()
|
|
118
118
|
for module_name, module_info in modules_info.items():
|
|
119
|
+
meta = module_info.get('info', {}).get('meta', {})
|
|
120
|
+
dependencies = module_info.get('info', {}).get('dependencies', {})
|
|
119
121
|
cursor.execute("""
|
|
120
122
|
INSERT OR REPLACE INTO modules (
|
|
121
123
|
module_name, status, version, description, author,
|
|
@@ -124,12 +126,12 @@ class EnvManager:
|
|
|
124
126
|
""", (
|
|
125
127
|
module_name,
|
|
126
128
|
int(module_info.get('status', True)),
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
json.dumps(
|
|
131
|
-
json.dumps(
|
|
132
|
-
json.dumps(
|
|
129
|
+
meta.get('version', ''),
|
|
130
|
+
meta.get('description', ''),
|
|
131
|
+
meta.get('author', ''),
|
|
132
|
+
json.dumps(dependencies.get('requires', [])),
|
|
133
|
+
json.dumps(dependencies.get('optional', [])),
|
|
134
|
+
json.dumps(dependencies.get('pip', []))
|
|
133
135
|
))
|
|
134
136
|
conn.commit()
|
|
135
137
|
|
|
@@ -144,39 +146,26 @@ class EnvManager:
|
|
|
144
146
|
modules_info[module_name] = {
|
|
145
147
|
'status': bool(status),
|
|
146
148
|
'info': {
|
|
147
|
-
'
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
149
|
+
'meta': {
|
|
150
|
+
'version': version,
|
|
151
|
+
'description': description,
|
|
152
|
+
'author': author,
|
|
153
|
+
'pip_dependencies': json.loads(pip_dependencies) if pip_dependencies else []
|
|
154
|
+
},
|
|
155
|
+
'dependencies': {
|
|
156
|
+
'requires': json.loads(dependencies) if dependencies else [],
|
|
157
|
+
'optional': json.loads(optional_dependencies) if optional_dependencies else [],
|
|
158
|
+
'pip': json.loads(pip_dependencies) if pip_dependencies else []
|
|
159
|
+
}
|
|
153
160
|
}
|
|
154
161
|
}
|
|
155
162
|
return modules_info
|
|
156
163
|
|
|
157
|
-
def get_module(self, module_name):
|
|
158
|
-
with sqlite3.connect(self.db_path) as conn:
|
|
159
|
-
cursor = conn.cursor()
|
|
160
|
-
cursor.execute("SELECT * FROM modules WHERE module_name = ?", (module_name,))
|
|
161
|
-
row = cursor.fetchone()
|
|
162
|
-
if row:
|
|
163
|
-
module_name, status, version, description, author, dependencies, optional_dependencies, pip_dependencies = row
|
|
164
|
-
return {
|
|
165
|
-
'status': bool(status),
|
|
166
|
-
'info': {
|
|
167
|
-
'version': version,
|
|
168
|
-
'description': description,
|
|
169
|
-
'author': author,
|
|
170
|
-
'dependencies': json.loads(dependencies) if dependencies else [],
|
|
171
|
-
'optional_dependencies': json.loads(optional_dependencies) if optional_dependencies else [],
|
|
172
|
-
'pip_dependencies': json.loads(pip_dependencies) if pip_dependencies else []
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
return None
|
|
176
|
-
|
|
177
164
|
def set_module(self, module_name, module_info):
|
|
178
165
|
with sqlite3.connect(self.db_path) as conn:
|
|
179
166
|
cursor = conn.cursor()
|
|
167
|
+
meta = module_info.get('info', {}).get('meta', {})
|
|
168
|
+
dependencies = module_info.get('info', {}).get('dependencies', {})
|
|
180
169
|
cursor.execute("""
|
|
181
170
|
INSERT OR REPLACE INTO modules (
|
|
182
171
|
module_name, status, version, description, author,
|
|
@@ -185,15 +174,40 @@ class EnvManager:
|
|
|
185
174
|
""", (
|
|
186
175
|
module_name,
|
|
187
176
|
int(module_info.get('status', True)),
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
json.dumps(
|
|
192
|
-
json.dumps(
|
|
193
|
-
json.dumps(
|
|
177
|
+
meta.get('version', ''),
|
|
178
|
+
meta.get('description', ''),
|
|
179
|
+
meta.get('author', ''),
|
|
180
|
+
json.dumps(dependencies.get('requires', [])),
|
|
181
|
+
json.dumps(dependencies.get('optional', [])),
|
|
182
|
+
json.dumps(dependencies.get('pip', []))
|
|
194
183
|
))
|
|
195
184
|
conn.commit()
|
|
196
185
|
|
|
186
|
+
def get_module(self, module_name):
|
|
187
|
+
with sqlite3.connect(self.db_path) as conn:
|
|
188
|
+
cursor = conn.cursor()
|
|
189
|
+
cursor.execute("SELECT * FROM modules WHERE module_name = ?", (module_name,))
|
|
190
|
+
row = cursor.fetchone()
|
|
191
|
+
if row:
|
|
192
|
+
module_name, status, version, description, author, dependencies, optional_dependencies, pip_dependencies = row
|
|
193
|
+
return {
|
|
194
|
+
'status': bool(status),
|
|
195
|
+
'info': {
|
|
196
|
+
'meta': {
|
|
197
|
+
'version': version,
|
|
198
|
+
'description': description,
|
|
199
|
+
'author': author,
|
|
200
|
+
'pip_dependencies': json.loads(pip_dependencies) if pip_dependencies else []
|
|
201
|
+
},
|
|
202
|
+
'dependencies': {
|
|
203
|
+
'requires': json.loads(dependencies) if dependencies else [],
|
|
204
|
+
'optional': json.loads(optional_dependencies) if optional_dependencies else [],
|
|
205
|
+
'pip': json.loads(pip_dependencies) if pip_dependencies else []
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return None
|
|
210
|
+
|
|
197
211
|
def update_module(self, module_name, module_info):
|
|
198
212
|
self.set_module(module_name, module_info)
|
|
199
213
|
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import inspect
|
|
3
|
-
from rich.logging import RichHandler
|
|
4
|
-
from . import sdk
|
|
5
3
|
from .envManager import env
|
|
6
4
|
|
|
7
5
|
_logger = logging.getLogger("RyhBot")
|
|
@@ -11,19 +9,10 @@ if _log_level is None:
|
|
|
11
9
|
_logger.setLevel(_log_level)
|
|
12
10
|
|
|
13
11
|
if not _logger.handlers:
|
|
14
|
-
|
|
15
|
-
console_handler = RichHandler(
|
|
16
|
-
show_time=True, # 显示时间
|
|
17
|
-
show_level=True, # 显示日志级别
|
|
18
|
-
show_path=False, # 不显示调用路径
|
|
19
|
-
markup=True, # 支持 Markdown
|
|
20
|
-
log_time_format="[%Y-%m-%d %H:%M:%S]", # 自定义时间格式
|
|
21
|
-
rich_tracebacks=True, # 支持更美观的异常堆栈
|
|
22
|
-
)
|
|
12
|
+
console_handler = logging.StreamHandler()
|
|
23
13
|
console_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
24
14
|
_logger.addHandler(console_handler)
|
|
25
15
|
|
|
26
|
-
|
|
27
16
|
def _get_caller():
|
|
28
17
|
frame = inspect.currentframe().f_back.f_back
|
|
29
18
|
module = inspect.getmodule(frame)
|
|
@@ -34,7 +23,6 @@ def _get_caller():
|
|
|
34
23
|
module_name = module_name[:-5]
|
|
35
24
|
return module_name
|
|
36
25
|
|
|
37
|
-
|
|
38
26
|
def debug(msg, *args, **kwargs):
|
|
39
27
|
caller_module = _get_caller()
|
|
40
28
|
_logger.debug(f"[{caller_module}] {msg}", *args, **kwargs)
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
from collections import defaultdict, deque
|
|
2
2
|
import asyncio
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
3
5
|
from concurrent.futures import ThreadPoolExecutor
|
|
4
6
|
|
|
5
7
|
executor = ThreadPoolExecutor()
|
|
6
8
|
|
|
7
|
-
|
|
8
9
|
def topological_sort(elements, dependencies, error):
|
|
9
10
|
graph = defaultdict(list)
|
|
10
11
|
in_degree = {element: 0 for element in elements}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ErisPulse
|
|
3
|
+
Version: 1.0.13
|
|
4
|
+
Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
5
|
+
Home-page: https://github.com/wsu2059q/ErisPulse
|
|
6
|
+
Author: 艾莉丝·格雷拉特(WSu2059)
|
|
7
|
+
Author-email: wsu2059@qq.com
|
|
8
|
+
Maintainer: runoneall
|
|
9
|
+
Maintainer-email: runoobsteve@gmail.com
|
|
10
|
+
License: MIT
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.7
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: aiohttp
|
|
27
|
+
Requires-Dist: rich
|
|
28
|
+
Requires-Dist: prompt_toolkit
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: maintainer
|
|
37
|
+
Dynamic: maintainer-email
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
Dynamic: summary
|
|
41
|
+
|
|
42
|
+
# 🚀 ErisPulse - 异步机器人开发框架
|
|
43
|
+
|
|
44
|
+
基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
|
|
45
|
+
|
|
46
|
+
## ✨ 核心特性
|
|
47
|
+
- 完全异步架构设计
|
|
48
|
+
- 模块化插件系统
|
|
49
|
+
- 多协议支持
|
|
50
|
+
- 模块热更新
|
|
51
|
+
- 跨平台兼容
|
|
52
|
+
|
|
53
|
+
## 📦 安装
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install ErisPulse --upgrade
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**系统要求**:
|
|
60
|
+
- Python ≥ 3.7
|
|
61
|
+
- pip ≥ 20.0
|
|
62
|
+
|
|
63
|
+
## 🚀 快速开始
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import asyncio
|
|
67
|
+
from ErisPulse import sdk, logger
|
|
68
|
+
|
|
69
|
+
async def main():
|
|
70
|
+
sdk.init()
|
|
71
|
+
logger.info("ErisPulse 已启动")
|
|
72
|
+
# 这里可以添加自定义逻辑 | 如模块的 AddHandle,AddTrigger 等
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 🛠️ 常用命令
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
epsdk update # 更新模块源
|
|
82
|
+
epsdk install AIChat # 安装模块
|
|
83
|
+
epsdk enable AIChat # 启用模块
|
|
84
|
+
epsdk list # 查看所有模块
|
|
85
|
+
```
|
|
86
|
+
更多命令详见 [命令行工具文档](docs/CLI.md)。
|
|
87
|
+
|
|
88
|
+
## 🧩 模块开发
|
|
89
|
+
|
|
90
|
+
你可以通过实现自定义模块扩展 ErisPulse 功能。详见 [开发指南](docs/DEVELOPMENT.md)。
|
|
91
|
+
|
|
92
|
+
## 📖 文档导航
|
|
93
|
+
- [开发指南](docs/DEVELOPMENT.md) - 完整的开发文档
|
|
94
|
+
- [命令行工具](docs/CLI.md) - CLI 使用手册
|
|
95
|
+
- [源配置指南](docs/ORIGIN.md) - 模块源配置说明
|
|
96
|
+
- [更新日志](docs/CHANGELOG.md) - 版本更新历史
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ErisPulse
|
|
3
|
+
Version: 1.0.13
|
|
4
|
+
Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
5
|
+
Home-page: https://github.com/wsu2059q/ErisPulse
|
|
6
|
+
Author: 艾莉丝·格雷拉特(WSu2059)
|
|
7
|
+
Author-email: wsu2059@qq.com
|
|
8
|
+
Maintainer: runoneall
|
|
9
|
+
Maintainer-email: runoobsteve@gmail.com
|
|
10
|
+
License: MIT
|
|
11
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
+
Classifier: Operating System :: OS Independent
|
|
23
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
+
Requires-Python: >=3.7
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
Requires-Dist: aiohttp
|
|
27
|
+
Requires-Dist: rich
|
|
28
|
+
Requires-Dist: prompt_toolkit
|
|
29
|
+
Dynamic: author
|
|
30
|
+
Dynamic: author-email
|
|
31
|
+
Dynamic: classifier
|
|
32
|
+
Dynamic: description
|
|
33
|
+
Dynamic: description-content-type
|
|
34
|
+
Dynamic: home-page
|
|
35
|
+
Dynamic: license
|
|
36
|
+
Dynamic: maintainer
|
|
37
|
+
Dynamic: maintainer-email
|
|
38
|
+
Dynamic: requires-dist
|
|
39
|
+
Dynamic: requires-python
|
|
40
|
+
Dynamic: summary
|
|
41
|
+
|
|
42
|
+
# 🚀 ErisPulse - 异步机器人开发框架
|
|
43
|
+
|
|
44
|
+
基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
|
|
45
|
+
|
|
46
|
+
## ✨ 核心特性
|
|
47
|
+
- 完全异步架构设计
|
|
48
|
+
- 模块化插件系统
|
|
49
|
+
- 多协议支持
|
|
50
|
+
- 模块热更新
|
|
51
|
+
- 跨平台兼容
|
|
52
|
+
|
|
53
|
+
## 📦 安装
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
pip install ErisPulse --upgrade
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
**系统要求**:
|
|
60
|
+
- Python ≥ 3.7
|
|
61
|
+
- pip ≥ 20.0
|
|
62
|
+
|
|
63
|
+
## 🚀 快速开始
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
import asyncio
|
|
67
|
+
from ErisPulse import sdk, logger
|
|
68
|
+
|
|
69
|
+
async def main():
|
|
70
|
+
sdk.init()
|
|
71
|
+
logger.info("ErisPulse 已启动")
|
|
72
|
+
# 这里可以添加自定义逻辑 | 如模块的 AddHandle,AddTrigger 等
|
|
73
|
+
|
|
74
|
+
if __name__ == "__main__":
|
|
75
|
+
asyncio.run(main())
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 🛠️ 常用命令
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
epsdk update # 更新模块源
|
|
82
|
+
epsdk install AIChat # 安装模块
|
|
83
|
+
epsdk enable AIChat # 启用模块
|
|
84
|
+
epsdk list # 查看所有模块
|
|
85
|
+
```
|
|
86
|
+
更多命令详见 [命令行工具文档](docs/CLI.md)。
|
|
87
|
+
|
|
88
|
+
## 🧩 模块开发
|
|
89
|
+
|
|
90
|
+
你可以通过实现自定义模块扩展 ErisPulse 功能。详见 [开发指南](docs/DEVELOPMENT.md)。
|
|
91
|
+
|
|
92
|
+
## 📖 文档导航
|
|
93
|
+
- [开发指南](docs/DEVELOPMENT.md) - 完整的开发文档
|
|
94
|
+
- [命令行工具](docs/CLI.md) - CLI 使用手册
|
|
95
|
+
- [源配置指南](docs/ORIGIN.md) - 模块源配置说明
|
|
96
|
+
- [更新日志](docs/CHANGELOG.md) - 版本更新历史
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# 🚀 ErisPulse - 异步机器人开发框架
|
|
2
|
+
|
|
3
|
+
基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
|
|
4
|
+
|
|
5
|
+
## ✨ 核心特性
|
|
6
|
+
- 完全异步架构设计
|
|
7
|
+
- 模块化插件系统
|
|
8
|
+
- 多协议支持
|
|
9
|
+
- 模块热更新
|
|
10
|
+
- 跨平台兼容
|
|
11
|
+
|
|
12
|
+
## 📦 安装
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pip install ErisPulse --upgrade
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**系统要求**:
|
|
19
|
+
- Python ≥ 3.7
|
|
20
|
+
- pip ≥ 20.0
|
|
21
|
+
|
|
22
|
+
## 🚀 快速开始
|
|
23
|
+
|
|
24
|
+
```python
|
|
25
|
+
import asyncio
|
|
26
|
+
from ErisPulse import sdk, logger
|
|
27
|
+
|
|
28
|
+
async def main():
|
|
29
|
+
sdk.init()
|
|
30
|
+
logger.info("ErisPulse 已启动")
|
|
31
|
+
# 这里可以添加自定义逻辑 | 如模块的 AddHandle,AddTrigger 等
|
|
32
|
+
|
|
33
|
+
if __name__ == "__main__":
|
|
34
|
+
asyncio.run(main())
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 🛠️ 常用命令
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
epsdk update # 更新模块源
|
|
41
|
+
epsdk install AIChat # 安装模块
|
|
42
|
+
epsdk enable AIChat # 启用模块
|
|
43
|
+
epsdk list # 查看所有模块
|
|
44
|
+
```
|
|
45
|
+
更多命令详见 [命令行工具文档](docs/CLI.md)。
|
|
46
|
+
|
|
47
|
+
## 🧩 模块开发
|
|
48
|
+
|
|
49
|
+
你可以通过实现自定义模块扩展 ErisPulse 功能。详见 [开发指南](docs/DEVELOPMENT.md)。
|
|
50
|
+
|
|
51
|
+
## 📖 文档导航
|
|
52
|
+
- [开发指南](docs/DEVELOPMENT.md) - 完整的开发文档
|
|
53
|
+
- [命令行工具](docs/CLI.md) - CLI 使用手册
|
|
54
|
+
- [源配置指南](docs/ORIGIN.md) - 模块源配置说明
|
|
55
|
+
- [更新日志](docs/CHANGELOG.md) - 版本更新历史
|
|
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|
|
2
2
|
|
|
3
3
|
setup(
|
|
4
4
|
name='ErisPulse',
|
|
5
|
-
version='1.0.
|
|
5
|
+
version='1.0.13',
|
|
6
6
|
author='艾莉丝·格雷拉特(WSu2059)',
|
|
7
7
|
author_email='wsu2059@qq.com',
|
|
8
8
|
maintainer='runoneall',
|
|
@@ -32,7 +32,9 @@ setup(
|
|
|
32
32
|
entry_points={
|
|
33
33
|
"console_scripts": [
|
|
34
34
|
"epsdk=ErisPulse.__main__:main",
|
|
35
|
-
"ep=ErisPulse.__main__:main"
|
|
35
|
+
"ep=ErisPulse.__main__:main",
|
|
36
|
+
"ErisPulse=ErisPulse.__main__:main",
|
|
37
|
+
"ErisPulse-CLI=ErisPulse.__main__:main",
|
|
36
38
|
]
|
|
37
39
|
},
|
|
38
40
|
python_requires='>=3.7',
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import asyncio
|
|
2
|
-
import aiohttp
|
|
3
|
-
from .envManager import env
|
|
4
|
-
|
|
5
|
-
class OriginManager:
|
|
6
|
-
def __init__(self):
|
|
7
|
-
self._init_origins()
|
|
8
|
-
|
|
9
|
-
def _init_origins(self):
|
|
10
|
-
if not env.get('origins'):
|
|
11
|
-
env.set('origins', [])
|
|
12
|
-
|
|
13
|
-
async def _validate_url(self, url):
|
|
14
|
-
if not url.startswith(('http://', 'https://')):
|
|
15
|
-
protocol = input("未指定协议,请输入使用的协议 (http 或 https): ").strip().lower()
|
|
16
|
-
if protocol not in ['http', 'https']:
|
|
17
|
-
print("无效的协议类型,必须是 http 或 https。")
|
|
18
|
-
return None
|
|
19
|
-
url = f"{protocol}://{url}"
|
|
20
|
-
|
|
21
|
-
if not url.endswith('.json'):
|
|
22
|
-
url = f"{url}/map.json"
|
|
23
|
-
|
|
24
|
-
try:
|
|
25
|
-
async with aiohttp.ClientSession() as session:
|
|
26
|
-
async with session.get(url) as response:
|
|
27
|
-
response.raise_for_status()
|
|
28
|
-
if response.headers.get('Content-Type', '').startswith('application/json'):
|
|
29
|
-
return url
|
|
30
|
-
else:
|
|
31
|
-
print(f"源 {url} 返回的内容不是有效的 JSON 格式。")
|
|
32
|
-
return None
|
|
33
|
-
except Exception as e:
|
|
34
|
-
print(f"访问源 {url} 失败: {e}")
|
|
35
|
-
return None
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def add_origin(self, value):
|
|
39
|
-
validated_url = asyncio.run(self._validate_url(value))
|
|
40
|
-
if not validated_url:
|
|
41
|
-
print("提供的源不是一个有效源,请检查后重试。")
|
|
42
|
-
return False
|
|
43
|
-
|
|
44
|
-
origins = env.get('origins')
|
|
45
|
-
if validated_url not in origins:
|
|
46
|
-
origins.append(validated_url)
|
|
47
|
-
env.set('origins', origins)
|
|
48
|
-
print(f"源 {validated_url} 已成功添加。")
|
|
49
|
-
return True
|
|
50
|
-
else:
|
|
51
|
-
print(f"源 {validated_url} 已存在,无需重复添加。")
|
|
52
|
-
return False
|
|
53
|
-
|
|
54
|
-
def update_origins(self):
|
|
55
|
-
origins = env.get('origins')
|
|
56
|
-
providers = {}
|
|
57
|
-
modules = {}
|
|
58
|
-
module_alias = {}
|
|
59
|
-
|
|
60
|
-
print("\033[1m{:<10} | {:<20} | {:<50}\033[0m".format("源", "模块", "地址"))
|
|
61
|
-
print("-" * 85)
|
|
62
|
-
|
|
63
|
-
async def fetch_origin_data():
|
|
64
|
-
async with aiohttp.ClientSession() as session:
|
|
65
|
-
for origin in origins:
|
|
66
|
-
print(f"\n\033[94m正在获取 {origin}\033[0m")
|
|
67
|
-
try:
|
|
68
|
-
async with session.get(origin) as response:
|
|
69
|
-
response.raise_for_status()
|
|
70
|
-
if response.headers.get('Content-Type', '').startswith('application/json'):
|
|
71
|
-
content = await response.json()
|
|
72
|
-
providers[content["name"]] = content["base"]
|
|
73
|
-
|
|
74
|
-
for module in list(content["modules"].keys()):
|
|
75
|
-
module_content = content["modules"][module]
|
|
76
|
-
modules[f'{module}@{content["name"]}'] = module_content
|
|
77
|
-
module_origin_name = module_content["path"]
|
|
78
|
-
module_alias_name = module
|
|
79
|
-
module_alias[f'{module_origin_name}@{content["name"]}'] = module_alias_name
|
|
80
|
-
|
|
81
|
-
print("{:<10} | {:<20} | {:<50}".format(
|
|
82
|
-
content['name'],
|
|
83
|
-
module,
|
|
84
|
-
f"{providers[content['name']]}{module_origin_name}"
|
|
85
|
-
))
|
|
86
|
-
else:
|
|
87
|
-
print(f"\033[91m源 {origin} 返回的内容不是有效的 JSON 格式。\033[0m")
|
|
88
|
-
except Exception as e:
|
|
89
|
-
print(f"\033[91m获取 {origin} 时出错: {e}\033[0m")
|
|
90
|
-
|
|
91
|
-
# 使用 asyncio.run 调用异步任务
|
|
92
|
-
asyncio.run(fetch_origin_data())
|
|
93
|
-
|
|
94
|
-
env.set('providers', providers)
|
|
95
|
-
env.set('modules', modules)
|
|
96
|
-
env.set('module_alias', module_alias)
|
|
97
|
-
|
|
98
|
-
print("\n\033[92m{}\033[0m".format("完成".center(85, "-")))
|
|
99
|
-
|
|
100
|
-
def list_origins(self):
|
|
101
|
-
origins = env.get('origins')
|
|
102
|
-
for origin in origins:
|
|
103
|
-
print(origin)
|
|
104
|
-
|
|
105
|
-
def del_origin(self, value):
|
|
106
|
-
origins = env.get('origins')
|
|
107
|
-
if value in origins:
|
|
108
|
-
origins.remove(value)
|
|
109
|
-
env.set('origins', origins)
|
|
110
|
-
print(f"源 {value} 已删除。")
|
|
111
|
-
else:
|
|
112
|
-
print(f"源 {value} 不存在。")
|
|
113
|
-
|
|
114
|
-
origin_manager = OriginManager()
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ErisPulse
|
|
3
|
-
Version: 1.0.11
|
|
4
|
-
Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
5
|
-
Home-page: https://github.com/wsu2059q/ErisPulse
|
|
6
|
-
Author: 艾莉丝·格雷拉特(WSu2059)
|
|
7
|
-
Author-email: wsu2059@qq.com
|
|
8
|
-
Maintainer: runoneall
|
|
9
|
-
Maintainer-email: runoobsteve@gmail.com
|
|
10
|
-
License: MIT
|
|
11
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
-
Classifier: Operating System :: OS Independent
|
|
23
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.7
|
|
25
|
-
Description-Content-Type: text/markdown
|
|
26
|
-
Requires-Dist: aiohttp
|
|
27
|
-
Requires-Dist: rich
|
|
28
|
-
Requires-Dist: prompt_toolkit
|
|
29
|
-
Dynamic: author
|
|
30
|
-
Dynamic: author-email
|
|
31
|
-
Dynamic: classifier
|
|
32
|
-
Dynamic: description
|
|
33
|
-
Dynamic: description-content-type
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: license
|
|
36
|
-
Dynamic: maintainer
|
|
37
|
-
Dynamic: maintainer-email
|
|
38
|
-
Dynamic: requires-dist
|
|
39
|
-
Dynamic: requires-python
|
|
40
|
-
Dynamic: summary
|
|
41
|
-
|
|
42
|
-
# ErisPulse
|
|
43
|
-
|
|
44
|
-
本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
|
|
45
|
-
|
|
46
|
-
ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
47
|
-
|
|
48
|
-
# 更新日志
|
|
49
|
-
## 1.0.4
|
|
50
|
-
修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
|
|
51
|
-
|
|
52
|
-
## 1.0.5
|
|
53
|
-
更新了SDK 模块对于pip依赖安装的支持
|
|
54
|
-
|
|
55
|
-
## 1.0.6
|
|
56
|
-
修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
|
|
57
|
-
|
|
58
|
-
## 1.0.7
|
|
59
|
-
修复诸多小问题
|
|
60
|
-
|
|
61
|
-
## 1.0.8
|
|
62
|
-
现在包会被添加至系统环境,用户可以直接通过命令行'ep'或'epsdk'命令调用cli
|
|
63
|
-
|
|
64
|
-
## 1.0.9
|
|
65
|
-
修复了部分命令行参数的错误
|
|
66
|
-
|
|
67
|
-
## 1.0.10
|
|
68
|
-
- 修复了模块加载逻辑中可选依赖未正确加载的问题。
|
|
69
|
-
- 增强了日志输出,便于调试模块加载过程。
|
|
70
|
-
- 改进了 `optional_dependencies` 的处理逻辑,支持部分依赖加载。
|
|
71
|
-
|
|
72
|
-
## 1.0.11
|
|
73
|
-
- 优化了模块加载时对空可选依赖列表的处理,避免不必要的警告日志输出。
|
|
74
|
-
- 改进了日志信息的清晰度,减少冗余提示,提升用户体验。
|
erispulse-1.0.11/PKG-INFO
DELETED
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: ErisPulse
|
|
3
|
-
Version: 1.0.11
|
|
4
|
-
Summary: ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
5
|
-
Home-page: https://github.com/wsu2059q/ErisPulse
|
|
6
|
-
Author: 艾莉丝·格雷拉特(WSu2059)
|
|
7
|
-
Author-email: wsu2059@qq.com
|
|
8
|
-
Maintainer: runoneall
|
|
9
|
-
Maintainer-email: runoobsteve@gmail.com
|
|
10
|
-
License: MIT
|
|
11
|
-
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
-
Classifier: Intended Audience :: Developers
|
|
13
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
-
Classifier: Programming Language :: Python :: 3
|
|
15
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
16
|
-
Classifier: Programming Language :: Python :: 3.8
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
20
|
-
Classifier: Programming Language :: Python :: 3.12
|
|
21
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
|
22
|
-
Classifier: Operating System :: OS Independent
|
|
23
|
-
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
24
|
-
Requires-Python: >=3.7
|
|
25
|
-
Description-Content-Type: text/markdown
|
|
26
|
-
Requires-Dist: aiohttp
|
|
27
|
-
Requires-Dist: rich
|
|
28
|
-
Requires-Dist: prompt_toolkit
|
|
29
|
-
Dynamic: author
|
|
30
|
-
Dynamic: author-email
|
|
31
|
-
Dynamic: classifier
|
|
32
|
-
Dynamic: description
|
|
33
|
-
Dynamic: description-content-type
|
|
34
|
-
Dynamic: home-page
|
|
35
|
-
Dynamic: license
|
|
36
|
-
Dynamic: maintainer
|
|
37
|
-
Dynamic: maintainer-email
|
|
38
|
-
Dynamic: requires-dist
|
|
39
|
-
Dynamic: requires-python
|
|
40
|
-
Dynamic: summary
|
|
41
|
-
|
|
42
|
-
# ErisPulse
|
|
43
|
-
|
|
44
|
-
本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
|
|
45
|
-
|
|
46
|
-
ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
47
|
-
|
|
48
|
-
# 更新日志
|
|
49
|
-
## 1.0.4
|
|
50
|
-
修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
|
|
51
|
-
|
|
52
|
-
## 1.0.5
|
|
53
|
-
更新了SDK 模块对于pip依赖安装的支持
|
|
54
|
-
|
|
55
|
-
## 1.0.6
|
|
56
|
-
修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
|
|
57
|
-
|
|
58
|
-
## 1.0.7
|
|
59
|
-
修复诸多小问题
|
|
60
|
-
|
|
61
|
-
## 1.0.8
|
|
62
|
-
现在包会被添加至系统环境,用户可以直接通过命令行'ep'或'epsdk'命令调用cli
|
|
63
|
-
|
|
64
|
-
## 1.0.9
|
|
65
|
-
修复了部分命令行参数的错误
|
|
66
|
-
|
|
67
|
-
## 1.0.10
|
|
68
|
-
- 修复了模块加载逻辑中可选依赖未正确加载的问题。
|
|
69
|
-
- 增强了日志输出,便于调试模块加载过程。
|
|
70
|
-
- 改进了 `optional_dependencies` 的处理逻辑,支持部分依赖加载。
|
|
71
|
-
|
|
72
|
-
## 1.0.11
|
|
73
|
-
- 优化了模块加载时对空可选依赖列表的处理,避免不必要的警告日志输出。
|
|
74
|
-
- 改进了日志信息的清晰度,减少冗余提示,提升用户体验。
|
erispulse-1.0.11/README.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# ErisPulse
|
|
2
|
-
|
|
3
|
-
本项目基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,并由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持。这是一个异步版本的 SDK,可能在功能和特性上与原库存在一定差异。
|
|
4
|
-
|
|
5
|
-
ErisPulse 是一个模块化、可扩展的异步 Python SDK 框架,主要用于构建高效、可维护的机器人应用程序。
|
|
6
|
-
|
|
7
|
-
# 更新日志
|
|
8
|
-
## 1.0.4
|
|
9
|
-
修复了部分命令行不支持logger颜色代码的问题 | 替换为rich
|
|
10
|
-
|
|
11
|
-
## 1.0.5
|
|
12
|
-
更新了SDK 模块对于pip依赖安装的支持
|
|
13
|
-
|
|
14
|
-
## 1.0.6
|
|
15
|
-
修复了SDK-CLI中的颜色乱码问题,并将db调整为包内存储,以解决多进程问题
|
|
16
|
-
|
|
17
|
-
## 1.0.7
|
|
18
|
-
修复诸多小问题
|
|
19
|
-
|
|
20
|
-
## 1.0.8
|
|
21
|
-
现在包会被添加至系统环境,用户可以直接通过命令行'ep'或'epsdk'命令调用cli
|
|
22
|
-
|
|
23
|
-
## 1.0.9
|
|
24
|
-
修复了部分命令行参数的错误
|
|
25
|
-
|
|
26
|
-
## 1.0.10
|
|
27
|
-
- 修复了模块加载逻辑中可选依赖未正确加载的问题。
|
|
28
|
-
- 增强了日志输出,便于调试模块加载过程。
|
|
29
|
-
- 改进了 `optional_dependencies` 的处理逻辑,支持部分依赖加载。
|
|
30
|
-
|
|
31
|
-
## 1.0.11
|
|
32
|
-
- 优化了模块加载时对空可选依赖列表的处理,避免不必要的警告日志输出。
|
|
33
|
-
- 改进了日志信息的清晰度,减少冗余提示,提升用户体验。
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|