FROM python:3.10-slim WORKDIR /app RUN apt-get update && apt-get install -y git wget curl vim build-essential bash RUN pip install --no-cache-dir fastapi uvicorn RUN python3 -c " content = ''' from fastapi import FastAPI, WebSocket from fastapi.responses import HTMLResponse import asyncio, os, pty, fcntl, termios, struct, json, signal app = FastAPI() @app.get(\"/\") async def root(): return HTMLResponse(open(\"index.html\").read()) @app.websocket(\"/ws\") async def ws_endpoint(websocket: WebSocket): await websocket.accept() master_fd, slave_fd = pty.openpty() env = {**os.environ, \"TERM\": \"xterm-256color\", \"HOME\": \"/root\", \"USER\": \"root\", \"SHELL\": \"/bin/bash\"} proc = await asyncio.create_subprocess_exec( \"/bin/bash\", \"--login\", stdin=slave_fd, stdout=slave_fd, stderr=slave_fd, close_fds=True, env=env ) os.close(slave_fd) loop = asyncio.get_event_loop() queue = asyncio.Queue() def on_output(): try: data = os.read(master_fd, 4096) loop.call_soon_threadsafe(queue.put_nowait, data) except OSError: loop.call_soon_threadsafe(queue.put_nowait, None) loop.add_reader(master_fd, on_output) async def sender(): while True: data = await queue.get() if data is None: break try: await websocket.send_bytes(data) except: break sender_task = asyncio.ensure_future(sender()) try: while True: msg = await websocket.receive_text() try: obj = json.loads(msg) if obj.get(\"type\") == \"resize\": fcntl.ioctl(master_fd, termios.TIOCSWINSZ, struct.pack(\"HHHH\", obj[\"rows\"], obj[\"cols\"], 0, 0)) continue except: pass os.write(master_fd, msg.encode()) except: pass finally: loop.remove_reader(master_fd) sender_task.cancel() try: os.close(master_fd) except: pass try: proc.terminate() except: pass ''' with open(\"app.py\", \"w\") as f: f.write(content) " RUN python3 -c " content = open('index.html.tpl', 'r').read() if False else ''' Terminal
''' with open('index.html','w') as f: f.write(content) " EXPOSE 7860 CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]