如何通过编写io :: Write特质通过期货流发送数据?

时间:2019-04-16 12:40:20

标签: stream rust future

我有一个接受&mut io::Write的函数,我想用它来发送来自actix-web服务器的流响应,而不必缓冲整个响应。该功能正在“推送”数据,并且我无法更改该功能(这是此问题的全部前提)以使用异步流或其他类型的轮询。

当前,我被迫使用&mut Vec(实现io::Write)来缓冲整个结果,然后将Vec发送为响应正文。但是,响应可能很大,因此我宁愿不用缓冲就对其进行流式处理。

是否有某种适配器可以实现io::Write,并在必要时响应反压而阻止写操作,并且与actix-web可以用于响应的类型兼容(例如,futures::Stream)?

fn generate(output: &mut io::Write) {
    // ...
}

fn request_handler() -> Result<HttpResponse> {
    thread::spawn(|| generate(/*???*/));
    Ok(HttpResponse::Ok().body(/*???*/))
}

std::sync::mpscfutures::mpsc要么两端异步,要么两端阻塞,因此如何将它们用作同步端和异步端之间的适配器还不是很清楚。

2 个答案:

答案 0 :(得分:2)

有可能。关键是futures::sink::Wait

  

接收器组合器,它将异步接收器转换为阻塞接收器

     

Sink::wait方法创建,此函数将所有接收器转换为阻塞版本。这是通过在接收器无法通过进度时阻止当前线程来实现的。

所需要做的只是将此类型包装在实现io::Write的结构中:

use futures::{
    sink::{Sink, Wait},
    sync::mpsc,
}; // 0.1.26
use std::{io, thread};

fn generate(_output: &mut io::Write) {
    // ...
}

struct MyWrite<T>(Wait<mpsc::Sender<T>>);

impl<T> io::Write for MyWrite<T>
where
    T: for<'a> From<&'a [u8]> + Send + Sync + 'static,
{
    fn write(&mut self, d: &[u8]) -> io::Result<usize> {
        let len = d.len();
        self.0
            .send(d.into())
            .map(|()| len)
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }

    fn flush(&mut self) -> io::Result<()> {
        self.0
            .flush()
            .map_err(|e| io::Error::new(io::ErrorKind::Other, e))
    }
}

fn foo() -> impl futures::Stream<Item = Vec<u8>, Error = ()> {
    let (tx, rx) = mpsc::channel(5);

    let mut w = MyWrite(tx.wait());

    thread::spawn(move || generate(&mut w));

    rx
}

答案 1 :(得分:-1)

不可能。 Actix-web管理自己的写缓冲区和套接字。