-
Notifications
You must be signed in to change notification settings - Fork 9
/
client.cljs
65 lines (58 loc) · 2.38 KB
/
client.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
(ns haslett.client
"A namespace for opening WebSockets in ClojureScript."
(:require [cljs.core.async :as a :refer [<! go-loop]]
[haslett.format :as fmt]))
(defn close
"Close a stream opened by connect."
[stream]
(.close (:socket stream) 1000 "Closed by creator")
(:close-status stream))
(defn connect
"Create a WebSocket to the specified URL, and returns a 'stream' map of four
keys:
:socket - contains the WebSocket object
:close-status - a promise channel that contains the final close status
:in - a core.async channel to read from
:out - a core.async channel to write to
Takes the following options:
:format - a formatter from haslett.format
:in - a custom channel to use as the reader
:out - a custom channel to use as the writer
:protocols - passed to the WebSocket, a vector of protocol strings
:binary-type - passed to the WebSocket, may be :blob or :arraybuffer
:close-chan? - true if channels should be closed if WebSocket is closed
(defaults to true)
The WebSocket may either be closed directly, or by closing the
stream's :sink channel."
([url]
(connect url {}))
([url options]
(let [protocols (into-array (:protocols options []))
socket (js/WebSocket. url protocols)
in (:in options (a/chan))
out (:out options (a/chan))
format (:format options fmt/identity)
status (a/promise-chan)
return (a/promise-chan)
close? (:close-chan? options true)
stream {:socket socket, :in in, :out out, :close-status status}]
(set! (.-binaryType socket) (name (:binary-type options :arraybuffer)))
(set! (.-onopen socket) (fn [_] (a/put! return stream)))
(set! (.-onmessage socket)
(fn [e] (a/put! in (fmt/read format (.-data e)))))
(set! (.-onclose socket)
(fn [e]
(a/put! status {:reason (.-reason e), :code (.-code e)})
(when close? (a/close! in))
(when close? (a/close! out))
(a/put! return stream)))
(go-loop []
(when-let [msg (<! out)]
(.send socket (fmt/write format msg))
(recur))
(close stream))
return)))
(defn connected?
"Return true if the stream is currently connected."
[{:keys [close-status]}]
(nil? (a/poll! close-status)))