Write upload handler

This commit is contained in:
heyarne 2020-05-10 23:27:55 +02:00
commit 9fa17f6f6c
3 changed files with 68 additions and 12 deletions

View file

@ -10,7 +10,8 @@
;; clojurescript build tool and dependencies (see also shadow-cljs.edn) ;; clojurescript build tool and dependencies (see also shadow-cljs.edn)
{:cljs {:extra-deps {thheller/shadow-cljs {:mvn/version "2.8.109"} {:cljs {:extra-deps {thheller/shadow-cljs {:mvn/version "2.8.109"}
appliedscience/js-interop {:mvn/version "0.2.5"} appliedscience/js-interop {:mvn/version "0.2.5"}
reagent {:mvn/version "1.0.0-alpha1"}}} reagent {:mvn/version "1.0.0-alpha1"}
cljs-http {:mvn/version "0.1.46"}}}
;; packaging the server as a standalone jar for production ;; packaging the server as a standalone jar for production
:uberjar {:extra-deps {luchiniatwork/cambada {:mvn/version "1.0.2"}} :uberjar {:extra-deps {luchiniatwork/cambada {:mvn/version "1.0.2"}}

View file

@ -9,12 +9,13 @@
(def rfc3339 (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ssXXX")) (def rfc3339 (java.text.SimpleDateFormat. "yyyy-MM-dd'T'HH:mm:ssXXX"))
(defn upload! [file id] (defn upload! [file predictions]
(let [now (.format rfc3339 (java.util.Date.)) (let [now (.format rfc3339 (java.util.Date.))
uuid (java.util.UUID/randomUUID) uuid (java.util.UUID/randomUUID)
ext (re-find #"\.[\w]+$" (-> file :filename))] ext (re-find #"\.[\w]+$" (-> file :filename))
(io/copy (-> file :tempfile) filename (str "uploads/" now "--" uuid)]
(io/file (str "uploads/" id "--" now "--" uuid ext))))) (io/copy (-> file :tempfile) (io/file (str filename ext)))
(spit (str filename ".json") predictions)))
(def app (def app
(ring/ring-handler (ring/ring-handler
@ -22,10 +23,10 @@
[["/upload" [["/upload"
;; TODO: Verify params ;; TODO: Verify params
{:post (fn [req] {:post (fn [req]
(let [{:keys [file friend]} (-> req :params)] (let [{:keys [snapshot predictions]} (-> req :params)]
(upload! file friend) (upload! snapshot predictions)
{:status 201 {:status 201
:body (str "Thanks, " friend)}))}]] :body (str "Thanks :)")}))}]]
["/*" (ring/create-resource-handler)]))) ["/*" (ring/create-resource-handler)])))
(defonce server (atom nil)) (defonce server (atom nil))

View file

@ -1,5 +1,7 @@
(ns heyarne.all-my-friends.views (ns heyarne.all-my-friends.views
(:require [reagent.core :as r] (:require [reagent.core :as r]
[cljs-http.client :as http]
[cljs.core.async :refer [<! go]]
[heyarne.all-my-friends.facemesh :refer [webcam-facemesh]] [heyarne.all-my-friends.facemesh :refer [webcam-facemesh]]
[heyarne.all-my-friends.visualize :as vis])) [heyarne.all-my-friends.visualize :as vis]))
@ -7,13 +9,41 @@
(defonce state (r/atom {:status :welcome-message})) (defonce state (r/atom {:status :welcome-message}))
(declare dispatch)
(def events (def events
{:welcome/continue (fn [db _] {:welcome/continue (fn [db _]
(assoc db :status :running)) (assoc db :status :running))
:running/snapshot (fn [db result] :running/snapshot (fn [db result]
(assoc-in db [:snapshots :current] result)) (assoc-in db [:snapshots :current] result))
:running/discard-snapshot (fn [db _] :running/discard-snapshot (fn [db _]
(update db :snapshots dissoc :current))}) (update db :snapshots dissoc :current))
:upload/post (fn [db post-body]
;; TODO: This is a bit dirty compared to the others because it
;; shoehorns http requests and database changes together
(let [req (http/post "/upload" {:multipart-params post-body})]
(println "request started")
(go (let [{:keys [success body error-text] :as res} (<! req)]
(prn res)
(if success
(dispatch [:upload/done (:message body)])
(dispatch [:upload/error error-text]))
(println "request finished")))
(assoc db :in-progress? true)))
:upload/error (fn [db message]
(dispatch [:message/show {:message message, :type :error}])
(dissoc db :in-progress?))
:upload/done (fn [db _]
(dispatch [:message/show {:message "Tippi toppi!", :type :success}])
(dissoc db :in-progress?))
:message/show (fn [db {:keys [message type]}]
(let [message-id (* (Math/random) (js/Date.now))]
(when (= type :success)
(js/window.setTimeout #(dispatch [:message/hide message-id]) 2500))
(assoc-in db [:messages message-id] {:type type
:message message})))
:message/hide (fn [db message-id]
(update db :messages dissoc message-id))})
(defn dispatch [[event data]] (defn dispatch [[event data]]
(when-let [handler (events event)] (when-let [handler (events event)]
@ -39,6 +69,14 @@ Seit der globalen Covid19-Pandemie sind wir alle dazu gezwungen, auf physischen
(.drawImage ctx video-elem 0 0 (.-width canvas) (.-height canvas)) (.drawImage ctx video-elem 0 0 (.-width canvas) (.-height canvas))
(.getImageData ctx 0 0 (.-width canvas) (.-height canvas)))) (.getImageData ctx 0 0 (.-width canvas) (.-height canvas))))
(defn image-data->blob [img-data cb]
(let [canvas (js/document.createElement "canvas")
ctx (.getContext canvas "2d")]
(set! (.-width canvas) (.-width img-data))
(set! (.-height canvas) (.-height img-data))
(.putImageData ctx img-data 0 0)
(.toBlob canvas cb "image/png")))
(defn preview [{{:keys [video predictions]} :snapshot}] (defn preview [{{:keys [video predictions]} :snapshot}]
(let [canvas (js/document.createElement "canvas") (let [canvas (js/document.createElement "canvas")
ctx (.getContext canvas "2d")] ctx (.getContext canvas "2d")]
@ -55,9 +93,20 @@ Seit der globalen Covid19-Pandemie sind wir alle dazu gezwungen, auf physischen
[:div#snapshot-preview.container [:div#snapshot-preview.container
[:p compliment] [:p compliment]
[preview {:snapshot current-snapshot}] [preview {:snapshot current-snapshot}]
[:button {:on-click #(println "submit")} "Abschicken"] [:button {:on-click #(image-data->blob (:video current-snapshot)
(fn [blob]
(dispatch
[:upload/post {:snapshot blob
:predictions (js/JSON.stringify (:predictions current-snapshot))}])))}
"Abschicken"]
[:button {:on-click #(dispatch [:running/discard-snapshot])} "Lieber noch eins"]])) [:button {:on-click #(dispatch [:running/discard-snapshot])} "Lieber noch eins"]]))
(defn notifications [{:keys [messages]}]
[:ul.notifications
(for [[id {:keys [type message]}] messages]
^{:key id} [:li.message {:class (name type)
:on-click #(dispatch [:message/hide id])} message])])
(defn running [{:keys [on-faces-detected halt?]}] (defn running [{:keys [on-faces-detected halt?]}]
(let [result (atom {:video nil (let [result (atom {:video nil
:predictions nil})] :predictions nil})]
@ -75,15 +124,20 @@ Seit der globalen Covid19-Pandemie sind wir alle dazu gezwungen, auf physischen
(defn app [] (defn app []
(let [state @state (let [state @state
status (:status state) status (:status state)
current-snapshot (get-in state [:snapshots :current])] messages (:messages state)
current-snapshot (get-in state [:snapshots :current])
uploading? (some? (get-in state [:http/requests "/upload"]))]
(prn messages)
[:<> [:<>
[welcome-message {:hidden? (not= :welcome-message status)}] [welcome-message {:hidden? (not= :welcome-message status)}]
[notifications {:messages messages}]
(when uploading?
[:p "Bild wird hochgeladen"])
(when current-snapshot (when current-snapshot
[snapshot {:current-snapshot current-snapshot}]) [snapshot {:current-snapshot current-snapshot}])
(case status (case status
:permission-rejected [:div "Sad :("] :permission-rejected [:div "Sad :("]
:running [running {:on-faces-detected vis/draw-sketch :running [running {:on-faces-detected vis/draw-sketch
:halt? (some? current-snapshot)}] :halt? (some? current-snapshot)}]
;; default ;; default
nil)])) nil)]))