Skip to content

Commit

Permalink
bumb toolchain & add sftp client example
Browse files Browse the repository at this point in the history
  • Loading branch information
AspectUnk authored and Eugeny committed Sep 20, 2023
1 parent 8fa6892 commit 7c03dd9
Show file tree
Hide file tree
Showing 5 changed files with 108 additions and 4 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ This is a fork of [Thrussh](https://nest.pijul.com/pijul/thrussh) by Pierre-Éti

## Ecosystem

* [russh-sftp](https://crates.io/crates/russh-sftp) - server-side SFTP subsystem support for `russh` - see `russh/examples/sftp_server.rs`.
* [russh-sftp](https://crates.io/crates/russh-sftp) - server-side and client-side SFTP subsystem support for `russh` - see `russh/examples/sftp_server.rs` or `russh/examples/sftp_client.rs`.
* [async-ssh2-tokio](https://crates.io/crates/async-ssh2-tokio) - simple high-level API for running commands over SSH.

## Contributors ✨
Expand Down
2 changes: 1 addition & 1 deletion russh/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ tokio = { version = "1.17.0", features = [
"sync",
"macros",
] }
russh-sftp = "1.1"
russh-sftp = "2.0.0-beta.1"

[package.metadata.docs.rs]
features = ["openssl"]
102 changes: 102 additions & 0 deletions russh/examples/sftp_client.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use async_trait::async_trait;
use log::{error, info, LevelFilter};
use russh::*;
use russh_keys::*;
use russh_sftp::client::SftpSession;
use std::sync::Arc;
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};

struct Client;

#[async_trait]
impl client::Handler for Client {
type Error = anyhow::Error;

async fn check_server_key(
self,
server_public_key: &key::PublicKey,
) -> Result<(Self, bool), Self::Error> {
info!("check_server_key: {:?}", server_public_key);
Ok((self, true))
}

async fn data(
self,
channel: ChannelId,
data: &[u8],
session: client::Session,
) -> Result<(Self, client::Session), Self::Error> {
info!("data on channel {:?}: {}", channel, data.len());
Ok((self, session))
}
}

#[tokio::main]
async fn main() {
env_logger::builder()
.filter_level(LevelFilter::Debug)
.init();

let config = russh::client::Config::default();
let sh = Client {};
let mut session = russh::client::connect(Arc::new(config), ("localhost", 22), sh)
.await
.unwrap();
if session.authenticate_password("root", "pass").await.unwrap() {
let mut channel = session.channel_open_session().await.unwrap();
channel.request_subsystem(true, "sftp").await.unwrap();
let sftp = SftpSession::new(channel.into_stream()).await.unwrap();
info!("current path: {:?}", sftp.canonicalize(".").await.unwrap());

// create dir and symlink
let path = "./some_kind_of_dir";
let symlink = "./symlink";

sftp.create_dir(path).await.unwrap();
sftp.symlink(path, symlink).await.unwrap();

info!("dir info: {:?}", sftp.metadata(path).await.unwrap());
info!(
"symlink info: {:?}",
sftp.symlink_metadata(path).await.unwrap()
);

// scanning directory
for entry in sftp.read_dir(".").await.unwrap() {
info!("file in directory: {:?}", entry.file_name());
}

sftp.remove_file(symlink).await.unwrap();
sftp.remove_dir(path).await.unwrap();

// interaction with i/o
let filename = "test_new.txt";
let mut file = sftp.create(filename).await.unwrap();
info!("metadata by handle: {:?}", file.metadata().await.unwrap());

file.write_all(b"magic text").await.unwrap();
info!("flush: {:?}", file.flush().await); // or file.sync_all()
info!(
"current cursor position: {:?}",
file.stream_position().await
);

let mut str = String::new();

file.rewind().await.unwrap();
file.read_to_string(&mut str).await.unwrap();
file.rewind().await.unwrap();

info!(
"our magical contents: {}, after rewind: {:?}",
str,
file.stream_position().await
);

file.shutdown().await.unwrap();
sftp.remove_file(filename).await.unwrap();

// should fail because handle was closed
error!("should fail: {:?}", file.read_u8().await);
}
}
4 changes: 3 additions & 1 deletion russh/examples/sftp_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,10 +151,12 @@ impl russh_sftp::server::Handler for SftpSession {
files: vec![
File {
filename: "foo".to_string(),
longname: "".to_string(),
attrs: FileAttributes::default(),
},
File {
filename: "bar".to_string(),
longname: "".to_string(),
attrs: FileAttributes::default(),
},
],
Expand All @@ -169,6 +171,7 @@ impl russh_sftp::server::Handler for SftpSession {
id,
files: vec![File {
filename: "/".to_string(),
longname: "".to_string(),
attrs: FileAttributes::default(),
}],
})
Expand All @@ -185,7 +188,6 @@ async fn main() {
auth_rejection_time: Duration::from_secs(3),
auth_rejection_time_initial: Some(Duration::from_secs(0)),
keys: vec![KeyPair::generate_ed25519().unwrap()],
inactivity_timeout: Some(Duration::from_secs(3600)),
..Default::default()
};

Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
[toolchain]
channel = "1.65.0"
channel = "1.70.0"

0 comments on commit 7c03dd9

Please sign in to comment.