|
17 | 17 |
|
18 | 18 | ;;;; Logging config
|
19 | 19 |
|
| 20 | +(defonce min-log-level_ (atom nil)) |
20 | 21 | (defn- set-min-log-level! [level]
|
21 | 22 | (sente/set-min-log-level! level) ; Min log level for internal Sente namespaces
|
22 | 23 | (timbre/set-ns-min-level! level) ; Min log level for this namespace
|
23 |
| - ) |
| 24 | + (reset! min-log-level_ level)) |
24 | 25 |
|
25 |
| -(set-min-log-level! :info) |
| 26 | +(when-let [el (.getElementById js/document "sente-min-log-level")] |
| 27 | + (let [level (if-let [attr (.getAttribute el "data-level")] |
| 28 | + (keyword attr) |
| 29 | + :warn)] |
| 30 | + (set-min-log-level! level))) |
26 | 31 |
|
27 | 32 | ;;;; Util for logging output to on-screen console
|
28 | 33 |
|
29 |
| -(def output-el (.getElementById js/document "output")) |
30 |
| -(defn ->output! [fmt & args] |
31 |
| - (let [msg (apply encore/format fmt args)] |
32 |
| - ;; (timbre/tracef "->output: %s" msg) |
33 |
| - (aset output-el "value" (str (.-value output-el) "\n• " msg)) |
| 34 | +(let [output-el (.getElementById js/document "output")] |
| 35 | + (defn- ->output!! [x] |
| 36 | + (aset output-el "value" (str (.-value output-el) x)) |
34 | 37 | (aset output-el "scrollTop" (.-scrollHeight output-el))))
|
35 | 38 |
|
| 39 | +(defn ->output! |
| 40 | + ([ ] (->output!! "\n")) |
| 41 | + ([fmt & args] |
| 42 | + (let [msg (apply encore/format fmt args)] |
| 43 | + (->output!! (str "\n• " msg))))) |
| 44 | + |
36 | 45 | (->output! "ClojureScript has successfully loaded")
|
| 46 | +(->output! "Sente version: %s" sente/sente-version) |
| 47 | +(->output! "Min log level: %s (use toggle button to change)" @min-log-level_) |
| 48 | +(->output!) |
37 | 49 |
|
38 | 50 | ;;;; Define our Sente channel socket (chsk) client
|
39 | 51 |
|
40 | 52 | (def ?csrf-token
|
41 | 53 | (when-let [el (.getElementById js/document "sente-csrf-token")]
|
42 |
| - (.getAttribute el "data-csrf-token"))) |
| 54 | + (.getAttribute el "data-token"))) |
43 | 55 |
|
44 | 56 | (if ?csrf-token
|
45 | 57 | (->output! "CSRF token detected in HTML, great!")
|
46 | 58 | (->output! "**IMPORTANT** CSRF token NOT detected in HTML, default Sente config will reject requests!"))
|
47 | 59 |
|
48 |
| -(let [;; For this example, select a random protocol: |
49 |
| - rand-chsk-type (if (>= (rand) 0.5) :ajax :auto) |
50 |
| - _ (->output! "Randomly selected chsk type: %s" rand-chsk-type) |
| 60 | +(def chsk-type |
| 61 | + "We'll select a random protocol for this example" |
| 62 | + (if (>= (rand) 0.5) :ajax :auto)) |
| 63 | + |
| 64 | +(->output! "Randomly selected chsk type: %s" chsk-type) |
| 65 | +(->output!) |
51 | 66 |
|
52 |
| - ;; Serializtion format, must use same val for client + server: |
| 67 | +(let [;; Serializtion format, must use same val for client + server: |
53 | 68 | packer :edn ; Default packer, a good choice in most cases
|
54 | 69 | ;; (sente-transit/get-transit-packer) ; Needs Transit dep
|
55 | 70 |
|
56 | 71 | {:keys [chsk ch-recv send-fn state]}
|
57 | 72 | (sente/make-channel-socket-client!
|
58 | 73 | "/chsk" ; Must match server Ring routing URL
|
59 | 74 | ?csrf-token
|
60 |
| - {:type rand-chsk-type |
| 75 | + {:type chsk-type |
61 | 76 | :packer packer})]
|
62 | 77 |
|
63 | 78 | (def chsk chsk)
|
|
117 | 132 |
|
118 | 133 | ;;;; UI events
|
119 | 134 |
|
120 |
| -(when-let [target-el (.getElementById js/document "btn1")] |
| 135 | +(when-let [target-el (.getElementById js/document "btn-send-with-reply")] |
121 | 136 | (.addEventListener target-el "click"
|
122 | 137 | (fn [ev]
|
123 |
| - (->output! "Will send event to server WITH callback") |
124 | 138 | (chsk-send! [:example/button2 {:had-a-callback? "indeed"}] 5000
|
125 |
| - (fn [cb-reply] (->output! "Callback reply: %s" cb-reply)))))) |
| 139 | + (fn [cb-reply] |
| 140 | + (->output! "Callback reply: %s" cb-reply)))))) |
126 | 141 |
|
127 |
| -(when-let [target-el (.getElementById js/document "btn2")] |
| 142 | +(when-let [target-el (.getElementById js/document "btn-send-wo-reply")] |
128 | 143 | (.addEventListener target-el "click"
|
129 | 144 | (fn [ev]
|
130 |
| - (->output! "Will send event to server WITHOUT callback") |
131 | 145 | (chsk-send! [:example/button1 {:had-a-callback? "nope"}]))))
|
132 | 146 |
|
133 |
| -(when-let [target-el (.getElementById js/document "btn3")] |
| 147 | +(when-let [target-el (.getElementById js/document "btn-test-broadcast")] |
134 | 148 | (.addEventListener target-el "click"
|
135 | 149 | (fn [ev]
|
136 |
| - (->output! "Will ask server to test rapid async push") |
137 |
| - (chsk-send! [:example/test-rapid-push])))) |
| 150 | + (->output!) |
| 151 | + (chsk-send! [:example/test-broadcast])))) |
138 | 152 |
|
139 |
| -(when-let [target-el (.getElementById js/document "btn4")] |
| 153 | +(when-let [target-el (.getElementById js/document "btn-toggle-broadcast-loop")] |
140 | 154 | (.addEventListener target-el "click"
|
141 | 155 | (fn [ev]
|
142 |
| - (chsk-send! [:example/toggle-broadcast] 5000 |
| 156 | + (chsk-send! [:example/toggle-broadcast-loop] 5000 |
143 | 157 | (fn [cb-reply]
|
144 | 158 | (when (cb-success? cb-reply)
|
145 |
| - (let [loop-enabled? cb-reply] |
146 |
| - (if loop-enabled? |
147 |
| - (->output! "Server async broadcast loop now ENABLED") |
148 |
| - (->output! "Server async broadcast loop now DISABLED"))))))))) |
| 159 | + (let [enabled? cb-reply] |
| 160 | + (if enabled? |
| 161 | + (->output! "Server broadcast loop now ENABLED") |
| 162 | + (->output! "Server broadcast loop now DISABLED"))))))))) |
149 | 163 |
|
150 |
| -(when-let [target-el (.getElementById js/document "btn5")] |
| 164 | +(when-let [target-el (.getElementById js/document "btn-disconnect")] |
151 | 165 | (.addEventListener target-el "click"
|
152 | 166 | (fn [ev]
|
153 |
| - (->output! "Disconnecting...\n\n") |
| 167 | + (->output!) |
154 | 168 | (sente/chsk-disconnect! chsk))))
|
155 | 169 |
|
156 |
| -(when-let [target-el (.getElementById js/document "btn6")] |
| 170 | +(when-let [target-el (.getElementById js/document "btn-reconnect")] |
157 | 171 | (.addEventListener target-el "click"
|
158 | 172 | (fn [ev]
|
159 |
| - (->output! "Reconnecting...\n\n") |
| 173 | + (->output!) |
160 | 174 | (sente/chsk-reconnect! chsk))))
|
161 | 175 |
|
162 |
| -(when-let [target-el (.getElementById js/document "btn7")] |
| 176 | +(when-let [target-el (.getElementById js/document "btn-break-with-close")] |
163 | 177 | (.addEventListener target-el "click"
|
164 | 178 | (fn [ev]
|
165 |
| - (->output! "Simulating basic broken connection (WITH close)...\n\n") |
| 179 | + (->output!) |
166 | 180 | (sente/chsk-break-connection! chsk {:close-ws? true}))))
|
167 | 181 |
|
168 |
| -(when-let [target-el (.getElementById js/document "btn8")] |
| 182 | +(when-let [target-el (.getElementById js/document "btn-break-wo-close")] |
169 | 183 | (.addEventListener target-el "click"
|
170 | 184 | (fn [ev]
|
171 |
| - (->output! "Simulating basic broken connection (WITHOUT close)...\n\n") |
| 185 | + (->output!) |
172 | 186 | (sente/chsk-break-connection! chsk {:close-ws? false}))))
|
173 | 187 |
|
174 |
| -(when-let [target-el (.getElementById js/document "btn9")] |
| 188 | +(when-let [target-el (.getElementById js/document "btn-toggle-logging")] |
175 | 189 | (.addEventListener target-el "click"
|
176 | 190 | (fn [ev]
|
177 |
| - (->output! "Will ask server to toggle minimum log level") |
178 | 191 | (chsk-send! [:example/toggle-min-log-level] 5000
|
179 | 192 | (fn [cb-reply]
|
180 | 193 | (if (cb-success? cb-reply)
|
181 | 194 | (let [level cb-reply]
|
182 | 195 | (set-min-log-level! level)
|
183 | 196 | (->output! "New minimum log level (client+server): %s" level))
|
184 |
| - (->output! "Failed to toggle minimum log level: %s" cb-reply))))))) |
| 197 | + (->output! "Request failed: %s" cb-reply))))))) |
| 198 | + |
| 199 | +(when-let [target-el (.getElementById js/document "btn-toggle-bad-conn-rate")] |
| 200 | + (.addEventListener target-el "click" |
| 201 | + (fn [ev] |
| 202 | + (chsk-send! [:example/toggle-bad-conn-rate] 5000 |
| 203 | + (fn [cb-reply] |
| 204 | + (if (cb-success? cb-reply) |
| 205 | + (->output! "New rate: %s" cb-reply) |
| 206 | + (->output! "Request failed: %s" cb-reply))))))) |
| 207 | + |
| 208 | +(when-let [target-el (.getElementById js/document "btn-connected-uids")] |
| 209 | + (.addEventListener target-el "click" |
| 210 | + (fn [ev] |
| 211 | + (chsk-send! [:example/connected-uids] 5000 |
| 212 | + (fn [cb-reply] |
| 213 | + (when (cb-success? cb-reply) |
| 214 | + (->output! "Connected uids: %s" cb-reply))))))) |
185 | 215 |
|
186 | 216 | (when-let [target-el (.getElementById js/document "btn-login")]
|
187 | 217 | (.addEventListener target-el "click"
|
|
190 | 220 | (if (str/blank? user-id)
|
191 | 221 | (js/alert "Please enter a user-id first")
|
192 | 222 | (do
|
193 |
| - (->output! "Logging in with user-id %s...\n\n" user-id) |
| 223 | + (->output!) |
| 224 | + (->output! "Logging in with user-id %s..." user-id) |
194 | 225 |
|
195 | 226 | ;;; Use any login procedure you'd like. Here we'll trigger an Ajax
|
196 | 227 | ;;; POST request that resets our server-side session. Then we ask
|
|
212 | 243 | (->output! "Login successful")
|
213 | 244 | (sente/chsk-reconnect! chsk))))))))))))
|
214 | 245 |
|
| 246 | +(when-let [target-el (.getElementById js/document "btn-repeated-logins")] |
| 247 | + (.addEventListener target-el "click" |
| 248 | + (fn [ev] |
| 249 | + (->output!) |
| 250 | + (->output! "Will rapidly change user-id from \"1\" to \"10\"...") |
| 251 | + (let [c (async/chan)] |
| 252 | + (go-loop [uids (range 11)] |
| 253 | + (when-let [[next-uid] uids] |
| 254 | + (sente/ajax-lite "/login" |
| 255 | + {:method :post |
| 256 | + :headers {:X-CSRF-Token (:csrf-token @chsk-state)} |
| 257 | + :params {:user-id (str next-uid)}} |
| 258 | + (fn [ajax-resp] |
| 259 | + (when (:success? ajax-resp) (sente/chsk-reconnect! chsk)) |
| 260 | + (put! c :continue))) |
| 261 | + (<! c) |
| 262 | + (<! (async/timeout 100)) |
| 263 | + (recur (next uids)))))))) |
| 264 | + |
215 | 265 | ;;;; Init stuff
|
216 | 266 |
|
217 | 267 | (defn start! [] (start-router!))
|
|
0 commit comments