Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| # -*- coding: utf-8 -*- | |
| """ | |
| Warp 服务统一启动器 | |
| """ | |
| import multiprocessing | |
| import time | |
| import sys | |
| import os | |
| import importlib | |
| import logging | |
| import asyncio | |
| import shutil | |
| # 在导入项目模块之前,确保项目根目录在sys.path中 | |
| # 这有助于解决在不同环境下模块导入失败的问题 | |
| project_root = os.path.dirname(os.path.abspath(__file__)) | |
| if project_root not in sys.path: | |
| sys.path.insert(0, project_root) | |
| import config | |
| def prepare_runtime_environment(): | |
| data_dir = os.path.dirname(config.DATABASE_PATH) | |
| log_dir = os.getenv("LOG_DIR") or os.path.join(os.getenv("DATA_DIR", "/data"), "logs") | |
| for path in {data_dir, log_dir}: | |
| if not path: | |
| continue | |
| try: | |
| os.makedirs(path, exist_ok=True) | |
| except Exception as exc: | |
| logger = logging.getLogger(__name__) | |
| logger.warning(f"无法创建目录 {path}: {exc}") | |
| default_db = os.path.join(project_root, "warp_accounts.db") | |
| if config.DATABASE_PATH and not os.path.exists(config.DATABASE_PATH) and os.path.exists(default_db): | |
| try: | |
| shutil.copy2(default_db, config.DATABASE_PATH) | |
| logging.getLogger(__name__).info(f"已初始化数据库文件: {config.DATABASE_PATH}") | |
| except Exception as exc: | |
| logging.getLogger(__name__).warning(f"初始化数据库失败: {exc}") | |
| # 配置日志 | |
| logging.basicConfig( | |
| level=config.LOG_LEVEL, | |
| format=config.LOG_FORMAT | |
| ) | |
| logger = logging.getLogger(__name__) | |
| prepare_runtime_environment() | |
| # ==================== 服务启动函数 ==================== | |
| def run_server(): | |
| """启动 Protobuf 主服务 (server.py)""" | |
| logger.info("正在启动 Protobuf 主服务...") | |
| try: | |
| # 动态导入并执行main函数 | |
| module = importlib.import_module("server") | |
| module.main() | |
| except Exception as e: | |
| logger.error(f"Protobuf 主服务启动失败: {e}", exc_info=True) | |
| def run_openai_compat(): | |
| """启动 OpenAI 兼容服务 (openai_compat.py)""" | |
| logger.info("正在启动 OpenAI 兼容服务...") | |
| try: | |
| # openai_compat.py 使用 uvicorn.run 并且没有main函数 | |
| # 我们需要模拟它的 __main__ 执行块 | |
| module = importlib.import_module("openai_compat") | |
| uvicorn = importlib.import_module("uvicorn") | |
| # 刷新JWT | |
| try: | |
| from warp2protobuf.core.auth import refresh_jwt_if_needed as _refresh_jwt | |
| asyncio.run(_refresh_jwt()) | |
| except Exception: | |
| pass | |
| uvicorn.run( | |
| module.app, | |
| host=config.OPENAI_COMPAT_HOST, | |
| port=config.OPENAI_COMPAT_PORT, | |
| log_level=config.LOG_LEVEL.lower(), | |
| ) | |
| except Exception as e: | |
| logger.error(f"OpenAI 兼容服务启动失败: {e}", exc_info=True) | |
| def run_pool_service(): | |
| """启动账号池HTTP服务 (pool_service.py)""" | |
| logger.info("正在启动账号池HTTP服务...") | |
| try: | |
| module = importlib.import_module("pool_service") | |
| asyncio.run(module.main()) | |
| except Exception as e: | |
| logger.error(f"账号池HTTP服务启动失败: {e}", exc_info=True) | |
| def run_pool_maintenance(): | |
| """启动账号池维护脚本 (pool_maintenance.py)""" | |
| logger.info("正在启动账号池维护脚本...") | |
| try: | |
| module = importlib.import_module("pool_maintenance") | |
| # 默认以 'auto' 模式运行 | |
| sys.argv = [sys.argv[0], 'auto'] | |
| asyncio.run(module.main()) | |
| except Exception as e: | |
| logger.error(f"账号池维护脚本启动失败: {e}", exc_info=True) | |
| def run_warp_register(): | |
| """启动Warp账号注册脚本 (warp_register.py)""" | |
| logger.info("正在启动Warp账号注册脚本...") | |
| try: | |
| module = importlib.import_module("warp_register") | |
| asyncio.run(module.main()) | |
| except Exception as e: | |
| logger.error(f"Warp账号注册脚本启动失败: {e}", exc_info=True) | |
| # ==================== 进程管理 ==================== | |
| SERVICES = { | |
| "server": run_server, | |
| "openai": run_openai_compat, | |
| "pool_service": run_pool_service, | |
| "pool_maintenance": run_pool_maintenance, | |
| "register": run_warp_register, | |
| } | |
| if not getattr(config, "ENABLE_AUTO_REGISTER", True): | |
| for name in ("pool_maintenance", "register"): | |
| SERVICES.pop(name, None) | |
| def start_all_services(): | |
| """启动所有服务""" | |
| processes = [] | |
| for name, target_func in SERVICES.items(): | |
| process = multiprocessing.Process(target=target_func, name=f"Process-{name}") | |
| processes.append(process) | |
| process.start() | |
| logger.info(f"服务 '{name}' 已在进程 {process.pid} 中启动。") | |
| try: | |
| while True: | |
| time.sleep(1) | |
| for process in processes: | |
| if not process.is_alive(): | |
| logger.warning(f"进程 '{process.name}' (PID: {process.pid}) 已退出。") | |
| # 可选择在这里添加重启逻辑 | |
| processes.remove(process) | |
| if not processes: | |
| logger.info("所有服务进程都已退出。") | |
| break | |
| except KeyboardInterrupt: | |
| logger.info("接收到停止信号,正在关闭所有服务...") | |
| for process in processes: | |
| process.terminate() | |
| process.join() | |
| logger.info("所有服务已停止。") | |
| def print_usage(): | |
| """打印使用说明""" | |
| print("=" * 60) | |
| print("Warp 服务统一启动器") | |
| print("=" * 60) | |
| print("用法:") | |
| print(" python main.py [命令]") | |
| print("\n可用命令:") | |
| print(" all - 启动所有服务") | |
| for name in SERVICES: | |
| print(f" {name:<18} - 仅启动 {name} 服务 (用于调试)") | |
| print("\n示例:") | |
| print(" python main.py all") | |
| print(" python main.py server") | |
| print("=" * 60) | |
| if __name__ == "__main__": | |
| # 设置多进程启动方式,这对于Windows和macOS是推荐的 | |
| multiprocessing.set_start_method("spawn", force=True) | |
| if len(sys.argv) < 2: | |
| print_usage() | |
| sys.exit(1) | |
| command = sys.argv[1].lower() | |
| if command == "all": | |
| start_all_services() | |
| elif command in SERVICES: | |
| logger.info(f"以调试模式启动单个服务: '{command}'") | |
| SERVICES[command]() | |
| else: | |
| print(f"错误: 未知命令 '{command}'\n") | |
| print_usage() | |
| sys.exit(1) | |