|
201 | 201 | ;;;; Packing
|
202 | 202 | ;; * Client<->server payloads are arbitrary Clojure vals (cb replies or events).
|
203 | 203 | ;; * Payloads are packed for client<->server transit.
|
204 |
| -;; * Packing includes ->str encoding, and may incl. wrapping to carry cb info. |
205 |
| - |
206 |
| -(defn- unpack "prefixed-pstr->[clj ?cb-uuid]" |
207 |
| - [packer prefixed-pstr] |
208 |
| - (have? string? prefixed-pstr) |
209 |
| - (let [wrapped? (enc/str-starts-with? prefixed-pstr "+") |
210 |
| - pstr (subs prefixed-pstr 1) |
211 |
| - clj |
| 204 | + |
| 205 | +(defn- parse-packed |
| 206 | + "Returns [<packed> <?format>]. Used to support some minimal backwards |
| 207 | + compatibility between v2 `pack` and v1 `unpack` formats." |
| 208 | + ;; TODO Remove this in a future ~breaking release |
| 209 | + [packed] |
| 210 | + (if (string? packed) |
| 211 | + (cond |
| 212 | + (enc/str-starts-with? packed "+") [(subs packed 1) :v1/wrapped] |
| 213 | + (enc/str-starts-with? packed "-") [(subs packed 1) :v1/unwrapped] |
| 214 | + :else [ packed :v2/unwrapped]) |
| 215 | + packed)) |
| 216 | + |
| 217 | +(comment (parse-packed "+[[\"foo\"] \"uuid\"]")) |
| 218 | + |
| 219 | +(defn- unpack "packed->[clj ?cb-uuid]" |
| 220 | + [packer packed] |
| 221 | + (let [[packed ?format] (parse-packed packed) |
| 222 | + unpacked #_[clj ?cb-uuid] |
212 | 223 | (try
|
213 |
| - (interfaces/unpack packer pstr) |
| 224 | + (interfaces/unpack packer packed) |
214 | 225 | (catch #?(:clj Throwable :cljs :default) t
|
215 |
| - (debugf "Bad package: %s (%s)" pstr t) |
216 |
| - [:chsk/bad-package pstr])) |
| 226 | + (debugf "Bad package: %s (%s)" packed t) |
| 227 | + [:chsk/bad-package packed])) |
| 228 | + |
| 229 | + [clj ?cb-uuid] |
| 230 | + (case ?format |
| 231 | + :v1/wrapped unpacked |
| 232 | + :v1/unwrapped [unpacked nil] |
| 233 | + :v2/unwrapped unpacked) |
217 | 234 |
|
218 |
| - [clj ?cb-uuid] (if wrapped? clj [clj nil]) |
219 | 235 | ?cb-uuid (if (= 0 ?cb-uuid) :ajax-cb ?cb-uuid)]
|
220 | 236 |
|
221 |
| - (tracef "Unpacking: %s -> %s" prefixed-pstr [clj ?cb-uuid]) |
222 | 237 | [clj ?cb-uuid]))
|
223 | 238 |
|
224 |
| -(defn- pack "clj->prefixed-pstr" |
225 |
| - ([packer clj] |
226 |
| - (let [;; "-" prefix => Unwrapped (has no callback) |
227 |
| - pstr (str "-" (interfaces/pack packer clj))] |
228 |
| - (tracef "Packing (unwrapped): %s -> %s" clj pstr) |
229 |
| - pstr)) |
| 239 | +(def ^:dynamic *write-legacy-pack-format?* |
| 240 | + "Advanced option, most users can ignore this var. Only necessary |
| 241 | + for those that want to use Sente < v1.18 with a non-standard |
| 242 | + IPacker that deals with non-string payloads. |
| 243 | +
|
| 244 | + Details: |
| 245 | +
|
| 246 | + Sente uses a private message format as an implementation detail |
| 247 | + for client<->server comms. |
| 248 | +
|
| 249 | + As part of [#398], this format is being updated to support |
| 250 | + non-string (e.g. binary) payloads. |
| 251 | +
|
| 252 | + Unfortunately updating the format is non-trivial because: |
| 253 | +
|
| 254 | + 1. Both the client & server need to support the same format. |
| 255 | + 2. Clients are often served as cached cl/js. |
| 256 | +
|
| 257 | + To help ease migration, the new pack format is being rolled out |
| 258 | + in 2 stages: |
| 259 | +
|
| 260 | + Sente <= v1.16: reads v1 format only |
| 261 | + writes v1 format only |
| 262 | +
|
| 263 | + Sente v1.17: reads v1 and v2 formats |
| 264 | + writes v1 and v2 formats (v1 default) <- Currently here |
| 265 | +
|
| 266 | + Sente v1.18: reads v1 and v2 formats |
| 267 | + writes v1 and v2 formats (v2 default) |
230 | 268 |
|
| 269 | + Sente >= v1.19: reads v2 format only |
| 270 | + writes v2 format only |
| 271 | +
|
| 272 | + This var controls which format to use for writing. |
| 273 | + Override default with `alter-var-root` or `binding`." |
| 274 | + |
| 275 | + ;; TODO -> false for Sente v1.18, remove for Sente >= v1.19 |
| 276 | + true) |
| 277 | + |
| 278 | +(defn- pack "[clj ?cb-uuid]->packed" |
| 279 | + ([packer clj ] (pack packer clj nil)) |
231 | 280 | ([packer clj ?cb-uuid]
|
232 |
| - (let [;;; Keep wrapping as light as possible: |
233 |
| - ?cb-uuid (if (= ?cb-uuid :ajax-cb) 0 ?cb-uuid) |
234 |
| - wrapped-clj (if ?cb-uuid [clj ?cb-uuid] [clj]) |
235 |
| - ;; "+" prefix => Wrapped (has callback) |
236 |
| - pstr (str "+" (interfaces/pack packer wrapped-clj))] |
237 |
| - (tracef "Packing (wrapped): %s -> %s" wrapped-clj pstr) |
238 |
| - pstr))) |
| 281 | + (let [?cb-uuid (if (= ?cb-uuid :ajax-cb) 0 ?cb-uuid) |
| 282 | + packed |
| 283 | + (interfaces/pack packer |
| 284 | + (if-some [cb-uuid ?cb-uuid] |
| 285 | + [clj cb-uuid] |
| 286 | + [clj ]))] |
| 287 | + |
| 288 | + (if *write-legacy-pack-format?* |
| 289 | + (str "+" (have string? packed)) |
| 290 | + (do packed))))) |
| 291 | + |
| 292 | +(comment |
| 293 | + (unpack default-edn-packer |
| 294 | + (binding [*write-legacy-pack-format?* true] |
| 295 | + (pack default-edn-packer [:foo])))) |
239 | 296 |
|
240 | 297 | (deftype EdnPacker []
|
241 | 298 | interfaces/IPacker
|
|
1083 | 1140 |
|
1084 | 1141 | #?(:cljs
|
1085 | 1142 | (defn- create-js-client-websocket!
|
1086 |
| - [{:as opts :keys [onerror-fn onmessage-fn onclose-fn uri-str headers]}] |
| 1143 | + [{:as opts |
| 1144 | + :keys [onerror-fn onmessage-fn onclose-fn binary-type |
| 1145 | + uri-str headers]}] |
| 1146 | + |
1087 | 1147 | (when-let [WebSocket
|
1088 | 1148 | (or
|
1089 | 1149 | (enc/oget goog/global "WebSocket")
|
|
1096 | 1156 | (aset "onmessage" onmessage-fn) ; Nb receives both push & cb evs!
|
1097 | 1157 | ;; Fires repeatedly (on each connection attempt) while server is down:
|
1098 | 1158 | (aset "onclose" onclose-fn))
|
| 1159 | + |
| 1160 | + (when-let [bt binary-type] ; "arraybuffer" or "blob" (default) |
| 1161 | + (aset socket "binaryType" bt)) |
| 1162 | + |
1099 | 1163 | socket))))
|
1100 | 1164 |
|
1101 | 1165 | (defn- create-websocket! [{:as opts :keys [onerror-fn onmessage-fn onclose-fn uri-str headers]}]
|
|
0 commit comments