|
1 | 1 | (ns ring.websocket
|
| 2 | + "Protocols and utility functions for websocket support." |
2 | 3 | (:refer-clojure :exclude [send])
|
3 | 4 | (:import [java.nio ByteBuffer]))
|
4 | 5 |
|
5 | 6 | (defprotocol Listener
|
6 |
| - (on-open [listener socket]) |
7 |
| - (on-message [listener socket message]) |
8 |
| - (on-pong [listener socket data]) |
9 |
| - (on-error [listener socket throwable]) |
10 |
| - (on-close [listener socket code reason])) |
| 7 | + "A protocol for handling websocket events. The second argument is |
| 8 | + always an object that satisfies the Socket protocol." |
| 9 | + (on-open [listener socket] |
| 10 | + "Called when the websocket is opened.") |
| 11 | + (on-message [listener socket message] |
| 12 | + "Called when a message is received. The message may be a String or a |
| 13 | + ByteBuffer.") |
| 14 | + (on-pong [listener socket data] |
| 15 | + "Called when a pong is received in response to an earlier ping. The client |
| 16 | + may provide additional binary data, represented by the data ByteBuffer.") |
| 17 | + (on-error [listener socket throwable] |
| 18 | + "Called when an Throwable error is thrown.") |
| 19 | + (on-close [listener socket code reason] |
| 20 | + "Called when the websocket is closed, along with an integer code and a |
| 21 | + plaintext string reason for being closed.")) |
11 | 22 |
|
12 | 23 | (extend-protocol Listener
|
13 | 24 | clojure.lang.IPersistentMap
|
|
23 | 34 | (when-let [kv (find m :on-close)] ((val kv) socket code reason))))
|
24 | 35 |
|
25 | 36 | (defprotocol Socket
|
26 |
| - (-send [socket message]) |
27 |
| - (-ping [socket data]) |
28 |
| - (-pong [socket data]) |
29 |
| - (-close [socket status reason])) |
| 37 | + "A protocol for sending data via websocket." |
| 38 | + (-send [socket message] |
| 39 | + "Sends a String or ByteBuffer to the client via the websocket.") |
| 40 | + (-ping [socket data] |
| 41 | + "Sends a ping message to the client with a ByteBuffer of extra data.") |
| 42 | + (-pong [socket data] |
| 43 | + "Sends an unsolicited pong message to the client, with a ByteBuffer of extra |
| 44 | + data.") |
| 45 | + (-close [socket code reason] |
| 46 | + "Closes the socket with an integer status code, and a String reason.")) |
30 | 47 |
|
31 | 48 | (defprotocol AsyncSocket
|
32 |
| - (-send-async [socket message succeed fail])) |
| 49 | + "A protocol for sending data asynchronously via websocket. Intended for use |
| 50 | + with the Socket protocol." |
| 51 | + (-send-async [socket message succeed fail] |
| 52 | + "Sends a String or ByteBuffer to the client via the websocket. If it |
| 53 | + succeeds, the 'succeed' callback function is called with zero arguments. If |
| 54 | + it fails, the 'fail' callback function is called with the exception that was |
| 55 | + thrown.")) |
33 | 56 |
|
34 | 57 | (defprotocol TextData
|
35 |
| - (->string [data])) |
| 58 | + "A protocol for converting text data into a String." |
| 59 | + (->string [data] |
| 60 | + "Convert some data into a String, ready to be sent as a websocket text |
| 61 | + message.")) |
36 | 62 |
|
37 | 63 | (defprotocol BinaryData
|
38 |
| - (->byte-buffer [data])) |
| 64 | + "A protocol for converting binary data into a java.nio.ByteBuffer object." |
| 65 | + (->byte-buffer [data] |
| 66 | + "Convert some binary data into a java.nio.ByteBuffer, ready to be sent as |
| 67 | + a websocket binary message.")) |
39 | 68 |
|
40 | 69 | (extend-protocol TextData
|
41 | 70 | String
|
|
55 | 84 | {:message message}))))
|
56 | 85 |
|
57 | 86 | (defn send
|
| 87 | + "Sends text or binary data via a websocket, either synchronously or |
| 88 | + asynchronously with callback functions. A convenient wrapper for the -send and |
| 89 | + -send-async protocol methods." |
58 | 90 | ([socket message]
|
59 | 91 | (-send socket (encode-message message)))
|
60 | 92 | ([socket message succeed fail]
|
61 | 93 | (-send-async socket (encode-message message) succeed fail)))
|
62 | 94 |
|
63 | 95 | (defn ping
|
| 96 | + "Sends a ping message via a websocket, with an optional byte array or |
| 97 | + ByteBuffer that may contain custom session data. A convenient wrapper for the |
| 98 | + -ping protocol method." |
64 | 99 | ([socket]
|
65 | 100 | (-ping socket (ByteBuffer/allocate 0)))
|
66 | 101 | ([socket data]
|
67 | 102 | (-ping socket (->byte-buffer data))))
|
68 | 103 |
|
69 | 104 | (defn pong
|
| 105 | + "Sends an unsolicited pong message via a websocket, with an optional byte |
| 106 | + array or ByteBuffer that may contain custom session data. A convenient wrapper |
| 107 | + for the -pong protocol method." |
70 | 108 | ([socket]
|
71 | 109 | (-pong socket (ByteBuffer/allocate 0)))
|
72 | 110 | ([socket data]
|
73 | 111 | (-pong socket (->byte-buffer data))))
|
74 | 112 |
|
75 | 113 | (defn close
|
| 114 | + "Closes the websocket, with an optional custom integer status code and reason |
| 115 | + string." |
76 | 116 | ([socket]
|
77 | 117 | (-close socket 1000 "Normal Closure"))
|
78 | 118 | ([socket code reason]
|
79 | 119 | (-close socket code reason)))
|
80 | 120 |
|
81 |
| -(defn websocket-request? [request] |
| 121 | +(defn websocket-request? |
| 122 | + "Returns true if the request map expects a websocket response." |
| 123 | + [request] |
82 | 124 | (let [headers (:headers request)]
|
83 | 125 | (and (.equalsIgnoreCase "upgrade" (get headers "connection"))
|
84 | 126 | (.equalsIgnoreCase "websocket" (get headers "upgrade")))))
|
85 | 127 |
|
86 |
| -(defn websocket-response? [response] |
| 128 | +(defn websocket-response? |
| 129 | + "Returns true if the response contains a websocket listener." |
| 130 | + [response] |
87 | 131 | (contains? response ::listener))
|
0 commit comments