You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
> This is a **non-breaking* release focused on efficiency+reliability improvements for very high stress environments.
3
+
> This is a **non-breaking** release focused on efficiency+reliability improvements for very high stress environments.
4
4
5
5
* Documentation improvements.
6
-
* CHANGE: server>user Ajax push is now more reliable against dodgy connections.
7
-
* NEW: server>user sends are now automatically+transparently batched for greater efficiency in _very_ high throughput environments. The server-side `make-channel-socket!` has picked up some knobs for this, but the defaults are sensible.
6
+
***CHANGE**: server>user Ajax push is now more reliable against dodgy connections.
7
+
***NEW**: server>user sends are now automatically+transparently batched for greater efficiency in _very_ high throughput environments. The server-side `make-channel-socket!` has picked up some knobs for this, but the defaults are sensible.
8
8
9
9
10
10
## v0.8.2 / 2014 Mar 7
11
11
12
-
* NEW: Copy improved error messages to server-side API.
13
-
* CHANGE: Provide entire, unfiltered Ring request map to server-side API.
12
+
***NEW**: Copy improved error messages to server-side API.
13
+
***CHANGE**: Provide entire, unfiltered Ring request map to server-side API.
14
14
15
15
16
16
## v0.8.1 / 2014 Mar 4
17
17
18
-
* NEW: Improved error messsages for malformed events.
18
+
***NEW**: Improved error messsages for malformed events.
(I'd also recommend checking out James Henderson's [Chord][] and Kevin Lynagh's [jetty7-websockets-async][] as possible alternatives!)
20
20
21
21
## What's in the box™?
22
-
***Bidirectional a/sync comms** over both **WebSockets** and **Ajax** (auto-selecting).
23
-
***Robust**: auto keep-alives, buffering, mode fallback, reconnects. **It just works™**.
24
-
*[edn][] rocks. So **send edn, get edn**: no json here.
22
+
***Bidirectional a/sync comms** over both **WebSockets** and **Ajax** (auto-fallback).
23
+
***Robust**: auto keep-alives, buffering, protocol selection, reconnects. **It just works™**.
24
+
* Efficient design incl. transparent event batching for **low-bandwidth use, even over Ajax**.
25
+
* Full, **transparent support for [edn][]** over the wire (JSON, XML, and other arbitrary string-encoded formats may be used as edn strings).
25
26
***Tiny, simple API**: `make-channel-socket!` and you're good to go.
26
27
* Automatic, sensible support for users connected with **multiple clients** and/or devices simultaneously.
27
-
***Flexible model**: use it anywhere you'd use WebSockets or Ajax.
28
-
*Normal**Ring security model**: auth as you like, HTTPS when available, CSRF support, etc.
29
-
***Fully documented, with examples** (more forthcoming).
30
-
* Small: **less than 600 lines of code** for the entire client+server implementation.
28
+
***Flexible model**: use it anywhere you'd use WebSockets/Ajax/Socket.IO, etc.
29
+
*Standard**Ring security model**: auth as you like, HTTPS when available, CSRF support, etc.
30
+
***Fully documented, with examples**.
31
+
* Small: **~600 lines of code** for the entire client+server implementation.
31
32
***Supported servers**: currently only [http-kit][], but easily extended. [PRs welcome](https://github.com/ptaoussanis/sente/issues/2) to add support for additional servers!
So the underlying protocol's irrelevant. Sente gives you a unified API that exposes the best of both WebSockets (bidirectionality + performance) and Ajax (optional evented ack/reply model).
42
+
So you can ignore the underlying protocol and deal directly with Sente's unified API. It's simple, and exposes the best of both WebSockets (bidirectionality + performance) and Ajax (optional evented ack/reply model).
42
43
43
44
44
45
## Getting started
45
46
46
-
> Note that there's also a full [example project][] in this repo. Call `lein start-dev` in that dir to get a (headless) development repl that you can connect to with [Cider][] (emacs) or your IDE.
47
-
48
47
Add the necessary dependency to your [Leiningen][]`project.clj`. This'll provide your project with both the client (ClojureScript) + server (Clojure) side library code:
49
48
50
49
```clojure
51
-
[com.taoensso/sente "0.8.2"]
50
+
[com.taoensso/sente "0.9.0"]
52
51
```
53
52
54
53
### On the server (Clojure) side
@@ -130,13 +129,13 @@ You're good to go! The client will automatically initiate a WebSocket or repeati
130
129
131
130
#### Client-side API
132
131
133
-
*`ch-recv` is a **core.async channel** that'll receive **`event`**s.
134
-
*`chsk-send!` is a `(fn [event & [?timeout-ms ?cb-fn]])`.
132
+
*`ch-recv` is a **core.async channel** that'll receive `event`s.
133
+
*`chsk-send!` is a `(fn [event & [?timeout-ms ?cb-fn]])`. This is for standard **client>server req>resp calls**.
135
134
136
135
#### Server-side API
137
136
138
-
*`ch-recv` is a **core.async channel** that'll receive **`event-msg`**s.
139
-
*`chsk-send!` is a `(fn [user-id event])`.
137
+
*`ch-recv` is a **core.async channel** that'll receive `event-msg`s.
138
+
*`chsk-send!` is a `(fn [user-id event])`. This is for async **server>user PUSH calls**.
140
139
141
140
===============
142
141
@@ -155,9 +154,7 @@ Term | Form
155
154
* The server can likewise use `chsk-send!` to send `event`s to _all_ the clients (browser tabs, devices, etc.) of a particular connected user by his/her `user-id`.
156
155
* The server can also use an `event-msg`'s `?reply-fn` to _reply_ to a client `event` using an _arbitrary edn value_.
157
156
158
-
===============
159
-
160
-
**And that's 80% of what you need to know to get going**. The remaining documentation is mostly for fleshing out the new patterns that this API enables.
157
+
> It's worth noting that the server>user push `(chsk-send! <user-id> <event>)` takes a mandatory **user-id** argument. See the FAQ later for more info.
#### What is the `user-id` provided to the server>user push fn?
228
195
229
-
```clojure
230
-
;;;; Client-side (.cljs), in `my-client-side-ns` -------------------------------
196
+
For the server to push events, we need a destination. Traditionally we might push to a _client_ (e.g. browser tab). But with modern rich web applications and the increasing use of multiple simultaneous devices (tablets, mobiles, etc.) - the value of a _client_ push is diminishing. You'll often see applications (even by Google) struggling to deal with these cases.
231
197
232
-
(defn-event-handler [[id data :as ev] _]
233
-
(logf"<! %s" id)
234
-
(match [id data]
198
+
Sente offers an out-the-box solution by pulling the concept of identity one level higher and dealing with unique _users_ rather than clients. **What constitutes a user is entirely at the discretion of each application**:
235
199
236
-
;; An event from `ch-ui` that our UI has generated:
237
-
[:on.keypress/div#msg-input _] (do-something!)
200
+
* Each user-id may have zero _or more_ connected clients at any given time.
201
+
* Each user-id _may_ survive across clients (browser tabs, devices), and sessions.
238
202
239
-
;; A channel socket event pushed from our server:
240
-
[:chsk/recv [:my-app/alert-from-server payload]]
241
-
(do (logf"Pushed payload received from server!: %s" payload)
242
-
(do-something! payload))
203
+
**Set the user's `:uid` Ring session key to give him/her an identity**.
If you want a simple _per-session_ identity, generate a _random uuid_. If you want an identity that persists across sessions, try use something with _semantic meaning_ that you may already have like a database-generated user-id, a login email address, a secure URL fragment, etc.
245
206
246
-
[:chsk/state new-state] (logf"Chsk state change: %s" new-state)
#### Will Sente work with [React][]/[Reagent][]/[Om][]/etc.?
256
210
257
-
### FAQ
211
+
Sure! I use it with Reagent myself. Sente's just a client<->server comms mechanism.
258
212
259
-
#### What is Sente useful for?
213
+
#### What if I need to use JSON, XML, raw strings, etc.?
260
214
261
-
[Single-page web applications](http://en.wikipedia.org/wiki/Single-page_application), realtime web applications, web applications that need to support efficient, high-performance push-to-client capabilities.
215
+
Sente uses edn as an _implementation detail_ of its transfer format. Anything sent with Sente will arrive at the other end as _Clojure data_.
262
216
263
-
Sente's channel sockets are basically a **replacement for both traditional WebSockets and Ajax** that is IMO:
217
+
Send a map, get a map. Send a vector, get a vector. Send a string, get a string.
264
218
265
-
* More flexible.
266
-
* Easier+faster to work with (esp. for rapid prototyping).
267
-
* More efficient in most cases, and never less efficient.
219
+
And since JSON, XML, etc. are all string-encoded formats, using them with Sente is trivial: just **send the encoded data as a string**, and remember to decode it on the other end however you like.
268
220
269
-
#### Any disadvantages?
221
+
Relative to network transfer times, the cost of (for example) `json->edn->json->data` vs `json->data` is negligable. It's also worth noting that the additional encoding isn't actually going to waste, it's buying you features implemented transparently by Sente like protocol negotiation and event batching. These can often outweigh any additional encoding cost anyway.
270
222
271
-
I've been using something similar to Sente in production for a couple months, but this particular public implementation is relatively immature. There aren't currently any known security holes, but I wouldn't rule out big or small bugs in the short term.
223
+
#### How do I route client/server events?
272
224
273
-
I'd like to try head for a `v1.0.0` w/in the next 2 months (~end of April).
225
+
However you like! If you don't have many events, a simple `cond` will probably do. I use [core.match][] myself since it's a nice fit and works well with both Clojure and ClojureScript. The [reference example project][] has a fully-baked example.
274
226
275
-
#### Is there HTTPS support?
227
+
#### Security: is there HTTPS support?
276
228
277
229
Yup, it's automatic for both Ajax and WebSockets. If the page serving your JavaScript (ClojureScript) is running HTTPS, your Sente channel sockets will run over HTTPS and/or the WebSocket equivalent (WSS).
278
230
279
-
#### CSRF security?
231
+
#### Security: CSRF protection?
280
232
281
233
**This is important**. Sente has support, but you'll need to do a couple things on your end:
282
234
283
235
1. Server-side: you'll need to use middleware like `ring-anti-forgery` to generate and check CSRF codes. The `ring-ajax-post` handler should be covered (i.e. protected).
284
236
2. Client-side: you'll need to pass the page's csrf code to the `make-channel-socket!` constructor.
285
237
286
-
#### What about authentication/authorization?
287
-
288
-
Auth isn't something Sente is opinionated about, so you can+should **use whatever standard Ring auth mechanism you normally would**.
289
-
290
-
Sente **does require** that you **include a unique user id** (`:uid key`) in authenticated Ring sessions.
291
-
292
-
> You'll then provide that id as an argument when calling the server-side's `chsk-send!` fn for server>clientS push.
293
-
294
-
So basically: mod your normal auth/login procedure to ensure that a `:uid` key is present in each authenticated session. The id should be unique per user (i.e. consistent over all that user's browser tabs and devices, etc.). It could be a unique username string, unique integer, uuid string, unique url, etc.
295
-
296
-
> The sessionized user id is necessary to support a consistent+secure user identity over multiple requests that may be received over multiple protocols.
297
-
298
-
The un/authenticated Ring session will be provided to all your handlers as usual, so you're free to do the usual server-side security checks: is this user authenticated (logged in?), is this user authorized to view the requested resource (authorization), etc.
299
-
300
-
#### Why isn't `x` documented?
301
-
302
-
Sorry, just haven't had the time (yet)! Am currently in the process of launching a couple products and only released Sente now to de-stress and take a couple days off work. It was a case of releasing what I could put together in a weekend, or not releasing anything. **PR's are very welcome for any improvements, incl. to documentation+examples**!
303
-
304
-
If you have a question you might also want to take a look at the source code which is short + quite approachable. Otherwise feel free to open an issue and I'll try reply ASAP.
305
-
306
-
#### Will Sente work with [React][]/[Reagent][]/[Om][]/etc.?
238
+
The [reference example project][] has a fully-baked example.
307
239
308
-
Sure! Sente's just a client<->server message mechanism, it's completely unopinionated about the shape or architecture of your application.
240
+
#### Examples: wherefore art thou?
309
241
242
+
There's a full [reference example project][] in the repo. Call `lein start-dev` in that dir to get a (headless) development repl that you can connect to with [Cider][] (emacs) or your IDE.
310
243
311
-
## This project supports the CDS and  goals
244
+
Further instructions are provided in the relevant namespace.
312
245
313
-
*[CDS][], the **Clojure Documentation Site**, is a **contributer-friendly** community project aimed at producing top-notch, **beginner-friendly** Clojure tutorials and documentation. Awesome resource.
246
+
#### Any other questions?
314
247
315
-
*[ClojureWerkz][] is a growing collection of open-source, **batteries-included Clojure libraries** that emphasise modern targets, great documentation, and thorough testing. They've got a ton of great stuff, check 'em out!
248
+
If I've missed something here, feel free to open a GitHub issue or pop me an email!
0 commit comments