feat: 改进配置加载逻辑并更新项目配置

当配置文件不存在时自动生成示例配置
添加pyproject.toml作为项目构建配置
更新.gitignore忽略更多文件类型
删除不再使用的反向WebSocket示例文件
This commit is contained in:
2026-03-23 20:55:41 +08:00
parent cc2f8d059a
commit efc9a397bb
4 changed files with 135 additions and 63 deletions

28
.gitignore vendored
View File

@@ -115,7 +115,7 @@ env/
venv/ venv/
ENV/ ENV/
env.bak/ env.bak/
venv.bak/ venv.bak()
# Spyder project settings # Spyder project settings
.spyderproject .spyderproject
@@ -138,6 +138,9 @@ dmypy.json
# pytype static type analyzer # pytype static type analyzer
.pytype/ .pytype/
# Cython
*.c
# End of https://www.toptal.com/developers/gitignore/api/python # End of https://www.toptal.com/developers/gitignore/api/python
# Build artifacts # Build artifacts
@@ -146,4 +149,27 @@ build/
# Scratch files # Scratch files
scratch_files/ scratch_files/
# Sensitive files (should never be committed)
config.toml
config.example.toml
ca/*
*.pem
*.key
# Data directory (may contain sensitive data)
/core/data/* /core/data/*
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# OS
.DS_Store
Thumbs.db
# Logs
logs/
*.log

View File

@@ -38,10 +38,10 @@ class Config:
:raises ConfigError: 如果加载配置时发生其他错误 :raises ConfigError: 如果加载配置时发生其他错误
""" """
if not self.path.exists(): if not self.path.exists():
error = ConfigNotFoundError(message=f"配置文件 {self.path} 未找到") self.logger.warning(f"配置文件 {self.path} 未找到,正在生成示例配置...")
self.logger.error(f"配置加载失败: {error.message}") self._generate_example_config()
self.logger.log_custom_exception(error) self.logger.success(f"示例配置已生成: {self.path}")
raise error self.logger.info("请编辑配置文件后重新启动程序")
try: try:
self.logger.info(f"正在从 {self.path} 加载配置...") self.logger.info(f"正在从 {self.path} 加载配置...")
@@ -86,6 +86,19 @@ class Config:
self.logger.log_custom_exception(error) self.logger.log_custom_exception(error)
raise error raise error
def _generate_example_config(self):
"""
生成示例配置文件
"""
example_path = Path("config.example.toml")
if not example_path.exists():
self.logger.error(f"示例配置文件 {example_path} 不存在,无法生成配置")
raise ConfigNotFoundError(message=f"示例配置文件 {example_path} 不存在")
content = example_path.read_text()
self.path.write_text(content)
# 通过属性访问配置 # 通过属性访问配置
@property @property
def napcat_ws(self) -> NapCatWSModel: def napcat_ws(self) -> NapCatWSModel:

View File

@@ -1,58 +0,0 @@
"""
反向 WebSocket 使用示例
该文件展示了如何使用反向 WebSocket 功能。
"""
from core.managers import reverse_ws_manager
async def example_usage():
"""
使用示例
"""
# 1. 启动反向 WebSocket 服务端
await reverse_ws_manager.start(host="0.0.0.0", port=3002)
# 2. 等待客户端连接
# 此时 OneBot 实现(如 NapCat应该连接到 ws://your-server-ip:3002
# 3. 查看已连接的客户端
connected_clients = reverse_ws_manager.get_connected_clients()
print(f"已连接的客户端: {connected_clients}")
# 4. 查看健康的客户端
healthy_clients = reverse_ws_manager.get_healthy_clients()
print(f"健康的客户端: {healthy_clients}")
# 5. 调用 API使用负载均衡
response = await reverse_ws_manager.call_api(
action="get_login_info",
params={},
use_load_balance=True # 启用负载均衡
)
print(f"API 响应: {response}")
# 6. 调用 API向特定客户端发送
if connected_clients:
client_id = list(connected_clients.keys())[0]
response = await reverse_ws_manager.call_api(
action="get_login_info",
params={},
client_id=client_id,
use_load_balance=False # 不使用负载均衡
)
print(f"特定客户端 API 响应: {response}")
# 7. 获取负载最低的客户端
least_load_client = reverse_ws_manager.get_client_with_least_load()
if least_load_client:
print(f"负载最低的客户端: {least_load_client}")
# 8. 停止服务端
await reverse_ws_manager.stop()
if __name__ == "__main__":
import asyncio
asyncio.run(example_usage())

91
pyproject.toml Normal file
View File

@@ -0,0 +1,91 @@
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "neobot"
version = "0.1.0"
description = "NEO Bot Framework - A high-performance bot framework"
readme = "README.md"
requires-python = ">=3.14"
license = {text = "MIT"}
authors = [
{name = "Neo", email = "neo@example.com"}
]
keywords = ["bot", "discord", "qq", "onebot"]
classifiers = [
"Development Status :: 4 - Beta",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.14",
]
dependencies = [
"aiohttp>=3.9.0",
"websockets>=12.0",
"playwright>=1.40.0",
"redis>=5.0.0",
"orjson>=3.9.0",
"loguru>=0.7.0",
"tomlkit>=0.12.0",
"watchdog>=3.0.0",
"discord.py>=2.0.0",
"aiohappyeyeballs>=2.6.1",
"aiomysql>=0.2.0",
"beautifulsoup4>=4.12.0",
"requests>=2.31.0",
"cython>=3.0.0",
]
[project.optional-dependencies]
dev = [
"pyinstrument>=4.5.0",
"memory-profiler>=0.61.0",
"psutil>=5.9.8",
"pytest>=7.4.0",
"pytest-asyncio>=0.21.0",
"flake8>=7.0.0",
"mypy>=1.5.0",
]
[project.urls]
Homepage = "https://github.com/yourusername/neobot"
Documentation = "https://github.com/yourusername/neobot#readme"
Repository = "https://github.com/yourusername/neobot"
"Bug Tracker" = "https://github.com/yourusername/neobot/issues"
[tool.setuptools]
packages = ["core", "models", "plugins", "adapters"]
package-dir = {"" = "."}
[tool.setuptools.package-data]
"core" = ["py.typed"]
"plugins" = ["**/*.py"]
"models" = ["**/*.py"]
[tool.setuptools.exclude-package-data]
"*" = [
"config.toml",
"config.example.toml",
"ca/*",
"*.pem",
"*.key",
]
[tool.pytest.ini_options]
testpaths = ["tests"]
python_files = ["test_*.py"]
asyncio_mode = "auto"
[tool.mypy]
python_version = "3.14"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
check_untyped_defs = true
no_implicit_optional = true
warn_redundant_casts = true
warn_subclassing = true
strict_optional = true
plugins = ["mypy.plugins.asyncio"]