refactor(config): 简化EULA验证并统一环境变量配置管理

- 重构EULA验证机制,从复杂的文件哈希验证改为简单的环境变量验证
- 统一host和port配置,优先从环境变量读取而非配置文件
- 移除ServerConfig配置类,简化配置结构
- 添加.env文件自动创建和管理功能
- 更新相关模板和文档注释
This commit is contained in:
雅诺狐
2025-09-14 10:35:14 +08:00
parent 06a6c71775
commit fc78ec88d5
6 changed files with 82 additions and 88 deletions

131
bot.py
View File

@@ -1,6 +1,5 @@
# import asyncio # import asyncio
import asyncio import asyncio
import hashlib
import os import os
import sys import sys
import time import time
@@ -9,6 +8,7 @@ import traceback
from pathlib import Path from pathlib import Path
from rich.traceback import install from rich.traceback import install
from colorama import init, Fore from colorama import init, Fore
from dotenv import load_dotenv # 处理.env文件
# maim_message imports for console input # maim_message imports for console input
@@ -34,6 +34,28 @@ script_dir = os.path.dirname(os.path.abspath(__file__))
os.chdir(script_dir) os.chdir(script_dir)
logger.info(f"已设置工作目录为: {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") confirm_logger = get_logger("confirm")
# 获取没有加载env时的环境变量 # 获取没有加载env时的环境变量
@@ -105,82 +127,41 @@ async def graceful_shutdown():
logger.error(f"麦麦关闭失败: {e}", exc_info=True) 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(): def check_eula():
"""检查EULA和隐私条款确认状态""" """检查EULA和隐私条款确认状态 - 环境变量版类似Minecraft"""
# 计算文件哈希值 # 检查环境变量中的EULA确认
eula_hash = _calculate_file_hash(Path("EULA.md"), "EULA.md") eula_confirmed = os.getenv('EULA_CONFIRMED', '').lower()
privacy_hash = _calculate_file_hash(Path("PRIVACY.md"), "PRIVACY.md")
if eula_confirmed == 'true':
# 检查确认状态 logger.info("EULA已通过环境变量确认")
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:
return return
# 如果有更新,需要重新确认 # 如果没有确认,提示用户
if eula_updated or privacy_updated: confirm_logger.critical("您需要同意EULA和隐私条款才能使用MoFox_Bot")
_prompt_user_confirmation(eula_hash, privacy_hash) confirm_logger.critical("请阅读以下文件:")
_save_confirmations(eula_updated, privacy_updated, eula_hash, privacy_hash) 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): class MaiBotMain(BaseMain):

View File

@@ -3,6 +3,7 @@ import importlib.metadata
from maim_message import MessageServer from maim_message import MessageServer
from src.common.logger import get_logger from src.common.logger import get_logger
from src.config.config import global_config from src.config.config import global_config
import os
global_api = None global_api = None
@@ -22,9 +23,18 @@ def get_global_api() -> MessageServer: # sourcery skip: extract-method
maim_message_config = global_config.maim_message 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 = { kwargs = {
"host": global_config.server.host, "host": host,
"port": int(global_config.server.port), "port": port,
"app": get_global_server().get_app(), "app": get_global_server().get_app(),
} }

View File

@@ -4,6 +4,7 @@ from typing import Optional
from uvicorn import Config, Server as UvicornServer from uvicorn import Config, Server as UvicornServer
from src.config.config import global_config from src.config.config import global_config
from rich.traceback import install from rich.traceback import install
import os
install(extra_lines=3) install(extra_lines=3)
@@ -98,5 +99,14 @@ def get_global_server() -> Server:
"""获取全局服务器实例""" """获取全局服务器实例"""
global global_server global global_server
if global_server is None: 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 return global_server

View File

@@ -43,8 +43,7 @@ from src.config.official_configs import (
CrossContextConfig, CrossContextConfig,
PermissionConfig, PermissionConfig,
CommandConfig, CommandConfig,
PlanningSystemConfig, PlanningSystemConfig
ServerConfig,
) )
from .api_ada_configs import ( from .api_ada_configs import (
@@ -399,7 +398,6 @@ class Config(ValidatedConfigBase):
cross_context: CrossContextConfig = Field( cross_context: CrossContextConfig = Field(
default_factory=lambda: CrossContextConfig(), description="跨群聊上下文共享配置" default_factory=lambda: CrossContextConfig(), description="跨群聊上下文共享配置"
) )
server: ServerConfig = Field(default_factory=lambda: ServerConfig(), description="主服务器配置")
class APIAdapterConfig(ValidatedConfigBase): class APIAdapterConfig(ValidatedConfigBase):

View File

@@ -477,12 +477,6 @@ class ExperimentalConfig(ValidatedConfigBase):
pfc_chatting: bool = Field(default=False, description="启用PFC聊天") 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): class MaimMessageConfig(ValidatedConfigBase):
"""maim_message配置类""" """maim_message配置类"""

View File

@@ -1,2 +1,3 @@
HOST=127.0.0.1 HOST=127.0.0.1
PORT=8000 PORT=8000
EULA_CONFIRMED=false