web 框架用的是 actix-web, sftp 访问用的是 ssh2, 以下测试代码, 调接口后 sftp 的文件加载到内存完成后才能开始下载。
想实现 sftp 的文件不用加载到内存和下载到本地服务器,调用 web 接口可以马上下载的效果
#[get("/")]
async fn file_download() -> HttpResponse{
let tcp = TcpStream::connect("1.2.3.4:22").unwrap();
let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("root", "abcde").unwrap();
let file_path = "/root/gg.zip";
let (mut remote_file, _stat) = sess.scp_recv(Path::new(file_path)).unwrap();
let (tx, rx) = local_channel::mpsc::channel::<Result<Bytes, Error>>();
actix_web::rt::spawn(async move {
let mut buffer = [0; 100];
loop {
if !remote_file.eof() {
if let Ok(_n) = remote_file.read(&mut buffer[..]) {
let data = Vec::from(buffer);
tx.send(Ok(Bytes::from(data))).unwrap();
} else {
break
}
} else {
break
}
}
});
HttpResponse::Ok()
.set_header(actix_web::http::header::CONTENT_DISPOSITION, format!("attachment; filename={}", file_path.split("/").last().unwrap()))
.streaming(rx)
}
如果换做用 go, 用 io.copy 就能实现
c.Writer.WriteHeader( http.StatusOK)
c.Header("Content-Disposition", "attachment; filename=gg.txt")
_, _ = io.Copy(c.Writer, sftpFile)
rust 这方面资料实在太少(连搜索英文都搜不到什么),rust 也有 io::copy 但不知道怎么绑定到 httpresponse, 希望有经验人士能解答下,即使换 web 框架都可以(不用 actix-web)
1
12101111 2021-06-23 17:45:42 +08:00
建议你使用异步的 io::copy https://docs.rs/async-std/1.9.0/async_std/io/fn.copy.html
然后 ssh2 也用异步的 https://docs.rs/async-ssh2-lite/0.2.1/async_ssh2_lite/struct.AsyncFile.html 上面两个用的似乎是 async-std/smol 的库, 不过 actix-web 用的是 tokio, 不知道是不是兼容, tokio 有自己的 io::copy https://docs.rs/tokio/1.7.1/tokio/io/fn.copy.html |
3
araaaa 2021-06-24 11:08:18 +08:00
用的是标准库的 stream 就用 std::io::copy,tokio 的就调 tokio::io::copy
|
4
Jrohy OP 我试了下 rocket.rs 框架的 bytestream 可以实现, 但没法指定下载流生成的文件名😭
``` ByteStream! { let mut buffer = [0; 1000]; loop { if !scp_file.eof() { if let Ok(_n) = scp_file.read(&mut buffer[..]) { let data = Vec::from(buffer); yield data; } else { break } } else { break } } } ``` |