Skip to content

Commit cd84f4d

Browse files
authored
Update sftp examples (#357)
The current examples are a bit outdated and have some issues like AspectUnk/russh-sftp#52 (comment)
1 parent 4cc3e09 commit cd84f4d

File tree

3 files changed

+38
-31
lines changed

3 files changed

+38
-31
lines changed

russh/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,5 +80,5 @@ features = ["openssl"]
8080

8181
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
8282
openssl = { workspace = true, optional = true }
83-
russh-sftp = "2.0.0-beta.2"
83+
russh-sftp = "2.0.5"
8484
tokio = { workspace = true }

russh/examples/sftp_client.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
use std::sync::Arc;
2-
31
use async_trait::async_trait;
42
use log::{error, info, LevelFilter};
5-
use russh::keys::*;
63
use russh::*;
7-
use russh_sftp::client::SftpSession;
4+
use russh_keys::*;
5+
use russh_sftp::{client::SftpSession, protocol::OpenFlags};
6+
use std::sync::Arc;
87
use tokio::io::{AsyncReadExt, AsyncSeekExt, AsyncWriteExt};
98

109
struct Client;
@@ -43,7 +42,11 @@ async fn main() {
4342
let mut session = russh::client::connect(Arc::new(config), ("localhost", 22), sh)
4443
.await
4544
.unwrap();
46-
if session.authenticate_password("root", "pass").await.unwrap() {
45+
if session
46+
.authenticate_password("root", "password")
47+
.await
48+
.unwrap()
49+
{
4750
let channel = session.channel_open_session().await.unwrap();
4851
channel.request_subsystem(true, "sftp").await.unwrap();
4952
let sftp = SftpSession::new(channel.into_stream()).await.unwrap();
@@ -72,7 +75,13 @@ async fn main() {
7275

7376
// interaction with i/o
7477
let filename = "test_new.txt";
75-
let mut file = sftp.create(filename).await.unwrap();
78+
let mut file = sftp
79+
.open_with_flags(
80+
filename,
81+
OpenFlags::CREATE | OpenFlags::TRUNCATE | OpenFlags::WRITE | OpenFlags::READ,
82+
)
83+
.await
84+
.unwrap();
7685
info!("metadata by handle: {:?}", file.metadata().await.unwrap());
7786

7887
file.write_all(b"magic text").await.unwrap();

russh/examples/sftp_server.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,12 @@
1-
use std::collections::HashMap;
2-
use std::net::SocketAddr;
3-
use std::sync::Arc;
4-
use std::time::Duration;
5-
61
use async_trait::async_trait;
72
use log::{error, info, LevelFilter};
8-
use russh::keys::key::KeyPair;
9-
use russh::server::{Auth, Msg, Server as _, Session};
10-
use russh::{Channel, ChannelId};
3+
use russh::{
4+
server::{Auth, Msg, Server as _, Session},
5+
Channel, ChannelId,
6+
};
7+
use russh_keys::key::KeyPair;
118
use russh_sftp::protocol::{File, FileAttributes, Handle, Name, Status, StatusCode, Version};
9+
use std::{collections::HashMap, net::SocketAddr, sync::Arc, time::Duration};
1210
use tokio::sync::Mutex;
1311

1412
#[derive(Clone)]
@@ -71,6 +69,17 @@ impl russh::server::Handler for SshSession {
7169
Ok(true)
7270
}
7371

72+
async fn channel_eof(
73+
&mut self,
74+
channel: ChannelId,
75+
session: &mut Session,
76+
) -> Result<(), Self::Error> {
77+
// After a client has sent an EOF, indicating that they don't want
78+
// to send more data in this session, the channel can be closed.
79+
session.close(channel);
80+
Ok(())
81+
}
82+
7483
async fn subsystem_request(
7584
&mut self,
7685
channel_id: ChannelId,
@@ -143,31 +152,20 @@ impl russh_sftp::server::Handler for SftpSession {
143152
return Ok(Name {
144153
id,
145154
files: vec![
146-
File {
147-
filename: "foo".to_string(),
148-
longname: "".to_string(),
149-
attrs: FileAttributes::default(),
150-
},
151-
File {
152-
filename: "bar".to_string(),
153-
longname: "".to_string(),
154-
attrs: FileAttributes::default(),
155-
},
155+
File::new("foo", FileAttributes::default()),
156+
File::new("bar", FileAttributes::default()),
156157
],
157158
});
158159
}
159-
Ok(Name { id, files: vec![] })
160+
// If all files have been sent to the client, respond with an EOF
161+
Err(StatusCode::Eof)
160162
}
161163

162164
async fn realpath(&mut self, id: u32, path: String) -> Result<Name, Self::Error> {
163165
info!("realpath: {}", path);
164166
Ok(Name {
165167
id,
166-
files: vec![File {
167-
filename: "/".to_string(),
168-
longname: "".to_string(),
169-
attrs: FileAttributes::default(),
170-
}],
168+
files: vec![File::dummy("/")],
171169
})
172170
}
173171
}

0 commit comments

Comments
 (0)