Skip to main content

SshConnectionManager

Struct SshConnectionManager 

Source
pub struct SshConnectionManager { /* private fields */ }
Expand description

SSH Connection Manager

Manages a persistent SSH connection with the following features:

  • Automatic reconnection when connection drops
  • Concurrent access protection via mutex/atomic flags
  • Optional su elevation for privileged operations
  • 30-second connection timeout

Implementations§

Source§

impl SshConnectionManager

Source

pub async fn exec_command( &self, command: &str, timeout_duration: Duration, ) -> Result<CommandOutput>

Execute a command over SSH

This method:

  1. Ensures the connection is active
  2. If elevated (su shell), uses the PTY shell channel
  3. Otherwise, opens a new exec channel
  4. Collects stdout/stderr with timeout
  5. On timeout, attempts graceful abort via pkill
§Arguments
  • command - The command to execute (should be pre-sanitized)
  • timeout_duration - Maximum time to wait for command completion
§Returns
  • Ok(CommandOutput) - Command output with stdout, stderr, and exit code
  • Err(SshMcpError::Timeout) - If command times out
  • Err(SshMcpError::Connection) - If connection issues occur
Source

pub async fn exec_raw_streaming<R, W>( &self, command: &str, stdin: Option<&mut R>, stdout: Option<&mut W>, timeout_duration: Duration, ) -> Result<TransferRawOutput>
where R: AsyncRead + Unpin, W: AsyncWrite + Unpin,

Execute a command over SSH with binary-safe streaming.

This method is designed for use-cases like file transfer where stdout must be treated as bytes and forwarded to a sink without UTF-8 decoding.

Notes:

  • This does not use the interactive su shell.
  • Timeouts are enforced locally via tokio timeout.
Source

pub async fn check_process( &self, job_id: &str, tail_lines: usize, registry: &JobRegistry, spooler: &LocalLogSpooler, ) -> Result<ProcessStatus>

Check the status of a background job by job_id.

Uses kill -0 for process detection (existence/permission check without sending a signal). This avoids parsing ps output (GNU vs BusyBox differences) and works on common Linux distributions.

§Arguments
  • job_id - Job id returned by background exec
  • tail_lines - Number of lines to read from log tail
  • registry - Job registry holding current job state
§Returns

ProcessStatus with running state, exit code, elapsed time, command, and log tail

Source§

impl SshConnectionManager

Source

pub async fn new(config: SshConfig) -> Self

Create a new SSH Connection Manager

Does not establish connection immediately; call connect() or ensure_connected() to establish the connection.

Source

pub async fn connect(&self) -> Result<()>

Establish SSH connection

If already connected, returns immediately. If another task is currently connecting, waits for that connection attempt to complete.

Source

pub async fn is_connected(&self) -> bool

Check if the connection is active

Source

pub async fn ensure_connected(&self) -> Result<()>

Ensure connection is established, reconnecting if necessary

Source

pub async fn with_session<F, T>(&self, f: F) -> Result<T>
where F: FnOnce(&Handle<SshHandler>) -> T,

Get a reference to the session for operations

Instead of cloning the Handle (which doesn’t implement Clone), we provide methods that work with the session directly.

Source

pub async fn open_channel(&self) -> Result<Channel<Msg>>

Open a new session channel

Source

pub fn is_elevated(&self) -> bool

Check if currently elevated to root via su

Source

pub fn use_timeout_wrapper(&self) -> bool

Check if the timeout command is available on the remote system

Uses cached result after first check. To trigger a new check, the connection must be re-established.

Source

pub fn disable_timeout_wrapper(&self)

Disables timeout wrapper for the rest of this connection lifetime

When called, this sets has_timeout_cmd to false, causing all subsequent commands to fall back to the tokio timeout + pkill method instead of using the remote timeout command wrapper.

Source

pub async fn check_timeout_availability(&self) -> bool

Detect whether the timeout command is available on the remote system

This performs a one-time detection check by running sh -c 'command -v timeout' on the remote system. The result is cached for the lifetime of the connection.

Returns true if timeout is available, false otherwise.

Source

pub async fn has_su_channel(&self) -> bool

Check if an elevated su channel is available

Source

pub async fn with_su_channel<F, Fut, T>(&self, f: F) -> Result<T>
where F: FnOnce(&mut Option<Channel<Msg>>) -> Fut, Fut: Future<Output = Result<T>>,

Execute a closure with access to the su channel

The closure receives a mutable reference to the Option, allowing it to use the channel for operations.

Source

pub async fn ensure_elevated(&self) -> Result<()>

Ensure we have an elevated shell via su

This starts an interactive PTY session, runs su -, sends the password, and waits for the root prompt (#).

Source

pub fn get_su_password(&self) -> Option<&str>

Get the su password if configured

Source

pub fn get_sudo_password(&self) -> Option<&str>

Get the sudo password if configured

Source

pub async fn set_su_password(&self, password: Option<String>) -> Result<()>

Set or update the su password

If setting a new password, will attempt to establish elevation. If clearing the password (None), will close any existing su shell.

Source

pub async fn close(&self)

Close the SSH connection

Source

pub async fn invalidate_session(&self, reason: &str)

Invalidate the current session and clear elevation state

This clears the session handle, su_channel, and resets elevation state. Used when a connection is detected as broken and needs reconnection.

Source

pub async fn reconnect(&self) -> Result<()>

Force a reconnection by invalidating the current session and reconnecting

This is used when the connection is known to be broken and a fresh connection is required. It clears all session state and performs a new connection attempt.

Trait Implementations§

Source§

impl Debug for SshConnectionManager

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more