Commit b110eb0e4d479472548896c41ca4c3445233348e
1 parent
eb9dfe04
Fixes #4 Basic upload endpoint done
Showing
9 changed files
with
76 additions
and
18 deletions
| ... | ... | @@ -25,17 +25,21 @@ edition = "2018" |
| 25 | 25 | |
| 26 | 26 | [dependencies] |
| 27 | 27 | actix-files = "0.2" |
| 28 | -actix-web = "2.0" | |
| 29 | 28 | actix-rt = "1.1.1" |
| 29 | +actix-web = "2.0" | |
| 30 | +anyhow = "1.0" | |
| 30 | 31 | artshop-common = { path = "../common" } |
| 32 | +async-std = "^1.10" | |
| 33 | +chrono = "0.4.15" | |
| 31 | 34 | diesel = { version = "1.4.7", features = ["sqlite", "r2d2"]} |
| 32 | -r2d2 = "0.8.9" | |
| 35 | +diffy = "0.2" | |
| 33 | 36 | dotenv = "0.15.0" |
| 37 | +flate2 = "^1.0" | |
| 38 | +futures = "^0.3" | |
| 39 | +listenfd = "0.3" | |
| 40 | +r2d2 = "0.8.9" | |
| 34 | 41 | serde = "1.0" |
| 35 | 42 | serde_derive = "1.0" |
| 36 | 43 | serde_json = "1.0" |
| 37 | -anyhow = "1.0" | |
| 38 | -chrono = "0.4.15" | |
| 39 | -listenfd = "0.3" | |
| 40 | -diffy = "0.2" | |
| 41 | -flate2 = "^1.0" | |
| 44 | +#tokio = { version = "1", features = ["full"] } | |
| 45 | +uuid = { version = "^0.8", features = ["v4"] } | ... | ... |
| ... | ... | @@ -15,6 +15,7 @@ use diesel::r2d2::{self, ConnectionManager}; |
| 15 | 15 | use diesel::SqliteConnection; |
| 16 | 16 | use listenfd::ListenFd; |
| 17 | 17 | use routes::markdown::get_markdown; |
| 18 | +use routes::upload::upload; | |
| 18 | 19 | |
| 19 | 20 | pub(crate) type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>; |
| 20 | 21 | |
| ... | ... | @@ -33,6 +34,9 @@ async fn main() -> std::io::Result<()> { |
| 33 | 34 | App::new() . data(database_pool.clone()) |
| 34 | 35 | . service(actix_files::Files::new("/static", "./static")) |
| 35 | 36 | . service( web::scope("/api/v0") |
| 37 | + . service( web::resource("/upload") | |
| 38 | + . route(web::post().to(upload)) | |
| 39 | + ) | |
| 36 | 40 | . service( web::resource("/markdowns") |
| 37 | 41 | . route(web::get().to(get_markdowns)) |
| 38 | 42 | ) | ... | ... |
server/src/routes/upload.rs
0 → 100644
| 1 | +use actix_web::{Error, HttpResponse, web}; | |
| 2 | +use anyhow::Result; | |
| 3 | +use futures::stream::StreamExt; | |
| 4 | +use async_std::{fs::OpenOptions, io::WriteExt}; | |
| 5 | +use uuid::Uuid; | |
| 6 | + | |
| 7 | +pub async fn upload(mut body: web::Payload) -> Result<HttpResponse, Error> | |
| 8 | +{ | |
| 9 | + let mut output = OpenOptions::new(); | |
| 10 | + output . create(true) | |
| 11 | + . write(true); | |
| 12 | + let mut output = output | |
| 13 | + . open(format!("/tmp/upload_{}", Uuid::new_v4())) | |
| 14 | + . await | |
| 15 | + . unwrap(); | |
| 16 | + | |
| 17 | + while let Some(item) = body.next().await { | |
| 18 | + output.write_all(&item?).await.unwrap(); | |
| 19 | + } | |
| 20 | + | |
| 21 | + Ok(HttpResponse::Ok().finish()) | |
| 22 | +} | ... | ... |
| ... | ... | @@ -18,6 +18,7 @@ impl UploadApi { |
| 18 | 18 | pub(crate) async fn store(&self, upload :&Upload) -> Result<&UploadApi> { |
| 19 | 19 | let response = self.client.post_stream( "/api/v0/upload" |
| 20 | 20 | , &upload.mime_type() |
| 21 | + , upload.size() | |
| 21 | 22 | , upload.data() ).await?; |
| 22 | 23 | match response.status() { |
| 23 | 24 | 200 => Ok(self), | ... | ... |
| 1 | 1 | use js_sys::JsString; |
| 2 | 2 | use mogwai::prelude::*; |
| 3 | 3 | use wasm_bindgen::prelude::*; |
| 4 | -use web_sys::{Window, window, Response, Request, RequestInit, RequestMode, ReadableStream}; | |
| 4 | +use web_sys::{Window, window, Response, Request, RequestInit, RequestMode, Headers}; | |
| 5 | 5 | use super::error::*; |
| 6 | 6 | |
| 7 | 7 | use std::result::Result as StdResult; |
| ... | ... | @@ -63,17 +63,20 @@ impl Client { |
| 63 | 63 | } |
| 64 | 64 | |
| 65 | 65 | pub async fn post_stream( &self |
| 66 | - , url :&str | |
| 66 | + , url :&str | |
| 67 | 67 | , mime_type :&str |
| 68 | - , data :ReadableStream) -> Result<Response> { | |
| 68 | + , length :usize | |
| 69 | + , data :&JsValue ) -> Result<Response> { | |
| 70 | + let headers = Headers::new()?; | |
| 71 | + headers.set("Content-Type", mime_type)?; | |
| 72 | + headers.set("Content-Length", &format!("{}", length))?; | |
| 73 | + | |
| 69 | 74 | let mut init = RequestInit::new(); |
| 70 | 75 | let request = REQUEST( url |
| 71 | 76 | , init . method("POST") |
| 72 | 77 | . mode(RequestMode::Cors) |
| 73 | - . body(Some(&data.into())) )?; | |
| 74 | - | |
| 75 | - request . headers() | |
| 76 | - . set("Content-Type", mime_type)?; | |
| 78 | + . headers(&headers.into()) | |
| 79 | + . body(Some(data)) )?; | |
| 77 | 80 | |
| 78 | 81 | let response = JsFuture::from( self.window |
| 79 | 82 | . fetch_with_request(&request)) | ... | ... |
| ... | ... | @@ -85,12 +85,29 @@ pub(super) async fn upload_logic( mut rx_logic :broadcast::Receiver<UploadLogic> |
| 85 | 85 | } |
| 86 | 86 | }, |
| 87 | 87 | UploadLogic::Upload => { |
| 88 | + let mut remove_ids = vec![]; | |
| 89 | + | |
| 88 | 90 | for upload in uploads.read().await.iter() { |
| 89 | 91 | match api.store(upload).await { |
| 90 | - Ok(_) => (), | |
| 92 | + Ok(_) => remove_ids.push(upload.id), | |
| 91 | 93 | Err(e) => log::error!("{:?}", e), |
| 92 | 94 | } |
| 93 | 95 | } |
| 96 | + | |
| 97 | + for id in remove_ids.iter() { | |
| 98 | + let mut found = None; | |
| 99 | + | |
| 100 | + for (upload, index) in uploads.read().await.iter().zip(0..) { | |
| 101 | + if upload.id == *id { | |
| 102 | + found = Some(index); | |
| 103 | + break; | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + if let Some(index) = found { | |
| 108 | + uploads.list_patch_remove(index).unwrap(); | |
| 109 | + } | |
| 110 | + } | |
| 94 | 111 | } |
| 95 | 112 | } |
| 96 | 113 | } | ... | ... |
| 1 | 1 | use mogwai::{prelude::*, utils::window}; |
| 2 | -use web_sys::{File, ImageBitmap, ReadableStream}; | |
| 2 | +use web_sys::{File, ImageBitmap}; | |
| 3 | +use wasm_bindgen::prelude::*; | |
| 3 | 4 | |
| 4 | 5 | use super::{view::upload_preview_view, logic::{upload_preview_logic, UploadLogic}}; |
| 5 | 6 | |
| ... | ... | @@ -30,8 +31,12 @@ impl Upload { |
| 30 | 31 | self.file.type_() |
| 31 | 32 | } |
| 32 | 33 | |
| 33 | - pub(crate) fn data(&self) -> ReadableStream { | |
| 34 | - self.file.stream() | |
| 34 | + pub(crate) fn data(&self) -> &JsValue { | |
| 35 | + &self.file | |
| 36 | + } | |
| 37 | + | |
| 38 | + pub(crate) fn size(&self) -> usize { | |
| 39 | + self.file.size() as usize | |
| 35 | 40 | } |
| 36 | 41 | |
| 37 | 42 | pub(super) fn bitmap(&self) -> ImageBitmap { | ... | ... |
Please
register
or
login
to post a comment