diff --git a/xiaomusic/cli.py b/xiaomusic/cli.py index 89c9a7556..ae8616142 100644 --- a/xiaomusic/cli.py +++ b/xiaomusic/cli.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 import argparse +import json +import os +import signal import uvicorn @@ -75,9 +78,6 @@ def main(): options = parser.parse_args() config = Config.from_options(options) - xiaomusic = XiaoMusic(config) - HttpInit(xiaomusic) - LOGGING_CONFIG = { "version": 1, "disable_existing_loggers": False, @@ -133,12 +133,61 @@ def main(): }, }, } - uvicorn.run( - HttpApp, - host=["::", "0.0.0.0"], - port=config.port, - log_config=LOGGING_CONFIG, - ) + + try: + filename = config.getsettingfile() + with open(filename) as f: + data = json.loads(f.read()) + config.update_config(data) + except Exception as e: + print(f"Execption {e}") + + def run_gate(): + uvicorn.run( + "gate:app", + host="0.0.0.0", + port=config.port, + log_config=LOGGING_CONFIG, + workers=2, + ) + + def run_server(): + xiaomusic = XiaoMusic(config) + HttpInit(xiaomusic) + uvicorn.run( + HttpApp, + host="127.0.0.1", + port=config.port + 1, + log_config=LOGGING_CONFIG, + ) + + # thread = threading.Thread(target=run_server) + # thread.start() + # run_gate() + + command = [ + "uvicorn", + "xiaomusic.gate:app", + "--workers", + "4", + "--host", + "0.0.0.0", + "--port", + str(config.port), + ] + + # process = subprocess.Popen(command) + def signal_handler(sig, frame): + print("主进程收到退出信号,准备退出...") + # process.terminate() # 终止子进程 + # process.wait() # 等待子进程退出 + print("子进程已退出") + os._exit(0) # 退出主进程 + + # 捕获主进程的退出信号 + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + run_server() if __name__ == "__main__": diff --git a/xiaomusic/gate.py b/xiaomusic/gate.py new file mode 100644 index 000000000..bf487b0df --- /dev/null +++ b/xiaomusic/gate.py @@ -0,0 +1,79 @@ +import json +import logging +import os +from contextlib import asynccontextmanager + +import httpx +from fastapi import FastAPI, Request +from fastapi.responses import Response +from fastapi.staticfiles import StaticFiles +from starlette.background import BackgroundTask + +from xiaomusic import __version__ +from xiaomusic.config import Config + +config = Config() +logging.basicConfig(level=logging.INFO) +log = logging.getLogger(__name__) + + +@asynccontextmanager +async def app_lifespan(app): + global config + try: + filename = config.getsettingfile() + with open(filename) as f: + data = json.loads(f.read()) + config.update_config(data) + except Exception as e: + log.exception(f"Execption {e}") + yield + + +app = FastAPI( + lifespan=app_lifespan, + version=__version__, +) + + +def reset_gate(): + # 更新 music 链接 + app.router.routes = [route for route in app.router.routes if route.path != "/music"] + app.mount( + "/music", + StaticFiles(directory=config.music_path, follow_symlink=True), + name="music", + ) + + +folder = os.path.dirname(__file__) +app.mount("/static", StaticFiles(directory=f"{folder}/static"), name="static") +reset_gate() + + +@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"]) +async def proxy(path: str, request: Request): + async with httpx.AsyncClient() as client: + port = config.port + 1 + url = f"http://127.0.0.1:{port}/{path}" + response = await client.request( + method=request.method, + url=url, + headers=request.headers, + params=request.query_params, + content=await request.body() if request.method in ["POST", "PUT"] else None, + ) + if path == "savesetting": + # 使用BackgroundTask在响应发送完毕后执行逻辑 + background_task = BackgroundTask(reset_gate) + return Response( + content=response.content, + status_code=response.status_code, + headers=dict(response.headers), + background=background_task, + ) + return Response( + content=response.content, + status_code=response.status_code, + headers=dict(response.headers), + )