-
Notifications
You must be signed in to change notification settings - Fork 20
/
Copy pathclient.rs
112 lines (94 loc) · 3.23 KB
/
client.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use async_trait::async_trait;
use log::{error, info, LevelFilter};
use russh::*;
use russh_keys::*;
use russh_sftp::{client::SftpSession, protocol::OpenFlags};
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(
&mut self,
server_public_key: &ssh_key::PublicKey,
) -> Result<bool, Self::Error> {
info!("check_server_key: {:?}", server_public_key);
Ok(true)
}
async fn data(
&mut self,
channel: ChannelId,
data: &[u8],
_session: &mut client::Session,
) -> Result<(), Self::Error> {
info!("data on channel {:?}: {}", channel, data.len());
Ok(())
}
}
#[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", "password")
.await
.unwrap()
{
let 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
.open_with_flags(
filename,
OpenFlags::CREATE | OpenFlags::TRUNCATE | OpenFlags::WRITE | OpenFlags::READ,
)
.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);
}
}