File size: 2,102 Bytes
d2aab3f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
import httpx
from fastapi import FastAPI, Request
from fastapi.responses import StreamingResponse, JSONResponse
from fastapi.middleware.cors import CORSMiddleware
import uvicorn
import subprocess
import signal

app = FastAPI()

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)


PYTHON_PORT = 7860
NODE_PORT = 4321
NODE_SCRIPT_PATH = "build"

node_process = subprocess.Popen(["node", NODE_SCRIPT_PATH])


def handle_sigterm(signum, frame):
    print("Stopping Node.js server...")
    node_process.terminate()
    node_process.wait()
    exit(0)


signal.signal(signal.SIGTERM, handle_sigterm)


@app.on_event("shutdown")
def shutdown_event():
    print("Stopping Node.js server...")
    node_process.terminate()
    node_process.wait()


@app.get("/config")
async def route_with_config():
    return JSONResponse(content={"one": "hello", "two": "from", "three": "Python"})


async def proxy_to_node(request: Request):
    client = httpx.AsyncClient()

    # Preserve the full path including query parameters
    full_path = request.url.path
    if request.url.query:
        full_path += f"?{request.url.query}"

    url = f"http://localhost:{NODE_PORT}{full_path}"

    headers = {
        k: v
        for k, v in request.headers.items()
        if k.lower() not in ["host", "content-length"]
    }
    body = await request.body()

    async with client:
        response = await client.request(
            method=request.method, url=url, headers=headers, content=body
        )

    return StreamingResponse(
        response.iter_bytes(),
        status_code=response.status_code,
        headers=response.headers,
    )


@app.api_route(
    "/{path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"]
)
async def catch_all(request: Request, path: str):
    return await proxy_to_node(request)


if __name__ == "__main__":
    print(
        f"Starting dual server. Python handles specific routes, Node handles the rest."
    )
    uvicorn.run(app, host="0.0.0.0", port=PYTHON_PORT)