ErisPulse 1.0.14.dev2__py3-none-any.whl → 1.0.15__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 CHANGED
@@ -5,6 +5,8 @@ from . import util
5
5
  from .raiserr import raiserr
6
6
  from .logger import logger
7
7
  from .db import env
8
+ from .mods import mods
9
+ from .adapter import adapter, adapterbase
8
10
 
9
11
  # 注册 ErrorHook 并预注册常用错误类型
10
12
  raiserr.register("MissingDependencyError", doc="缺少依赖错误")
@@ -14,16 +16,19 @@ raiserr.register("ModuleLoadError" , doc="模块加载错误")
14
16
 
15
17
  sdk = types.SimpleNamespace()
16
18
  setattr(sdk, "env", env)
19
+ setattr(sdk, "mods", mods)
20
+ setattr(sdk, "util", util)
17
21
  setattr(sdk, "raiserr", raiserr)
18
22
  setattr(sdk, "logger", logger)
19
- setattr(sdk, "util", util)
23
+ setattr(sdk, "adapter", adapter)
24
+ setattr(sdk, "BaseAdapter", adapterbase)
20
25
 
21
26
  env.load_env_file()
22
27
 
23
28
  def init():
24
29
  try:
25
30
  sdkModulePath = os.path.join(os.path.dirname(__file__), "modules")
26
-
31
+
27
32
  if not os.path.exists(sdkModulePath):
28
33
  os.makedirs(sdkModulePath)
29
34
 
@@ -49,21 +54,21 @@ def init():
49
54
  if not hasattr(moduleObj, "Main"):
50
55
  logger.warning(f"模块 {module_name} 缺少 'Main' 类.")
51
56
  continue
52
-
53
- module_info = env.get_module(moduleObj.moduleInfo.get("meta", {}).get("name", None))
57
+
58
+ module_info = mods.get_module(moduleObj.moduleInfo.get("meta", {}).get("name", None))
54
59
  if module_info is None:
55
60
  module_info = {
56
61
  "status": True,
57
62
  "info": moduleObj.moduleInfo
58
63
  }
59
- env.set_module(moduleObj.moduleInfo.get("meta", {}).get("name", None), module_info)
64
+ mods.set_module(moduleObj.moduleInfo.get("meta", {}).get("name", None), module_info)
60
65
  logger.info(f"模块 {moduleObj.moduleInfo.get('meta', {}).get('name', None)} 信息已初始化并存储到数据库")
61
-
66
+
62
67
  if not module_info.get('status', True):
63
68
  disabledModules.append(module_name)
64
69
  logger.warning(f"模块 {moduleObj.moduleInfo.get('meta', {}).get('name', None)} 已禁用,跳过加载")
65
70
  continue
66
-
71
+
67
72
  required_deps = moduleObj.moduleInfo.get("dependencies", []).get("requires", [])
68
73
  missing_required_deps = [dep for dep in required_deps if dep not in TempModules]
69
74
  if missing_required_deps:
@@ -105,7 +110,7 @@ def init():
105
110
  if dep in disabledModules:
106
111
  logger.warning(f"模块 {module_name} 的依赖模块 {dep} 已禁用,跳过加载")
107
112
  continue
108
-
113
+
109
114
  if not all(dep in sdkInstalledModuleNames for dep in moduleDependecies):
