115 lines
3.5 KiB
Python
115 lines
3.5 KiB
Python
import asyncio
|
||
# ===== Main.py 顶部放置(所有 import 之前)=====
|
||
import os
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
from hypercorn.asyncio import serve
|
||
from hypercorn.config import Config
|
||
|
||
from Module.DeviceInfo import DeviceInfo
|
||
from Module.FlaskSubprocessManager import FlaskSubprocessManager
|
||
from Utils.AiUtils import AiUtils
|
||
from Utils.DevDiskImageDeployer import DevDiskImageDeployer
|
||
from Utils.LogManager import LogManager
|
||
|
||
if "IOSAI_PYTHON" not in os.environ:
|
||
base_path = Path(sys.argv[0]).resolve()
|
||
base_dir = base_path.parent if base_path.is_file() else base_path
|
||
sidecar = base_dir / "python-rt" / ("python.exe" if os.name == "nt" else "python")
|
||
if sidecar.exists():
|
||
os.environ["IOSAI_PYTHON"] = str(sidecar)
|
||
# ==============================================
|
||
|
||
# 确定 exe 或 py 文件所在目录
|
||
BASE = Path(getattr(sys, 'frozen', False) and sys.executable or __file__).resolve().parent
|
||
LOG_DIR = BASE / "log"
|
||
LOG_DIR.mkdir(exist_ok=True) # 确保 log 目录存在
|
||
|
||
print(f"日志目录: {LOG_DIR}")
|
||
|
||
def _run_flask_role():
|
||
from Module.FlaskService import get_app, bootstrap_server_side_effects
|
||
print("Flask Pid:", os.getpid())
|
||
port = int(os.getenv("FLASK_COMM_PORT", "34566")) # 固定端口的兜底仍是 34567
|
||
app = get_app()
|
||
flaskPort = port + 1
|
||
AiUtils.flask_port_free(flaskPort)
|
||
bootstrap_server_side_effects()
|
||
|
||
# ==== 关键:统一获取 resources 目录 ====
|
||
if "__compiled__" in globals():
|
||
# 被 Nuitka 编译后的 exe 运行时
|
||
base_dir = os.path.dirname(sys.executable) # exe 所在目录
|
||
else:
|
||
# 开发环境,直接跑 .py
|
||
cur_file = os.path.abspath(__file__) # Module/Main.py 所在目录
|
||
base_dir = os.path.dirname(os.path.dirname(cur_file)) # 回到项目根 iOSAi
|
||
|
||
resource_dir = os.path.join(base_dir, "resources")
|
||
|
||
# Hypercorn 配置
|
||
config = Config()
|
||
config.bind = [f"0.0.0.0:{flaskPort}"]
|
||
config.certfile = os.path.join(resource_dir, "server.crt")
|
||
config.keyfile = os.path.join(resource_dir, "server.key")
|
||
config.alpn_protocols = ["h2"] # 👈 这一行
|
||
config.workers = 6 # 你机器 4GB → 推荐 3~4 个 worker
|
||
|
||
# 直接跑 Quart(ASGI 原生,不再用 WsgiToAsgi)
|
||
asyncio.run(serve(app, config))
|
||
|
||
if "--role=flask" in sys.argv:
|
||
_run_flask_role()
|
||
sys.exit(0)
|
||
|
||
# 启动锁
|
||
def main(arg):
|
||
if len(arg) != 2 or arg[1] != "iosai":
|
||
sys.exit(0)
|
||
|
||
# 项目入口
|
||
if __name__ == "__main__":
|
||
|
||
# 清空日志
|
||
LogManager.clearLogs()
|
||
|
||
main(sys.argv)
|
||
|
||
# 添加iOS开发包到电脑上
|
||
deployer = DevDiskImageDeployer(verbose=True)
|
||
deployer.deploy_all()
|
||
|
||
# 启动 Flask 子进程
|
||
manager = FlaskSubprocessManager.get_instance()
|
||
manager.start()
|
||
|
||
# 设备监听(即使失败/很快返回,也不会导致主进程退出)
|
||
try:
|
||
info = DeviceInfo()
|
||
info.listen()
|
||
except Exception as e:
|
||
print("[WARN] Device listener not running:", e)
|
||
|
||
# === 保活:阻塞主线程,直到收到 Ctrl+C/关闭 ===
|
||
import threading, time, signal
|
||
stop = threading.Event()
|
||
|
||
def _handle(_sig, _frm):
|
||
stop.set()
|
||
|
||
# Windows 上 SIGINT/SIGTERM 都可以拦到
|
||
try:
|
||
signal.signal(signal.SIGINT, _handle)
|
||
signal.signal(signal.SIGTERM, _handle)
|
||
except Exception:
|
||
pass # 某些环境可能不支持,忽略
|
||
|
||
try:
|
||
while not stop.is_set():
|
||
time.sleep(1)
|
||
finally:
|
||
# 进程退出前记得把子进程关掉
|
||
manager.stop()
|
||
|