92 lines
2.3 KiB
Python
Executable File
92 lines
2.3 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import json
|
|
import os
|
|
import pty
|
|
import select
|
|
import sys
|
|
|
|
|
|
def emit(event_type, **payload):
|
|
print(json.dumps({"type": event_type, **payload}), flush=True)
|
|
|
|
|
|
def handle_message(pid, fd, raw_line):
|
|
try:
|
|
message = json.loads(raw_line.decode("utf-8", "replace"))
|
|
except json.JSONDecodeError:
|
|
return
|
|
|
|
if message.get("type") == "input":
|
|
os.write(fd, str(message.get("data", "")).encode("utf-8", "replace"))
|
|
elif message.get("type") == "signal":
|
|
os.kill(pid, int(message.get("signal", 15)))
|
|
|
|
|
|
def main():
|
|
if "--" not in sys.argv:
|
|
emit("exit", code=2, signaled=False)
|
|
return 2
|
|
|
|
command = sys.argv[sys.argv.index("--") + 1 :]
|
|
if not command:
|
|
emit("exit", code=2, signaled=False)
|
|
return 2
|
|
|
|
pid, fd = pty.fork()
|
|
if pid == 0:
|
|
os.execvp(command[0], command)
|
|
|
|
emit("start", pid=pid)
|
|
stdin_fd = sys.stdin.fileno()
|
|
open_fds = [fd, stdin_fd]
|
|
stdin_buffer = b""
|
|
|
|
while open_fds:
|
|
readable, _, _ = select.select(open_fds, [], [], 0.2)
|
|
|
|
if fd in readable:
|
|
try:
|
|
data = os.read(fd, 4096)
|
|
except OSError:
|
|
data = b""
|
|
|
|
if data:
|
|
emit("out", data=data.decode("utf-8", "replace"))
|
|
else:
|
|
open_fds.remove(fd)
|
|
|
|
if stdin_fd in readable:
|
|
try:
|
|
chunk = os.read(stdin_fd, 4096)
|
|
except OSError:
|
|
chunk = b""
|
|
|
|
if not chunk:
|
|
open_fds.remove(stdin_fd)
|
|
continue
|
|
|
|
stdin_buffer += chunk
|
|
while b"\n" in stdin_buffer:
|
|
line, stdin_buffer = stdin_buffer.split(b"\n", 1)
|
|
handle_message(pid, fd, line)
|
|
|
|
try:
|
|
finished_pid, status = os.waitpid(pid, os.WNOHANG)
|
|
except ChildProcessError:
|
|
break
|
|
|
|
if finished_pid == pid:
|
|
if os.WIFSIGNALED(status):
|
|
emit("exit", code=os.WTERMSIG(status), signaled=True)
|
|
return 128 + os.WTERMSIG(status)
|
|
|
|
code = os.WEXITSTATUS(status)
|
|
emit("exit", code=code, signaled=False)
|
|
return code
|
|
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|