Files

121 lines
3.9 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
"""
CountBot 应用启动脚本
开发模式启动,支持热重载
支持本地网络 IP 监控,类似 Vue3 启动模式
"""
import os
import sys
from pathlib import Path
from backend.utils.network import get_local_ips
from backend.utils.runtime_env import (
apply_bind_env,
is_public_bind_host,
resolve_bind_address,
)
# Windows 平台强制 UTF-8 编码,避免 GBK 编码错误
if sys.platform == "win32":
# Python 3.7+ 支持
os.environ["PYTHONIOENCODING"] = "utf-8"
# 设置控制台代码页为 UTF-8
try:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleCP(65001)
kernel32.SetConsoleOutputCP(65001)
except Exception:
pass
# 添加项目根目录到 Python 路径
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
def main():
"""
启动应用(开发模式)
功能:
- 启动 FastAPI 应用服务器(开发模式)
- 启用热重载,文件更改自动重启
- 显示本地和网络访问地址
- 监控 backend 目录的文件变化
"""
import uvicorn
from loguru import logger
from backend.utils.logger import build_uvicorn_log_config
# 读取配置
host, port = resolve_bind_address()
apply_bind_env(host, port)
# 获取本地 IP 地址
local_ips = get_local_ips()
# 打印启动信息
logger.info("=" * 60)
logger.info("CountBot 开发模式启动中...")
logger.info("=" * 60)
try:
# 启动服务器前显示"服务器启动完成"消息和访问地址
logger.info("服务器启动完成!")
logger.info("=" * 60)
# 显示本地访问地址
logger.info(f"Local: http://localhost:{port}")
# 显示网络访问地址(如果监听了所有接口或用户明确设置了 0.0.0.0
if is_public_bind_host(host):
if local_ips:
for ip in local_ips:
logger.info(f"Network: http://{ip}:{port}")
else:
logger.info("Network: (无法检测到本地 IP 地址)")
logger.info(f"提示: 请检查网络连接或手动访问 http://<your-ip>:{port}")
else:
# 即使监听 127.0.0.1,也显示可用的网络 IP 供参考
if local_ips:
logger.info(f"Network: http://{host}:{port}")
logger.info("提示: 如需从其他设备访问,请设置 COUNTBOT_HOST=0.0.0.0")
logger.info(f"可用网络 IP: {', '.join(local_ips)}")
else:
logger.info(f"Network: http://{host}:{port}")
logger.info("提示: 如需从其他设备访问,请设置 COUNTBOT_HOST=0.0.0.0")
logger.info("-" * 60)
logger.info("热重载已启用 - 文件更改将自动重启")
logger.info("按下 Ctrl+C 停止服务器")
logger.info("=" * 60)
# 在 Windows 开发模式下uvicorn 的 reload 会切到 SelectorEventLoop
# 这会让 asyncio.create_subprocess_shell 无法使用。
run_kwargs = dict(
app="backend.app:app",
host=host,
port=port,
reload=True, # 开发模式启用热重载
reload_dirs=["backend"], # 监控 backend 目录
log_level="debug", # 开发模式使用 debug 日志级别
log_config=build_uvicorn_log_config(),
)
if sys.platform == "win32":
run_kwargs["loop"] = "none"
# 启动服务器(开发模式)
uvicorn.run(**run_kwargs)
except KeyboardInterrupt:
logger.info("Received keyboard interrupt")
except Exception as e:
logger.error(f"Server error: {e}")
raise
finally:
logger.info("Application shutdown complete")
if __name__ == "__main__":
main()