host.interact

Interactive shell bridging for remote hosts.

UnixHost._interact() uses this module to run otto host <id> login: an interactive SSH or telnet shell whose stdin/stdout are bridged to the user’s terminal and whose output is also recorded to otto.log in the active output directory.

The bridge is structured around three coroutines:

  • a thread-backed stdin reader (_spawn_stdin_reader) that pushes chunks onto an asyncio.Queue so the event loop never blocks on os.read;

  • _pump_stdin_to_remote, which forwards those chunks verbatim to the remote side, intercepting the local escape byte (Ctrl+], the same escape character used by the classic telnet(1) binary);

  • _pump_remote_to_stdout, which writes remote bytes directly to fd 1 for full terminal fidelity and also feeds them to a line buffer that strips ANSI escape sequences and appends clean lines to otto.log.

Only the remote-read stream is logged. The user’s keystrokes reach the log transcript naturally via the remote PTY’s echo — the same trick script(1) uses — so there is no need to differentiate stdin from stdout on a telnet connection that has no directional labelling.

Window-size changes are forwarded to the remote PTY on SIGWINCH. Without this, remote TUIs keep drawing at their original dimensions when the local terminal is resized: SSH and telnet both need an out-of-band resize message because the remote kernel has no link to the local terminal.

async otto.host.interact.run_ssh_login(*, conn, host_name, command=None)

Open a PTY-backed SSH shell on conn and bridge it to the terminal.

The process requests term_type from $TERM so remote TUIs recognize the terminal capabilities. On local SIGWINCH the new size is forwarded to the remote PTY via SSHClientProcess.change_terminal_size — without this, the remote has no way to know the local terminal was resized.

When command is supplied, the SSH side runs that command instead of the default login shell — used by container hosts to wrap docker exec -it <container> /bin/sh over the parent’s existing SSH connection.

Return type:

None

async otto.host.interact.run_telnet_login(*, client, host_name)

Bridge an already-connected interactive TelnetClient to the terminal.

The client must have been opened with interactive=True so the remote is left in its default echo mode (otto’s non-interactive connect flow sends DONT ECHO to silence command echo — not what we want here). Local SIGWINCH is forwarded as a NAWS subnegotiation via TelnetClient._send_naws.

Return type:

None