174 lines
5.3 KiB
Python
174 lines
5.3 KiB
Python
#!/usr/bin/env python
|
|
"""
|
|
WebSocket 开发服务器启动脚本
|
|
同时启动 Daphne (WebSocket) 和 Django runserver (开发服务器)
|
|
支持 Windows 和 Linux
|
|
"""
|
|
|
|
import os
|
|
import sys
|
|
import subprocess
|
|
import platform
|
|
import signal
|
|
from pathlib import Path
|
|
from threading import Thread
|
|
import time
|
|
|
|
|
|
def main():
|
|
# 获取项目根目录
|
|
base_dir = Path(__file__).resolve().parent
|
|
os.chdir(base_dir)
|
|
|
|
print("=" * 70)
|
|
print("启动 Django 开发服务器 + WebSocket 服务器")
|
|
print("=" * 70)
|
|
print()
|
|
|
|
# 检测操作系统
|
|
is_windows = platform.system() == "Windows"
|
|
|
|
# 检查虚拟环境(跨平台)
|
|
if is_windows:
|
|
# Windows: .venv/Scripts/python.exe
|
|
venv_python = base_dir / ".venv" / "Scripts" / "python.exe"
|
|
else:
|
|
# Linux/Mac: .venv/bin/python
|
|
venv_python = base_dir / ".venv" / "bin" / "python"
|
|
|
|
if venv_python.exists():
|
|
print("[✓] 使用虚拟环境: .venv")
|
|
python_exec = str(venv_python)
|
|
else:
|
|
print("[!] 未找到 .venv 虚拟环境,使用全局 Python")
|
|
print("[!] 建议创建虚拟环境: python -m venv .venv")
|
|
python_exec = sys.executable
|
|
|
|
# 检查 daphne 是否安装
|
|
try:
|
|
result = subprocess.run(
|
|
[python_exec, "-m", "daphne", "--version"], capture_output=True, text=True
|
|
)
|
|
if result.returncode != 0 and result.returncode != 2:
|
|
print("[✗] 错误: Daphne 未安装")
|
|
print("请运行: pip install daphne channels channels-redis")
|
|
sys.exit(1)
|
|
except FileNotFoundError:
|
|
print("[✗] 错误: 无法找到 Python 解释器")
|
|
sys.exit(1)
|
|
# 进程列表
|
|
processes = []
|
|
|
|
# 启动两个服务器
|
|
try:
|
|
# 启动 Django runserver (端口 8000)
|
|
print("[*] 启动 Django 开发服务器 (端口 8000)...")
|
|
runserver_cmd = ["uv", "run", "manage.py", "runserver", "0.0.0.0:8000"]
|
|
runserver_process = subprocess.Popen(
|
|
runserver_cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
universal_newlines=True,
|
|
)
|
|
processes.append(("Django Runserver", runserver_process))
|
|
|
|
# 等待一下,让 runserver 先启动
|
|
time.sleep(1)
|
|
|
|
# 启动 Daphne (端口 8001)
|
|
print("[*] 启动 Daphne WebSocket 服务器 (端口 8001)...")
|
|
daphne_cmd = [
|
|
python_exec,
|
|
"-m",
|
|
"daphne",
|
|
"-b",
|
|
"0.0.0.0",
|
|
"-p",
|
|
"8001",
|
|
"oj.asgi:application",
|
|
]
|
|
daphne_process = subprocess.Popen(
|
|
daphne_cmd,
|
|
stdout=subprocess.PIPE,
|
|
stderr=subprocess.STDOUT,
|
|
text=True,
|
|
bufsize=1,
|
|
universal_newlines=True,
|
|
)
|
|
processes.append(("Daphne", daphne_process))
|
|
|
|
print()
|
|
print("[✓] 所有服务器已启动")
|
|
print()
|
|
|
|
# 创建输出线程
|
|
def print_output(name, process):
|
|
"""打印进程输出"""
|
|
for line in process.stdout:
|
|
print(f"[{name}] {line}", end="")
|
|
|
|
# 启动输出线程
|
|
threads = []
|
|
for name, process in processes:
|
|
thread = Thread(target=print_output, args=(name, process), daemon=True)
|
|
thread.start()
|
|
threads.append(thread)
|
|
|
|
# 等待进程(任意一个退出就退出)
|
|
while True:
|
|
for name, process in processes:
|
|
if process.poll() is not None:
|
|
print(f"\n[!] {name} 已退出")
|
|
raise KeyboardInterrupt
|
|
time.sleep(0.5)
|
|
|
|
except KeyboardInterrupt:
|
|
print()
|
|
print()
|
|
print("[*] 正在停止所有服务器...")
|
|
|
|
# 终止所有进程
|
|
for name, process in processes:
|
|
try:
|
|
if process.poll() is None: # 如果进程还在运行
|
|
print(f"[*] 停止 {name}...")
|
|
if is_windows:
|
|
# Windows 使用 CTRL_C_EVENT
|
|
process.send_signal(signal.CTRL_C_EVENT)
|
|
else:
|
|
# Unix 使用 SIGTERM
|
|
process.terminate()
|
|
|
|
# 等待进程结束(最多 5 秒)
|
|
try:
|
|
process.wait(timeout=5)
|
|
except subprocess.TimeoutExpired:
|
|
print(f"[!] {name} 未响应,强制终止...")
|
|
process.kill()
|
|
process.wait()
|
|
except Exception as e:
|
|
print(f"[!] 停止 {name} 时出错: {e}")
|
|
|
|
print()
|
|
print("[✓] 所有服务器已停止")
|
|
|
|
except Exception as e:
|
|
print(f"[✗] 错误: {e}")
|
|
|
|
# 清理所有进程
|
|
for name, process in processes:
|
|
try:
|
|
if process.poll() is None:
|
|
process.kill()
|
|
process.wait()
|
|
except Exception:
|
|
pass
|
|
|
|
sys.exit(1)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|