|
1 | | -use std::{ |
2 | | - ffi::OsStr, |
3 | | - fs::{self, File}, |
4 | | - io::Write, |
5 | | - path::Path, |
6 | | -}; |
| 1 | +use std::{ffi::OsStr, fs::File, io::Write, path::Path}; |
7 | 2 |
|
8 | | -use actix_multipart::Multipart; |
| 3 | +use actix_multipart::{Multipart, Field}; |
9 | 4 | use actix_web::{web, HttpResponse}; |
10 | 5 | use atomic_lib::{ |
11 | 6 | commit::CommitResponse, hierarchy::check_write, urls, utils::now, Resource, Storelike, Value, |
12 | 7 | }; |
| 8 | + |
13 | 9 | use futures::{StreamExt, TryStreamExt}; |
14 | 10 | use serde::Deserialize; |
15 | 11 |
|
16 | 12 | use crate::{ |
17 | 13 | appstate::AppState, |
18 | 14 | errors::AtomicServerResult, |
19 | | - files::{self, FileStore}, |
| 15 | + files::{self, FSConfig, FileStore}, |
20 | 16 | helpers::get_client_agent, |
21 | 17 | }; |
22 | 18 |
|
@@ -54,43 +50,24 @@ pub async fn upload_handler( |
54 | 50 | let mut created_resources: Vec<Resource> = Vec::new(); |
55 | 51 | let mut commit_responses: Vec<CommitResponse> = Vec::new(); |
56 | 52 |
|
57 | | - while let Ok(Some(mut field)) = body.try_next().await { |
| 53 | + while let Ok(Some(field)) = body.try_next().await { |
58 | 54 | let content_type = field.content_disposition().clone(); |
59 | 55 | let filename = content_type.get_filename().ok_or("Filename is missing")?; |
60 | 56 |
|
61 | | - std::fs::create_dir_all(&appstate.config.uploads_path)?; |
62 | | - |
63 | | - let fs_file_id = format!( |
64 | | - "{}-{}", |
| 57 | + let file_store = &appstate.file_store; |
| 58 | + let file_id = format!( |
| 59 | + "{}{}-{}", |
| 60 | + file_store.prefix(), |
65 | 61 | now(), |
66 | 62 | sanitize_filename::sanitize(filename) |
67 | 63 | // Spacebars lead to very annoying bugs in browsers |
68 | 64 | .replace(' ', "-") |
69 | 65 | ); |
70 | 66 |
|
71 | | - let mut file_path = appstate.config.uploads_path.clone(); |
72 | | - file_path.push(&fs_file_id); |
73 | | - let mut file = File::create(&file_path)?; |
74 | | - |
75 | | - // Field in turn is stream of *Bytes* object |
76 | | - while let Some(chunk) = field.next().await { |
77 | | - let data = chunk.map_err(|e| format!("Error while reading multipart data. {}", e))?; |
78 | | - // TODO: Update a SHA256 hash here for checksum |
79 | | - file.write_all(&data)?; |
80 | | - } |
81 | | - |
82 | | - let byte_count: i64 = file |
83 | | - .metadata()? |
84 | | - .len() |
85 | | - .try_into() |
86 | | - .map_err(|_e| "Too large")?; |
87 | | - |
88 | | - let file_store = &appstate.file_store; |
89 | | - let file_id = format!("{}{}", file_store.prefix(), &fs_file_id); |
90 | | - if let FileStore::S3(_) = file_store { |
91 | | - files::s3_upload_object(&file_store, &file_id, &file_path).await?; |
92 | | - fs::remove_file(&file_path)?; |
93 | | - } |
| 67 | + let byte_count = match file_store { |
| 68 | + FileStore::S3(_) => files::s3_upload(&file_store, &file_id, field).await?, |
| 69 | + FileStore::FS(config) => fs_upload(&file_store, &config, &file_id, field).await?, |
| 70 | + }; |
94 | 71 |
|
95 | 72 | let subject_path = format!("files/{}", urlencoding::encode(&file_id)); |
96 | 73 | let new_subject = format!("{}/{}", store.get_server_url(), subject_path); |
@@ -132,6 +109,33 @@ pub async fn upload_handler( |
132 | 109 | )?)) |
133 | 110 | } |
134 | 111 |
|
| 112 | + |
| 113 | +async fn fs_upload( |
| 114 | + file_store: &FileStore, |
| 115 | + config: &FSConfig, |
| 116 | + file_id: &str, |
| 117 | + mut field: Field, |
| 118 | +) -> AtomicServerResult<i64> { |
| 119 | + std::fs::create_dir_all(config.path.clone())?; |
| 120 | + |
| 121 | + let mut file = File::create(file_store.get_fs_file_path(file_id)?)?; |
| 122 | + |
| 123 | + let byte_count: i64 = file |
| 124 | + .metadata()? |
| 125 | + .len() |
| 126 | + .try_into() |
| 127 | + .map_err(|_e| "Too large")?; |
| 128 | + |
| 129 | + // Field in turn is stream of *Bytes* object |
| 130 | + while let Some(chunk) = field.next().await { |
| 131 | + let data = chunk.map_err(|e| format!("Error while reading multipart data. {}", e))?; |
| 132 | + // TODO: Update a SHA256 hash here for checksum |
| 133 | + file.write_all(&data)?; |
| 134 | + } |
| 135 | + |
| 136 | + Ok(byte_count) |
| 137 | +} |
| 138 | + |
135 | 139 | fn guess_mime_for_filename(filename: &str) -> String { |
136 | 140 | if let Some(ext) = get_extension_from_filename(filename) { |
137 | 141 | actix_files::file_extension_to_mime(ext).to_string() |
|
0 commit comments