110
115
  raiserr.InvalidDependencyError(
111
116
  f"模块 {module_name} 的依赖无效: {moduleDependecies}"
@@ -121,8 +126,8 @@ def init():
121
126
  moduleObj = __import__(module_name)
122
127
  moduleInfo: dict = moduleObj.moduleInfo
123
128
 
124
- module_info = env.get_module(moduleInfo.get("meta", {}).get("name", None))
125
- env.set_module(moduleInfo.get("meta", {}).get("name", None), {
129
+ module_info = mods.get_module(moduleInfo.get("meta", {}).get("name", None))
130
+ mods.set_module(moduleInfo.get("meta", {}).get("name", None), {
126
131
  "status": True,
127
132
  "info": moduleInfo
128
133
  })
@@ -131,14 +136,25 @@ def init():
131
136
  for module_name in sdkInstalledModuleNames:
132
137
  moduleObj = __import__(module_name)
133
138
  moduleInfo = moduleObj.moduleInfo
134
- module_status = env.get_module_status(moduleInfo.get("meta", {}).get("name", None))
139
+ module_status = mods.get_module_status(moduleInfo.get("meta", {}).get("name", None))
135
140
  if not module_status:
136
141
  continue
137
-
142
+
138
143
  moduleMain = moduleObj.Main(sdk)
139
144
  setattr(moduleMain, "moduleInfo", moduleInfo)
140
145
  setattr(sdk, moduleInfo.get("meta", {}).get("name", None), moduleMain)
141
146
  logger.debug(f"模块 {moduleInfo.get('meta', {}).get('name', None)} 正在初始化")
147
+
148
+ if hasattr(moduleMain, "register_adapters"):
149
+ try:
150
+ adapters = moduleMain.register_adapters()
151
+ if isinstance(adapters, dict):
152
+ for platform_name, adapter_class in adapters.items():
153
+ sdk.adapter.register(platform_name, adapter_class)
154
+ logger.info(f"模块 {moduleInfo['meta']['name']} 注册了适配器: {platform_name}")
155
+ except Exception as e:
156
+ logger.error(f"注册适配器失败: {e}")
157
+
142
158
  except Exception as e:
143
159
  logger.error(f"初始化失败: {e}")
144
160
  raise e
ErisPulse/__main__.py CHANGED
@@ -9,6 +9,7 @@ import asyncio
9
9
  import subprocess
10
10
  import json
11
11
  from .db import env
12
+ from .mods import mods
12
13
 
13
14
  def print_panel(msg, title=None, border_style=None):
14
15
  print("=" * 60)
@@ -157,17 +158,17 @@ class SourceManager:
157
158
  print_panel(f"源 {value} 不存在", "错误")
158
159
 
159
160
  def enable_module(module_name):
160
- module_info = env.get_module(module_name)
161
+ module_info = mods.get_module(module_name)
161
162
  if module_info:
162
- env.set_module_status(module_name, True)
163
+ mods.set_module_status(module_name, True)
163
164
  print_panel(f"✓ 模块 {module_name} 已成功启用", "成功")
164
165
  else:
165
166
  print_panel(f"模块 {module_name} 不存在", "错误")
166
167
 
167
168
  def disable_module(module_name):
168
- module_info = env.get_module(module_name)
169
+ module_info = mods.get_module(module_name)
169
170
  if module_info:
170
- env.set_module_status(module_name, False)
171
+ mods.set_module_status(module_name, False)
171
172
  print_panel(f"✓ 模块 {module_name} 已成功禁用", "成功")
172
173
  else:
173
174
  print_panel(f"模块 {module_name} 不存在", "错误")
@@ -255,7 +256,7 @@ def install_module(module_name, force=False):
255
256
  SourceManager().update_sources()
256
257
  env.set('last_origin_update_time', datetime.now().isoformat())
257
258
  print("✓ 源更新完成")
258
- module_info = env.get_module(module_name)
259
+ module_info = mods.get_module(module_name)
259
260
  if module_info and not force:
260
261
  meta = module_info.get('info', {}).get('meta', {})
261
262
  print_panel(
@@ -332,7 +333,7 @@ def install_module(module_name, force=False):
332
333
  module_dir=module_dir
333
334
  ):
334
335
  return
335
- env.set_module(module_name, {
336
+ mods.set_module(module_name, {
336
337
  'status': True,
337
338
  'info': {
338
339
  'meta': {
@@ -352,7 +353,7 @@ def install_module(module_name, force=False):
352
353
 
353
354
  def uninstall_module(module_name):
354
355
  print_panel(f"准备卸载模块: {module_name}", "卸载摘要")
355
- module_info = env.get_module(module_name)
356
+ module_info = mods.get_module(module_name)
356
357
  if not module_info:
357
358
  print_panel(f"模块 {module_name} 不存在", "错误")
358
359
  return
@@ -383,7 +384,7 @@ def uninstall_module(module_name):
383
384
  return
384
385
  pip_dependencies = depsinfo.get('pip', [])
385
386
  if pip_dependencies:
386
- all_modules = env.get_all_modules()
387
+ all_modules = mods.get_all_modules()
387
388
  unused_pip_dependencies = []
388
389
  essential_packages = {'aiohttp'}
389
390
  for dep in pip_dependencies:
@@ -419,13 +420,13 @@ def uninstall_module(module_name):
419
420
  f"卸载 pip 依赖失败: {e.stderr.decode()}",
420
421
  "错误"
421
422
  )
422
- if env.remove_module(module_name):
423
+ if mods.remove_module(module_name):
423
424
  print_panel(f"✓ 模块 {module_name} 已成功卸载", "成功")
424
425
  else:
425
426
  print_panel(f"模块 {module_name} 不存在", "错误")
426
427
 
427
428
  def upgrade_all_modules(force=False):
428
- all_modules = env.get_all_modules()
429
+ all_modules = mods.get_all_modules()
429
430
  if not all_modules:
430
431
  print("未找到任何模块,无法更新")
431
432
  return
@@ -478,16 +479,16 @@ def upgrade_all_modules(force=False):
478
479
  ):
479
480
  continue
480
481
  all_modules[update['name']]['info']['version'] = update['remote_version']
481
- env.set_all_modules(all_modules)
482
+ mods.set_all_modules(all_modules)
482
483
  print(f"模块 {update['name']} 已更新至版本 {update['remote_version']}")
483
484
 
484
485
  def list_modules(module_name=None):
485
- all_modules = env.get_all_modules()
486
+ all_modules = mods.get_all_modules()
486
487
  if not all_modules:
487
488
  print_panel("未在数据库中发现注册模块,正在初始化模块列表...", "提示")
488
489
  from . import init as init_module
489
490
  init_module()
490
- all_modules = env.get_all_modules()
491
+ all_modules = mods.get_all_modules()
491
492
  if not all_modules:
492
493
  print_panel("未找到任何模块", "错误")
493
494
  return
@@ -576,7 +577,7 @@ def main():
576
577
  continue
577
578
  if '*' in module_name or '?' in module_name:
578
579
  print(f"正在匹配模块模式: {module_name}...")
579
- all_modules = env.get_all_modules()
580
+ all_modules = mods.get_all_modules()
580
581
  if not all_modules:
581
582
  print_panel("未找到任何模块,请先更新源或检查配置", "错误")
582
583
  continue
@@ -601,7 +602,7 @@ def main():
601
602
  continue
602
603
  if '*' in module_name or '?' in module_name:
603
604
  print(f"正在匹配模块模式: {module_name}...")
604
- all_modules = env.get_all_modules()
605
+ all_modules = mods.get_all_modules()
605
606
  if not all_modules:
606
607
  print_panel("未找到任何模块,请先更新源或检查配置", "错误")
607
608
  continue
@@ -628,7 +629,7 @@ def main():
628
629
  continue
629
630
  if '*' in module_name or '?' in module_name:
630
631
  print(f"正在匹配模块模式: {module_name}...")
631
- all_modules = env.get_all_modules()
632
+ all_modules = mods.get_all_modules()
632
633
  if not all_modules:
633
634
  print_panel("未找到任何模块,请先更新源或检查配置", "错误")
634
635
  continue
@@ -653,7 +654,7 @@ def main():
653
654
  continue
654
655
  if '*' in module_name or '?' in module_name:
655
656
  print(f"正在匹配模块模式: {module_name}...")
656
- all_modules = env.get_all_modules()
657
+ all_modules = mods.get_all_modules()
657
658
  if not all_modules:
658
659
  print_panel("未找到任何模块,请先更新源或检查配置", "错误")
659
660
  continue
ErisPulse/adapter.py ADDED
@@ -0,0 +1,81 @@
1
+ import functools
2
+ import asyncio
3
+ from typing import Callable, Any, Dict, List, Type
4
+ from collections import defaultdict
5
+
6
+ class BaseAdapter:
7
+ def __init__(self):
8
+ self._handlers = defaultdict(list)
9
+ self._middlewares = []
10
+
11
+ def on(self, event_type: str):
12
+ def decorator(func: Callable):
13
+ @functools.wraps(func)
14
+ async def wrapper(*args, **kwargs):
15
+ return await func(*args, **kwargs)
16
+ self._handlers[event_type].append(wrapper)
17
+ return wrapper
18
+ return decorator
19
+
20
+ def middleware(self, func: Callable):
21
+ self._middlewares.append(func)
22
+ return func
23
+
24
+ async def send(self, target: Any, message: Any, **kwargs):
25
+ raise NotImplementedError
26
+
27
+ async def call_api(self, endpoint: str, **params):
28
+ raise NotImplementedError
29
+
30
+ async def emit(self, event_type: str, data: Any):
31
+ for middleware in self._middlewares:
32
+ data = await middleware(data)
33
+
34
+ for handler in self._handlers.get(event_type, []):
35
+ await handler(data)
36
+
37
+ class AdapterManager:
38
+ def __init__(self):
39
+ self._adapters: Dict[str, BaseAdapter] = {}
40
+
41
+ def register(self, platform: str, adapter_class: Type[BaseAdapter]) -> bool:
42
+ if not issubclass(adapter_class, BaseAdapter):
43
+ raise TypeError("适配器必须继承自BaseAdapter")
44
+ from . import sdk
45
+ self._adapters[platform] = adapter_class(sdk)
46
+ return True
47
+
48
+ async def startup(self, platforms: List[str] = None):
49
+ if platforms is None:
50
+ platforms = self._adapters.keys()
51
+
52
+ for platform in platforms:
53
+ if platform not in self._adapters:
54
+ raise ValueError(f"平台 {platform} 未注册")
55
+ adapter = self._adapters[platform]
56
+ asyncio.create_task(self._run_adapter(adapter, platform))
57
+
58
+ async def _run_adapter(self, adapter: BaseAdapter, platform: str):
59
+ try:
60
+ await adapter.start()
61
+ except Exception as e:
62
+ self.logger.error(f"平台 {platform} 停止时遇到了错误: {e}")
63
+
64
+ async def shutdown(self):
65
+ for adapter in self._adapters.values():
66
+ await adapter.shutdown()
67
+
68
+ def get(self, platform: str) -> BaseAdapter:
69
+ return self._adapters.get(platform)
70
+
71
+ def __getattr__(self, platform: str) -> BaseAdapter:
72
+ if platform not in self._adapters:
73
+ raise AttributeError(f"平台 {platform} 的适配器未注册")
74
+ return self._adapters[platform]
75
+
76
+ @property
77
+ def platforms(self) -> list:
78
+ return list(self._adapters.keys())
79
+
80
+ adapter = AdapterManager()
81
+ adapterbase = BaseAdapter
ErisPulse/db.py CHANGED
@@ -11,17 +11,15 @@ class EnvManager:
11
11
  def __new__(cls, *args, **kwargs):
12
12
  if not cls._instance:
13
13
  cls._instance = super().__new__(cls)
14
- cls._instance.dev_mode = kwargs.get('dev_mode', False)
15
14
  return cls._instance
16
15
 
17
- def __init__(self, dev_mode=False):
16
+ def __init__(self):
18
17
  if not hasattr(self, "_initialized"):
19
- self.dev_mode = dev_mode
20
18
  self._init_db()
21
-
19
+ self._initialized = True
20
+
22
21
  def _init_db(self):
23
22
  os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
24
-
25
23
  conn = sqlite3.connect(self.db_path)
26
24
  cursor = conn.cursor()
27
25
  cursor.execute("""
@@ -30,18 +28,6 @@ class EnvManager:
30
28
  value TEXT NOT NULL
31
29
  )
32
30
  """)
33
- cursor.execute("""
34
- CREATE TABLE IF NOT EXISTS modules (
35
- module_name TEXT PRIMARY KEY,
36
- status INTEGER NOT NULL,
37
- version TEXT,
38
- description TEXT,
39
- author TEXT,
40
- dependencies TEXT,
41
- optional_dependencies TEXT,
42
- pip_dependencies TEXT
43
- )
44
- """)
45
31
  conn.commit()
46
32
  conn.close()
47
33
 
@@ -64,6 +50,12 @@ class EnvManager:
64
50
  else:
65
51
  raise
66
52
 
53
+ def get_all_keys(self) -> list:
54
+ with sqlite3.connect(self.db_path) as conn:
55
+ cursor = conn.cursor()
56
+ cursor.execute("SELECT key FROM config")
57
+ return [row[0] for row in cursor.fetchall()]
58
+
67
59
  def set(self, key, value):
68
60
  serialized_value = json.dumps(value) if isinstance(value, (dict, list)) else str(value)
69
61
  conn = sqlite3.connect(self.db_path)
@@ -78,7 +70,7 @@ class EnvManager:
78
70
  cursor.execute("DELETE FROM config WHERE key = ?", (key,))
79
71
  conn.commit()
80
72
  conn.close()
81
-
73
+
82
74
  def clear(self):
83
75
  conn = sqlite3.connect(self.db_path)
84
76
  cursor = conn.cursor()
@@ -95,129 +87,7 @@ class EnvManager:
95
87
  for key, value in vars(env_module).items():
96
88
  if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
97
89
  self.set(key, value)
98
- def set_module_status(self, module_name, status):
99
- with sqlite3.connect(self.db_path) as conn:
100
- cursor = conn.cursor()
101
- cursor.execute("""
102
- UPDATE modules SET status = ? WHERE module_name = ?
103
- """, (int(status), module_name))
104
- conn.commit()
105
-
106
- def get_module_status(self, module_name):
107
- with sqlite3.connect(self.db_path) as conn:
108
- cursor = conn.cursor()
109
- cursor.execute("""
110
- SELECT status FROM modules WHERE module_name = ?
111
- """, (module_name,))
112
- result = cursor.fetchone()
113
- return bool(result[0]) if result else True
114
90
 
115
- def set_all_modules(self, modules_info):
116
- with sqlite3.connect(self.db_path) as conn:
117
- cursor = conn.cursor()
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', {})
121
- cursor.execute("""
122
- INSERT OR REPLACE INTO modules (
123
- module_name, status, version, description, author,
124
- dependencies, optional_dependencies, pip_dependencies
125
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
126
- """, (
127
- module_name,
128
- int(module_info.get('status', True)),
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', []))
135
- ))
136
- conn.commit()
137
-
138
- def get_all_modules(self):
139
- with sqlite3.connect(self.db_path) as conn:
140
- cursor = conn.cursor()
141
- cursor.execute("SELECT * FROM modules")
142
- rows = cursor.fetchall()
143
- modules_info = {}
144
- for row in rows:
145
- module_name, status, version, description, author, dependencies, optional_dependencies, pip_dependencies = row
146
- modules_info[module_name] = {
147
- 'status': bool(status),
148
- 'info': {
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
- }
160
- }
161
- }
162
- return modules_info
163
-
164
- def set_module(self, module_name, module_info):
165
- with sqlite3.connect(self.db_path) as conn:
166
- cursor = conn.cursor()
167
- meta = module_info.get('info', {}).get('meta', {})
168
- dependencies = module_info.get('info', {}).get('dependencies', {})
169
- cursor.execute("""
170
- INSERT OR REPLACE INTO modules (
171
- module_name, status, version, description, author,
172
- dependencies, optional_dependencies, pip_dependencies
173
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)
174
- """, (
175
- module_name,
176
- int(module_info.get('status', True)),
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', []))
183
- ))
184
- conn.commit()
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
-
211
- def update_module(self, module_name, module_info):
212
- self.set_module(module_name, module_info)
213
-
214
- def remove_module(self, module_name):
215
- with sqlite3.connect(self.db_path) as conn:
216
- cursor = conn.cursor()
217
- cursor.execute("DELETE FROM modules WHERE module_name = ?", (module_name,))
218
- conn.commit()
219
- return cursor.rowcount > 0
220
-
221
91
  def __getattr__(self, key):
222
92
  try:
223
93
  return self.get(key)
ErisPulse/logger.py CHANGED
@@ -19,7 +19,7 @@ class Logger:
19
19
  level = level.upper()
20
20
  if hasattr(logging, level):
21
21
  self._logger.setLevel(getattr(logging, level))
22
-
22
+
23
23
  def set_module_level(self, module_name: str, level: str) -> bool:
24
24
  from .db import env
25
25
  if not env.get_module_status(module_name):
@@ -33,15 +33,15 @@ class Logger:
33
33
  else:
34
34
  self._logger.error(f"无效的日志等级: {level}")
35
35
  return False
36
-
36
+
37
37
  def set_output_file(self, path: str | list):
38
38
  if self._file_handler:
39
39
  self._logger.removeHandler(self._file_handler)
40
40
  self._file_handler.close()
41
-
41
+
42
42
  if isinstance(path, str):
43
43
  path = [path]
44
-
44
+
45
45
  for p in path:
46
46
  try:
47
47
  file_handler = logging.FileHandler(p, encoding='utf-8')
@@ -51,14 +51,14 @@ class Logger:
51
51
  except Exception as e:
52
52
  self._logger.error(f"无法设置日志文件 {p}: {e}")
53
53
  raise e
54
-
54
+
55
55
  def save_logs(self, path: str | list):
56
56
  if self._logs == None:
57
57
  self._logger.warning("没有log记录可供保存。")
58
58
  return
59
59
  if isinstance(path, str):
60
60
  path = [path]
61
-
61
+
62
62
  for p in path:
63
63
  try:
64
64
  with open(p, "w", encoding="utf-8") as file:
@@ -70,14 +70,14 @@ class Logger:
70
70
  except Exception as e:
71
71
  self._logger.error(f"无法保存日志到 {p}: {e}。")
72
72
  raise e
73
-
73
+
74
74
  def catch(self, func_or_level=None, level="error"):
75
75
  if isinstance(func_or_level, str):
76
76
  return lambda func: self.catch(func, level=func_or_level)
77
77
  if func_or_level is None:
78
78
  return lambda func: self.catch(func, level=level)
79
79
  func = func_or_level
80
-
80
+
81
81
  @functools.wraps(func)
82
82
  def wrapper(*args, **kwargs):
83
83
  try:
@@ -85,17 +85,17 @@ class Logger:
85
85
  except Exception as e:
86
86
  import traceback
87
87
  error_info = traceback.format_exc()
88
-
88
+
89
89
  module_name = func.__module__
90
90
  if module_name == "__main__":
91
91
  module_name = "Main"
92
92
  func_name = func.__name__
93
-
93
+
94
94
  error_msg = f"Exception in {func_name}: {str(e)}\n{error_info}"
95
-
95
+
96
96
  log_method = getattr(self, level, self.error)
97
97
  log_method(error_msg)
98
-
98
+
99
99
  return None
100
100
  return wrapper
101
101
 
@@ -105,10 +105,10 @@ class Logger:
105
105
  timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
106
106
  msg = f"{timestamp} - {msg}"
107
107
  self._logs[ModuleName].append(msg)
108
-
108
+
109
109
  def _get_effective_level(self, module_name):
110
110
  return self._module_levels.get(module_name, self._logger.level)
111
-
111
+
112
112
  def _get_caller(self):
113
113
  frame = inspect.currentframe().f_back.f_back
114
114
  module = inspect.getmodule(frame)
ErisPulse/mods.py ADDED
@@ -0,0 +1,86 @@
1
+ import json
2
+ from typing import Dict, Optional
3
+
4
+ class ModuleManager:
5
+ DEFAULT_MODULE_PREFIX = "erispulse.module.data:"
6
+ DEFAULT_STATUS_PREFIX = "erispulse.module.status:"
7
+
8
+ def __init__(self):
9
+ from .db import env
10
+ self.env = env
11
+ self._ensure_prefixes()
12
+
13
+ def _ensure_prefixes(self):
14
+ if not self.env.get("erispulse.system.module_prefix"):
15
+ self.env.set("erispulse.system.module_prefix", self.DEFAULT_MODULE_PREFIX)
16
+ if not self.env.get("erispulse.system.status_prefix"):
17
+ self.env.set("erispulse.system.status_prefix", self.DEFAULT_STATUS_PREFIX)
18
+
19
+ @property
20
+ def module_prefix(self) -> str:
21
+ return self.env.get("erispulse.system.module_prefix")
22
+
23
+ @property
24
+ def status_prefix(self) -> str:
25
+ return self.env.get("erispulse.system.status_prefix")
26
+
27
+ def set_module_status(self, module_name: str, status: bool) -> None:
28
+ self.env.set(f"{self.status_prefix}{module_name}", bool(status))
29
+
30
+ def get_module_status(self, module_name: str) -> bool:
31
+ status = self.env.get(f"{self.status_prefix}{module_name}", True)
32
+ if isinstance(status, str):
33
+ return status.lower() == 'true'
34
+ return bool(status)
35
+
36
+ def set_module(self, module_name: str, module_info: dict) -> None:
37
+ self.env.set(f"{self.module_prefix}{module_name}", module_info)
38
+ self.set_module_status(module_name, module_info.get('status', True))
39
+
40
+ def get_module(self, module_name: str) -> Optional[dict]:
41
+ return self.env.get(f"{self.module_prefix}{module_name}")
42
+
43
+ def set_all_modules(self, modules_info: Dict[str, dict]) -> None:
44
+ for module_name, module_info in modules_info.items():
45
+ self.set_module(module_name, module_info)
46
+
47
+ def get_all_modules(self) -> dict:
48
+ modules_info = {}
49
+ all_keys = self.env.get_all_keys()
50
+ prefix_len = len(self.module_prefix)
51
+
52
+ for key in all_keys:
53
+ if key.startswith(self.module_prefix):
54
+ module_name = key[prefix_len:]
55
+ module_info = self.get_module(module_name)
56
+ if module_info:
57
+ status = self.get_module_status(module_name)
58
+ module_info['status'] = bool(status)
59
+ modules_info[module_name] = module_info
60
+ return modules_info
61
+
62
+ def update_module(self, module_name: str, module_info: dict) -> None:
63
+ self.set_module(module_name, module_info)
64
+
65
+ def remove_module(self, module_name: str) -> bool:
66
+ module_key = f"{self.module_prefix}{module_name}"
67
+ status_key = f"{self.status_prefix}{module_name}"
68
+
69
+ if self.env.get(module_key) is not None:
70
+ self.env.delete(module_key)
71
+ self.env.delete(status_key)
72
+ return True
73
+ return False
74
+
75
+ def update_prefixes(self, module_prefix: str = None, status_prefix: str = None) -> None:
76
+ if module_prefix:
77
+ if not module_prefix.endswith(':'):
78
+ module_prefix += ':'
79
+ self.env.set("erispulse.system.module_prefix", module_prefix)
80
+
81
+ if status_prefix:
82
+ if not status_prefix.endswith(':'):
83
+ status_prefix += ':'
84
+ self.env.set("erispulse.system.status_prefix", status_prefix)
85
+
86
+ mods = ModuleManager()
ErisPulse/raiserr.py CHANGED
@@ -40,5 +40,5 @@ class Error:
40
40
  "doc": getattr(err_cls, "__doc__", ""),
41
41
  "class": err_cls,
42
42
  }
43
-
43
+
44
44
  raiserr = Error()
ErisPulse/util.py CHANGED
@@ -1,4 +1,6 @@
1
+ import time
1
2
  import asyncio
3
+ import functools
2
4
  from concurrent.futures import ThreadPoolExecutor
3
5
  from collections import defaultdict, deque
4
6
 
@@ -26,4 +28,37 @@ def topological_sort(elements, dependencies, error):
26
28
 
27
29
  def ExecAsync(async_func, *args, **kwargs):
28
30
  loop = asyncio.get_event_loop()
29
- return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
31
+ return loop.run_in_executor(executor, lambda: asyncio.run(async_func(*args, **kwargs)))
32
+
33
+ def cache(func):
34
+ cache_dict = {}
35
+ @functools.wraps(func)
36
+ def wrapper(*args, **kwargs):
37
+ key = (args, tuple(sorted(kwargs.items())))
38
+ if key not in cache_dict:
39
+ cache_dict[key] = func(*args, **kwargs)
40
+ return cache_dict[key]
41
+ return wrapper
42
+
43
+ def run_in_executor(func):
44
+ @functools.wraps(func)
45
+ async def wrapper(*args, **kwargs):
46
+ loop = asyncio.get_event_loop()
47
+ return await loop.run_in_executor(None, lambda: func(*args, **kwargs))
48
+ return wrapper
49
+
50
+ def retry(max_attempts=3, delay=1):
51
+ def decorator(func):
52
+ @functools.wraps(func)
53
+ def wrapper(*args, **kwargs):
54
+ attempts = 0
55
+ while attempts < max_attempts:
56
+ try:
57
+ return func(*args, **kwargs)
58
+ except Exception as e:
59
+ attempts += 1
60
+ if attempts == max_attempts:
61
+ raise
62
+ time.sleep(delay)
63
+ return wrapper
64
+ return decorator
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ErisPulse
3
- Version: 1.0.14.dev2
3
+ Version: 1.0.15
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,8 +20,6 @@ Requires-Python: >=3.7
20
20
  Description-Content-Type: text/markdown
21
21
  Requires-Dist: aiohttp
22
22
 
23
- ⚠ 当前版本处于开发中,请谨慎使用。
24
-
25
23
  ![](./.github/assets/erispulse_logo.png)
26
24
 
27
25
  基于 [RyhBotPythonSDK V2](https://github.com/runoneall/RyhBotPythonSDK2) 构建,由 [sdkFrame](https://github.com/runoneall/sdkFrame) 提供支持的异步机器人开发框架。
@@ -0,0 +1,13 @@
1
+ ErisPulse/__init__.py,sha256=di4Bii26xJYMk1xqoPNGM0lk2CABlxa3MC-9iOvKPYs,7318
2
+ ErisPulse/__main__.py,sha256=-UdhsYP_X7EagomCjo73Y_qQdXwtMbDS5KoOSrI-OcU,32181
3
+ ErisPulse/adapter.py,sha256=9BxzBrr5LkQcKY8ONuv7MYxlUrvkINuG9TtdzKgwUWY,2687
4
+ ErisPulse/db.py,sha256=oLdOe8LgklBSOWHXu8QDEnaVkjf0bvJLsbJVoT_uw2U,3188
5
+ ErisPulse/logger.py,sha256=HIQMYD75K-PL4IETMlm7V6Eyg0ussZ11_riEw5E5a08,5899
6
+ ErisPulse/mods.py,sha256=M9XQWUQYNZ11m845hxbewBAauWXnysy-aOdLwb5xy_M,3312
7
+ ErisPulse/raiserr.py,sha256=MPA3ZcPEzuhJldmFG19oSvjxzVojcQ9jZYfmcEQr_SU,1292
8
+ ErisPulse/util.py,sha256=01kUQwVFeE7gyD1skCwjpANYzVUHjLC6J1UUzfQXPco,2139
9
+ erispulse-1.0.15.dist-info/METADATA,sha256=VmyDSAX2FLp-kHcsMeby2KImmwi_g_xwD8LJEVOsivI,2443
10
+ erispulse-1.0.15.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
11
+ erispulse-1.0.15.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
12
+ erispulse-1.0.15.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
13
+ erispulse-1.0.15.dist-info/RECORD,,
@@ -1,11 +0,0 @@
1
- ErisPulse/__init__.py,sha256=75SfkJEYHy73K3UGaEuMYlHtJadjpoNWd1yF-f5-aGc,6662
2
- ErisPulse/__main__.py,sha256=1-mWPmZArG-o_eYxZiabmMs4MokQn_-TBa43R4_WYlc,32141
3
- ErisPulse/db.py,sha256=2vBVFFEU-AcR-GkzWTqpn8fFV9EvuQee2mi1XzfDXVI,9077
4
- ErisPulse/logger.py,sha256=HwceD81nLiLCh_WGcCVsEG6OqL-NL5HmdONFTGH-8Og,6023
5
- ErisPulse/raiserr.py,sha256=WTMQEUbUSx4PS9_l9cEnuNuvm6zulgwQFipqVZZg3zc,1296
6
- ErisPulse/util.py,sha256=90j71c32yP-s2zy1SM-1FExJRu7pWpkuPVQSXCaVTrg,1087
7
- erispulse-1.0.14.dev2.dist-info/METADATA,sha256=THVd9A1Nl5F0ij89R0mOuwvZxgO2ufyJlk72GZeBjAQ,2502
8
- erispulse-1.0.14.dev2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
9
- erispulse-1.0.14.dev2.dist-info/entry_points.txt,sha256=AjKvOdYR7QGXVpEJhjUYUwV2JluE4lm9vNbknC3hjOM,155
10
- erispulse-1.0.14.dev2.dist-info/top_level.txt,sha256=Lm_qtkVvNJR8_dXh_qEDdl_12cZGpic-i4HUlVVUMZc,10
11
- erispulse-1.0.14.dev2.dist-info/RECORD,,