File size: 2,729 Bytes
277e435
01e96cb
46c75bc
 
277e435
 
46c75bc
 
d24dec8
 
46c75bc
 
2c2ff35
9bf31c9
2c2ff35
66e5e1b
33341ab
66e5e1b
9bf31c9
2c2ff35
 
 
33341ab
2c2ff35
 
 
 
 
 
66e5e1b
2c2ff35
66e5e1b
33341ab
2c2ff35
 
 
be0aa6a
33341ab
 
 
2c2ff35
be0aa6a
2c2ff35
 
 
be0aa6a
 
33341ab
 
 
be0aa6a
01e96cb
 
be0aa6a
01e96cb
 
33341ab
 
01e96cb
33341ab
be0aa6a
33341ab
be0aa6a
 
 
46c75bc
 
66e5e1b
d24dec8
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
import uvicorn
from fastapi import FastAPI, Request, WebSocket
from fastapi.responses import HTMLResponse, StreamingResponse
import httpx
import asyncio
import websockets

app = FastAPI()
client = httpx.AsyncClient(timeout=None)

@app.get("/", response_class=HTMLResponse)
async def root():
    return "<body style='background:#000;color:#0f0;text-align:center;padding-top:100px;font-family:monospace;'><h1>[ SYSTEM ACTIVE ]</h1><p>Path: /terminal</p></body>"

# PROXY HTTP (Aset Terminal)
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy_http(request: Request, path: str):
    if not path or path == "/": return await root()
    target_url = f"http://127.0.0.1:8080/{path}"
    headers = {k: v for k, v in request.headers.items() if k.lower() not in ["host", "origin"]}
    headers["Host"] = "127.0.0.1:8080"
    headers["Origin"] = "http://127.0.0.1:8080"
    
    try:
        req = client.build_request(method=request.method, url=target_url, headers=headers, params=request.query_params, content=await request.body())
        resp = await client.send(req, stream=True)
        return StreamingResponse(resp.aiter_raw(), status_code=resp.status_code, headers=dict(resp.headers))
    except:
        return HTMLResponse("Backend Offline", status_code=503)

# PROXY WEBSOCKET (Fix Reconnect & Cant Type)
@app.websocket("/{path:path}")
async def proxy_ws(websocket: WebSocket, path: str):
    # Terima koneksi dengan subprotocol asli dari ttyd
    subproto = websocket.headers.get("sec-websocket-protocol")
    await websocket.accept(subprotocol=subproto)
    
    target_ws_url = f"ws://127.0.0.1:8080/{path}"

    try:
        # KUNCI: Jangan pake extra_headers agar tidak Exit 1 di log
        async with websockets.connect(
            target_ws_url,
            subprotocols=[subproto] if subproto else None,
            ping_interval=None # Agar tidak gampang putus
        ) as target_ws:
            
            async def forward(source, destination):
                try:
                    while True:
                        if hasattr(source, 'receive_text'):
                            msg = await source.receive_text()
                            await destination.send(msg)
                        else:
                            msg = await source.recv()
                            await destination.send_text(msg)
                except: pass

            await asyncio.gather(forward(websocket, target_ws), forward(target_ws, websocket))
    except Exception as e:
        print(f"WS Error: {str(e)}")
    finally:
        try:
            await websocket.close()
        except: pass

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=7860)