defmodule TrongleSSH.SSH.ConnectionCLIManager do alias TrongleSSH.SSH.{Session, Tui} alias IO.ANSI require Logger @behaviour :ssh_server_channel @session_closed_message [ ANSI.clear(), ["This session has been closed."] ] defmodule State do defstruct channel_id: nil, width: nil, height: nil, client_pid: nil, connection_ref: nil, session: %Session{} end def init([%State{} = init_state]) do {:ok, init_state} end def handle_msg({:ssh_channel_up, channel_id, connection_ref}, %State{} = state) do connected_user = :ssh.connection_info(connection_ref) |> Keyword.fetch!(:user) |> String.Chars.to_string() {:ok, %State{ state | channel_id: channel_id, connection_ref: connection_ref, session: %Session{username: connected_user} }} end def handle_msg( {:EXIT, client_pid, _reason}, %State{client_pid: client_pid, channel_id: channel_id} = state ) do send(client_pid, :quit) {:stop, channel_id, state} end def handle_msg( {:send_data, data}, %State{connection_ref: connection_ref, channel_id: channel_id} = state ) do :ssh_connection.send(connection_ref, channel_id, data) {:ok, state} end def handle_msg( :session_closed, %State{connection_ref: connection_ref, channel_id: channel_id} = state ) do :ssh_connection.send(connection_ref, channel_id, @session_closed_message) {:stop, channel_id, state} end def handle_msg(msg, term) do Logger.debug("Unknown msg #{inspect(msg)}, #{inspect(term)}") end def handle_ssh_msg( {:ssh_cm, _connection_handler, {:data, _channel_id, _type, data}}, %State{} = state ) do send(state.client_pid, {:data, data}) {:ok, state} end def handle_ssh_msg( {:ssh_cm, connection_handler, {:pty, channel_id, want_reply?, {_term, width, height, _pixwidth, _pixheight, _opts}}}, %State{} = state ) do :ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id) {:ok, %{ state | width: width, height: height }} end def handle_ssh_msg( {:ssh_cm, connection_handler, {:env, channel_id, want_reply?, _var, _value}}, state ) do :ssh_connection.reply_request(connection_handler, want_reply?, :failure, channel_id) {:ok, state} end def handle_ssh_msg( {:ssh_cm, _connection_handler, {:window_change, _channel_id, width, height, _pixwidth, _pixheight}}, %State{client_pid: client_pid} = state ) do send(client_pid, {:resize, {width, height}}) {:ok, %State{ state | width: width, height: height }} end def handle_ssh_msg( {:ssh_cm, connection_handler, {:shell, channel_id, want_reply?}}, %State{width: width, height: height, session: session} = state ) do :ssh_connection.reply_request(connection_handler, want_reply?, :success, channel_id) {:ok, client_pid} = GenServer.start_link(Tui, [ %Tui.State{ connection_manager_pid: self(), width: width, height: height, session: session } ]) send(client_pid, :refresh) {:ok, %State{state | client_pid: client_pid}} end def handle_ssh_msg( msg, %State{channel_id: channel_id} = state ) do Logger.debug("unknown ssh #{inspect(msg)}") {:stop, channel_id, state} end def terminate(_reason, _state), do: :ok end