|
| 1 | +(ns taoensso.sente.packers.gzip |
| 2 | + {:author "Peter Taoussanis (@ptaoussanis)"} |
| 3 | + (:require |
| 4 | + [taoensso.truss :as truss] |
| 5 | + [taoensso.sente.packers.impl.gzip :as impl] |
| 6 | + [taoensso.sente.interfaces :as i])) |
| 7 | + |
| 8 | +#?(:clj (defn- ba->str ^String [^bytes ba] (String. ba java.nio.charset.StandardCharsets/UTF_8))) |
| 9 | +#?(:clj (defn- str->ba ^bytes [^String s] (.getBytes s java.nio.charset.StandardCharsets/UTF_8))) |
| 10 | + |
| 11 | +#?(:cljs (let [encoder (js/TextEncoder.)] (defn- str->u8s [^string s] (.encode encoder s)))) |
| 12 | +#?(:cljs (let [decoder (js/TextDecoder. "utf-8")] (defn- u8s->str [^js u8s] (.decode decoder u8s)))) |
| 13 | + |
| 14 | +(defn wrap-packer |
| 15 | + "Experimental, please test carefully and report any issues! |
| 16 | +
|
| 17 | + Returns Sente packer that wraps another with gzip compression. |
| 18 | + Needs `js/CompressionStream` browser support. |
| 19 | +
|
| 20 | + If `packer` takes+returns platform bytes: `binary?` should be true. |
| 21 | + If `packer` takes+returns platform strings: `binary?` should be false." |
| 22 | + |
| 23 | + [packer {:keys [binary?]}] |
| 24 | + #?(:clj |
| 25 | + (reify i/IPacker2 |
| 26 | + (unpack [_ ws? ba cb] |
| 27 | + (if binary? |
| 28 | + (i/unpack packer ws? (impl/gunzip ba) cb) |
| 29 | + (i/unpack packer ws? (ba->str (impl/gunzip ba)) cb))) |
| 30 | + |
| 31 | + (pack [_ ws? x cb] |
| 32 | + (i/pack packer ws? x |
| 33 | + (fn [{:keys [value error]}] |
| 34 | + (if error |
| 35 | + (cb {:error error}) |
| 36 | + (cb {:value (impl/gzip (if binary? value (str->ba value)))})))))) |
| 37 | + |
| 38 | + :cljs |
| 39 | + (do |
| 40 | + (when-not (exists? js/CompressionStream) (truss/ex-info! "CompressionStream not supported")) |
| 41 | + (when-not (exists? js/DecompressionStream) (truss/ex-info! "DecompressionStream not supported")) |
| 42 | + (reify i/IPacker2 |
| 43 | + (unpack [_ ws? packed cb] |
| 44 | + (-> |
| 45 | + (impl/gunzip (impl/as-u8s packed)) ; Decompress -> u8s promise |
| 46 | + (.then |
| 47 | + (fn [u8s] |
| 48 | + (if binary? |
| 49 | + (i/unpack packer ws? u8s cb) |
| 50 | + (i/unpack packer ws? (u8s->str u8s) cb)))) |
| 51 | + (.catch (fn [err] (cb {:error err}))))) |
| 52 | + |
| 53 | + (pack [_ ws? cljs-val cb] |
| 54 | + (i/pack packer ws? cljs-val |
| 55 | + (fn [{:keys [error value]}] ; Serialize -> text/bin value |
| 56 | + (if error |
| 57 | + (cb {:error error}) |
| 58 | + (-> (impl/gzip (if binary? (impl/as-u8s value) (str->u8s value))) ; Compress -> u8s promise |
| 59 | + (.then (fn [u8s] (cb {:value u8s}))) |
| 60 | + (.catch (fn [err] (cb {:error err})))))))))))) |
| 61 | + |
| 62 | +(comment |
| 63 | + (let [p (wrap-packer (taoensso.sente.packers.edn/get-packer) {:binary? false})] |
| 64 | + (i/pack p :ws [:chsk/ws-ping "foo"] |
| 65 | + (fn [{packed :value}] |
| 66 | + (i/unpack p :ws packed |
| 67 | + (fn [{clj :value}] clj)))))) |
0 commit comments