zero4rs 2.0.0

zero4rs is a powerful, pragmatic, and extremely fast web framework for Rust
Documentation
use crate::prelude2::*;
use std::str::FromStr;

use actix_multipart::Field;
use futures_util::TryStreamExt as _;

use crate::commons::{extract_filename, field_to_futures_reader};
use crate::core::auth0::Requestor;
use crate::core::auth0::UserId;
use actix_web::http::header;
use mongodb::bson::doc;

use crate::sitepages::upload0::{UploadType, GRID_FS_DATABASE_NAME};

// 上传文件
// curl -v -F 'file0=@\"C:/myfile.txt\"' 'http://localhost:8000/upload_videos'
pub async fn upload_files(
    mut payload: actix_multipart::Multipart,
    request: HttpRequest,
    ac: web::Data<AppContext>,
    user_id: web::ReqData<UserId>,
    requestor: web::ReqData<Requestor>,
) -> impl Responder {
    let user_id = user_id.into_inner();
    let user_details = requestor.user();

    let content_length = match request.headers().get(header::CONTENT_LENGTH) {
        Some(val) => val.to_str().unwrap_or("0").parse().unwrap(),
        None => 0,
    };

    if content_length == 0 {
        return request.json(200, R::failed(400, "文件为空!".to_string()));
    }

    let mut upload_type: Option<String> = None;
    let mut file_field: Option<Field> = None;
    let mut field_name;

    while let Ok(Some(mut field)) = payload.try_next().await {
        if field.name().is_none() {
            continue;
        }

        field_name = field.name().unwrap();

        if field_name == "upload_type" {
            while let Ok(Some(_chunk)) = field.try_next().await {
                if let Ok(value) = std::str::from_utf8(&_chunk) {
                    upload_type = Some(value.to_string());
                    break;
                }
            }

            continue;
        }

        if field_name != "file0" {
            continue;
        }

        file_field = Some(field);
    }

    if file_field.is_none() {
        return request.json(200, R::failed(400, "file0 is required!".to_string()));
    }

    let file_field = file_field.unwrap();
    let file_name = extract_filename(&file_field)?;

    if let Some(upload_type) = upload_type {
        match UploadType::from_str(&upload_type) {
            Ok(upload_type) => {
                if let Some(_file_type) = file_field.content_type() {
                    let mime_type = _file_type.to_string();
                    let stream = field_to_futures_reader(file_field);

                    let metadata = doc! {
                        "user_id": &user_id.0,
                        "resource_id": &user_details.resource_id,
                        "upload_type": upload_type.as_str(),
                        "mime_type": mime_type,
                        "created_at": crate::commons::timestamp_millis()
                    };

                    let id = ac
                        .mongo()
                        .save_stream_with_opts(&GRID_FS_DATABASE_NAME, &file_name, stream, metadata)
                        .await?;

                    request.json(200, R::ok(id))
                } else {
                    request.json(200, R::failed(400, "upload_type unknow!".to_string()))
                }
            }
            Err(_) => request.json(
                200,
                R::failed(400, format!("不支持的视频上传类型: {}", upload_type)),
            ),
        }
    } else {
        request.json(200, R::failed(400, "upload_type is required!".to_string()))
    }
}