0

I have the following code, in which I want to send an InputStream of a file in the function fetch-items, which handles the route /fetch-items.

(defn id->image [image-id]
    (let [image (.getInputStream (gfs/find-by-id fs image-id))] image))

(defn item-resp [item]
  (assoc item :_id (str (:_id item))
         :images (into [] (map id->image (:image-ids item))))
  )

(defn fetch-items [req]
  (res/response 
   (map item-resp (find fs "items" {}))))

Here's my request in the client side, using cljs-ajax:

   (ajax-request
    {:uri "http://localhost:5000/fetch-items"
     :method :get
     :handler #(prn (into [] %))
     :format (json-request-format)
     :response-format (raw-response-format)
     }
    )

But the response I get on the client is this:

[:failure :parse] [:response nil] [:status-text "No reader function for tag object.  Format should have been EDN"]
:original-text "{:_id \"5e63f5c591585c30985793cd\", :images [#object[com.mongodb.gridfs.GridFSDBFile$GridFSInputStream 0x22556652 \"com.mongodb.gridfs.GridFSDBFile$GridFSInputStream@22556652\"]]}{:_id \"5e63f5d891585c30985793d0\", :images [#object[com.mongodb.gridfs.GridFSDBFile$GridFSInputStream 0x266ae6c0 \"com.mongodb.gridfs.GridFSDBFile$GridFSInputStream@266ae6c0\"]]}{:_id \"5e63f5e891585c30985793d3\", ...

Why would the response say that the format should have been edn? How do I extract this file/image out in the client side?

--- EDIT ----

Doing the following:

(IOUtils/toString image "utf-8")

returns a string of size 1594 bytes, which is much smaller than the expected image size. I think this is because it's converting the file object to base64 and not the actual chunk of data associated with it. database instance

How do I make it convert the actual GridFS chunk to base64 string and not the file object?

zengod
  • 1,114
  • 13
  • 26

1 Answers1

1

It seems that you are building a response and directly putting an reference to an InputStream object into the response, without encoding the contents of the stream into an array of bytes and serializing the contents on the response.

You'll need to find a way to read the contents of the stream and encode it in the response (maybe send them encoded as base 64?)

On the other end, the client seems to be expecting an EDN response, and when it found the string #object, it complained that it didn't have a way to read an object with such a tag.

Here's a simple example of how to read an EDN string with a tagged literal, you can extend it so you decode the image in the client (note I'm using Java in the decoder, you'll need a different implementation on JS):

(defn b64decode [s]
  (->> s .getBytes (.decode (java.util.Base64/getDecoder)) String.))

(def message "{:hello :world :msg #base64str \"SGV5LCBpdCB3b3JrcyE=\"}")

;; Now we can read the EDN string above adding our handler for #base64str

(clojure.edn/read-string {:readers {'base64str b64decode}} message)
;; => {:hello :world, :msg "Hey, it works!"}


Denis Fuenzalida
  • 3,271
  • 1
  • 17
  • 22
  • What's a quick way to convert InputStream into base64 string? – zengod Mar 07 '20 at 21:02
  • Check this: https://gist.github.com/dfuenzalida/cb5056bfa0743200f787185d3275026e – Denis Fuenzalida Mar 07 '20 at 21:35
  • Neither the link code or (IOUtils/toString my-input-stream "utf-8") seems to work for GridFSDBInputStream, since I get the same base64 string for every file in both cases, and is also not long enough to be the images. – zengod Mar 07 '20 at 21:59
  • In your code example the function `id->image` seems to be incomplete. Check if you have actually changed it to `slurp` the contents of the InputStream, and use `count` to determine if it's as big as you expect – Denis Fuenzalida Mar 07 '20 at 22:12
  • Seems like all these methods convert the file object to base64 and not the actual gridfs chunk associated with the file object. Check out the edit for details. – zengod Mar 07 '20 at 22:29
  • It seems to me the problem is still in the function `id->image`. Instead of returning the InputSteam, read the contents of it using `slurp` and see what's in there (maybe you can test it on the REPL). I'm not familiar with the monger driver, but it could be that the InputStream contains the data already encoded in BSON? – Denis Fuenzalida Mar 08 '20 at 04:14