Commit 73d74786aec522850c6c7dd627216749b63ef059

Authored by Georg GH. Hopp
2 parents eb9dfe04 b110eb0e

Merge branch 'create-basic-upload-endpoint-in-server-4' into 'master'

Fixes #4 Basic upload endpoint done

Closes #4

See merge request !3
... ... @@ -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 )
... ...
1 1 pub(crate) mod markdown;
2 2 pub(crate) mod other;
  3 +pub(crate) mod upload;
3 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 43 "File",
44 44 "FileList",
45 45 "FileReader",
  46 + "FormData",
46 47 "ImageBitmap",
47 48 "Headers",
48 49 "HtmlCanvasElement",
... ...
... ... @@ -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