irosh 0.1.0

SSH sessions over Iroh peer-to-peer transport
Documentation
use tokio::process::Command;

use crate::error::{Result, ServerError, TransportError};
use crate::transport::stream::IrohDuplex;
use crate::transport::transfer::{
    CwdResponse, ExistsRequest, ExistsResponse, TransferFailure, TransferFailureCode,
    write_cwd_response, write_exists_response, write_transfer_error,
};

use super::{LiveShellContext, resolve_remote_path};

pub(super) async fn handle_exists_request(
    stream: &mut IrohDuplex,
    request: ExistsRequest,
    shell_pid: Option<u32>,
) -> Result<()> {
    let resolved = resolve_remote_path(&request.path)?;
    let helper_path = resolved.display().to_string();

    let mut exists_cmd = Command::new("test");
    if let Some(shell) = LiveShellContext::from_pid(shell_pid) {
        let exists = shell.path_exists(&helper_path).await?;
        write_exists_response(stream, &ExistsResponse { exists })
            .await
            .map_err(TransportError::from)?;
        return Ok(());
    }
    exists_cmd.arg("-e").arg(&helper_path);
    let status = exists_cmd
        .status()
        .await
        .map_err(|e| ServerError::ShellError {
            details: format!("probing remote existence without live shell failed: {e}"),
        })?;
    write_exists_response(
        stream,
        &ExistsResponse {
            exists: status.success(),
        },
    )
    .await
    .map_err(TransportError::from)?;
    Ok(())
}

pub(super) async fn handle_cwd_request(
    stream: &mut IrohDuplex,
    shell_pid: Option<u32>,
) -> Result<()> {
    let Some(shell) = LiveShellContext::from_pid(shell_pid) else {
        write_transfer_error(
            stream,
            &TransferFailure::new(
                TransferFailureCode::RemoteShellUnavailable,
                "no live shell process",
            ),
        )
        .await
        .map_err(TransportError::from)?;
        return Ok(());
    };

    let cwd = shell.cwd().await?;
    write_cwd_response(
        stream,
        &CwdResponse {
            path: cwd.display().to_string(),
        },
    )
    .await
    .map_err(TransportError::from)?;
    Ok(())
}