From e5e97e14e080cf492a0487bd5a180b49481a7b7c Mon Sep 17 00:00:00 2001 From: heyarne Date: Sat, 22 Aug 2020 10:56:55 +0200 Subject: [PATCH] Implement parsing for image/jpeg responses --- src/heyarne/vanilla_sky/tiptaps.clj | 42 ++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/src/heyarne/vanilla_sky/tiptaps.clj b/src/heyarne/vanilla_sky/tiptaps.clj index 3dd5213..40c8226 100644 --- a/src/heyarne/vanilla_sky/tiptaps.clj +++ b/src/heyarne/vanilla_sky/tiptaps.clj @@ -14,8 +14,13 @@ (defn fetch-url [url] (future (html/html-snippet (:body (http/get url))))) +;; here are some hand-picked webcams: +;; colorado springs: https://www.insecam.org/en/view/481423/ +;; salzburg: https://www.insecam.org/en/view/540433/ +;; not madrid: https://www.insecam.org/en/view/856408/ + (def some-detail-page - @(fetch-url "https://www.insecam.org/en/view/540433/")) + @(fetch-url "https://www.insecam.org/en/view/856408/")) (def some-camera-image (-> @@ -36,12 +41,7 @@ ;; we're only interested in the first chunk of data, so we need to figure out ;; how we can close the connection afterwards and discard the other ones. -;; TODO: To read the image the following is done -;; - Find the first boundary -;; - Load all following bytes into a buffer until the buffer appears the next time -;; - Return the buffer - -;; NOTE A more elegant method might be this: +;; Our approach is this: ;; - Convert the stream into a lazy sequence of bytes ;; - Partition the lazy sequence whenever you find (str "--" boundary) ;; - Select the part of the sequence you want @@ -83,12 +83,9 @@ {:header (apply str (map char (first parsed))) :body (byte-array (apply concat (rest parsed)))})) -(defn parse-multipart [request] +(defn parse-mixed-replace [request] (let [content-type (get-in request [:headers "Content-Type"]) - boundary (str "--" (second (re-find #"boundary=\"(.*?)\"" content-type)) "\r\n")] - ;; let's throw in an assert because we have no idea how other servers - ;; implement streaming or wether they implement it at all - (assert (some? boundary) "Could not parse multipart/x-mixed-replace boundary") + boundary (str "--" (second (re-find #"boundary=(?:\")?(.*?)(?:\")?(;|$)" content-type)) "\r\n")] (with-open [input (:body request)] ;; find indices of the bytes between the first and second boundary; the byte ;; sequence always starts with the boundary, which is why can skip the first @@ -99,7 +96,26 @@ ;; first (empty) split (parse-multipart-alternative (second (partition-with-seq boundary-seq byte-seq))))))) -(def first-multipart-chunk (parse-multipart (http/get some-camera-image {:as :stream}))) +(defn parse-image [request] + (with-open [input (:body request)] + (byte-array (input->byte-seq input)))) + +(defmulti parse-response-body (fn [req] + (second (re-find #"^(.*?)(;|$)" (get-in req [:headers "Content-Type"]))))) + +(defmethod parse-response-body "multipart/x-mixed-replace" [req] + (:body (parse-mixed-replace req))) + +(defmethod parse-response-body "image/jpeg" [req] + (parse-image req)) + +#_(ns-unmap *ns* 'parse-response-body) + +(defmethod parse-response-body :default [req] + (throw (IllegalArgumentException. + (str "No parser defined for content-type " (pr-str (get-in req [:headers "Content-Type"])))))) + +(def webcam-picture (parse-response-body (http/get some-camera-image {:as :stream}))) ;; we need javax to convert the byte array that is contained in the body of the ;; first multipart alternative to a `BufferedImage` that we can use