# sshr

[![Crates.io](https://img.shields.io/crates/v/sshr)](https://crates.io/crates/sshr)
[![Docs.rs](https://docs.rs/sshr/badge.svg)](https://docs.rs/sshr)
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)

A Rust SSH toolkit built on `russh` — command execution, PTY terminals, and SFTP file operations.

## Features

- **Command execution** — Run commands on remote hosts with structured input/output, timeout, env vars, sudo
- **PTY terminal** — Full interactive terminal sessions (supports `vim`, `top`, etc.)
- **SFTP file operations** — List, read, write, download, and upload files via SFTP
- **System detection** — Auto-detect remote OS type (Linux, macOS, Windows) and package manager
- **Host key verification** — Strict, AcceptNew, or Disable policies with known_hosts support
- **Connection pooling** — Reuse authenticated connections for batch operations

## Quick Start

### Command Execution

```rust
use sshr::ssh::{AuthMethod, ExecRequest, ExecService, RusshTool, SshConfig};

let cfg = SshConfig::new("10.0.0.1", "root", AuthMethod::Password {
    password: "secret".to_string(),
});

let tool = RusshTool::new();
let result = tool.exec(cfg, ExecRequest::new("uname -a")).await?;
println!("{}", result.stdout_string());
```

### SFTP File Operations

```rust
use sshr::ssh::{AuthMethod, FileService, ReadFileRequest, RusshTool, SshConfig};

let cfg = SshConfig::new("10.0.0.1", "root", AuthMethod::Password {
    password: "secret".to_string(),
});
let tool = RusshTool::new();

// List directory
let entries = tool.list_dir(cfg.clone(), "/etc".to_string()).await?;
for entry in &entries {
    println!("{} {}", if entry.is_dir { "d" } else { "-" }, entry.name);
}

// Read file
let content = tool.read_file(cfg, ReadFileRequest {
    path: "/etc/os-release".to_string(),
    limit: Some(512),
    ..Default::default()
}).await?;
println!("{}", String::from_utf8_lossy(&content));
```

### System Detection

```rust
use sshr::ssh::{AuthMethod, ExecService, RusshTool, SshConfig};

let cfg = SshConfig::new("10.0.0.1", "root", AuthMethod::Password {
    password: "secret".to_string(),
});
let tool = RusshTool::new();

let profile = ExecService::detect_system(&tool, cfg).await?;
// profile.os_id, profile.os_version, profile.arch, profile.package_manager, profile.shell
```

### Connection Pooling (Batch Operations)

```rust
use sshr::ssh::{AuthMethod, ConnectionPool, ExecRequest, RusshTool, SshConfig};

let cfg = SshConfig::new("10.0.0.1", "root", AuthMethod::Password {
    password: "secret".to_string(),
});

let pool = ConnectionPool::default_pool();
let tool = RusshTool::with_pool(pool);

// Multiple calls reuse the same connection
for cmd in ["uname -a", "uptime", "df -h"] {
    let result = tool.exec(cfg.clone(), ExecRequest::new(cmd)).await?;
    println!("{}", result.stdout_string().trim());
}
```

### PTY Interactive Terminal

```rust
use sshr::ssh::{AuthMethod, PtyOpenRequest, PtyService, RusshTerminalService, SshConfig, SessionEvent};

let cfg = SshConfig::new("10.0.0.1", "root", AuthMethod::Password {
    password: "secret".to_string(),
});

let service = RusshTerminalService::new();
let session_id = service.open(cfg, PtyOpenRequest::default()).await?;
let mut events = service.subscribe(session_id).await?;

while let Ok(event) = events.recv().await {
    match event {
        SessionEvent::Stdout(data) => { /* render terminal output */ }
        SessionEvent::Stderr(data) => { /* render stderr */ }
        SessionEvent::Closed { .. } => break,
        _ => {}
    }
}
```

## More Examples

See [`examples/`](examples/) for runnable examples:

```bash
cargo run --example exec -- <host> <user> <password>
cargo run --example sftp -- <host> <user> <password>
cargo run --example detect -- <host> <user> <password>
cargo run --example pool -- <host> <user> <password>
```

## CLI Usage

With the `cli` feature enabled:

```bash
# Validate connection
cargo run --features cli -- validate

# Execute command
cargo run --features cli -- exec -- uname -a

# Simple REPL shell (non-PTY)
cargo run --features cli -- shell

# Full PTY interactive session
cargo run --features cli -- pty
```

## License

This project is licensed under the MIT License. See [LICENSE](LICENSE) for details.
