-
Notifications
You must be signed in to change notification settings - Fork 84
Expand file tree
/
Copy pathstart_app.py
More file actions
137 lines (116 loc) · 4.07 KB
/
start_app.py
File metadata and controls
137 lines (116 loc) · 4.07 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env python3
"""
CountBot 应用启动脚本
生产模式启动,自动打开浏览器
支持本地网络 IP 监控,类似 Vue3 启动模式
"""
import os
import sys
import webbrowser
import threading
from pathlib import Path
from backend.utils.network import get_local_ips
from backend.utils.runtime_env import (
apply_bind_env,
get_local_client_host,
is_public_bind_host,
resolve_bind_address,
)
# 添加项目根目录到 Python 路径
# Windows UTF-8 编码
if sys.platform == "win32":
os.environ["PYTHONIOENCODING"] = "utf-8"
try:
import ctypes
kernel32 = ctypes.windll.kernel32
kernel32.SetConsoleCP(65001)
kernel32.SetConsoleOutputCP(65001)
except Exception:
pass
# 项目根目录
project_root = Path(__file__).parent
sys.path.insert(0, str(project_root))
def open_browser_delayed(url: str, delay: float = 15.0) -> None:
"""
延迟打开浏览器
Args:
url: 要打开的 URL 地址
delay: 延迟时间(秒),默认 15 秒,确保服务器完全启动
"""
def _open():
import time
time.sleep(delay)
try:
webbrowser.open(url)
except Exception:
pass
threading.Thread(target=_open, daemon=True).start()
def main() -> None:
"""
启动应用(生产模式)
功能:
- 启动 FastAPI 应用服务器
- 自动打开浏览器(延迟 15 秒)
- 显示本地和网络访问地址
- 支持优雅关闭
"""
import uvicorn
from backend.utils.logger import build_uvicorn_log_config, setup_logger
from backend.utils.process_manager import setup_graceful_shutdown
from loguru import logger
# 初始化日志系统
setup_logger()
# 设置优雅关闭处理
process_manager = setup_graceful_shutdown(logger=logger)
# 读取配置
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}")
# 显示网络访问地址(如果监听了所有接口)
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:
logger.info(f"Network: http://{host}:{port}")
logger.info("提示: 如需从其他设备访问,请设置 COUNTBOT_HOST=0.0.0.0")
logger.info("-" * 60)
logger.info("浏览器将在 15 秒后自动打开")
logger.info("按下 Ctrl+C 停止服务器")
logger.info("=" * 60)
# 延迟 15 秒打开浏览器,确保服务器完全启动
open_browser_delayed(f"http://{get_local_client_host(host)}:{port}")
# 启动服务器(生产模式)
uvicorn.run(
"backend.app:app",
host=host,
port=port,
reload=False, # 生产模式禁用热重载
log_level="info",
log_config=build_uvicorn_log_config(),
)
except KeyboardInterrupt:
logger.info("Received keyboard interrupt")
except Exception as e:
logger.error(f"Server error: {e}")
raise
finally:
process_manager.remove_pid_file()
logger.info("Application shutdown complete")
if __name__ == "__main__":
main()