ErisPulse 1.0.0__zip

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.
@@ -0,0 +1,131 @@
1
+ from . import sdk
2
+ from . import util
3
+ from . import errors
4
+ from . import logger
5
+ from .envManager import env
6
+
7
+ setattr(sdk, "env", env)
8
+ # setattr(sdk, "logger", logger)
9
+ setattr(sdk, "util", util)
10
+
11
+ env.load_env_file()
12
+
13
+ def init():
14
+ import os
15
+ import sys
16
+ try:
17
+ sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
18
+ sys.path.append(sdkModulePath)
19
+
20
+ TempModules = [
21
+ x for x in os.listdir(sdkModulePath)
22
+ if os.path.isdir(os.path.join(sdkModulePath, x))
23
+ ]
24
+
25
+ sdkInstalledModuleNames: list[str] = []
26
+ disabledModules: list[str] = []
27
+
28
+ for module_name in TempModules:
29
+ try:
30
+ moduleObj = __import__(module_name)
31
+ if not hasattr(moduleObj, "moduleInfo") or not isinstance(moduleObj.moduleInfo, dict):
32
+ logger.warning(f"模块 {module_name} 缺少有效的 'moduleInfo' 字典.")
33
+ continue
34
+ if "name" not in moduleObj.moduleInfo:
35
+ logger.warning(f"模块 {module_name} 的 'moduleInfo' 字典 缺少必要 'name' 键.")
36
+ continue
37
+ if not hasattr(moduleObj, "Main"):
38
+ logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
39
+ continue
40
+
41
+ module_info = env.get_module(moduleObj.moduleInfo["name"])
42
+ if module_info is None:
43
+ module_info = {
44
+ "status": True,
45
+ "info": moduleObj.moduleInfo
46
+ }
47
+ env.set_module(moduleObj.moduleInfo["name"], module_info)
48
+ logger.info(f"模块 {moduleObj.moduleInfo['name']} 信息已初始化并存储到数据库")
49
+
50
+ if not module_info.get('status', True):
51
+ disabledModules.append(module_name)
52
+ logger.warning(f"模块 {moduleObj.moduleInfo['name']} 已禁用,跳过加载")
53
+ continue
54
+
55
+ required_deps = moduleObj.moduleInfo.get("dependencies", [])
56
+ missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
57
+ if missing_required_deps:
58
+ logger.error(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
59
+ raise errors.MissingDependencyError(f"模块 {module_name} 缺少必需依赖: {missing_required_deps}")
60
+
61
+ optional_deps = moduleObj.moduleInfo.get("optional_dependencies", [])
62
+ available_optional_deps = []
63
+
64
+ for dep in optional_deps:
65
+ if isinstance(dep, list):
66
+ if all(d in TempModules for d in dep):
67
+ available_optional_deps.extend(dep)
68
+ elif dep in TempModules:
69
+ available_optional_deps.append(dep)
70
+
71
+ if optional_deps and not available_optional_deps:
72
+ logger.warning(f"模块 {module_name} 缺少所有可选依赖: {optional_deps}")
73
+ continue
74
+
75
+ sdkInstalledModuleNames.append(module_name)
76
+ except Exception as e:
77
+ logger.warning(f"模块 {module_name} 加载失败: {e}")
78
+ continue
79
+
80
+ sdkModuleDependencies = {}
81
+ for module_name in sdkInstalledModuleNames:
82
+ moduleObj = __import__(module_name)
83
+ moduleDependecies: list[str] = moduleObj.moduleInfo.get("dependencies", [])
84
+
85
+ optional_deps = moduleObj.moduleInfo.get("optional_dependencies", [])
86
+ available_optional_deps = [dep for dep in optional_deps if dep in sdkInstalledModuleNames]
87
+ moduleDependecies.extend(available_optional_deps)
88
+
89
+ for dep in moduleDependecies:
90
+ if dep in disabledModules:
91
+ logger.warning(f"模块 {module_name} 的依赖模块 {dep} 已禁用,跳过加载")
92
+ continue
93
+
94
+ if not all(dep in sdkInstalledModuleNames for dep in moduleDependecies):
95
+ raise errors.InvalidDependencyError(
96
+ f"模块 {module_name} 的依赖无效: {moduleDependecies}"
97
+ )
98
+ sdkModuleDependencies[module_name] = moduleDependecies
99
+
100
+ sdkInstalledModuleNames: list[str] = sdk.util.topological_sort(
101
+ sdkInstalledModuleNames, sdkModuleDependencies, errors.CycleDependencyError
102
+ )
103
+
104
+ all_modules_info = {}
105
+ for module_name in sdkInstalledModuleNames:
106
+ moduleObj = __import__(module_name)
107
+ moduleInfo: dict = moduleObj.moduleInfo
108
+
109
+ module_info = env.get_module(moduleInfo["name"])
110
+ env.set_module(moduleInfo["name"], {
111
+ "status": True,
112
+ "info": moduleInfo
113
+ })
114
+ logger.debug("所有模块信息已加载并存储到数据库")
115
+
116
+ for module_name in sdkInstalledModuleNames:
117
+ moduleObj = __import__(module_name)
118
+ moduleInfo = moduleObj.moduleInfo
119
+ module_status = env.get_module_status(moduleInfo["name"])
120
+ if not module_status:
121
+ continue
122
+
123
+ moduleMain = moduleObj.Main(sdk, logger)
124
+ setattr(moduleMain, "moduleInfo", moduleInfo)
125
+ setattr(sdk, moduleInfo["name"], moduleMain)
126
+ logger.debug(f"模块 {moduleInfo['name']} 正在初始化")
127
+ except Exception as e:
128
+ logger.error(f"初始化失败: {e}")
129
+ raise e
130
+
131
+ sdk.init = init
@@ -0,0 +1,417 @@
1
+ import argparse
2
+ import os
3
+ import sys
4
+ import shutil
5
+ import aiohttp
6
+ import zipfile
7
+ import asyncio
8
+ from .envManager import env
9
+ from .origin import origin_manager
10
+
11
+ def enable_module(module_name):
12
+ module_info = env.get_module(module_name)
13
+ if module_info:
14
+ env.set_module_status(module_name, True)
15
+ print(f"模块 {module_name} 已启用")
16
+ else:
17
+ print(f"模块 {module_name} 不存在")
18
+
19
+ def disable_module(module_name):
20
+ module_info = env.get_module(module_name)
21
+ if module_info:
22
+ env.set_module_status(module_name, False)
23
+ print(f"模块 {module_name} 已禁用")
24
+ else:
25
+ print(f"模块 {module_name} 不存在")
26
+ async def fetch_url(session, url):
27
+ try:
28
+ async with session.get(url) as response:
29
+ response.raise_for_status()
30
+ return await response.read()
31
+ except Exception as e:
32
+ print(f"请求失败: {e}")
33
+ return None
34
+ def extract_and_setup_module(module_name, module_url, zip_path, module_dir):
35
+ try:
36
+ print(f"正在从 {module_url} 下载模块...")
37
+
38
+ async def download_module():
39
+ async with aiohttp.ClientSession() as session:
40
+ content = await fetch_url(session, module_url)
41
+ if content is None:
42
+ return False
43
+
44
+ with open(zip_path, 'wb') as zip_file:
45
+ zip_file.write(content)
46
+
47
+ if not os.path.exists(module_dir):
48
+ os.makedirs(module_dir)
49
+
50
+ with zipfile.ZipFile(zip_path, 'r') as zip_ref:
51
+ zip_ref.extractall(module_dir)
52
+
53
+ init_file_path = os.path.join(module_dir, '__init__.py')
54
+ if not os.path.exists(init_file_path):
55
+ sub_module_dir = os.path.join(module_dir, module_name)
56
+ m_sub_module_dir = os.path.join(module_dir, f"m_{module_name}")
57
+ for sub_dir in [sub_module_dir, m_sub_module_dir]:
58
+ if os.path.exists(sub_dir) and os.path.isdir(sub_dir):
59
+ for item in os.listdir(sub_dir):
60
+ source_item = os.path.join(sub_dir, item)
61
+ target_item = os.path.join(module_dir, item)
62
+ if os.path.exists(target_item):
63
+ os.remove(target_item)
64
+ shutil.move(source_item, module_dir)
65
+ os.rmdir(sub_dir)
66
+
67
+ print(f"模块 {module_name} 文件已成功解压并设置")
68
+ return True
69
+
70
+ return asyncio.run(download_module())
71
+
72
+ except Exception as e:
73
+ print(f"处理模块 {module_name} 文件失败: {e}")
74
+ if os.path.exists(zip_path):
75
+ try:
76
+ os.remove(zip_path)
77
+ except Exception as cleanup_error:
78
+ print(f"清理失败: {cleanup_error}")
79
+ return False
80
+
81
+ finally:
82
+ if os.path.exists(zip_path):
83
+ try:
84
+ os.remove(zip_path)
85
+ except Exception as cleanup_error:
86
+ print(f"清理失败: {cleanup_error}")
87
+
88
+ def install_module(module_name, force=False):
89
+ module_info = env.get_module(module_name)
90
+ if module_info and not force:
91
+ print(f"模块 {module_name} 已存在,使用 --force 参数强制重装")
92
+ return
93
+
94
+ providers = env.get('providers', {})
95
+ if isinstance(providers, str):
96
+ providers = json.loads(providers)
97
+ module_info = []
98
+
99
+ for provider, url in providers.items():
100
+ module_key = f"{module_name}@{provider}"
101
+ modules_data = env.get('modules', {})
102
+ if isinstance(modules_data, str):
103
+ modules_data = json.loads(modules_data)
104
+
105
+ if module_key in modules_data:
106
+ module_data = modules_data[module_key]
107
+ module_info.append({
108
+ 'provider': provider,
109
+ 'url': url,
110
+ 'path': module_data.get('path', ''),
111
+ 'version': module_data.get('version', '未知'),
112
+ 'description': module_data.get('description', '无描述'),
113
+ 'author': module_data.get('author', '未知'),
114
+ 'dependencies': module_data.get('dependencies', []),
115
+ 'optional_dependencies': module_data.get('optional_dependencies', [])
116
+ })
117
+
118
+ if not module_info:
119
+ print(f"未找到模块 {module_name}")
120
+ return
121
+
122
+ if len(module_info) > 1:
123
+ print(f"找到 {len(module_info)} 个源的 {module_name} 模块:")
124
+ for i, info in enumerate(module_info):
125
+ print(f"{i+1}. 源: {info['provider']}")
126
+ print(f" 版本: {info['version']}")
127
+ print(f" 描述: {info['description']}")
128
+ print(f" 作者: {info['author']}")
129
+ print(f" 依赖: {', '.join(info['dependencies']) if info['dependencies'] else '无'}")
130
+ print()
131
+
132
+ while True:
133
+ try:
134
+ choice = int(input("请选择要安装的源 (输入编号): "))
135
+ if 1 <= choice <= len(module_info):
136
+ selected_module = module_info[choice-1]
137
+ break
138
+ else:
139
+ print("输入无效,请重新选择")
140
+ except ValueError:
141
+ print("请输入有效的数字")
142
+ else:
143
+ selected_module = module_info[0]
144
+
145
+ for dep in selected_module['dependencies']:
146
+ print(f"正在安装依赖模块 {dep}...")
147
+ install_module(dep)
148
+
149
+ if selected_module['optional_dependencies']:
150
+ optional_deps_message = []
151
+ for dep in selected_module['optional_dependencies']:
152
+ if isinstance(dep, list):
153
+ optional_deps_message.append(f"组合: {' + '.join(dep)}")
154
+ else:
155
+ optional_deps_message.append(f"模块: {dep}")
156
+ print("\033[93m\033[1m" + f"模块 {module_name} 有可选依赖:{', '.join(optional_deps_message)},请稍后手动选择安装!" + "\033[0m")
157
+ module_url = selected_module['url'] + selected_module['path']
158
+ script_dir = os.path.dirname(os.path.abspath(__file__))
159
+ module_dir = os.path.join(script_dir, 'modules', module_name)
160
+ zip_path = os.path.join(script_dir, f"{module_name}.zip")
161
+
162
+ if not extract_and_setup_module(
163
+ module_name=module_name,
164
+ module_url=module_url,
165
+ zip_path=zip_path,
166
+ module_dir=module_dir
167
+ ):
168
+ return
169
+ env.set_module(module_name, {
170
+ 'status': True,
171
+ 'info': {
172
+ 'version': selected_module['version'],
173
+ 'description': selected_module['description'],
174
+ 'author': selected_module['author'],
175
+ 'dependencies': selected_module['dependencies'],
176
+ 'optional_dependencies': selected_module['optional_dependencies']
177
+ }
178
+ })
179
+ print(f"模块 {module_name} 安装成功")
180
+
181
+ def uninstall_module(module_name):
182
+ script_dir = os.path.dirname(os.path.abspath(__file__))
183
+ module_path = os.path.join(script_dir, 'modules', module_name)
184
+
185
+ module_file_path = module_path + '.py'
186
+ if os.path.exists(module_file_path):
187
+ try:
188
+ os.remove(module_file_path)
189
+ except Exception as e:
190
+ print(f"删除模块文件 {module_name} 时出错: {e}")
191
+ elif os.path.exists(module_path) and os.path.isdir(module_path):
192
+ try:
193
+ shutil.rmtree(module_path)
194
+ except Exception as e:
195
+ print(f"删除模块目录 {module_name} 时出错: {e}")
196
+ else:
197
+ print(f"模块 {module_name} 不存在")
198
+ return
199
+
200
+ if env.remove_module(module_name):
201
+ print(f"模块 {module_name} 已删除")
202
+ else:
203
+ print(f"模块 {module_name} 不存在")
204
+
205
+ def upgrade_all_modules(force=False):
206
+ all_modules = env.get_all_modules()
207
+ if not all_modules:
208
+ print("未找到任何模块,无法更新")
209
+ return
210
+
211
+ providers = env.get('providers', {})
212
+ if isinstance(providers, str):
213
+ providers = json.loads(providers)
214
+
215
+ modules_data = env.get('modules', {})
216
+ if isinstance(modules_data, str):
217
+ modules_data = json.loads(modules_data)
218
+
219
+ updates_available = []
220
+ for module_name, module_info in all_modules.items():
221
+ local_version = module_info['info'].get('version', '0.0.0')
222
+ for provider, url in providers.items():
223
+ module_key = f"{module_name}@{provider}"
224
+ if module_key in modules_data:
225
+ remote_module = modules_data[module_key]
226
+ remote_version = remote_module.get('version', '0.0.0')
227
+ if remote_version > local_version:
228
+ updates_available.append({
229
+ 'name': module_name,
230
+ 'local_version': local_version,
231
+ 'remote_version': remote_version,
232
+ 'provider': provider,
233
+ 'url': url,
234
+ 'path': remote_module.get('path', ''),
235
+ })
236
+
237
+ if not updates_available:
238
+ print("所有模块已是最新版本,无需更新")
239
+ return
240
+
241
+ print("\n以下模块有可用更新:")
242
+ for update in updates_available:
243
+ print(f"模块: {update['name']}")
244
+ print(f"当前版本: {update['local_version']}")
245
+ print(f"最新版本: {update['remote_version']}")
246
+ print(f"源: {update['provider']}")
247
+ print()
248
+
249
+ if not force:
250
+ confirm = input("\033[93m\033[1m警告:更新模块可能会导致兼容性问题,请在更新前查看插件作者的相关声明。\n"
251
+ "是否继续?(y/n): \033[0m").strip().lower()
252
+ if confirm != 'y':
253
+ print("更新已取消")
254
+ return
255
+
256
+ for update in updates_available:
257
+ print(f"正在更新模块 {update['name']}...")
258
+ module_url = update['url'] + update['path']
259
+ script_dir = os.path.dirname(os.path.abspath(__file__))
260
+ module_dir = os.path.join(script_dir, 'modules', update['name'])
261
+ zip_path = os.path.join(script_dir, f"{update['name']}.zip")
262
+
263
+ if not extract_and_setup_module(
264
+ module_name=update['name'],
265
+ module_url=module_url,
266
+ zip_path=zip_path,
267
+ module_dir=module_dir
268
+ ):
269
+ continue
270
+
271
+ all_modules[update['name']]['info']['version'] = update['remote_version']
272
+ env.set_all_modules(all_modules)
273
+ print(f"模块 {update['name']} 已更新至版本 {update['remote_version']}")
274
+
275
+ def list_modules(module_name=None, page_size=5):
276
+ all_modules = env.get_all_modules()
277
+ if not all_modules:
278
+ print("正在初始化模块列表...")
279
+ from . import init as init_module
280
+ init_module()
281
+ all_modules = env.get_all_modules()
282
+
283
+ modules = [{"name": name, **info} for name, info in all_modules.items()]
284
+
285
+ if module_name:
286
+ module = next((m for m in modules if m['name'] == module_name), None)
287
+ if module:
288
+ status = "启用" if module.get("status", True) else "禁用"
289
+ print(f"模块: {module['name']}")
290
+ print(f"状态: {status}")
291
+ print(f"版本: {module['info'].get('version', '未知')}")
292
+ print(f"描述: {module['info'].get('description', '无描述')}")
293
+ print(f"作者: {module['info'].get('author', '未知')}")
294
+ print(f"依赖: {', '.join(module['info'].get('dependencies', [])) if module['info'].get('dependencies') else '无'}")
295
+ else:
296
+ print(f"模块 {module_name} 不存在")
297
+ else:
298
+ total_modules = len(modules)
299
+ total_pages = (total_modules + page_size - 1) // page_size
300
+ current_page = 1
301
+
302
+ try:
303
+ while True:
304
+ print("\033c", end="")
305
+
306
+ start_index = (current_page - 1) * page_size
307
+ end_index = min(start_index + page_size, total_modules)
308
+ print(f"\n--- 模块列表 (第 {current_page}/{total_pages} 页) ---")
309
+
310
+ for i in range(start_index, end_index):
311
+ module = modules[i]
312
+ status = "启用" if module.get("status", True) else "禁用"
313
+ dependencies = ', '.join(module['info'].get('dependencies', [])) if module['info'].get('dependencies') else '无'
314
+ print(f"{i+1}. 模块: {module['name']} | 状态: {status} | 版本: {module['info'].get('version', '未知')}")
315
+ print(f" 描述: {module['info'].get('description', '无描述')}")
316
+ print(f" 依赖: {dependencies}\n")
317
+
318
+ print("\n输入页码直接跳转,或输入 'e' 下一页, 'q' 上一页 | 使用 Ctrl+C 退出")
319
+ user_input = input("> ").strip().lower()
320
+ if user_input.isdigit():
321
+ target_page = int(user_input)
322
+ if target_page < 1:
323
+ current_page = 1
324
+ elif target_page > total_pages:
325
+ current_page = total_pages
326
+ else:
327
+ current_page = target_page
328
+ elif user_input == 'e' and current_page < total_pages:
329
+ current_page += 1
330
+ elif user_input == 'q' and current_page > 1:
331
+ current_page -= 1
332
+ except KeyboardInterrupt:
333
+ print("\n")
334
+ sys.exit(0)
335
+ def main():
336
+ parser = argparse.ArgumentParser(
337
+ description="ErisPulse 命令行工具",
338
+ prog="python -m ErisPulse"
339
+ )
340
+ subparsers = parser.add_subparsers(dest='command', help='可用命令')
341
+
342
+ enable_parser = subparsers.add_parser('enable', help='启用指定模块')
343
+ enable_parser.add_argument('module_name', type=str, help='要启用的模块名称')
344
+ enable_parser.add_argument('--init', action='store_true', help='在启用模块前初始化模块数据库')
345
+
346
+ disable_parser = subparsers.add_parser('disable', help='禁用指定模块')
347
+ disable_parser.add_argument('module_name', type=str, help='要禁用的模块名称')
348
+ disable_parser.add_argument('--init', action='store_true', help='在禁用模块前初始化模块数据库')
349
+
350
+ list_parser = subparsers.add_parser('list', help='列出所有模块信息')
351
+ list_parser.add_argument('--init', action='store_true', help='在列出模块前初始化模块数据库')
352
+ list_parser.add_argument('--module', '-m', type=str, help='指定要展示的模块名称')
353
+
354
+ update_parser = subparsers.add_parser('update', help='更新模块列表')
355
+
356
+ upgrade_parser = subparsers.add_parser('upgrade', help='升级模块列表')
357
+ upgrade_parser.add_argument('--force', action='store_true', help='跳过二次确认,强制更新')
358
+
359
+ uninstall_parser = subparsers.add_parser('uninstall', help='删除指定模块')
360
+ uninstall_parser.add_argument('module_name', type=str, help='要删除的模块名称')
361
+
362
+ install_parser = subparsers.add_parser('install', help='安装指定模块(支持多个模块,用逗号分隔)')
363
+ install_parser.add_argument('module_name', type=str, help='要安装的模块名称')
364
+ install_parser.add_argument('--force', action='store_true', help='强制重新安装模块')
365
+ install_parser.add_argument('--init', action='store_true', help='在安装模块前初始化模块数据库')
366
+
367
+ origin_parser = subparsers.add_parser('origin', help='管理模块源')
368
+ origin_subparsers = origin_parser.add_subparsers(dest='origin_command', help='源管理命令')
369
+
370
+ add_origin_parser = origin_subparsers.add_parser('add', help='添加模块源')
371
+ add_origin_parser.add_argument('url', type=str, help='要添加的模块源URL')
372
+
373
+ list_origin_parser = origin_subparsers.add_parser('list', help='列出所有模块源')
374
+
375
+ del_origin_parser = origin_subparsers.add_parser('del', help='删除模块源')
376
+ del_origin_parser.add_argument('url', type=str, help='要删除的模块源URL')
377
+
378
+ args = parser.parse_args()
379
+
380
+ if hasattr(args, 'init') and args.init:
381
+ print("正在初始化模块列表...")
382
+ from . import init as init_module
383
+ init_module()
384
+
385
+ # 全部指令:enable, disable, list, uninstall, install, update, origin(add, list, del)
386
+ if args.command == 'enable':
387
+ enable_module(args.module_name)
388
+ elif args.command == 'disable':
389
+ disable_module(args.module_name)
390
+ elif args.command == 'list':
391
+ list_modules(args.module)
392
+ elif args.command == 'uninstall':
393
+ uninstall_module(args.module_name)
394
+ elif args.command == 'install':
395
+ module_names = args.module_name.split(',')
396
+ for module_name in module_names:
397
+ module_name = module_name.strip()
398
+ if module_name:
399
+ install_module(module_name, args.force)
400
+ elif args.command == 'update':
401
+ origin_manager.update_origins()
402
+ elif args.command == 'upgrade':
403
+ upgrade_all_modules(args.force)
404
+ elif args.command == 'origin':
405
+ if args.origin_command == 'add':
406
+ origin_manager.add_origin(args.url)
407
+ elif args.origin_command == 'list':
408
+ origin_manager.list_origins()
409
+ elif args.origin_command == 'del':
410
+ origin_manager.del_origin(args.url)
411
+ else:
412
+ origin_parser.print_help()
413
+ else:
414
+ parser.print_help()
415
+
416
+ if __name__ == "__main__":
417
+ main()