PK ! pyxtermjs/__init__.py__version__ = "0.1.0" PK ! f pyxtermjs/app.py#!/usr/bin/env python3 from flask import Flask, render_template from flask_socketio import SocketIO import pty import os import subprocess import select app = Flask( __name__, template_folder=".", static_folder=".", static_url_path="") app.config["SECRET_KEY"] = "secret!" app.config["fd"] = None app.config["child_pid"] = None socketio = SocketIO(app) def read_and_forward_pty_output(): max_read_bytes = 1024 * 20 while True: socketio.sleep(0.01) if app.config["fd"]: timeout_sec = 0 (data_ready, _, _) = select.select([app.config["fd"]], [], [], timeout_sec) if data_ready: output = os.read(app.config["fd"], max_read_bytes).decode() socketio.emit( "pty-output", {"output": output}, namespace="/pty") @app.route("/") def index(): return render_template("index.html") @socketio.on("pty-input", namespace="/pty") def pty_input(data): """write to the child pty""" if app.config["fd"]: os.write(app.config["fd"], data["input"].encode()) @socketio.on("connect", namespace="/pty") def connect(): """new client connected""" if app.config["child_pid"]: # already started child process, don't start another return # create child process attached to a pty we can read from and write to (child_pid, fd) = pty.fork() if child_pid == 0: # this is the child process fork. # anything printed here will show up in the pty, including the output # of this subprocess subprocess.run(["bash"]) else: # this is the parent process fork. # store child fd and pid app.config["fd"] = fd app.config["child_pid"] = child_pid print("child pid is", child_pid) print("starting background task to continously read and forward pty " "output to client") socketio.start_background_task(target=read_and_forward_pty_output) print("task started") def main(debug=False, port=5000): print(f"serving on http://127.0.0.1:{port}") socketio.run(app, debug=debug, port=port) if __name__ == "__main__": main(debug=True) PK ! wL pyxtermjs/index.html