VPS_BY_ALPHA / app.py
pabla1322's picture
Update app.py
73eab1d verified
Raw
History Blame Contribute Delete
2.91 kB
import os
import pty
import asyncio
import struct
import fcntl
import termios
import json
from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/")
async def index():
return FileResponse("static/index.html")
@app.websocket("/ws")
async def terminal(websocket: WebSocket):
await websocket.accept()
master_fd, slave_fd = pty.openpty()
proc = await asyncio.create_subprocess_exec(
"/bin/bash",
stdin=slave_fd,
stdout=slave_fd,
stderr=slave_fd,
env={
**os.environ,
"TERM": "xterm-256color",
"HOME": "/home/ubuntu",
"USER": "ubuntu"
}
)
os.close(slave_fd)
loop = asyncio.get_event_loop()
# Read terminal output
async def read_pty():
while True:
try:
data = await loop.run_in_executor(
None,
lambda: os.read(master_fd, 4096)
)
if data:
try:
text = data.decode("utf-8")
except UnicodeDecodeError:
text = data.decode(
"utf-8",
errors="ignore"
)
await websocket.send_text(text)
except OSError:
break
read_task = asyncio.create_task(read_pty())
try:
while True:
message = await websocket.receive_text()
try:
msg = json.loads(message)
if msg.get("type") == "input":
os.write(
master_fd,
msg["data"].encode("utf-8")
)
elif msg.get("type") == "resize":
cols = msg.get("cols", 80)
rows = msg.get("rows", 24)
fcntl.ioctl(
master_fd,
termios.TIOCSWINSZ,
struct.pack(
"HHHH",
rows,
cols,
0,
0
)
)
except (json.JSONDecodeError, OSError):
break
except (WebSocketDisconnect, Exception):
pass
finally:
read_task.cancel()
try:
proc.terminate()
await asyncio.wait_for(
proc.wait(),
timeout=2
)
except Exception:
proc.kill()
try:
os.close(master_fd)
except Exception:
pass