taoensso / sente

Realtime web comms library for Clojure/Script
https://www.taoensso.com/sente
Eclipse Public License 1.0
1.74k stars 193 forks source link

is there a way to give sente extra serialisation logic? #309

Closed thedavidmeister closed 6 years ago

thedavidmeister commented 6 years ago

Because i'm using clj-time and cljs-time i often end up with org.joda.time.DateTime objects server side and goog.date.DateTime objects client side.

If I ever accidentally give either of these to sente I get a cryptic Cb reply w/o local cb-fn: :chsk/bad-package warning and then my app stops working (it just hangs in my case).

I feel like I'm missing something obvious, that there should be a way to define some logic that serialises and parses dates at each end automatically, or at the very least can convert the dates to an ISO8601 string and then I can deal with it at the other end without cryptic errors.

theasp commented 6 years ago

You could wrap send with a function to normalize the data so that your date objects are converted to the same type, using clojure.walk or something specific to your data.

There is an example for dealing with joda objects in the readme: https://github.com/ptaoussanis/sente/blob/master/README.md#how-do-i-add-custom-transit-read-and-write-handlers

I'm sure you could do something similar with the default edn transport.

thedavidmeister commented 6 years ago

OK great i'll try this out thanks!

danielcompton commented 6 years ago

On the server we have

(def packer (sente-transit/->TransitPacker :json utils/transit-writers utils/transit-readers))

;...

;; http://increasinglyfunctional.com/2014/09/02/custom-transit-writers-clojure-joda-time/
;; http://blog.cognitect.com/blog/2015/9/10/extending-transit
(def transit-writers {:handlers {DateTime (transit/write-handler
                                            (constantly "m")
                                            (fn [v] (-> ^ReadableInstant v .getMillis))
                                            (fn [v] (-> ^ReadableInstant v .getMillis .toString)))}})

(def transit-readers {:handlers {"m" (transit/read-handler
                                       (fn [s] (DateTime. (Long/parseLong s))))}})

and on the client:

(def packer (sente-transit/->TransitPacker :json utils/transit-writers utils/transit-readers))

;; http://blog.cognitect.com/blog/2015/9/10/extending-transit
(def transit-readers
  {:handlers
   {"m" (transit/read-handler (fn [s] (UtcDateTime.fromTimestamp s)))
    "u" uuid}})

(def transit-writers
  {:handlers
   {UtcDateTime (transit/write-handler
                  (constantly "m")
                  (fn [v] (.getTime v))
                  (fn [v] (str (.getTime v))))}})
ptaoussanis commented 6 years ago

Marking this as closed, but please feel free to reopen if you still have any questions - cheers! :-)

(And big thanks to @danielcompton and @theasp for helping to field questions in my absence!)