From efc9a397bb02f20b514ddbd68cec167f1645856a Mon Sep 17 00:00:00 2001 From: K2Cr2O1 <2221577113@qq.com> Date: Mon, 23 Mar 2026 20:55:41 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=94=B9=E8=BF=9B=E9=85=8D=E7=BD=AE?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E9=80=BB=E8=BE=91=E5=B9=B6=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E9=A1=B9=E7=9B=AE=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 当配置文件不存在时自动生成示例配置 添加pyproject.toml作为项目构建配置 更新.gitignore忽略更多文件类型 删除不再使用的反向WebSocket示例文件 --- .gitignore | 28 ++++++++++- core/config_loader.py | 21 ++++++-- examples/reverse_ws_example.py | 58 ---------------------- pyproject.toml | 91 ++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 63 deletions(-) delete mode 100644 examples/reverse_ws_example.py create mode 100644 pyproject.toml diff --git a/.gitignore b/.gitignore index 866e375..9cab923 100644 --- a/.gitignore +++ b/.gitignore @@ -115,7 +115,7 @@ env/ venv/ ENV/ env.bak/ -venv.bak/ +venv.bak() # Spyder project settings .spyderproject @@ -138,6 +138,9 @@ dmypy.json # pytype static type analyzer .pytype/ +# Cython +*.c + # End of https://www.toptal.com/developers/gitignore/api/python # Build artifacts @@ -146,4 +149,27 @@ build/ # 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/* + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Logs +logs/ +*.log diff --git a/core/config_loader.py b/core/config_loader.py index f2b506f..ad332aa 100644 --- a/core/config_loader.py +++ b/core/config_loader.py @@ -38,10 +38,10 @@ class Config: :raises ConfigError: 如果加载配置时发生其他错误 """ if not self.path.exists(): - error = ConfigNotFoundError(message=f"配置文件 {self.path} 未找到!") - self.logger.error(f"配置加载失败: {error.message}") - self.logger.log_custom_exception(error) - raise error + self.logger.warning(f"配置文件 {self.path} 未找到,正在生成示例配置...") + self._generate_example_config() + self.logger.success(f"示例配置已生成: {self.path}") + self.logger.info("请编辑配置文件后重新启动程序") try: self.logger.info(f"正在从 {self.path} 加载配置...") @@ -86,6 +86,19 @@ class Config: self.logger.log_custom_exception(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 def napcat_ws(self) -> NapCatWSModel: diff --git a/examples/reverse_ws_example.py b/examples/reverse_ws_example.py deleted file mode 100644 index f3c9b23..0000000 --- a/examples/reverse_ws_example.py +++ /dev/null @@ -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()) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..dd735b5 --- /dev/null +++ b/pyproject.toml @@ -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"]