V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Jrohy
V2EX  ›  Rust

rust 怎么实现 sftp 文件的 web 流式下载

  •  
  •   Jrohy · 2021-06-23 16:46:26 +08:00 · 2296 次点击
    这是一个创建于 1249 天前的主题,其中的信息可能已经有所发展或是发生改变。

    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)

    4 条回复    2021-06-24 14:08:28 +08:00
    12101111
        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
    Jrohy
        2
    Jrohy  
    OP
       2021-06-23 18:02:53 +08:00
    @12101111 感谢回复,如果能有例子最好了(rust 新手摸索中),我先看下
    araaaa
        3
    araaaa  
       2021-06-24 11:08:18 +08:00
    用的是标准库的 stream 就用 std::io::copy,tokio 的就调 tokio::io::copy
    Jrohy
        4
    Jrohy  
    OP
       2021-06-24 14:08:28 +08:00
    我试了下 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
    }
    }
    }
    ```
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1024 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 23:13 · PVG 07:13 · LAX 15:13 · JFK 18:13
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.