def make_interactive( channel: paramiko.Channel ) -> typing.Tuple[int, typing.BinaryIO, typing.BinaryIO]: """ Manages an interactive command Takes in a paramiko.Channel shared by stdin, stdout, stderr of a currently running command The current interpreter stdin is duplicated and written to the command's stdin The command's stdout and stderr are written to the interpreter's stdout and stderr and also buffered in a ByteStream for later reading Returns (exit status, Stdout buffer, Stderr bufer) """ infd = sys.stdin.fileno() channelfd = channel.fileno() poll = select.poll() poll.register( infd, select.POLLIN + select.POLLPRI + select.POLLERR + select.POLLHUP) poll.register( channelfd, select.POLLIN + select.POLLPRI + select.POLLERR + select.POLLHUP) stdout = io.BytesIO() stderr = io.BytesIO() while not channel.exit_status_ready(): for fd, event in poll.poll(0.5): if fd == infd and event & (select.POLLIN + select.POLLPRI): # Text available on python stdin channel.send(os.read(infd, 4096)) if channel.recv_ready(): content = channel.recv(4096) sys.stdout.write(content.decode()) sys.stdout.flush() stdout.write(content) if channel.recv_stderr_ready(): content = channel.recv_stderr(4096) sys.stderr.write(content.decode()) sys.stderr.flush() stderr.write(content) if channel.recv_ready(): content = channel.recv(4096) sys.stdout.write(content.decode()) sys.stdout.flush() stdout.write(content) if channel.recv_stderr_ready(): content = channel.recv_stderr(4096) sys.stderr.write(content.decode()) sys.stderr.flush() stderr.write(content) stdout.seek(0, 0) stderr.seek(0, 0) return channel.recv_exit_status(), stdout, stderr
def wait_until_end(self, channel: Channel): status = channel.recv_exit_status() return status