UNPKG

24 kBMarkdownView Raw
1# Pusher Channels Javascript Client
2
3This Pusher Channels client library supports web browsers, web workers, Node.js
4and React Native.
5
6If you're looking for the Pusher Channels server library for Node.js, use
7[pusher-http-node](https://github.com/pusher/pusher-http-node) instead.
8
9For tutorials and more in-depth information about Pusher Channels, visit
10our [official docs](https://pusher.com/docs/javascript_quick_start).
11
12## Usage Overview
13
14The following topics are covered:
15
16* [Installation](https://github.com/pusher/pusher-js#installation)
17 * [Web](https://github.com/pusher/pusher-js#web)
18 * [React Native](https://github.com/pusher/pusher-js#react-native)
19 * [Web Workers](https://github.com/pusher/pusher-js#web-workers)
20 * [Node.js](https://github.com/pusher/pusher-js#nodejs)
21* [Initialization](https://github.com/pusher/pusher-js#initialization)
22* [Configuration](https://github.com/pusher/pusher-js#configuration)
23* [Global Configuration](https://github.com/pusher/pusher-js#global-configuration)
24* [Connection](https://github.com/pusher/pusher-js#connection)
25 * [Socket IDs](https://github.com/pusher/pusher-js#socket-ids)
26* [Subscribing to Channels (Public and Private)](https://github.com/pusher/pusher-js#subscribing-to-channels)
27* [Accessing Channels](https://github.com/pusher/pusher-js#accessing-channels)
28* [Binding to Events](https://github.com/pusher/pusher-js#binding-to-events)
29* [Default events](https://github.com/pusher/pusher-js#default-events)
30* [Developing](https://github.com/pusher/pusher-js#developing)
31 * [Core vs. Platform-specific Code](https://github.com/pusher/pusher-js#core-vs-platform-specific-code)
32 * [Building](https://github.com/pusher/pusher-js#building)
33 * [Testing](https://github.com/pusher/pusher-js#testing)
34
35## Installation
36
37### Web
38
39If you're using Pusher Channels on a web page, you can install the library via:
40
41#### Yarn (or NPM)
42
43You can use any NPM-compatible package manager, including NPM itself and Yarn.
44
45```bash
46yarn add pusher-js
47```
48
49Then:
50
51```javascript
52import Pusher from 'pusher-js';
53```
54
55Or, if you're not using ES6 modules:
56
57```javascript
58const Pusher = require('pusher-js');
59```
60
61#### CDN
62
63```html
64<script src="https://js.pusher.com/4.4/pusher.min.js"></script>
65```
66
67You can also use [cdnjs.com](https://cdnjs.com/libraries/pusher) if you prefer
68or as a fallback.
69
70#### Bower (discouraged)
71
72Or via [Bower](http://bower.io/):
73
74```bash
75bower install pusher
76```
77
78and then:
79
80```html
81<script src="bower_components/pusher/dist/web/pusher.min.js"></script>
82```
83
84### React Native
85
86**Warning it's now necessary to install
87[@react-native-community/netinfo](https://github.com/react-native-community/react-native-netinfo)
88in order to use pusher-js with react-native.** pusher-js depends on NetInfo.
89NetInfo. NetInfo was included within react-native core until v0.60, when it was
90moved to the
91[@react-native-community/netinfo](https://github.com/react-native-community/react-native-netinfo)
92library. Please follow the [install
93instructions](https://github.com/react-native-community/react-native-netinfo#getting-started)
94for the
95[@react-native-community/netinfo](https://github.com/react-native-community/react-native-netinfo)
96library before trying to use pusher-js in your react-native project.
97
98Use a package manager like Yarn or NPM to install `pusher-js` and then import
99it as follows:
100
101```javascript
102import Pusher from 'pusher-js/react-native';
103```
104
105Notes:
106
107* The fallbacks available for this runtime are HTTP streaming and polling.
108* This build uses React Native's NetInfo API to detect changes on connectivity state. It will use this to automatically reconnect.
109
110### Web Workers
111(`pusher-js`'s Web Workers implementation is currently not compatible with Internet Explorer)
112You can import the worker script (`pusher.worker.js`, not `pusher.js`) from the CDN:
113
114```javascript
115importScripts('https://js.pusher.com/4.4/pusher.worker.min.js');
116```
117
118### Node.js
119
120Having installed `pusher-js` via an NPM-compatible package manager, simply:
121
122```javascript
123import Pusher from 'pusher-js';
124```
125
126Notes:
127
128* For standard `WebWorkers`, this build will use HTTP as a fallback.
129* For `ServiceWorkers`, as the `XMLHttpRequest` API is unavailable, there is currently no support for HTTP fallbacks. However, we are open to requests for fallbacks using `fetch` if there is demand.
130
131## Initialization
132
133```js
134const socket = new Pusher(APP_KEY, {
135 cluster: APP_CLUSTER,
136});
137```
138
139You can get your `APP_KEY` and `APP_CLUSTER` from the [Pusher Channels dashboard](https://dashboard.pusher.com/).
140
141## Configuration
142
143There are a number of configuration parameters which can be set for the client, which can be passed as an object to the Pusher constructor, i.e.:
144
145```js
146const socket = new Pusher(APP_KEY, {
147 cluster: APP_CLUSTER,
148 authEndpoint: 'http://example.com/pusher/auth',
149 forceTLS: true
150});
151```
152
153For most users, there is little need to change these. See [client API guide](http://pusher.com/docs/client_api_guide/client_connect) for more details.
154
155#### `forceTLS` (Boolean)
156
157Forces the connection to use TLS.
158
159#### `authEndpoint` (String)
160
161Endpoint on your server that will return the authentication signature needed for private and presence channels. Defaults to `'/pusher/auth'`.
162
163For more information see [authenticating users](https://pusher.com/docs/authenticating_users).
164
165#### `authTransport` (String)
166
167Defines how the authentication endpoint, defined using authEndpoint, will be called. There are two options available: `ajax` and `jsonp`.
168
169* `ajax` - The **default** option where an `XMLHttpRequest` object will be used to make a request. The parameters will be passed as `POST` parameters.
170* `jsonp` - The authentication endpoint will be called by a `<script>` tag being dynamically created pointing to the endpoint defined by `authEndpoint`. This can be used when the authentication endpoint is on a different domain to the web application. The endpoint will therefore be requested as a `GET` and parameters passed in the query string.
171
172For more information see the [Channel authentication transport section of our authenticating users docs](http://pusher.com/docs/authenticating_users#authTransport).
173
174#### `auth` (Hash)
175
176Allows passing additional data to authorizers. Supports query string params and headers (AJAX only). For example, following will pass `foo=bar` via the query string and `baz: boo` via headers:
177
178```js
179const socket = new Pusher(APP_KEY, {
180 cluster: APP_CLUSTER,
181 auth: {
182 params: { foo: 'bar' },
183 headers: { baz: 'boo' }
184 }
185});
186```
187
188Additional parameters to be sent when the channel authentication endpoint is called. When using [ajax authentication](https://pusher.com/docs/authenticating_users#ajax_authentication) the parameters are passed as additional `POST` parameters. When using [jsonp authentication](http://pusher.com/docs/authenticating_users#jsonp_authentication) the parameters are passed as `GET` parameters. This can be useful with web application frameworks that guard against [CSRF (Cross-site request forgery)](http://en.wikipedia.org/wiki/Cross-site_request_forgery).
189
190##### CSRF
191
192If you require a CSRF header for incoming requests to the private channel authentication endpoint on your server, you should add a CSRF token to the `auth` hash under `headers`. This is applicable to frameworks which apply CSRF protection by default.
193
194```js
195const socket = new Pusher(APP_KEY, {
196 cluster: APP_CLUSTER,
197 auth: {
198 params: { foo: 'bar' },
199 headers: { 'X-CSRF-Token': 'SOME_CSRF_TOKEN' }
200 }
201});
202```
203
204#### `authorizer` (Function)
205
206If you need custom authorization behavior you can provide your own `authorizer` function as follows:
207
208```js
209const socket = new Pusher(APP_KEY, {
210 cluster: APP_CLUSTER,
211 authorizer: function (channel, options) {
212 return {
213 authorize: function (socketId, callback) {
214 // Do some ajax to get the auth information
215 callback(false, authInformation);
216 }
217 };
218 }
219})
220```
221
222#### `cluster` (String)
223
224Specifies the cluster that pusher-js should connect to. [If you'd like to see a full list of our clusters, click here](https://pusher.com/docs/clusters). If you do not specify a cluster, `mt1` will be used by default.
225
226```js
227const socket = new Pusher(APP_KEY, {
228 cluster: APP_CLUSTER,
229});
230```
231
232#### `disableStats` (Boolean)
233
234Disables stats collection, so that connection metrics are not submitted to Pusher’s servers. These stats are used for internal monitoring only and they do not affect the account stats.
235
236#### `enabledTransports` (Array)
237
238Specifies which transports should be used by pusher-js to establish a connection. Useful for applications running in controlled, well-behaving environments. Available transports for web: `ws`, `wss`, `xhr_streaming`, `xhr_polling`, `sockjs`. If you specify your transports in this way, you may miss out on new transports we add in the future.
239
240```js
241// Only use WebSockets
242const socket = new Pusher(APP_KEY, {
243 cluster: APP_CLUSTER,
244 enabledTransports: ['ws']
245});
246```
247
248#### `disabledTransports` (Array)
249
250Specifies which transports must not be used by pusher-js to establish a connection. This settings overwrites transports whitelisted via the `enabledTransports` options. Available transports for web: `ws`, `wss`, `xhr_streaming`, `xhr_polling`, `sockjs`. This is a whitelist, so any new transports we introduce in the future will be used until you explicitly add them to this list.
251
252```js
253// Use all transports except for sockjs
254const socket = new Pusher(APP_KEY, {
255 cluster: APP_CLUSTER,
256 disabledTransports: ['sockjs']
257});
258
259// Only use WebSockets
260const socket = new Pusher(APP_KEY, {
261 cluster: APP_CLUSTER,
262 enabledTransports: ['ws', 'xhr_streaming'],
263 disabledTransports: ['xhr_streaming']
264});
265```
266
267#### `wsHost`, `wsPort`, `wssPort`, `httpHost`, `httpPort`, `httpsPort`
268
269These can be changed to point to alternative Pusher Channels URLs (used internally for our staging server).
270
271#### `wsPath`
272
273Useful in special scenarios if you're using the library against an endpoint you control yourself. This is used internally for testing.
274
275#### `ignoreNullOrigin` (Boolean)
276
277Ignores null origin checks for HTTP fallbacks. Use with care, it should be disabled only if necessary (i.e. PhoneGap).
278
279#### `activityTimeout` (Integer)
280
281If there is no activity for this length of time (in milliseconds), the client will ping the server to check if the connection is still working. The default value is set by the server. Setting this value to be too low will result in unnecessary traffic.
282
283#### `pongTimeout` (Integer)
284
285Time before the connection is terminated after a ping is sent to the server. Default is 30000 (30s). Low values will cause false disconnections, if latency is high.
286
287## Global configuration
288
289### `Pusher.logToConsole` (Boolean)
290
291Enables logging to the browser console via calls to `console.log`.
292
293### `Pusher.log` (Function)
294
295Assign a custom log handler for the pusher-js library logging. For example:
296
297```js
298Pusher.log = (msg) => {
299 console.log(msg);
300};
301```
302
303By setting the `log` property you also override the use of `Pusher.enableLogging`.
304
305## Connection
306
307A connection to Pusher Channels is established by providing your `APP_KEY` and `APP_CLUSTER` to the constructor function:
308
309```js
310const socket = new Pusher(APP_KEY, {
311 cluster: APP_CLUSTER,
312});
313```
314
315This returns a socket object which can then be used to subscribe to channels.
316
317One reason this connection might fail is your account being over its' limits. You can detect this in the client by binding to the `error` event on the `pusher.connection` object. For example:
318
319```js
320var pusher = new Pusher('app_key');
321pusher.connection.bind( 'error', function( err ) {
322 if( err.error.data.code === 4004 ) {
323 log('Over limit!');
324 }
325});
326```
327
328You may disconnect again by invoking the `disconnect` method:
329
330```js
331socket.disconnect();
332```
333
334### Connection States
335The connection can be in any one of these states.
336
337**State**|**Note**
338--- | ---
339initialized|Initial state. No event is emitted in this state.
340connecting|All dependencies have been loaded and Channels is trying to connect. The connection will also enter this state when it is trying to reconnect after a connection failure.
341connected|The connection to Channels is open and authenticated with your app.
342unavailable|The connection is temporarily unavailable. In most cases this means that there is no internet connection. It could also mean that Channels is down
343failed|Channels is not supported by the browser. This implies that WebSockets are not natively available and an HTTP-based transport could not be found.
344disconnected|The Channels connection was previously connected and has now intentionally been closed.
345
346### Socket IDs
347
348Making a connection provides the client with a new `socket_id` that is assigned by the server. This can be used to distinguish the client's own events. A change of state might otherwise be duplicated in the client. More information on this pattern is available [here](http://pusherapp.com/docs/duplicates).
349
350It is also stored within the socket, and used as a token for generating signatures for private channels.
351
352## Subscribing to channels
353
354### Public channels
355
356The default method for subscribing to a channel involves invoking the `subscribe` method of your socket object:
357
358```js
359const channel = socket.subscribe('my-channel');
360```
361
362This returns a Channel object which events can be bound to.
363
364### Private channels
365
366Private channels are created in exactly the same way as normal channels, except that they reside in the 'private-' namespace. This means prefixing the channel name:
367
368```js
369const channel = socket.subscribe('private-my-channel');
370```
371
372### Encrypted Channels (BETA)
373
374Like private channels, encrypted channels have their own namespace, 'private-encrypted-'. For more information about encrypted channels, please see the [docs](https://pusher.com/docs/client_api_guide/client_encrypted_channels).
375
376Please note that encrypted channels are only officially supported for our 'web' and 'node' clients for now. We know for sure this won't work in React Native builds since the React Native runtime does not include the required crypto functionality we depend on. Please let us know if you need this functionality in our web-worker or React Native builds!
377
378```js
379const channel = socket.subscribe('private-encrypted-my-channel');
380```
381
382## Accessing Channels
383
384It is possible to access channels by name, through the `channel` function:
385
386```js
387const channel = socket.channel('private-my-channel');
388```
389
390It is possible to access all subscribed channels through the `allChannels` function:
391
392```js
393socket.allChannels().forEach(channel => console.log(channel.name));
394```
395
396Private, presence and encrypted channels will make a request to your `authEndpoint` (`/pusher/auth`) by default, where you will have to [authenticate the subscription](https://pusher.com/docs/authenticating_users). You will have to send back the correct auth response and a 200 status code.
397
398## Unsubscribing from channels
399
400To unsubscribe from a channel, invoke the `unsubscribe` method of your socket object:
401
402```js
403socket.unsubscribe('my-channel');
404```
405
406Unsubscribing from private channels is done in exactly the same way, just with the additional `private-` prefix:
407
408```js
409socket.unsubscribe('private-my-channel');
410```
411
412## Binding to events
413
414Event binding takes a very similar form to the way events are handled in jQuery. You can use the following methods either on a channel object, to bind to events on a particular channel; or on the pusher object, to bind to events on all subscribed channels simultaneously.
415
416### `bind` and `unbind`
417Binding to "new-message" on channel: The following logs message data to the console when "new-message" is received
418```js
419channel.bind('new-message', function (data) {
420 console.log(data.message);
421});
422```
423
424We can also provide the `this` value when calling a handler as a third optional parameter. The following logs "hi Pusher" when "my-event" is fired.
425
426```js
427channel.bind('my-event', function () {
428 console.log(`hi ${this.name}`);
429}, { name: 'Pusher' });
430```
431
432For client-events on presence channels, bound callbacks will be called with an additional argument. This argument is an object containing the `user_id` of the user who triggered the event
433
434```
435presenceChannel.bind('client-message', function (data, metadata) {
436 console.log('received data from', metadata.user_id, ':', data);
437});
438```
439
440Unsubscribe behaviour varies depending on which parameters you provide it with. For example:
441
442```js
443// Remove just `handler` for the `new-comment` event
444channel.unbind('new-comment', handler);
445
446// Remove all handlers for the `new-comment` event
447channel.unbind('new-comment');
448
449// Remove `handler` for all events
450channel.unbind(null, handler);
451
452// Remove all handlers for `context`
453channel.unbind(null, null, context);
454
455// Remove all handlers on `channel`
456channel.unbind();
457```
458
459### `bind_global` and `unbind_global`
460
461`bind_global` and `unbind_global` work much like `bind` and `unbind`, but instead of only firing callbacks on a specific event, they fire callbacks on any event, and provide that event along to the handler along with the event data. For example:
462
463```js
464channel.bind_global(function (event, data) {
465 console.log(`The event ${event} was triggered with data ${data}`);
466})
467```
468
469`unbind_global` works similarly to `unbind`.
470
471```js
472// remove just `handler` from global bindings
473channel.unbind_global(handler);
474
475// remove all global bindings
476channel.unbind_global();
477```
478
479### `unbind_all`
480
481The `unbind_all` method is equivalent to calling `unbind()` and `unbind_global()` together; it removes all bindings, global and event specific.
482
483## Batching auth requests (aka multi-auth)
484
485Currently, pusher-js itself does not support authenticating multiple channels in one HTTP request. However, thanks to @dirkbonhomme you can use the [pusher-js-auth](https://github.com/dirkbonhomme/pusher-js-auth) plugin that buffers subscription requests and sends auth requests to your endpoint in batches.
486
487## Default events
488
489There are a number of events which are used internally, but can also be of use elsewhere, for instance `subscribe`. There is also a `state_change` event - which fires whenever there is a state change. You can use it like this:
490
491```js
492pusher.connection.bind('state_change', function(states) {
493 // states = {previous: 'oldState', current: 'newState'}
494 $('div#status').text("Channels current state is " + states.current);
495});
496```
497
498## Connection Events
499
500To listen for when you connect to Pusher Channels:
501
502```js
503socket.connection.bind('connected', callback);
504```
505
506And to bind to disconnections:
507
508```js
509socket.connection.bind('disconnected', callback);
510```
511
512## Self-serving JS files
513
514You can host JavaScript files yourself, but it's a bit more complicated than putting them somewhere and just linking `pusher.js` in the source of your website. Because pusher-js loads fallback files dynamically, the dependency loader must be configured correctly or it will be using `js.pusher.com`.
515
516First, clone this repository and run `npm install && git submodule init && git submodule update`. Then run:
517
518 $ CDN_HTTP='http://your.http.url' CDN_HTTPS='https://your.https.url' make web
519
520In the `dist/web` folder, you should see the files you need: `pusher.js`, `pusher.min.js`, `json2.js`, `json.min.js`, `sockjs.js` and `sockjs.min.js`. `pusher.js` should be built referencing your URLs as the dependency hosts.
521
522First, make sure you expose all files from the `dist` directory. They need to be in a directory with named after the version number. For example, if you're hosting version 4.4.0 under `http://example.com/pusher-js` (and https for SSL), files should be accessible under following URL's:
523
524 http://example.com/pusher-js/4.4.0/pusher.js
525 http://example.com/pusher-js/4.4.0/json2.js
526 http://example.com/pusher-js/4.4.0/sockjs.js
527
528Minified files should have `.min` in their names, as in the `dist/web` directory:
529
530 http://example.com/pusher-js/4.4.0/pusher.min.js
531 http://example.com/pusher-js/4.4.0/json2.min.js
532 http://example.com/pusher-js/4.4.0/sockjs.min.js
533
534## SockJS compatibility
535
536Most browsers have a limit of 6 simultaneous connections to a single domain, but Internet Explorer 6 and 7 have a limit of just 2. This means that you can only use a single Pusher Channels connection in these browsers, because SockJS requires an HTTP connection for incoming data and another one for sending. Opening the second connection will break the first one as the client won't be able to respond to ping messages and get disconnected eventually.
537
538All other browsers work fine with two or three connections.
539
540## Developing
541
542Install all dependencies via Yarn:
543
544```bash
545yarn install
546```
547
548Run a development server which serves bundled javascript from <http://localhost:5555/pusher.js> so that you can edit files in /src freely.
549
550```bash
551make serve
552```
553
554You can optionally pass a `PORT` environment variable to run the server on a different port. You can also pass `CDN_HTTP` and `CDN_HTTPS` variables if you wish the library to load dependencies from a new host.
555
556This command will serve `pusher.js`, `sockjs.js`, `json2.js`, and their respective minified versions.
557
558### Core Vs. Platform-Specific Code
559
560New to pusher-js 3.1 is the ability for the library to produce builds for different runtimes: classic web, React Native, NodeJS and
561Web Workers.
562
563In order for this to happen, we have split the library into two directories: `core/` and `runtimes/`. In `core` we keep anything that is platform-independent. In `runtimes` we keep code that depends on certain runtimes.
564
565Throughout the `core/` directory you'll find this line:
566
567```javascript
568import Runtime from "runtime";
569```
570
571We use webpack module resolution to make the library look for different versions of this module depending on the build.
572
573For web it will look for `src/runtimes/web/runtime.ts`. For ReactNative, `src/runtimes/react-native/runtime.ts`. For Node: `src/runtimes/node/runtime.ts`. For worker: `src/runtimes/worker/runtime.ts`.
574
575Each of these runtime files exports an object (conforming to the interface you can see in `src/runtimes/interface.ts`) that abstracts away everything platform-specific. The core library pulls this object in without any knowledge of how it implements it. This means web build can use the DOM underneath, the ReactNative build can use its native NetInfo API, Workers can use `fetch` and so on.
576
577### Building
578
579In order to build SockJS, you must first initialize and update the Git submodule:
580
581```bash
582git submodule init
583git submodule update
584```
585
586Then simply run:
587
588```bash
589make web
590```
591
592This will build the source files relevant for the web build into `dist/web`.
593
594In order to specify the library version, you can either update `package.json` or pass a `VERSION` environment variable upon building.
595
596Other build commands include:
597
598```bash
599make react-native # for the React Native build
600make node # for the NodeJS build
601make worker # for the worker build
602```
603
604### Testing
605
606Each test environment contains two types of tests:
607
6081. unit tests,
6092. integration tests.
610
611Unit tests are simple, fast and don't need any external dependencies. Integration tests usually connect to production and js-integration-api servers and can use a local server for loading JS files, so they need an Internet connection to work.
612
613There are 3 different testing environments: one for web, one for NodeJS and one for workers. We may consider adding another one for React Native in the future.
614
615The web and worker tests use [Karma](https://github.com/karma-runner/karma) to execute specs in real browsers. The NodeJS tests use [jasmine-node](https://github.com/mhevery/jasmine-node).
616
617To run the tests:
618
619```bash
620# For web
621make web_unit
622make web_integration
623
624# For NodeJS
625make node_unit
626make node_integration
627
628# For workers
629make worker_unit
630make worker_integration
631```
632
633If you want your Karma tests to automatically reload, then in `spec/karma/config.common.js` set `singleRun` to `false`.