Commit b110eb0e4d479472548896c41ca4c3445233348e

Authored by Georg Hopp
1 parent eb9dfe04

Fixes #4 Basic upload endpoint done

@@ -25,17 +25,21 @@ edition = "2018" @@ -25,17 +25,21 @@ edition = "2018"
25 25
26 [dependencies] 26 [dependencies]
27 actix-files = "0.2" 27 actix-files = "0.2"
28 -actix-web = "2.0"  
29 actix-rt = "1.1.1" 28 actix-rt = "1.1.1"
  29 +actix-web = "2.0"
  30 +anyhow = "1.0"
30 artshop-common = { path = "../common" } 31 artshop-common = { path = "../common" }
  32 +async-std = "^1.10"
  33 +chrono = "0.4.15"
31 diesel = { version = "1.4.7", features = ["sqlite", "r2d2"]} 34 diesel = { version = "1.4.7", features = ["sqlite", "r2d2"]}
32 -r2d2 = "0.8.9" 35 +diffy = "0.2"
33 dotenv = "0.15.0" 36 dotenv = "0.15.0"
  37 +flate2 = "^1.0"
  38 +futures = "^0.3"
  39 +listenfd = "0.3"
  40 +r2d2 = "0.8.9"
34 serde = "1.0" 41 serde = "1.0"
35 serde_derive = "1.0" 42 serde_derive = "1.0"
36 serde_json = "1.0" 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,6 +15,7 @@ use diesel::r2d2::{self, ConnectionManager};
15 use diesel::SqliteConnection; 15 use diesel::SqliteConnection;
16 use listenfd::ListenFd; 16 use listenfd::ListenFd;
17 use routes::markdown::get_markdown; 17 use routes::markdown::get_markdown;
  18 +use routes::upload::upload;
18 19
19 pub(crate) type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>; 20 pub(crate) type Pool = r2d2::Pool<ConnectionManager<SqliteConnection>>;
20 21
@@ -33,6 +34,9 @@ async fn main() -> std::io::Result<()> { @@ -33,6 +34,9 @@ async fn main() -> std::io::Result<()> {
33 App::new() . data(database_pool.clone()) 34 App::new() . data(database_pool.clone())
34 . service(actix_files::Files::new("/static", "./static")) 35 . service(actix_files::Files::new("/static", "./static"))
35 . service( web::scope("/api/v0") 36 . service( web::scope("/api/v0")
  37 + . service( web::resource("/upload")
  38 + . route(web::post().to(upload))
  39 + )
36 . service( web::resource("/markdowns") 40 . service( web::resource("/markdowns")
37 . route(web::get().to(get_markdowns)) 41 . route(web::get().to(get_markdowns))
38 ) 42 )
1 pub(crate) mod markdown; 1 pub(crate) mod markdown;
2 pub(crate) mod other; 2 pub(crate) mod other;
  3 +pub(crate) mod upload;
3 pub(crate) mod user; 4 pub(crate) mod user;
  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 +}
@@ -43,6 +43,7 @@ features = [ @@ -43,6 +43,7 @@ features = [
43 "File", 43 "File",
44 "FileList", 44 "FileList",
45 "FileReader", 45 "FileReader",
  46 + "FormData",
46 "ImageBitmap", 47 "ImageBitmap",
47 "Headers", 48 "Headers",
48 "HtmlCanvasElement", 49 "HtmlCanvasElement",
@@ -18,6 +18,7 @@ impl UploadApi { @@ -18,6 +18,7 @@ impl UploadApi {
18 pub(crate) async fn store(&self, upload :&Upload) -> Result<&UploadApi> { 18 pub(crate) async fn store(&self, upload :&Upload) -> Result<&UploadApi> {
19 let response = self.client.post_stream( "/api/v0/upload" 19 let response = self.client.post_stream( "/api/v0/upload"
20 , &upload.mime_type() 20 , &upload.mime_type()
  21 + , upload.size()
21 , upload.data() ).await?; 22 , upload.data() ).await?;
22 match response.status() { 23 match response.status() {
23 200 => Ok(self), 24 200 => Ok(self),
1 use js_sys::JsString; 1 use js_sys::JsString;
2 use mogwai::prelude::*; 2 use mogwai::prelude::*;
3 use wasm_bindgen::prelude::*; 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 use super::error::*; 5 use super::error::*;
6 6
7 use std::result::Result as StdResult; 7 use std::result::Result as StdResult;
@@ -63,17 +63,20 @@ impl Client { @@ -63,17 +63,20 @@ impl Client {
63 } 63 }
64 64
65 pub async fn post_stream( &self 65 pub async fn post_stream( &self
66 - , url :&str 66 + , url :&str
67 , mime_type :&str 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 let mut init = RequestInit::new(); 74 let mut init = RequestInit::new();
70 let request = REQUEST( url 75 let request = REQUEST( url
71 , init . method("POST") 76 , init . method("POST")
72 . mode(RequestMode::Cors) 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 let response = JsFuture::from( self.window 81 let response = JsFuture::from( self.window
79 . fetch_with_request(&request)) 82 . fetch_with_request(&request))
@@ -85,12 +85,29 @@ pub(super) async fn upload_logic( mut rx_logic :broadcast::Receiver<UploadLogic> @@ -85,12 +85,29 @@ pub(super) async fn upload_logic( mut rx_logic :broadcast::Receiver<UploadLogic>
85 } 85 }
86 }, 86 },
87 UploadLogic::Upload => { 87 UploadLogic::Upload => {
  88 + let mut remove_ids = vec![];
  89 +
88 for upload in uploads.read().await.iter() { 90 for upload in uploads.read().await.iter() {
89 match api.store(upload).await { 91 match api.store(upload).await {
90 - Ok(_) => (), 92 + Ok(_) => remove_ids.push(upload.id),
91 Err(e) => log::error!("{:?}", e), 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 use mogwai::{prelude::*, utils::window}; 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 use super::{view::upload_preview_view, logic::{upload_preview_logic, UploadLogic}}; 5 use super::{view::upload_preview_view, logic::{upload_preview_logic, UploadLogic}};
5 6
@@ -30,8 +31,12 @@ impl Upload { @@ -30,8 +31,12 @@ impl Upload {
30 self.file.type_() 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 pub(super) fn bitmap(&self) -> ImageBitmap { 42 pub(super) fn bitmap(&self) -> ImageBitmap {
Please register or login to post a comment