Rust 两个用户如何使用actix field stream?

Rust 两个用户如何使用actix field stream?,rust,async-await,actix-web,Rust,Async Await,Actix Web,我有一个actix web服务,希望在流式传输时解析多部分字段的内容,并将其存储在数据库中 但是,我不知道如何将流馈送到,同时将字节收集到Vec或字符串中 我面临的第一个问题是字段是一个actix::web::Bytes流,而不是u8 #[post("/upload")] pub async fn upload_job( mut payload: Multipart, ) -> Result<HttpResponse, Error> { le

我有一个actix web服务,希望在流式传输时解析多部分字段的内容,并将其存储在数据库中

但是,我不知道如何将流馈送到,同时将字节收集到
Vec
字符串中

我面临的第一个问题是
字段
是一个
actix::web::Bytes
流,而不是
u8

#[post("/upload")]
pub async fn upload_job(
    mut payload: Multipart,
) -> Result<HttpResponse, Error> {
    let mut contents : Vec<u8> = Vec::new();
    while let Ok(Some(mut field)) = payload.try_next().await {
        let content_disp = field.content_disposition().unwrap();
        match content_disp.get_name().unwrap() {
            "file" => {
                while let Some(chunk) = field.next().await {
                    contents.append(&mut chunk.unwrap().to_vec());
                    // already parse the contents 
                    // and additionally store contents somewhere
                }
            }
            _ => (),
        }
    }
    Ok(HttpResponse::Ok().finish())
}
#[post(“/upload”)]
发布异步fn上载作业(
mut有效载荷:多部分,
)->结果{
让mut contents:Vec=Vec::new();
而让Ok(Some(mut field))=有效负载。请尝试下一步()。等待{
让content_disp=field.content_disposition().unwrap();
匹配内容显示获取名称展开{
“文件”=>{
而让一些(块)=field.next()等待{
contents.append(&mut chunk.unwrap())到_-vec();
//已经解析了内容
//并将内容储存在某处
}
}
_ => (),
}
}
Ok(HttpResponse::Ok().finish())
}

非常感谢您的任何提示或建议。

选项之一是将字段包装到结构中,并为其实现流特征

use actix_web::{HttpRequest, HttpResponse, Error};
use futures_util::stream::Stream;
use std::pin::Pin;
use actix_multipart::{Multipart, Field};
use futures::stream::{self, StreamExt};
use futures_util::TryStreamExt;
use std::task::{Context, Poll};
use async_gcode::{Parser, Error as PError};
use bytes::BytesMut;
use std::cell::RefCell;

pub struct Wrapper {
    field: Field,
    buffer: RefCell<BytesMut>,
    index: usize,
}

impl Wrapper {
    pub fn new(field: Field, buffer: RefCell<BytesMut>) -> Self {
        buffer.borrow_mut().truncate(0);
        Wrapper {
            field,
            buffer,
            index: 0
        }
    }
}

impl Stream for Wrapper {
    type Item = Result<u8, PError>;

    fn poll_next(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Option<Result<u8, PError>>> {
        if self.index == self.buffer.borrow().len() {
            match Pin::new(&mut self.field).poll_next(cx) {
                Poll::Ready(Some(Ok(chunk))) => self.buffer.get_mut().extend_from_slice(&chunk),
                Poll::Pending => return Poll::Pending,
                Poll::Ready(None) => return Poll::Ready(None),
                Poll::Ready(Some(Err(_))) => return Poll::Ready(Some(Err(PError::BadNumberFormat/* ??? */)))
            };
        } else {
            let b = self.buffer.borrow()[self.index];
            self.index += 1;
            return Poll::Ready(Some(Ok(b)));
        }
        Poll::Ready(None)
    }
}

#[post("/upload")]
pub async fn upload_job(
    mut payload: Multipart,
) -> Result<HttpResponse, Error> {
    while let Ok(Some(field)) = payload.try_next().await {
        let content_disp = field.content_disposition().unwrap();
        match content_disp.get_name().unwrap() {
            "file" => {
                let mut contents: RefCell<BytesMut> = RefCell::new(BytesMut::new());
                let mut w = Wrapper::new(field, contents.clone());
                let mut p = Parser::new(w);
                while let Some(res) = p.next().await {
                    // Do something with results
                };
                // Do something with the buffer
                let a = contents.get_mut()[0];
            }
            _ => (),
        }
    }
    Ok(HttpResponse::Ok().finish())
}
使用actix_web:{HttpRequest,HttpResponse,Error};
使用futures_util::stream::stream;
使用std::pin::pin;
使用actix_multipart::{multipart,Field};
使用futures::stream::{self,StreamExt};
使用futures_util::trystreamText;
使用std::task::{Context,Poll};
使用异步代码:{Parser,Error as peror};
使用bytes::BytesMut;
使用std::cell::RefCell;
发布结构包装器{
字段:字段,
缓冲区:RefCell,
索引:usize,
}
impl包装器{
pub fn new(字段:字段,缓冲区:RefCell)->Self{
buffer.borrow_mut().truncate(0);
包装纸{
领域
缓冲器
索引:0
}
}
}
包装器的impl流{
类型项=结果;
fn poll_next(
mut self:Pin,
cx:&mut Contextdmitryvm的回答(感谢您的努力)告诉我,实际上有两个问题。首先,将
字节
展平为
u8
,其次,将流“拆分”为缓冲区以备以后存储和
异步gcode
解析器

这显示了我是如何解决的:

#[post(“/upload”)]
发布异步fn上载作业(
mut有效载荷:多部分,
)->结果{
让mut contents:Vec=Vec::new();
而让Ok(Some(mut field))=有效负载。请尝试下一步()。等待{
让content_disp=field.content_disposition().unwrap();
匹配内容显示获取名称展开{
“文件”=>{
让field\u stream=field
.map_err(| |异步|gcode::Error::BadNumberFormat)//转换错误
.map_ok(| y |{//使用Vec将字节转换为流
contents.extend_from_slice(&y);//复制并存储以供以后使用
流::iter(y).map(结果:确定)
})
.try_flatte();//展平u8的流
让mut parser=parser::new(字段\流);
而让一些(gcode)=parser.next()等待{
//来自解析器的处理结果
}
}
_ => (),
}
}
Ok(HttpResponse::Ok().finish())
}
您可能想试试。它非常活跃,您应该在那里得到一些帮助。