ErisPulse 2.1.13rc2__py3-none-any.whl → 2.1.14a1__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.
@@ -2,9 +2,10 @@ from .adapter import AdapterFather, SendDSL, adapter
2
2
  from .env import env
3
3
  from .logger import logger
4
4
  from .mods import mods
5
- from .raiserr import raiserr
6
- from .util import util
7
- from .server import adapter_server
5
+ from .router import router, adapter_server
6
+ from .config import config
7
+ from . import exceptions
8
+
8
9
  BaseAdapter = AdapterFather
9
10
 
10
11
  __all__ = [
@@ -15,7 +16,8 @@ __all__ = [
15
16
  'env',
16
17
  'logger',
17
18
  'mods',
18
- 'raiserr',
19
- 'util',
20
- 'adapter_server'
19
+ 'exceptions',
20
+ 'router',
21
+ 'adapter_server',
22
+ 'config'
21
23
  ]
ErisPulse/Core/adapter.py CHANGED
@@ -13,14 +13,12 @@ ErisPulse 适配器系统
13
13
 
14
14
  import functools
15
15
  import asyncio
16
- import uuid
17
- import time
18
16
  from typing import (
19
17
  Callable, Any, Dict, List, Type, Optional, Set,
20
- Union, Awaitable, TypeVar, Generic, Tuple, Coroutine, FrozenSet
18
+ Union, Awaitable
21
19
  )
22
20
  from collections import defaultdict
23
-
21
+ from .logger import logger
24
22
 
25
23
  class SendDSLBase:
26
24
  """
@@ -114,7 +112,6 @@ class BaseAdapter:
114
112
  :example:
115
113
  >>> await adapter.Send.To("123").Example("Hello")
116
114
  """
117
- from .logger import logger
118
115
  logger.debug(f"适配器 {self._adapter.__class__.__name__} 发送了实例类型的消息: {text}")
119
116
 
120
117
 
@@ -378,7 +375,7 @@ class AdapterManager:
378
375
  for name in set(combinations):
379
376
  setattr(self, name, instance)
380
377
  else:
381
- self.logger.warning(f"平台名 {platform} 过长,如果您是开发者,请考虑使用更短的名称")
378
+ logger.warning(f"平台名 {platform} 过长,如果您是开发者,请考虑使用更短的名称")
382
379
  setattr(self, platform.lower(), instance)
383
380
  setattr(self, platform.upper(), instance)
384
381
  setattr(self, platform.capitalize(), instance)
@@ -401,10 +398,18 @@ class AdapterManager:
401
398
  """
402
399
  if platforms is None:
403
400
  platforms = list(self._adapters.keys())
401
+ if not isinstance(platforms, list):
402
+ platforms = [platforms]
403
+ for platform in platforms:
404
+ if platform not in self._adapters:
405
+ raise ValueError(f"平台 {platform} 未注册")
406
+
407
+ logger.info(f"启动适配器 {platforms}")
404
408
 
405
- from .server import adapter_server
406
- from .config import get_server_config
409
+ from .router import adapter_server
410
+ from .erispulse_config import get_server_config
407
411
  server_config = get_server_config()
412
+
408
413
  host = server_config["host"]
409
414
  port = server_config["port"]
410
415
  ssl_cert = server_config.get("ssl_certfile", None)
@@ -441,16 +446,14 @@ class AdapterManager:
441
446
  :param adapter: 适配器实例
442
447
  :param platform: 平台名称
443
448
  """
444
- from .. import sdk
445
449
 
446
- # 加锁防止并发启动
447
450
  if not getattr(adapter, "_starting_lock", None):
448
451
  adapter._starting_lock = asyncio.Lock()
449
452
 
450
453
  async with adapter._starting_lock:
451
454
  # 再次确认是否已经被启动
452
455
  if adapter in self._started_instances:
453
- sdk.logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已被其他协程启动,跳过")
456
+ logger.info(f"适配器 {platform}(实例ID: {id(adapter)})已被其他协程启动,跳过")
454
457
  return
455
458
 
456
459
  retry_count = 0
@@ -464,12 +467,12 @@ class AdapterManager:
464
467
  return
465
468
  except Exception as e:
466
469
  retry_count += 1
467
- sdk.logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
470
+ logger.error(f"平台 {platform} 启动失败(第{retry_count}次重试): {e}")
468
471
 
469
472
  try:
470
473
  await adapter.shutdown()
471
474
  except Exception as stop_err:
472
- sdk.logger.warning(f"停止适配器失败: {stop_err}")
475
+ logger.warning(f"停止适配器失败: {stop_err}")
473
476
 
474
477
  # 计算等待时间
475
478
  if retry_count <= len(backoff_intervals):
@@ -477,7 +480,7 @@ class AdapterManager:
477
480
  else:
478
481
  wait_time = fixed_delay
479
482
 
480
- sdk.logger.info(f"将在 {wait_time // 60} 分钟后再次尝试重启 {platform}")
483
+ logger.info(f"将在 {wait_time // 60} 分钟后再次尝试重启 {platform}")
481
484
  await asyncio.sleep(wait_time)
482
485
 
483
486
  async def shutdown(self) -> None:
@@ -490,7 +493,7 @@ class AdapterManager:
490
493
  for adapter in self._adapters.values():
491
494
  await adapter.shutdown()
492
495
 
493
- from .server import adapter_server
496
+ from .router import adapter_server
494
497
  await adapter_server.stop()
495
498
 
496
499
  def get(self, platform: str) -> Optional[BaseAdapter]:
ErisPulse/Core/config.py CHANGED
@@ -72,101 +72,3 @@ class ConfigManager:
72
72
  return False
73
73
 
74
74
  config = ConfigManager()
75
-
76
- # 默认配置
77
- DEFAULT_CONFIG = {
78
- "server": {
79
- "host": "0.0.0.0",
80
- "port": 8000,
81
- "ssl_certfile": None,
82
- "ssl_keyfile": None
83
- },
84
- "logger": {
85
- "level": "INFO",
86
- "log_files": [],
87
- "memory_limit": 1000
88
- }
89
- }
90
-
91
- def _ensure_config_structure(config: Dict[str, Any]) -> Dict[str, Any]:
92
- """
93
- 确保配置结构完整,补全缺失的配置项
94
-
95
- :param config: 当前配置
96
- :return: 补全后的完整配置
97
- """
98
- merged_config = DEFAULT_CONFIG.copy()
99
-
100
- # 深度合并配置
101
- for section, default_values in DEFAULT_CONFIG.items():
102
- if section not in config:
103
- config[section] = default_values.copy()
104
- continue
105
-
106
- if not isinstance(config[section], dict):
107
- config[section] = default_values.copy()
108
- continue
109
-
110
- for key, default_value in default_values.items():
111
- if key not in config[section]:
112
- config[section][key] = default_value
113
-
114
- return config
115
-
116
- def get_config() -> Dict[str, Any]:
117
- """
118
- 获取当前配置,自动补全缺失的配置项并保存
119
-
120
- :return: 完整的配置字典
121
- """
122
-
123
- # 获取现有配置
124
- current_config = config.getConfig("ErisPulse")
125
-
126
- # 如果完全没有配置,设置默认配置
127
- if current_config is None:
128
- config.setConfig("ErisPulse", DEFAULT_CONFIG)
129
- return DEFAULT_CONFIG
130
-
131
- # 检查并补全缺失的配置项
132
- complete_config = _ensure_config_structure(current_config)
133
-
134
- # 如果配置有变化,更新到存储
135
- if current_config != complete_config:
136
- config.setConfig("ErisPulse", complete_config)
137
-
138
- return complete_config
139
-
140
- def update_config(new_config: Dict[str, Any]) -> bool:
141
- """
142
- 更新配置,自动补全缺失的配置项
143
-
144
- :param new_config: 新的配置字典
145
- :return: 是否更新成功
146
- """
147
- # 获取当前配置并合并新配置
148
- current = get_config()
149
- merged = {**current, **new_config}
150
-
151
- # 确保合并后的配置结构完整
152
- complete_config = _ensure_config_structure(merged)
153
-
154
- return config.setConfig("ErisPulse", complete_config)
155
-
156
- def get_server_config() -> Dict[str, Any]:
157
- """
158
- 获取服务器配置,确保结构完整
159
-
160
- :return: 服务器配置字典
161
- """
162
- config = get_config()
163
- return config["server"]
164
-
165
- def get_logger_config() -> Dict[str, Any]:
166
- """
167
- 获取日志配置,确保结构完整
168
-
169
- :return: 日志配置字典
170
- """
171
- config = get_config()
172
- return config["logger"]
ErisPulse/Core/env.py CHANGED
@@ -13,14 +13,10 @@ ErisPulse 环境配置模块
13
13
  import os
14
14
  import json
15
15
  import sqlite3
16
- import importlib.util
17
16
  import shutil
18
17
  import time
19
- import toml
20
- from pathlib import Path
21
18
  from datetime import datetime
22
- from functools import lru_cache
23
- from typing import List, Dict, Optional, Any, Set, Tuple, Union, Type, FrozenSet
19
+ from typing import List, Dict, Optional, Any, Tuple, Type
24
20
 
25
21
  class EnvManager:
26
22
  """
@@ -39,7 +35,6 @@ class EnvManager:
39
35
  db_path = os.path.join(os.path.dirname(__file__), "../data/config.db")
40
36
  SNAPSHOT_DIR = os.path.join(os.path.dirname(__file__), "../data/snapshots")
41
37
 
42
- CONFIG_FILE = "config.toml"
43
38
 
44
39
  def __new__(cls, *args, **kwargs):
45
40
  if not cls._instance:
@@ -192,8 +187,6 @@ class EnvManager:
192
187
  from .config import config
193
188
  return config.getConfig(key, default)
194
189
  except Exception as e:
195
- from . import logger
196
- logger.error(f"读取配置文件 {self.CONFIG_FILE} 失败: {e}")
197
190
  return default
198
191
 
199
192
  def setConfig(self, key: str, value: Any) -> bool:
@@ -207,8 +200,6 @@ class EnvManager:
207
200
  from .config import config
208
201
  return config.setConfig(key, value)
209
202
  except Exception as e:
210
- from . import logger
211
- logger.error(f"写入配置文件 {self.CONFIG_FILE} 失败: {e}")
212
203
  return False
213
204
 
214
205
  def delete(self, key: str) -> bool:
@@ -385,29 +376,7 @@ class EnvManager:
385
376
  return True
386
377
  except Exception as e:
387
378
  return False
388
-
389
- def load_env_file(self) -> bool:
390
- """
391
- 加载env.py文件中的配置项
392
379
 
393
- :return: 操作是否成功
394
-
395
- :example:
396
- >>> env.load_env_file() # 加载env.py中的配置
397
- """
398
- try:
399
- env_file = Path("env.py")
400
- if env_file.exists():
401
- spec = importlib.util.spec_from_file_location("env_module", env_file)
402
- env_module = importlib.util.module_from_spec(spec)
403
- spec.loader.exec_module(env_module)
404
- for key, value in vars(env_module).items():
405
- if not key.startswith("__") and isinstance(value, (dict, list, str, int, float, bool)):
406
- self.set(key, value)
407
- return True
408
- except Exception as e:
409
- return False
410
-
411
380
  def __getattr__(self, key: str) -> Any:
412
381
  """
413
382
  通过属性访问配置项
@@ -0,0 +1,105 @@
1
+ """
2
+ ErisPulse 框架配置管理
3
+
4
+ 专门管理 ErisPulse 框架自身的配置项。
5
+ """
6
+
7
+ from typing import Dict, Any
8
+ from .config import config
9
+
10
+ # 默认配置
11
+ DEFAULT_ERISPULSE_CONFIG = {
12
+ "server": {
13
+ "host": "0.0.0.0",
14
+ "port": 8000,
15
+ "ssl_certfile": None,
16
+ "ssl_keyfile": None
17
+ },
18
+ "logger": {
19
+ "level": "INFO",
20
+ "log_files": [],
21
+ "memory_limit": 1000
22
+ }
23
+ }
24
+
25
+ def _ensure_erispulse_config_structure(config_dict: Dict[str, Any]) -> Dict[str, Any]:
26
+ """
27
+ 确保 ErisPulse 配置结构完整,补全缺失的配置项
28
+
29
+ :param config_dict: 当前配置
30
+ :return: 补全后的完整配置
31
+ """
32
+ merged_config = DEFAULT_ERISPULSE_CONFIG.copy()
33
+
34
+ # 深度合并配置
35
+ for section, default_values in DEFAULT_ERISPULSE_CONFIG.items():
36
+ if section not in config_dict:
37
+ config_dict[section] = default_values.copy()
38
+ continue
39
+
40
+ if not isinstance(config_dict[section], dict):
41
+ config_dict[section] = default_values.copy()
42
+ continue
43
+
44
+ for key, default_value in default_values.items():
45
+ if key not in config_dict[section]:
46
+ config_dict[section][key] = default_value
47
+
48
+ return config_dict
49
+
50
+ def get_erispulse_config() -> Dict[str, Any]:
51
+ """
52
+ 获取 ErisPulse 框架配置,自动补全缺失的配置项并保存
53
+
54
+ :return: 完整的 ErisPulse 配置字典
55
+ """
56
+ # 获取现有配置
57
+ current_config = config.getConfig("ErisPulse")
58
+
59
+ # 如果完全没有配置,设置默认配置
60
+ if current_config is None:
61
+ config.setConfig("ErisPulse", DEFAULT_ERISPULSE_CONFIG)
62
+ return DEFAULT_ERISPULSE_CONFIG
63
+
64
+ # 检查并补全缺失的配置项
65
+ complete_config = _ensure_erispulse_config_structure(current_config)
66
+
67
+ # 如果配置有变化,更新到存储
68
+ if current_config != complete_config:
69
+ config.setConfig("ErisPulse", complete_config)
70
+
71
+ return complete_config
72
+
73
+ def update_erispulse_config(new_config: Dict[str, Any]) -> bool:
74
+ """
75
+ 更新 ErisPulse 配置,自动补全缺失的配置项
76
+
77
+ :param new_config: 新的配置字典
78
+ :return: 是否更新成功
79
+ """
80
+ # 获取当前配置并合并新配置
81
+ current = get_erispulse_config()
82
+ merged = {**current, **new_config}
83
+
84
+ # 确保合并后的配置结构完整
85
+ complete_config = _ensure_erispulse_config_structure(merged)
86
+
87
+ return config.setConfig("ErisPulse", complete_config)
88
+
89
+ def get_server_config() -> Dict[str, Any]:
90
+ """
91
+ 获取服务器配置,确保结构完整
92
+
93
+ :return: 服务器配置字典
94
+ """
95
+ erispulse_config = get_erispulse_config()
96
+ return erispulse_config["server"]
97
+
98
+ def get_logger_config() -> Dict[str, Any]:
99
+ """
100
+ 获取日志配置,确保结构完整
101
+
102
+ :return: 日志配置字典
103
+ """
104
+ erispulse_config = get_erispulse_config()
105
+ return erispulse_config["logger"]
@@ -0,0 +1,108 @@
1
+ """
2
+ ErisPulse 全局异常处理系统
3
+
4
+ 提供统一的异常捕获和格式化功能,支持同步和异步代码的异常处理。
5
+ """
6
+
7
+ import sys
8
+ import traceback
9
+ import asyncio
10
+ import os
11
+ from typing import Dict, Any, Type
12
+
13
+ class ExceptionHandler:
14
+ @staticmethod
15
+ def format_exception(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> str:
16
+ """
17
+ :param exc_type: 异常类型
18
+ :param exc_value: 异常值
19
+ :param exc_traceback: 追踪信息
20
+ :return: 格式化后的异常信息
21
+ """
22
+ tb_list = traceback.extract_tb(exc_traceback)
23
+ if tb_list:
24
+ last_frame = tb_list[-1]
25
+ filename = os.path.basename(last_frame.filename)
26
+ line_number = last_frame.lineno
27
+ function_name = last_frame.name
28
+ return f"ERROR: {filename}:{function_name}:{line_number}: {exc_type.__name__}: {exc_value}"
29
+ else:
30
+ return f"ERROR: {exc_type.__name__}: {exc_value}"
31
+
32
+ @staticmethod
33
+ def format_async_exception(exception: Exception) -> str:
34
+ """
35
+ :param exception: 异常对象
36
+ :return: 格式化后的异常信息
37
+ """
38
+ if exception.__traceback__:
39
+ tb_list = traceback.extract_tb(exception.__traceback__)
40
+ if tb_list:
41
+ last_frame = tb_list[-1]
42
+ filename = os.path.basename(last_frame.filename)
43
+ line_number = last_frame.lineno
44
+ function_name = last_frame.name
45
+ return f"ERROR: {filename}:{function_name}:{line_number}: {type(exception).__name__}: {exception}"
46
+
47
+ return f"ERROR: {type(exception).__name__}: {exception}"
48
+
49
+ def global_exception_handler(exc_type: Type[Exception], exc_value: Exception, exc_traceback: Any) -> None:
50
+ """
51
+ 全局异常处理器
52
+
53
+ :param exc_type: 异常类型
54
+ :param exc_value: 异常值
55
+ :param exc_traceback: 追踪信息
56
+ """
57
+ try:
58
+ from ErisPulse import logger
59
+ err_logger = logger.error
60
+ except ImportError:
61
+ err_logger = sys.stderr.write
62
+
63
+ formatted_error = ExceptionHandler.format_exception(exc_type, exc_value, exc_traceback)
64
+ err_logger(formatted_error)
65
+
66
+ def async_exception_handler(loop: asyncio.AbstractEventLoop, context: Dict[str, Any]) -> None:
67
+ """
68
+ 异步异常处理器
69
+
70
+ :param loop: 事件循环
71
+ :param context: 上下文字典
72
+ """
73
+ try:
74
+ from ErisPulse import logger
75
+ err_logger = logger.error
76
+ except ImportError:
77
+ err_logger = sys.stderr.write
78
+
79
+ exception = context.get('exception')
80
+ if exception:
81
+ try:
82
+ formatted_error = ExceptionHandler.format_async_exception(exception)
83
+ err_logger(formatted_error + '\n')
84
+ except Exception:
85
+ err_logger(f"ERROR: 捕捉器发生错误,原始异常信息:\n\n{exception}\n\n" + traceback.format_exc())
86
+ else:
87
+ msg = context.get('message', '未知异步错误')
88
+ err_logger(f"ERROR: 未处理的异步错误: {msg}\n")
89
+
90
+ def setup_async_loop(loop: asyncio.AbstractEventLoop = None) -> None:
91
+ """
92
+ 为指定的事件循环设置异常处理器
93
+
94
+ :param loop: 事件循环实例,如果为None则使用当前事件循环
95
+ """
96
+ if loop is None:
97
+ try:
98
+ loop = asyncio.get_running_loop()
99
+ except RuntimeError:
100
+ loop = asyncio.get_event_loop()
101
+
102
+ loop.set_exception_handler(async_exception_handler)
103
+
104
+ sys.excepthook = global_exception_handler
105
+ try:
106
+ asyncio.get_event_loop().set_exception_handler(async_exception_handler)
107
+ except RuntimeError:
108
+ pass
ErisPulse/Core/logger.py CHANGED
@@ -56,6 +56,10 @@ class Logger:
56
56
  """
57
57
  if limit > 0:
58
58
  self._max_logs = limit
59
+ # 更新所有已存在的日志列表大小
60
+ for module_name in self._logs:
61
+ while len(self._logs[module_name]) > self._max_logs:
62
+ self._logs[module_name].pop(0)
59
63
  return True
60
64
  else:
61
65
  self._logger.warning("日志存储上限必须大于0。")
@@ -174,7 +178,7 @@ class Logger:
174
178
  self._logs[ModuleName].append(msg)
175
179
 
176
180
  def _setup_config(self):
177
- from .config import get_logger_config
181
+ from .erispulse_config import get_logger_config
178
182
  logger_config = get_logger_config()
179
183
  if "level" in logger_config:
180
184
  self.set_level(logger_config["level"])
@@ -198,6 +202,20 @@ class Logger:
198
202
  module_name = "ErisPulse"
199
203
  return module_name
200
204
 
205
+ def get_child(self, child_name: str = None):
206
+ """
207
+ 获取子日志记录器
208
+
209
+ :param child_name: 子模块名称(可选)
210
+ :return: LoggerChild 子日志记录器实例
211
+ """
212
+ caller_module = self._get_caller()
213
+ if child_name:
214
+ full_module_name = f"{caller_module}.{child_name}"
215
+ else:
216
+ full_module_name = caller_module
217
+ return LoggerChild(self, full_module_name)
218
+
201
219
  def debug(self, msg, *args, **kwargs):
202
220
  caller_module = self._get_caller()
203
221
  if self._get_effective_level(caller_module) <= logging.DEBUG:
@@ -229,4 +247,59 @@ class Logger:
229
247
  self._logger.critical(f"[{caller_module}] {msg}", *args, **kwargs)
230
248
  raise Exception(msg)
231
249
 
250
+
251
+ class LoggerChild:
252
+ """
253
+ 子日志记录器
254
+
255
+ 用于创建具有特定名称的子日志记录器,仅改变模块名称,其他功能全部委托给父日志记录器
256
+ """
257
+
258
+ def __init__(self, parent_logger: Logger, name: str):
259
+ """
260
+ 初始化子日志记录器
261
+
262
+ :param parent_logger: 父日志记录器实例
263
+ :param name: 子日志记录器名称
264
+ """
265
+ self._parent = parent_logger
266
+ self._name = name
267
+
268
+ def debug(self, msg, *args, **kwargs):
269
+ if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.DEBUG:
270
+ self._parent._save_in_memory(self._name, msg)
271
+ self._parent._logger.debug(f"[{self._name}] {msg}", *args, **kwargs)
272
+
273
+ def info(self, msg, *args, **kwargs):
274
+ if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.INFO:
275
+ self._parent._save_in_memory(self._name, msg)
276
+ self._parent._logger.info(f"[{self._name}] {msg}", *args, **kwargs)
277
+
278
+ def warning(self, msg, *args, **kwargs):
279
+ if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.WARNING:
280
+ self._parent._save_in_memory(self._name, msg)
281
+ self._parent._logger.warning(f"[{self._name}] {msg}", *args, **kwargs)
282
+
283
+ def error(self, msg, *args, **kwargs):
284
+ if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.ERROR:
285
+ self._parent._save_in_memory(self._name, msg)
286
+ self._parent._logger.error(f"[{self._name}] {msg}", *args, **kwargs)
287
+
288
+ def critical(self, msg, *args, **kwargs):
289
+ if self._parent._get_effective_level(self._name.split('.')[0]) <= logging.CRITICAL:
290
+ self._parent._save_in_memory(self._name, msg)
291
+ self._parent._logger.critical(f"[{self._name}] {msg}", *args, **kwargs)
292
+ raise Exception(msg)
293
+
294
+ def get_child(self, child_name: str):
295
+ """
296
+ 获取子日志记录器的子记录器
297
+
298
+ :param child_name: 子模块名称
299
+ :return: LoggerChild 子日志记录器实例
300
+ """
301
+ full_child_name = f"{self._name}.{child_name}"
302
+ return LoggerChild(self._parent, full_child_name)
303
+
304
+
232
305
  logger = Logger()