From fc78ec88d5a4a3a08e96244fb3d1c439d162f775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=85=E8=AF=BA=E7=8B=90?= <212194964+foxcyber907@users.noreply.github.com> Date: Sun, 14 Sep 2025 10:35:14 +0800 Subject: [PATCH] =?UTF-8?q?refactor(config):=20=E7=AE=80=E5=8C=96EULA?= =?UTF-8?q?=E9=AA=8C=E8=AF=81=E5=B9=B6=E7=BB=9F=E4=B8=80=E7=8E=AF=E5=A2=83?= =?UTF-8?q?=E5=8F=98=E9=87=8F=E9=85=8D=E7=BD=AE=E7=AE=A1=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 重构EULA验证机制,从复杂的文件哈希验证改为简单的环境变量验证 - 统一host和port配置,优先从环境变量读取而非配置文件 - 移除ServerConfig配置类,简化配置结构 - 添加.env文件自动创建和管理功能 - 更新相关模板和文档注释 --- bot.py | 131 ++++++++++++++------------------- src/common/message/api.py | 14 +++- src/common/server.py | 12 ++- src/config/config.py | 4 +- src/config/official_configs.py | 6 -- template/template.env | 3 +- 6 files changed, 82 insertions(+), 88 deletions(-) diff --git a/bot.py b/bot.py index aab5cd4f1..2490e6a97 100644 --- a/bot.py +++ b/bot.py @@ -1,6 +1,5 @@ # import asyncio import asyncio -import hashlib import os import sys import time @@ -9,6 +8,7 @@ import traceback from pathlib import Path from rich.traceback import install from colorama import init, Fore +from dotenv import load_dotenv # 处理.env文件 # maim_message imports for console input @@ -34,6 +34,28 @@ script_dir = os.path.dirname(os.path.abspath(__file__)) os.chdir(script_dir) logger.info(f"已设置工作目录为: {script_dir}") +# 检查并创建.env文件 +def ensure_env_file(): + """确保.env文件存在,如果不存在则从模板创建""" + env_file = Path(".env") + template_env = Path("template/template.env") + + if not env_file.exists(): + if template_env.exists(): + logger.info("未找到.env文件,正在从模板创建...") + import shutil + shutil.copy(template_env, env_file) + logger.info("已从template/template.env创建.env文件") + logger.warning("请编辑.env文件,将EULA_CONFIRMED设置为true并配置其他必要参数") + else: + logger.error("未找到.env文件和template.env模板文件") + sys.exit(1) + +# 确保环境文件存在 +ensure_env_file() + +# 加载环境变量 +load_dotenv() confirm_logger = get_logger("confirm") # 获取没有加载env时的环境变量 @@ -105,82 +127,41 @@ async def graceful_shutdown(): logger.error(f"麦麦关闭失败: {e}", exc_info=True) -def _calculate_file_hash(file_path: Path, file_type: str) -> str: - """计算文件的MD5哈希值""" - if not file_path.exists(): - logger.error(f"{file_type} 文件不存在") - raise FileNotFoundError(f"{file_type} 文件不存在") - - with open(file_path, "r", encoding="utf-8") as f: - content = f.read() - return hashlib.md5(content.encode("utf-8")).hexdigest() - - -def _check_agreement_status(file_hash: str, confirm_file: Path, env_var: str) -> tuple[bool, bool]: - """检查协议确认状态 - - Returns: - tuple[bool, bool]: (已确认, 未更新) - """ - # 检查环境变量确认 - if file_hash == os.getenv(env_var): - return True, False - - # 检查确认文件 - if confirm_file.exists(): - with open(confirm_file, "r", encoding="utf-8") as f: - confirmed_content = f.read() - if file_hash == confirmed_content: - return True, False - - return False, True - - -def _prompt_user_confirmation(eula_hash: str, privacy_hash: str) -> None: - """提示用户确认协议""" - confirm_logger.critical("EULA或隐私条款内容已更新,请在阅读后重新确认,继续运行视为同意更新后的以上两款协议") - confirm_logger.critical( - f'输入"同意"或"confirmed"或设置环境变量"EULA_AGREE={eula_hash}"和"PRIVACY_AGREE={privacy_hash}"继续运行' - ) - - while True: - user_input = input().strip().lower() - if user_input in ["同意", "confirmed"]: - return - confirm_logger.critical('请输入"同意"或"confirmed"以继续运行') - - -def _save_confirmations(eula_updated: bool, privacy_updated: bool, eula_hash: str, privacy_hash: str) -> None: - """保存用户确认结果""" - if eula_updated: - logger.info(f"更新EULA确认文件{eula_hash}") - Path("eula.confirmed").write_text(eula_hash, encoding="utf-8") - - if privacy_updated: - logger.info(f"更新隐私条款确认文件{privacy_hash}") - Path("privacy.confirmed").write_text(privacy_hash, encoding="utf-8") - - def check_eula(): - """检查EULA和隐私条款确认状态""" - # 计算文件哈希值 - eula_hash = _calculate_file_hash(Path("EULA.md"), "EULA.md") - privacy_hash = _calculate_file_hash(Path("PRIVACY.md"), "PRIVACY.md") - - # 检查确认状态 - eula_confirmed, eula_updated = _check_agreement_status(eula_hash, Path("eula.confirmed"), "EULA_AGREE") - privacy_confirmed, privacy_updated = _check_agreement_status( - privacy_hash, Path("privacy.confirmed"), "PRIVACY_AGREE" - ) - - # 早期返回:如果都已确认且未更新 - if eula_confirmed and privacy_confirmed: + """检查EULA和隐私条款确认状态 - 环境变量版(类似Minecraft)""" + # 检查环境变量中的EULA确认 + eula_confirmed = os.getenv('EULA_CONFIRMED', '').lower() + + if eula_confirmed == 'true': + logger.info("EULA已通过环境变量确认") return - - # 如果有更新,需要重新确认 - if eula_updated or privacy_updated: - _prompt_user_confirmation(eula_hash, privacy_hash) - _save_confirmations(eula_updated, privacy_updated, eula_hash, privacy_hash) + + # 如果没有确认,提示用户 + confirm_logger.critical("您需要同意EULA和隐私条款才能使用MoFox_Bot") + confirm_logger.critical("请阅读以下文件:") + confirm_logger.critical(" - EULA.md (用户许可协议)") + confirm_logger.critical(" - PRIVACY.md (隐私条款)") + confirm_logger.critical("然后编辑 .env 文件,将 'EULA_CONFIRMED=false' 改为 'EULA_CONFIRMED=true'") + + # 等待用户确认 + while True: + try: + load_dotenv(override=True) # 重新加载.env文件 + + eula_confirmed = os.getenv('EULA_CONFIRMED', '').lower() + if eula_confirmed == 'true': + confirm_logger.info("EULA确认成功,感谢您的同意") + return + + confirm_logger.critical("请修改 .env 文件中的 EULA_CONFIRMED=true 后重新启动程序") + input("按Enter键检查.env文件状态...") + + except KeyboardInterrupt: + confirm_logger.info("用户取消,程序退出") + sys.exit(0) + except Exception as e: + confirm_logger.error(f"检查EULA状态失败: {e}") + sys.exit(1) class MaiBotMain(BaseMain): diff --git a/src/common/message/api.py b/src/common/message/api.py index 75e5c84e9..d24574d6e 100644 --- a/src/common/message/api.py +++ b/src/common/message/api.py @@ -3,6 +3,7 @@ import importlib.metadata from maim_message import MessageServer from src.common.logger import get_logger from src.config.config import global_config +import os global_api = None @@ -22,9 +23,18 @@ def get_global_api() -> MessageServer: # sourcery skip: extract-method maim_message_config = global_config.maim_message # 设置基本参数 + + host = os.getenv("HOST", "127.0.0.1") + port_str = os.getenv("PORT", "8000") + + try: + port = int(port_str) + except ValueError: + port = 8000 + kwargs = { - "host": global_config.server.host, - "port": int(global_config.server.port), + "host": host, + "port": port, "app": get_global_server().get_app(), } diff --git a/src/common/server.py b/src/common/server.py index 30c55d72d..3263589a2 100644 --- a/src/common/server.py +++ b/src/common/server.py @@ -4,6 +4,7 @@ from typing import Optional from uvicorn import Config, Server as UvicornServer from src.config.config import global_config from rich.traceback import install +import os install(extra_lines=3) @@ -98,5 +99,14 @@ def get_global_server() -> Server: """获取全局服务器实例""" global global_server if global_server is None: - global_server = Server(host=global_config.server.host,port=int(global_config.server.port),) + + host = os.getenv("HOST", "127.0.0.1") + port_str = os.getenv("PORT", "8000") + + try: + port = int(port_str) + except ValueError: + port = 8000 + + global_server = Server(host=host, port=port) return global_server diff --git a/src/config/config.py b/src/config/config.py index a38122300..933b7e567 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -43,8 +43,7 @@ from src.config.official_configs import ( CrossContextConfig, PermissionConfig, CommandConfig, - PlanningSystemConfig, - ServerConfig, + PlanningSystemConfig ) from .api_ada_configs import ( @@ -399,7 +398,6 @@ class Config(ValidatedConfigBase): cross_context: CrossContextConfig = Field( default_factory=lambda: CrossContextConfig(), description="跨群聊上下文共享配置" ) - server: ServerConfig = Field(default_factory=lambda: ServerConfig(), description="主服务器配置") class APIAdapterConfig(ValidatedConfigBase): diff --git a/src/config/official_configs.py b/src/config/official_configs.py index 94102dce4..40a521886 100644 --- a/src/config/official_configs.py +++ b/src/config/official_configs.py @@ -477,12 +477,6 @@ class ExperimentalConfig(ValidatedConfigBase): pfc_chatting: bool = Field(default=False, description="启用PFC聊天") -class ServerConfig(ValidatedConfigBase): - """主服务器配置类""" - - host: str = Field(default="127.0.0.1", description="主服务器监听地址") - port: int = Field(default=8080, description="主服务器监听端口") - class MaimMessageConfig(ValidatedConfigBase): """maim_message配置类""" diff --git a/template/template.env b/template/template.env index d9b6e2bd1..c838bcaa8 100644 --- a/template/template.env +++ b/template/template.env @@ -1,2 +1,3 @@ HOST=127.0.0.1 -PORT=8000 \ No newline at end of file +PORT=8000 +EULA_CONFIRMED=false \ No newline at end of file