centrifuge 2.8.3 → 3.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +348 -665
- package/build/centrifuge.d.ts +156 -0
- package/build/centrifuge.js +1526 -0
- package/build/centrifuge.js.map +1 -0
- package/build/codes.d.ts +35 -0
- package/build/codes.js +39 -0
- package/build/codes.js.map +1 -0
- package/build/index.d.ts +4 -0
- package/build/index.js +10 -0
- package/build/index.js.map +1 -0
- package/build/json.d.ts +1 -0
- package/build/json.js +18 -0
- package/build/json.js.map +1 -0
- package/build/protobuf/client.proto.json +791 -0
- package/build/protobuf/index.d.ts +18 -0
- package/build/protobuf/index.js +64 -0
- package/build/protobuf/index.js.map +1 -0
- package/build/subscription.d.ts +82 -0
- package/build/subscription.js +575 -0
- package/build/subscription.js.map +1 -0
- package/build/transport_http_stream.d.ts +1 -0
- package/build/transport_http_stream.js +207 -0
- package/build/transport_http_stream.js.map +1 -0
- package/build/transport_sockjs.d.ts +1 -0
- package/build/transport_sockjs.js +55 -0
- package/build/transport_sockjs.js.map +1 -0
- package/build/transport_sse.d.ts +1 -0
- package/build/transport_sse.js +95 -0
- package/build/transport_sse.js.map +1 -0
- package/build/transport_websocket.d.ts +1 -0
- package/build/transport_websocket.js +58 -0
- package/build/transport_websocket.js.map +1 -0
- package/build/types.d.ts +282 -0
- package/build/types.js +18 -0
- package/build/types.js.map +1 -0
- package/build/utils.d.ts +1 -0
- package/build/utils.js +52 -0
- package/build/utils.js.map +1 -0
- package/dist/centrifuge.js +5 -3554
- package/dist/centrifuge.js.map +7 -1
- package/dist/centrifuge.protobuf.js +8 -11380
- package/dist/centrifuge.protobuf.js.map +7 -1
- package/package.json +48 -33
- package/.babelrc +0 -4
- package/.editorconfig +0 -12
- package/.eslintrc +0 -179
- package/.gitattributes +0 -1
- package/.github/workflows/ci.yml +0 -23
- package/.github/workflows/release.yml +0 -24
- package/.nvmrc +0 -1
- package/CHANGELOG.md +0 -462
- package/dist/centrifuge.d.ts +0 -219
- package/dist/centrifuge.min.js +0 -2
- package/dist/centrifuge.min.js.map +0 -1
- package/dist/centrifuge.protobuf.d.ts +0 -3
- package/dist/centrifuge.protobuf.min.js +0 -2
- package/dist/centrifuge.protobuf.min.js.map +0 -1
- package/make-proto +0 -3
- package/src/centrifuge.js +0 -1917
- package/src/client.proto.json +0 -573
- package/src/index.js +0 -2
- package/src/index_protobuf.js +0 -2
- package/src/json.js +0 -48
- package/src/protobuf.js +0 -257
- package/src/subscription.js +0 -273
- package/src/utils.js +0 -40
- package/test/index.spec.js +0 -47
- package/webpack.config.js +0 -52
package/README.md
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
|
-
# Centrifuge
|
|
1
|
+
# Centrifuge and Centrifugo bidirectional SDK for NodeJS, React-Native and browser
|
|
2
2
|
|
|
3
|
-
This client
|
|
3
|
+
This SDK provides a client to connect to [Centrifugo](https://github.com/centrifugal/centrifugo) or any [Centrifuge-based](https://github.com/centrifugal/centrifuge) server using pure WebSocket or one of the fallback transports from web browser, ReactNative, or NodeJS environments.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
* [
|
|
5
|
+
The client behaves according to a common [Centrifigo SDK spec](https://centrifugal.dev/docs/transports/client_api). It's recommended to read that before starting to work with this SDK as the spec covers common SDK behavior - describes client and subscription state transitions, main options and methods. Then proceed with this readme for more specifics about `centrifuge-js`.
|
|
6
|
+
|
|
7
|
+
* [Install](#install)
|
|
8
|
+
* [Quick start](#quick-start)
|
|
9
|
+
* [WebSocket transport](#websocket-transport)
|
|
10
|
+
* [Using fallbacks](#using-fallbacks)
|
|
11
|
+
* [SockJS](#using-fallbacks)
|
|
12
|
+
* [Bidirectional emulation](#bidirectional-emulation)
|
|
8
13
|
* [Client API](#client-api)
|
|
9
|
-
* [
|
|
14
|
+
* [Client methods and events](#client-methods-and-events)
|
|
15
|
+
* [Connection token](#connection-token)
|
|
16
|
+
* [Subscription API](#subscription-api)
|
|
17
|
+
* [Subscription methods and events](#client-methods-and-events)
|
|
18
|
+
* [Subscription token](#connection-token)
|
|
19
|
+
* [Message batching](#message-batching)
|
|
10
20
|
* [Server-side subscriptions](#server-side-subscriptions)
|
|
11
|
-
* [
|
|
21
|
+
* [Configuration parameters](#configuration-parameters)
|
|
12
22
|
* [Protobuf support](#protobuf-support)
|
|
13
23
|
* [Browser support](#browser-support)
|
|
14
24
|
* [Using with NodeJS](#using-with-nodejs)
|
|
15
|
-
* [Custom XMLHttpRequest](#custom-xmlhttprequest)
|
|
16
25
|
* [Custom WebSocket constructor](#custom-websocket-constructor)
|
|
17
|
-
* [Subscribe since known position](#subscribe-since-known-position)
|
|
18
|
-
* [Feature Matrix](#feature-matrix)
|
|
19
26
|
|
|
20
|
-
## Install
|
|
27
|
+
## Install
|
|
21
28
|
|
|
22
|
-
|
|
29
|
+
Using cdn (replace `X` to a concrete version number):
|
|
23
30
|
|
|
24
31
|
```html
|
|
25
|
-
<script src="centrifuge.js"></script>
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/gh/centrifugal/centrifuge-js@3.X.X/dist/centrifuge.min.js"></script>
|
|
26
33
|
```
|
|
27
34
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
```html
|
|
31
|
-
<script src="https://cdn.jsdelivr.net/gh/centrifugal/centrifuge-js@2.X.X/dist/centrifuge.min.js"></script>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Client is also available via `npm`:
|
|
35
|
+
Also available via `npm`:
|
|
35
36
|
|
|
36
37
|
```bash
|
|
37
38
|
npm install centrifuge
|
|
@@ -40,274 +41,170 @@ npm install centrifuge
|
|
|
40
41
|
And then:
|
|
41
42
|
|
|
42
43
|
```javascript
|
|
43
|
-
|
|
44
|
+
import { Centrifuge } from 'centrifuge';
|
|
44
45
|
```
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
By default, library works with JSON only, see [Protobuf support](#protobuf-support) section to see how to import client with Protobuf support.
|
|
48
|
+
|
|
49
|
+
## Quick start
|
|
47
50
|
|
|
48
|
-
|
|
51
|
+
The basic usage example may look like this:
|
|
49
52
|
|
|
50
53
|
```javascript
|
|
51
|
-
|
|
54
|
+
// Use WebSocket transport endpoint.
|
|
55
|
+
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
});
|
|
57
|
+
// Allocate Subscription to a channel.
|
|
58
|
+
const sub = centrifuge.newSubscription('news');
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
60
|
+
// React on `news` channel real-time publications.
|
|
61
|
+
sub.on('publication', function(ctx) {
|
|
62
|
+
console.log(ctx.data);
|
|
63
|
+
});
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
// Trigger subscribe process.
|
|
66
|
+
sub.subscribe();
|
|
61
67
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
```html
|
|
65
|
-
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.3/dist/sockjs.min.js" type="text/javascript"></script>
|
|
66
|
-
<script src="centrifuge.js" type="text/javascript"></script>
|
|
68
|
+
// Trigger actual connection establishement.
|
|
69
|
+
centrifuge.connect();
|
|
67
70
|
```
|
|
68
71
|
|
|
69
|
-
|
|
72
|
+
Note, that we explicitly call `.connect()` method to initiate connection establishement with a server and `.subscribe()` method to move Subscription to `subsribing` state (which should transform into `subscribed` state soon after connection with a server is established). The order of `.connect()` and `.subscribe` calls does not actually matter here.
|
|
70
73
|
|
|
71
|
-
|
|
72
|
-
var Centrifuge = require("centrifuge");
|
|
73
|
-
var SockJS = require('sockjs-client');
|
|
74
|
+
**`Centrifuge` object and `Subscription` object are both instances of [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).** Below we will describe events that can be exposed in detail.
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
sockjs: SockJS
|
|
77
|
-
})
|
|
78
|
-
```
|
|
76
|
+
## Websocket transport
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
WebSocket is the main protocol used by `centrifuge-js` to communicate with a server. In browser environment it's available globally, but if you want to connect from NodeJS env – then you need to provide WebSocket constructor to `centrifuge-js` explicitly. [See below](#using-with-nodejs) more information about this.
|
|
81
79
|
|
|
82
|
-
##
|
|
80
|
+
## Using fallbacks
|
|
83
81
|
|
|
84
|
-
|
|
82
|
+
In the quick start example above we used WebSocket endpoint to configure Centrifuge. WebSocket is the main transport – it's bidirectional out of the box.
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
var centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');
|
|
84
|
+
In some cases though, WebSocket connection may not be established (for example, due to corporate firewalls and proxies). For such situations `centrifuge-js` offers several WebSocket fallback options.
|
|
88
85
|
|
|
89
|
-
|
|
86
|
+
### Using SockJS
|
|
90
87
|
|
|
91
|
-
centrifuge.
|
|
92
|
-
console.log(message);
|
|
93
|
-
});
|
|
88
|
+
If you want to use SockJS you must also import SockJS client before centrifuge.js
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
```html
|
|
91
|
+
<script src="https://cdn.jsdelivr.net/npm/sockjs-client@1.3/dist/sockjs.min.js" type="text/javascript"></script>
|
|
92
|
+
<script src="centrifuge.js" type="text/javascript"></script>
|
|
96
93
|
```
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
**Connection JWT comes to Javascript code from application backend - i.e. must be generated on backend**.
|
|
101
|
-
|
|
102
|
-
## Configuration parameters
|
|
103
|
-
|
|
104
|
-
Let's also look at optional configuration parameters available when initializing `Centrifuge` object instance.
|
|
105
|
-
|
|
106
|
-
#### websocket
|
|
107
|
-
|
|
108
|
-
`websocket` option allows to explicitly provide custom WebSocket client to use. By default centrifuge-js will try to use global WebSocket object, so if you are in web browser – it will just use native WebSocket implementation. See notes about using `centrifuge-js` with NodeJS below.
|
|
109
|
-
|
|
110
|
-
#### sockjs
|
|
111
|
-
|
|
112
|
-
`sockjs` option allows to explicitly provide SockJS client object to Centrifuge client.
|
|
113
|
-
|
|
114
|
-
For example this can be useful if you develop in ES6 with imports:
|
|
95
|
+
Or provide it explicitly as a dependency:
|
|
115
96
|
|
|
116
97
|
```javascript
|
|
117
|
-
import Centrifuge from 'centrifuge'
|
|
98
|
+
import { Centrifuge } from 'centrifuge'
|
|
118
99
|
import SockJS from 'sockjs-client'
|
|
119
100
|
|
|
120
|
-
|
|
101
|
+
const centrifuge = new Centrifuge("http://localhost:8000/connection/sockjs", {
|
|
121
102
|
sockjs: SockJS
|
|
122
|
-
})
|
|
103
|
+
})
|
|
123
104
|
```
|
|
124
105
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
In case of using SockJS additional configuration parameter can be used - `sockjsTransports`.
|
|
106
|
+
Note, that in SockJS case endpoint starts with `http://`, not with `ws://` as we used above when connecting to a pure WebSocket endpoint.
|
|
128
107
|
|
|
129
|
-
|
|
108
|
+
### Bidirectional emulation
|
|
130
109
|
|
|
131
|
-
|
|
132
|
-
var centrifuge = new Centrifuge(
|
|
133
|
-
'http://centrifuge.example.com/connection/sockjs',
|
|
134
|
-
{
|
|
135
|
-
sockjsTransports: [
|
|
136
|
-
'websocket',
|
|
137
|
-
'xdr-streaming',
|
|
138
|
-
'xhr-streaming',
|
|
139
|
-
'eventsource',
|
|
140
|
-
'iframe-eventsource',
|
|
141
|
-
'iframe-htmlfile',
|
|
142
|
-
'xdr-polling',
|
|
143
|
-
'xhr-polling',
|
|
144
|
-
'iframe-xhr-polling',
|
|
145
|
-
'jsonp-polling'
|
|
146
|
-
]
|
|
147
|
-
});
|
|
148
|
-
```
|
|
110
|
+
SockJS is robust and stable product, but it's an extra dependency, it's pretty old, comes with some overhead and sticky sessions requirement for a distributed backend case. In most scenarios these days clients are fine to use WebSocket protocol for messaging. There are rare connection issues though which are caused by corporate firewall and proxy software. To deal with users behind such proxies Centrifuge SDK offers its own bidirectional emulation layer. This layer uses two HTTP-based transports:
|
|
149
111
|
|
|
150
|
-
|
|
112
|
+
* HTTP-streaming based on ReadableStream API
|
|
113
|
+
* SSE (EventSource).
|
|
151
114
|
|
|
152
|
-
|
|
153
|
-
using SockJS endpoint:
|
|
115
|
+
Bidirectional emulation must be first enabled on a server-side. For example, see Centrifugo docs to find out how. Then in Javascript you can slightly change client initialization and point it to a list of endpoints and transports you want to use:
|
|
154
116
|
|
|
155
117
|
```javascript
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
`debug` is a boolean option which is `false` by default. When enabled lots of various debug
|
|
169
|
-
messages will be logged into javascript console. Mostly useful for development or
|
|
170
|
-
troubleshooting.
|
|
171
|
-
|
|
172
|
-
#### minRetry
|
|
173
|
-
|
|
174
|
-
When client disconnected from server it will automatically try to reconnect using exponential
|
|
175
|
-
backoff algorithm to get interval between reconnect attempts which value grows exponentially.
|
|
176
|
-
`minRetry` option sets minimal interval value in milliseconds. Default is `1000` milliseconds.
|
|
177
|
-
|
|
178
|
-
#### maxRetry
|
|
179
|
-
|
|
180
|
-
`maxRetry` sets upper interval value limit when reconnecting. Or your clients will never reconnect
|
|
181
|
-
as exponent grows very fast:) Default is `20000` milliseconds.
|
|
182
|
-
|
|
183
|
-
#### subscribeEndpoint
|
|
184
|
-
|
|
185
|
-
`subscribeEndpoint` is url to use when sending auth request for authorizing subscription on private channel. By default `/centrifuge/subscribe`. See also useful related options:
|
|
186
|
-
|
|
187
|
-
* `subscribeHeaders` - map of headers to send with subscribe request (default `{}`)
|
|
188
|
-
* `subscribeParams` - map of params to include in subscribe endpoint url (default `{}`)
|
|
189
|
-
|
|
190
|
-
#### refreshEndpoint
|
|
191
|
-
|
|
192
|
-
`refreshEndpoint` is url to use when refreshing client connection parameters when connection check mechanism enabled in Centrifugo configuration. See also related options:
|
|
193
|
-
|
|
194
|
-
* `refreshHeaders` - map of headers to send with refresh request (default `{}`)
|
|
195
|
-
* `refreshParams` - map of params to include in refresh url (default `{}`)
|
|
196
|
-
* `refreshData` - send extra data in body (as JSON payload) when sending AJAX POST refresh request.
|
|
197
|
-
* `refreshAttempts` - limit amount of refresh requests before giving up (by default `null` - unlimited)
|
|
198
|
-
* `onRefreshFailed` - callback function called when `refreshAttempts` came to the end. By default `null` - i.e. nothing called.
|
|
199
|
-
* `onRefresh` - optional callback to fully control refresh behaviour. This function will ve called as soon as connection token needs to be refreshed. After this it's up to application to get new token in a way it needs. As soon as application got token it must call callback passed as argument with proper data - see example below. *In this case `centrifuge-js` will not send automatic AJAX requests to your application*.
|
|
200
|
-
|
|
201
|
-
Here is an example of using custom `onRefresh` function:
|
|
202
|
-
|
|
203
|
-
```javascript
|
|
204
|
-
centrifuge = new Centrifuge("http://localhost:8000/connection/websocket", {
|
|
205
|
-
debug: true,
|
|
206
|
-
onRefresh: function(ctx, cb) {
|
|
207
|
-
let promise = fetch("http://localhost:3000/centrifuge/refresh", {
|
|
208
|
-
method: "POST"
|
|
209
|
-
}).then(function(resp) {
|
|
210
|
-
resp.json().then(function(data) {
|
|
211
|
-
// Data must be like {"status": 200, "data": {"token": "JWT"}} - see
|
|
212
|
-
// type definitions in dist folder. Note that setting status to 200 is
|
|
213
|
-
// required at moment. Any other status will result in refresh process
|
|
214
|
-
// failure so client will eventually be disconnected by server.
|
|
215
|
-
cb(data);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
118
|
+
const transports = [
|
|
119
|
+
{
|
|
120
|
+
transport: 'websocket',
|
|
121
|
+
endpoint: 'ws://example.com/connection/websocket'
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
transport: 'http_stream',
|
|
125
|
+
endpoint: 'http://example.com/connection/http_stream'
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
transport: 'sse',
|
|
129
|
+
endpoint: 'http://example.com/connection/sse'
|
|
218
130
|
}
|
|
219
|
-
|
|
131
|
+
];
|
|
132
|
+
const centrifuge = new Centrifuge(transports);
|
|
133
|
+
centrifuge.connect()
|
|
220
134
|
```
|
|
221
135
|
|
|
222
|
-
|
|
136
|
+
In this case, client will try transports in order, one by one, during the initial handshake. Until success. Then will only use a successful transport during reconnects.
|
|
137
|
+
|
|
138
|
+
Supported transports are:
|
|
223
139
|
|
|
224
|
-
`
|
|
225
|
-
|
|
226
|
-
|
|
140
|
+
* `websocket`
|
|
141
|
+
* `http_stream`
|
|
142
|
+
* `sse`
|
|
143
|
+
* `sockjs` (yes, SockJS can also be used as a fallback in the bidirectional emulation layer, but sticky session must be used on the backend in distributed case).
|
|
227
144
|
|
|
228
145
|
## Client API
|
|
229
146
|
|
|
230
|
-
|
|
147
|
+
Let's look at top-level API of `Centrifuge` client.
|
|
148
|
+
|
|
149
|
+
### Client methods and events
|
|
231
150
|
|
|
232
151
|
#### connect method
|
|
233
152
|
|
|
234
|
-
As we showed
|
|
153
|
+
As we already showed above, we must call `connect()` method to make an actual connection
|
|
235
154
|
request to Centrifugo server:
|
|
236
155
|
|
|
237
156
|
```javascript
|
|
238
|
-
|
|
239
|
-
|
|
157
|
+
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');
|
|
240
158
|
centrifuge.connect();
|
|
241
159
|
```
|
|
242
160
|
|
|
243
161
|
`connect()` triggers an actual connection request to server.
|
|
244
162
|
|
|
245
|
-
####
|
|
163
|
+
#### connected event
|
|
246
164
|
|
|
247
|
-
|
|
248
|
-
then `connect` event on `Centrifuge` object instance will be called.
|
|
165
|
+
As soon as connection is established and client successfully authenticated – `connected` event on `Centrifuge` object instance will be called.
|
|
249
166
|
|
|
250
|
-
|
|
167
|
+
It's possible to listen to this event by setting event listener function on `connected` event:
|
|
251
168
|
|
|
252
169
|
```javascript
|
|
253
|
-
centrifuge.on('
|
|
254
|
-
// now client connected to Centrifugo and
|
|
170
|
+
centrifuge.on('connected', function(ctx) {
|
|
171
|
+
// now client connected to Centrifugo and authenticated.
|
|
255
172
|
});
|
|
256
173
|
```
|
|
257
174
|
|
|
258
|
-
|
|
175
|
+
#### connecting event
|
|
176
|
+
|
|
177
|
+
`connecting` event fired when Centrifuge object goes to connecting state. This may be called during initial connect, or after being `connected` due to temporary connection loss.
|
|
259
178
|
|
|
260
179
|
```javascript
|
|
261
|
-
{
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
latency: 21
|
|
265
|
-
}
|
|
180
|
+
centrifuge.on('connecting', function(ctx) {
|
|
181
|
+
// do whatever you need in case of connecting to a server
|
|
182
|
+
});
|
|
266
183
|
```
|
|
267
184
|
|
|
268
|
-
|
|
269
|
-
* `transport` – name of transport used to establish connection with server (string)
|
|
270
|
-
* `latency` – latency in milliseconds (int). This measures time passed between sending
|
|
271
|
-
`connect` client protocol command and receiving connect response.
|
|
185
|
+
#### disconnected event
|
|
272
186
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
`disconnect` event fired on centrifuge object every time client disconnects for
|
|
276
|
-
some reason. This can be network disconnect or disconnect initiated by Centrifugo server.
|
|
187
|
+
`disconnected` event fired on Centrifuge object every time client disconnects for some reason. This can be terminal disconnect due to advice from a server or disconnect initiated by client-side.
|
|
277
188
|
|
|
278
189
|
```javascript
|
|
279
|
-
centrifuge.on('
|
|
190
|
+
centrifuge.on('disconnected', function(ctx) {
|
|
280
191
|
// do whatever you need in case of disconnect from server
|
|
281
192
|
});
|
|
282
193
|
```
|
|
283
194
|
|
|
284
|
-
What's in `context`?
|
|
285
|
-
|
|
286
|
-
```javascript
|
|
287
|
-
{
|
|
288
|
-
reason: "connection closed",
|
|
289
|
-
reconnect: true
|
|
290
|
-
}
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
* `reason` – the reason of client's disconnect (string)
|
|
294
|
-
* `reconnect` – flag indicating if client will reconnect or not (boolean)
|
|
295
|
-
|
|
296
195
|
#### disconnect method
|
|
297
196
|
|
|
298
|
-
In some cases you may need to disconnect your client from server, use
|
|
299
|
-
do this:
|
|
197
|
+
In some cases you may need to disconnect your client from server, use `.disconnect()` method to do this:
|
|
300
198
|
|
|
301
199
|
```javascript
|
|
302
200
|
centrifuge.disconnect();
|
|
303
201
|
```
|
|
304
202
|
|
|
305
|
-
After calling this client will not try to reestablish connection periodically. You must call
|
|
306
|
-
`connect` method manually again.
|
|
203
|
+
After calling this client will not try to reestablish connection periodically. You must call `.connect()` method manually again.
|
|
307
204
|
|
|
308
205
|
#### publish method
|
|
309
206
|
|
|
310
|
-
Sometimes you need to publish into channel
|
|
207
|
+
Sometimes you need to publish into channel without actually being subscribed to it. In this case you can use `publish` method:
|
|
311
208
|
|
|
312
209
|
```javascript
|
|
313
210
|
centrifuge.publish("channel", {"input": "hello"}).then(function(res) {
|
|
@@ -319,7 +216,7 @@ centrifuge.publish("channel", {"input": "hello"}).then(function(res) {
|
|
|
319
216
|
|
|
320
217
|
#### send method
|
|
321
218
|
|
|
322
|
-
This is only valid for Centrifuge library and does not work for Centrifugo server. `send` method allows
|
|
219
|
+
This is only valid for Centrifuge library and does not work for Centrifugo server at the moment. `send` method allows sending asynchronous message from a client to a server.
|
|
323
220
|
|
|
324
221
|
```javascript
|
|
325
222
|
centrifuge.send({"input": "hello"}).then(function(res) {
|
|
@@ -331,22 +228,10 @@ centrifuge.send({"input": "hello"}).then(function(res) {
|
|
|
331
228
|
|
|
332
229
|
#### rpc method
|
|
333
230
|
|
|
334
|
-
`rpc` method allows to send
|
|
231
|
+
`rpc` method allows to send rpc request from client to server and wait for data response.
|
|
335
232
|
|
|
336
233
|
```javascript
|
|
337
|
-
centrifuge.rpc({"input": "hello"}).then(function(res) {
|
|
338
|
-
console.log('rpc result', res);
|
|
339
|
-
}, function(err) {
|
|
340
|
-
console.log('rpc error', err);
|
|
341
|
-
});
|
|
342
|
-
```
|
|
343
|
-
|
|
344
|
-
#### namedRPC method
|
|
345
|
-
|
|
346
|
-
`namedRPC` method allows to send rpc request from client to server and wait for data response. Unlike `rpc` it additionally allows to provide method name string (which can be handy to have on RPC request top level).
|
|
347
|
-
|
|
348
|
-
```javascript
|
|
349
|
-
centrifuge.namedRPC({"input": "hello"}).then(function(res) {
|
|
234
|
+
centrifuge.rpc("my.method.name", {"input": "hello"}).then(function(res) {
|
|
350
235
|
console.log('rpc result', res);
|
|
351
236
|
}, function(err) {
|
|
352
237
|
console.log('rpc error', err);
|
|
@@ -355,8 +240,6 @@ centrifuge.namedRPC({"input": "hello"}).then(function(res) {
|
|
|
355
240
|
|
|
356
241
|
#### history method
|
|
357
242
|
|
|
358
|
-
Available since v2.7.0
|
|
359
|
-
|
|
360
243
|
Allows to get history from a server. This is a top-level analogue of `Subscription.history` method. But accepts a channel as first argument.
|
|
361
244
|
|
|
362
245
|
```javascript
|
|
@@ -369,8 +252,6 @@ centrifuge.history("channel", {since: {offset: 0, epoch: "xyz"}, limit: 10}).the
|
|
|
369
252
|
|
|
370
253
|
#### presence method
|
|
371
254
|
|
|
372
|
-
Available since v2.7.0
|
|
373
|
-
|
|
374
255
|
Allows to get presence info from a server. This is a top-level analogue of `Subscription.presence` method. But accepts a channel as first argument.
|
|
375
256
|
|
|
376
257
|
```javascript
|
|
@@ -383,8 +264,6 @@ centrifuge.presence("channel").then(function(resp) {
|
|
|
383
264
|
|
|
384
265
|
#### presenceStats method
|
|
385
266
|
|
|
386
|
-
Available since v2.7.0
|
|
387
|
-
|
|
388
267
|
Allows to get presence stats from a server. This is a top-level analogue of `Subscription.presenceStats` method. But accepts a channel as first argument.
|
|
389
268
|
|
|
390
269
|
```javascript
|
|
@@ -395,243 +274,139 @@ centrifuge.presenceStats("channel").then(function(resp) {
|
|
|
395
274
|
});
|
|
396
275
|
```
|
|
397
276
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
Allows setting custom data sent to a server in first message. This data will be available on a server side in OnConnecting callback (if using Centrifugo library) or proxied to application backend (in using Centrifugo with connect proxy enabled).
|
|
277
|
+
#### ready method
|
|
401
278
|
|
|
402
|
-
|
|
403
|
-
centrifuge.setConnectData({"any": "key"});
|
|
404
|
-
```
|
|
279
|
+
Returns a Promise which will be resolved upon connection establishement (i.e. when Client goes to `connected` state).
|
|
405
280
|
|
|
406
|
-
|
|
281
|
+
#### error event
|
|
407
282
|
|
|
408
|
-
|
|
409
|
-
receive new messages published into channels. So our next step is `subscribe` on channel
|
|
410
|
-
from which we want to receive real-time messages.
|
|
411
|
-
|
|
412
|
-
### subscribe method
|
|
413
|
-
|
|
414
|
-
To subscribe on channel we must use `subscribe` method of `Centrifuge` object instance.
|
|
415
|
-
|
|
416
|
-
The simplest usage that allow to subscribe on channel and listen to new messages is:
|
|
283
|
+
To listen asynchronous error happening internally while Centrifuge client works you can set an `error` handler:
|
|
417
284
|
|
|
418
285
|
```javascript
|
|
419
|
-
|
|
420
|
-
// handle new message coming from channel "news"
|
|
421
|
-
console.log(message);
|
|
422
|
-
});
|
|
423
|
-
```
|
|
286
|
+
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket');
|
|
424
287
|
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
* `publish` – called when new publication message received (callback function in our previous example is `publish` event callback btw)
|
|
429
|
-
* `join` – called when someone joined channel
|
|
430
|
-
* `leave` – called when someone left channel
|
|
431
|
-
* `subscribe` – called when subscription on channel successful and acknowledged by Centrifugo
|
|
432
|
-
server. It can be called several times during lifetime as browser client automatically resubscribes on channels after successful reconnect (caused by temporary network disconnect for example or Centrifugo server restart)
|
|
433
|
-
* `error` – called when subscription on channel failed with error. It can be called several times
|
|
434
|
-
during lifetime as browser client automatically resubscribes on channels after successful reconnect
|
|
435
|
-
(caused by temporary network disconnect for example or Centrifugo server restart)
|
|
436
|
-
* `unsubscribe` – called every time subscription that was successfully subscribed
|
|
437
|
-
unsubscribes from channel (can be caused by network disconnect or by calling
|
|
438
|
-
`unsubscribe` method of subscription object)
|
|
439
|
-
|
|
440
|
-
Don't be frightened by amount of events available. In most cases you only need some of them
|
|
441
|
-
until you need full control to what happens with your subscriptions. We will look at format
|
|
442
|
-
of messages for this event callbacks later below.
|
|
443
|
-
|
|
444
|
-
There are 2 ways setting callback functions for events above.
|
|
445
|
-
|
|
446
|
-
First is providing object containing event callbacks as second argument to `subscribe` method.
|
|
447
|
-
|
|
448
|
-
```javascript
|
|
449
|
-
var callbacks = {
|
|
450
|
-
"publish": function(message) {
|
|
451
|
-
// See below description of message format
|
|
452
|
-
console.log(message);
|
|
453
|
-
},
|
|
454
|
-
"join": function(message) {
|
|
455
|
-
// See below description of join message format
|
|
456
|
-
console.log(message);
|
|
457
|
-
},
|
|
458
|
-
"leave": function(message) {
|
|
459
|
-
// See below description of leave message format
|
|
460
|
-
console.log(message);
|
|
461
|
-
},
|
|
462
|
-
"subscribe": function(context) {
|
|
463
|
-
// See below description of subscribe callback context format
|
|
464
|
-
console.log(context);
|
|
465
|
-
},
|
|
466
|
-
"error": function(errContext) {
|
|
467
|
-
// See below description of subscribe error callback context format
|
|
468
|
-
console.log(err);
|
|
469
|
-
},
|
|
470
|
-
"unsubscribe": function(context) {
|
|
471
|
-
// See below description of unsubscribe event callback context format
|
|
472
|
-
console.log(context);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
var subscription = centrifuge.subscribe("news", callbacks);
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
Another way is setting callbacks using `on` method of subscription. Subscription object
|
|
480
|
-
is event emitter so you can simply do the following:
|
|
481
|
-
|
|
482
|
-
```javascript
|
|
483
|
-
var subscription = centrifuge.subscribe("news");
|
|
484
|
-
|
|
485
|
-
subscription.on("publish", publishHandlerFunction);
|
|
486
|
-
subscription.on("subscribe", subscribeHandlerFunction);
|
|
487
|
-
subscription.on("error", subscribeErrorHandlerFunction);
|
|
288
|
+
centrifuge.on('error', function(ctx) {
|
|
289
|
+
console.log(ctx);
|
|
290
|
+
});
|
|
488
291
|
```
|
|
489
292
|
|
|
490
|
-
|
|
293
|
+
This can help you to log failed connection attempts, or token refresh errors, etc.
|
|
491
294
|
|
|
492
|
-
###
|
|
295
|
+
### Connection Token
|
|
493
296
|
|
|
494
|
-
|
|
495
|
-
This gives you an opportunity to listen to `join` and `leave` events in those channels.
|
|
496
|
-
Just set event handlers on `join` and `leave` events of subscription.
|
|
297
|
+
Depending on authentication scheme used by a server you may also want to provide connection token:
|
|
497
298
|
|
|
498
299
|
```javascript
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
}).on("join", function(message) {
|
|
502
|
-
console.log("Client joined channel", message);
|
|
503
|
-
}).on("leave", function(message) {
|
|
504
|
-
console.log("Client left channel", message);
|
|
300
|
+
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket', {
|
|
301
|
+
token: '<CONNECTION_TOKEN>'
|
|
505
302
|
});
|
|
506
303
|
```
|
|
507
304
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
### subscription event context formats
|
|
305
|
+
In case of Centrifugo on a server side this may be a JSON Web Token - see [authentication documentation](https://centrifugal.github.io/centrifugo/server/authentication/) for details on how to generate it on your backend side.
|
|
511
306
|
|
|
512
|
-
|
|
513
|
-
messages event callback functions receive as arguments.
|
|
307
|
+
**Connection token must come to the frontend from application backend - i.e. must be generated on the backend side**. The way to deliver token to the application frontend is up to the developer. Usually you can pass it in template rendering context or issue a separate call to request a connection token from the backend.
|
|
514
308
|
|
|
515
|
-
|
|
309
|
+
If the token sets connection expiration then the client SDK will keep the token refreshed. It does this by calling a special callback function. This callback must return a new token. If a new token with updated connection expiration is returned from callback then it's sent to Centrifugo. If your callback returns an empty string – this means the user has no permission to connect to Centrifugo and the Client will move to a disconnected state. In case of error returned by your callback SDK will retry the operation after some jittered time.
|
|
516
310
|
|
|
517
|
-
|
|
311
|
+
An example of possible `getToken` function implementation:
|
|
518
312
|
|
|
519
313
|
```javascript
|
|
520
|
-
{
|
|
521
|
-
|
|
314
|
+
function getToken(url, ctx) {
|
|
315
|
+
return new Promise((resolve, reject) => {
|
|
316
|
+
fetch(url, {
|
|
317
|
+
method: 'POST',
|
|
318
|
+
headers: new Headers({ 'Content-Type': 'application/json' }),
|
|
319
|
+
body: JSON.stringify(ctx)
|
|
320
|
+
})
|
|
321
|
+
.then(res => {
|
|
322
|
+
if (!res.ok) {
|
|
323
|
+
throw new Error(`Unexpected status code ${res.status}`);
|
|
324
|
+
}
|
|
325
|
+
return res.json();
|
|
326
|
+
})
|
|
327
|
+
.then(data => {
|
|
328
|
+
resolve(data.token);
|
|
329
|
+
})
|
|
330
|
+
.catch(err => {
|
|
331
|
+
reject(err);
|
|
332
|
+
});
|
|
333
|
+
});
|
|
522
334
|
}
|
|
523
|
-
```
|
|
524
|
-
|
|
525
|
-
I.e. `data` field contains actual data that was published.
|
|
526
|
-
|
|
527
|
-
Message can optionally contain additional client `info` in case when this message was published by javascript client directly using `publish` method (see details below):
|
|
528
335
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
}
|
|
336
|
+
const client = new Centrifuge(
|
|
337
|
+
'ws://localhost:8000/connection/websocket',
|
|
338
|
+
{
|
|
339
|
+
token: 'JWT-GENERATED-ON-BACKEND-SIDE',
|
|
340
|
+
getToken: function (ctx) {
|
|
341
|
+
return getToken('/centrifuge/connection_token', ctx);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
);
|
|
539
345
|
```
|
|
540
346
|
|
|
541
|
-
|
|
347
|
+
:::tip
|
|
542
348
|
|
|
543
|
-
|
|
349
|
+
If initial token is not provided, but `getToken` is specified – then SDK assumes that developer wants to use token authentication. In this case SDK attempts to get a connection token before establishing an initial connection.
|
|
544
350
|
|
|
545
|
-
|
|
546
|
-
{
|
|
547
|
-
"info":{
|
|
548
|
-
"user":"2694",
|
|
549
|
-
"client":"2724adea-6e9b-460b-4430-a9f999e94c36",
|
|
550
|
-
"conn_info":{"first_name":"Alexandr"},
|
|
551
|
-
"chan_info":{"extra":"extra JSON data when authorizing"}
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
|
-
```
|
|
351
|
+
:::
|
|
555
352
|
|
|
556
|
-
|
|
353
|
+
## Subscription API
|
|
557
354
|
|
|
558
|
-
|
|
355
|
+
What we usually want from Centrifugo is to receive new messages published into channels. To do this we must create `Subscription` object.
|
|
559
356
|
|
|
560
|
-
|
|
357
|
+
### Subscription methods and events
|
|
561
358
|
|
|
562
|
-
|
|
563
|
-
{
|
|
564
|
-
"channel": "$public:chat",
|
|
565
|
-
"isResubscribe": true,
|
|
566
|
-
"recovered": false
|
|
567
|
-
}
|
|
568
|
-
```
|
|
359
|
+
#### Subscribe to a channel
|
|
569
360
|
|
|
570
|
-
|
|
571
|
-
`recovered` – boolean flag that indicated whether missed messages were recovered on reconnect or not (recovery works according to Centrifugo channel configuration)
|
|
361
|
+
The simplest usage that allow to subscribe on channel and listen to new messages is:
|
|
572
362
|
|
|
573
|
-
|
|
363
|
+
```javascript
|
|
364
|
+
const sub = centrifuge.newSubscription('example');
|
|
574
365
|
|
|
575
|
-
|
|
366
|
+
sub.on('publication', function(ctx) {
|
|
367
|
+
// handle new Publication data coming from channel "news".
|
|
368
|
+
console.log(ctx.data);
|
|
369
|
+
});
|
|
576
370
|
|
|
577
|
-
|
|
578
|
-
{
|
|
579
|
-
"error": "permission denied",
|
|
580
|
-
"channel": "$public:chat",
|
|
581
|
-
"isResubscribe": true
|
|
582
|
-
}
|
|
371
|
+
sub.subscribe();
|
|
583
372
|
```
|
|
584
373
|
|
|
585
|
-
|
|
586
|
-
|
|
374
|
+
#### Subscription events
|
|
375
|
+
|
|
376
|
+
Some events which can be listened on Subscription object are:
|
|
587
377
|
|
|
588
|
-
|
|
378
|
+
* `publication` – called when new publication received from a Subscription channel
|
|
379
|
+
* `join` – called when someone joined channel
|
|
380
|
+
* `leave` – called when someone left channel
|
|
381
|
+
* `subscribing` - called when Subscription goes to `subscribing` state (initial subscribe and re-subscribes)
|
|
382
|
+
* `subscribed` – called when Subscription goes to `subscribed` state
|
|
383
|
+
* `unsubscribed` – called when Subscription goes to `unsubscribed` state
|
|
384
|
+
* `error` – called when subscription on channel failed with error. It can be called several times
|
|
385
|
+
during lifetime as browser client automatically resubscribes on channels after successful reconnect
|
|
386
|
+
(caused by temporary network disconnect for example or Centrifugo server restart)
|
|
589
387
|
|
|
590
|
-
|
|
388
|
+
Don't be frightened by amount of events available. In most cases you only need some of them until you need full control to what happens with your subscriptions.
|
|
591
389
|
|
|
592
|
-
|
|
593
|
-
{
|
|
594
|
-
"channel": "$public:chat"
|
|
595
|
-
}
|
|
596
|
-
```
|
|
390
|
+
**`Subscription` objects are instances of [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter).**
|
|
597
391
|
|
|
598
|
-
|
|
392
|
+
#### presence method of Subscription
|
|
599
393
|
|
|
600
394
|
`presence` allows to get information about clients which are subscribed on channel at
|
|
601
395
|
this moment. Note that this information is only available if `presence` option enabled
|
|
602
396
|
in Centrifugo configuration for all channels or for channel namespace.
|
|
603
397
|
|
|
604
398
|
```javascript
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
});
|
|
399
|
+
const sub = centrifuge.newSubscription("news");
|
|
400
|
+
sub.subscribe()
|
|
608
401
|
|
|
609
|
-
|
|
610
|
-
|
|
402
|
+
sub.presence().then(function(ctx) {
|
|
403
|
+
console.log(ctx.clients);
|
|
611
404
|
}, function(err) {
|
|
612
405
|
// presence call failed with error
|
|
613
406
|
});
|
|
614
407
|
```
|
|
615
408
|
|
|
616
|
-
`presence` is internally a promise that will be
|
|
617
|
-
when subscription actually subscribed.
|
|
618
|
-
|
|
619
|
-
Format of success callback `message`:
|
|
620
|
-
|
|
621
|
-
```javascript
|
|
622
|
-
{
|
|
623
|
-
"presence":{
|
|
624
|
-
"2724adea-6e9b-460b-4430-a9f999e94c36": {
|
|
625
|
-
"user":"2694",
|
|
626
|
-
"client":"2724adea-6e9b-460b-4430-a9f999e94c36"
|
|
627
|
-
},
|
|
628
|
-
"d274505c-ce63-4e24-77cf-971fd8a59f00":{
|
|
629
|
-
"user":"2694",
|
|
630
|
-
"client":"d274505c-ce63-4e24-77cf-971fd8a59f00"
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
}
|
|
634
|
-
```
|
|
409
|
+
`presence` is internally a promise that will be waiting for subscription subscribe success if required.
|
|
635
410
|
|
|
636
411
|
As you can see presence data is a map where keys are client IDs and values are objects
|
|
637
412
|
with client information.
|
|
@@ -640,8 +415,8 @@ Format of `err` in error callback:
|
|
|
640
415
|
|
|
641
416
|
```javascript
|
|
642
417
|
{
|
|
643
|
-
"code":
|
|
644
|
-
"message": "
|
|
418
|
+
"code": 108,
|
|
419
|
+
"message": "not available"
|
|
645
420
|
}
|
|
646
421
|
```
|
|
647
422
|
|
|
@@ -650,68 +425,37 @@ Format of `err` in error callback:
|
|
|
650
425
|
|
|
651
426
|
*Note, that in order presence to work corresponding options must be enabled in server channel configuration (on top level or for channel namespace)*
|
|
652
427
|
|
|
653
|
-
|
|
428
|
+
#### presenceStats method of subscription
|
|
654
429
|
|
|
655
430
|
`presenceStats` allows to get two counters from a server: number of total clients currently subscribed and number of unique users currently subscribed. Note that this information is only available if `presence` option enabled in server configuration for a channel.
|
|
656
431
|
|
|
657
432
|
```javascript
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
});
|
|
661
|
-
|
|
662
|
-
subscription.presenceStats().then(function(resp) {
|
|
663
|
-
// presence stats data received
|
|
433
|
+
sub.presenceStats().then(function(ctx) {
|
|
434
|
+
console.log(ctx.numClients);
|
|
664
435
|
}, function(err) {
|
|
665
436
|
// presence stats call failed with error
|
|
666
437
|
});
|
|
667
438
|
```
|
|
668
439
|
|
|
669
|
-
|
|
440
|
+
#### history method of subscription
|
|
670
441
|
|
|
671
|
-
`history` method allows to get last messages published into channel. Note that history
|
|
672
|
-
for channel must be configured in Centrifugo to be available for `history` calls from
|
|
673
|
-
client.
|
|
442
|
+
`history` method allows to get last messages published into channel. Note that history for channel must be configured in Centrifugo to be available for `history` calls from client.
|
|
674
443
|
|
|
675
444
|
```javascript
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
subscription.history().then(function(response) {
|
|
681
|
-
// history messages received
|
|
445
|
+
sub.history({limit: 100}).then(function(ctx) {
|
|
446
|
+
console.log(ctx.publications);
|
|
682
447
|
}, function(err) {
|
|
683
448
|
// history call failed with error
|
|
684
449
|
});
|
|
685
450
|
```
|
|
686
451
|
|
|
687
|
-
Success callback `response` format:
|
|
688
|
-
|
|
689
|
-
```javascript
|
|
690
|
-
{
|
|
691
|
-
"publications": [
|
|
692
|
-
{
|
|
693
|
-
"data": {"input": "hello2"},
|
|
694
|
-
"offset": 1
|
|
695
|
-
},
|
|
696
|
-
{
|
|
697
|
-
"data": {"input": "hello1"},
|
|
698
|
-
"offset": 2
|
|
699
|
-
}
|
|
700
|
-
],
|
|
701
|
-
"offset": 2,
|
|
702
|
-
"epoch": "xcf4w"
|
|
703
|
-
}
|
|
704
|
-
```
|
|
705
|
-
|
|
706
|
-
Where `publications` is an array of messages published into channel, `offset` is a current stream top offset (added in v2.7.0), `epoch` is a current stream epoch (added in v2.7.0).
|
|
707
|
-
|
|
708
|
-
Note that also additional fields can be included in publication objects - `client`, `info` if those fields were set in original publications.
|
|
709
|
-
|
|
710
|
-
`err` format – the same as for `presence` method.
|
|
711
|
-
|
|
712
452
|
*Note, that in order history to work corresponding options must be enabled in server channel configuration (on top level or for channel namespace)*
|
|
713
453
|
|
|
714
|
-
|
|
454
|
+
Some history options available:
|
|
455
|
+
|
|
456
|
+
* `limit` (number)
|
|
457
|
+
* `since` (StreamPosition)
|
|
458
|
+
* `reverse` (boolean)
|
|
715
459
|
|
|
716
460
|
```javascript
|
|
717
461
|
resp = await subscription.history({'since': {'offset': 2, 'epoch': 'xcf4w'}, limit: 100});
|
|
@@ -727,22 +471,16 @@ resp = await subscription.history({limit: 0});
|
|
|
727
471
|
|
|
728
472
|
I.e. not providing `since` and using zero `limit`.
|
|
729
473
|
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
### publish method of subscription
|
|
474
|
+
#### publish method of subscription
|
|
733
475
|
|
|
734
|
-
`publish` method of
|
|
476
|
+
`publish` method of Subscription object allows publishing data into channel directly from a client.
|
|
735
477
|
|
|
736
|
-
**
|
|
478
|
+
**Using client-side publish is not an idiomatic Centrifugo usage in many cases. Centrifugo is standalone server and when publishing from a client you won't get the message on the backend side (except using publish proxy feature of Centrifugo). In most real-life apps you need to send new data to your application backend first (using the convenient way, for example AJAX request in web app) and then publish data to Centrifugo over Centrifugo API.**
|
|
737
479
|
|
|
738
|
-
|
|
480
|
+
*Just like presence and history publish must be allowed in Centrifugo configuration for all channels or for channel namespace.*
|
|
739
481
|
|
|
740
482
|
```javascript
|
|
741
|
-
|
|
742
|
-
// handle message
|
|
743
|
-
});
|
|
744
|
-
|
|
745
|
-
subscription.publish({"input": "hello world"}).then(function() {
|
|
483
|
+
sub.publish({"input": "hello world"}).then(function() {
|
|
746
484
|
// success ack from Centrifugo received
|
|
747
485
|
}, function(err) {
|
|
748
486
|
// publish call failed with error
|
|
@@ -750,78 +488,91 @@ subscription.publish({"input": "hello world"}).then(function() {
|
|
|
750
488
|
});
|
|
751
489
|
```
|
|
752
490
|
|
|
753
|
-
|
|
491
|
+
*Note, that in order publish to work in Centrifugo corresponding option must be enabled in server channel configuration or client should have capability to publish*.
|
|
754
492
|
|
|
755
|
-
|
|
493
|
+
#### unsubscribe method of subscription
|
|
756
494
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
You can call `unsubscribe` method to unsubscribe from subscription:
|
|
495
|
+
You can call `unsubscribe` method to unsubscribe from a channel:
|
|
760
496
|
|
|
761
497
|
```javascript
|
|
762
|
-
|
|
498
|
+
sub.unsubscribe();
|
|
763
499
|
```
|
|
764
500
|
|
|
765
|
-
**Important thing to know** is that unsubscribing from subscription does not remove event
|
|
501
|
+
**Important thing to know** is that unsubscribing from subscription does not remove event handlers you already set to that Subscription object. This allows to simply subscribe to channel again later calling `.subscribe()` method of subscription (see below). But there are cases when your code structured in a way that you need to remove event handlers after unsubscribe **to prevent them be executed twice** in the future. To do this remove event listeners explicitly after calling `unsubscribe()`:
|
|
766
502
|
|
|
767
503
|
```javascript
|
|
768
|
-
|
|
769
|
-
|
|
504
|
+
sub.unsubscribe();
|
|
505
|
+
sub.removeAllListeners();
|
|
770
506
|
```
|
|
771
507
|
|
|
772
|
-
|
|
508
|
+
#### ready method of subscription
|
|
509
|
+
|
|
510
|
+
Returns a Promise which will be resolved upon subscription success (i.e. when Subscription goes to `subscribed` state).
|
|
511
|
+
|
|
512
|
+
### Subscription token
|
|
773
513
|
|
|
774
|
-
You
|
|
514
|
+
You may want to provide subscription token:
|
|
775
515
|
|
|
776
516
|
```javascript
|
|
777
|
-
|
|
517
|
+
const sub = centrifuge.newSubscription("news", {
|
|
518
|
+
token: '<SUBSCRIPTION_TOKEN>'
|
|
519
|
+
});
|
|
778
520
|
```
|
|
779
521
|
|
|
780
|
-
|
|
522
|
+
In case of Centrifugo on a server side this may be a JSON Web Token - see [channel token auth documentation](https://centrifugal.github.io/centrifugo/server/channel_token_auth) for details on how to generate it on your backend side.
|
|
781
523
|
|
|
782
|
-
|
|
783
|
-
handlers can be set after `subscribe` event of underlying subscription already fired. This
|
|
784
|
-
is not a problem in general but can be actual if you use one subscription (i.e. subscription
|
|
785
|
-
to the same channel) from different parts of your javascript application - so be careful.
|
|
524
|
+
**Subscription token must come to the frontend from application backend - i.e. must be generated on the backend side**. The way to deliver token to the application frontend is up to the developer. Usually you can pass it in template rendering context or issue a separate call to request a connection token from the backend.
|
|
786
525
|
|
|
787
|
-
|
|
788
|
-
`callback` if subscription already subscribed and calls `errback` if subscription already
|
|
789
|
-
failed to subscribe with some error (because you subscribed on this channel before). So
|
|
790
|
-
when you want to call subscribe on channel already subscribed before you may find `ready()`
|
|
791
|
-
method useful:
|
|
526
|
+
If token sets subscription expiration client SDK will keep token refreshed. It does this by calling special callback function. This callback must return a new token. If new token with updated subscription expiration returned from a calbback then it's sent to Centrifugo. If your callback returns an empty string – this means user has no permission to subscribe to a channel anymore and subscription will be unsubscribed. In case of error returned by your callback SDK will retry operation after some jittered time.
|
|
792
527
|
|
|
793
|
-
|
|
794
|
-
var subscription = centrifuge.subscribe("news", function(message) {
|
|
795
|
-
// handle message;
|
|
796
|
-
});
|
|
528
|
+
An example:
|
|
797
529
|
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
530
|
+
```javascript
|
|
531
|
+
function getToken(url, ctx) {
|
|
532
|
+
return new Promise((resolve, reject) => {
|
|
533
|
+
fetch(url, {
|
|
534
|
+
method: 'POST',
|
|
535
|
+
headers: new Headers({ 'Content-Type': 'application/json' }),
|
|
536
|
+
body: JSON.stringify(ctx)
|
|
537
|
+
})
|
|
538
|
+
.then(res => {
|
|
539
|
+
if (!res.ok) {
|
|
540
|
+
throw new Error(`Unexpected status code ${res.status}`);
|
|
541
|
+
}
|
|
542
|
+
return res.json();
|
|
543
|
+
})
|
|
544
|
+
.then(data => {
|
|
545
|
+
resolve(data.token);
|
|
546
|
+
})
|
|
547
|
+
.catch(err => {
|
|
548
|
+
reject(err);
|
|
549
|
+
});
|
|
808
550
|
});
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
const client = new Centrifuge('ws://localhost:8000/connection/websocket', {});
|
|
554
|
+
|
|
555
|
+
const sub = centrifuge.newSubscription(channel, {
|
|
556
|
+
token: 'JWT-GENERATED-ON-BACKEND-SIDE',
|
|
557
|
+
getToken: function (ctx) {
|
|
558
|
+
// ctx has channel in the Subscription token case.
|
|
559
|
+
return getToken('/centrifuge/subscription_token', ctx);
|
|
560
|
+
},
|
|
561
|
+
});
|
|
562
|
+
sub.subscribe();
|
|
813
563
|
```
|
|
814
564
|
|
|
815
|
-
|
|
816
|
-
|
|
565
|
+
:::tip
|
|
566
|
+
|
|
567
|
+
If initial token is not provided, but `getToken` is specified – then SDK assumes that developer wants to use token authorization for a channel subscription. In this case SDK attempts to get a subscription token before initial subscribe.
|
|
817
568
|
|
|
818
|
-
|
|
569
|
+
:::
|
|
819
570
|
|
|
820
|
-
|
|
821
|
-
in one request - this can be especially useful when connection established via one of
|
|
822
|
-
SockJS polling transports.
|
|
571
|
+
## Message batching
|
|
823
572
|
|
|
824
|
-
|
|
573
|
+
There is also a command batching support. It allows to send several commands to a server in one request - may be especially useful when connection established via one of HTTP-based transports.
|
|
574
|
+
|
|
575
|
+
You can start collecting commands by calling `startBatching()` method:
|
|
825
576
|
|
|
826
577
|
```javascript
|
|
827
578
|
centrifuge.startBatching();
|
|
@@ -833,98 +584,111 @@ Finally if you don't want batching anymore call `stopBatching()` method:
|
|
|
833
584
|
centrifuge.stopBatching();
|
|
834
585
|
```
|
|
835
586
|
|
|
836
|
-
This call will flush all collected
|
|
587
|
+
This call will flush all collected commands to a network.
|
|
837
588
|
|
|
838
|
-
##
|
|
589
|
+
## Server-side subscriptions
|
|
839
590
|
|
|
840
|
-
|
|
591
|
+
TODO.
|
|
841
592
|
|
|
842
|
-
|
|
593
|
+
## Configuration parameters
|
|
843
594
|
|
|
844
|
-
|
|
845
|
-
centrifuge.subscribe('$private', function(message) {
|
|
846
|
-
// process message
|
|
847
|
-
});
|
|
848
|
-
```
|
|
595
|
+
Let's look at available configuration parameters when initializing `Centrifuge` object instance.
|
|
849
596
|
|
|
850
|
-
|
|
597
|
+
### debug
|
|
851
598
|
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
"channels": ["$chan1", "$chan2"]
|
|
856
|
-
}
|
|
857
|
-
```
|
|
599
|
+
`debug` is a boolean option which is `false` by default. When enabled lots of various debug
|
|
600
|
+
messages will be logged into javascript console. Mostly useful for development or
|
|
601
|
+
troubleshooting.
|
|
858
602
|
|
|
859
|
-
|
|
603
|
+
### minReconnectDelay
|
|
860
604
|
|
|
861
|
-
|
|
605
|
+
When client disconnected from a server it will automatically try to reconnect using a backoff algorithm with jitter. `minReconnectDelay` option sets minimal interval value in milliseconds before first reconnect attempt. Default is `500` milliseconds.
|
|
862
606
|
|
|
863
|
-
|
|
864
|
-
{
|
|
865
|
-
"channels": [
|
|
866
|
-
{
|
|
867
|
-
"channel": "$chan1",
|
|
868
|
-
"token": "<SUBSCRIPTION JWT TOKEN>"
|
|
869
|
-
},
|
|
870
|
-
{
|
|
871
|
-
"channel": "$chan2",
|
|
872
|
-
"token": <SUBSCRIPTION JWT TOKEN>
|
|
873
|
-
}
|
|
874
|
-
]
|
|
875
|
-
}
|
|
876
|
-
```
|
|
607
|
+
### maxReconnectDelay
|
|
877
608
|
|
|
878
|
-
|
|
609
|
+
`maxReconnectDelay` sets an upper reconnect delay value. Default is `20000` milliseconds - i.e. clients won't have delays between reconnect attempts which are larger than 20 seconds.
|
|
879
610
|
|
|
880
|
-
|
|
611
|
+
### maxServerPingDelay
|
|
881
612
|
|
|
882
|
-
|
|
613
|
+
`maxServerPingDelay` sets the maximum delay of server pings after which connection is considered broken and client reconnects.
|
|
883
614
|
|
|
884
|
-
|
|
615
|
+
### protocol
|
|
885
616
|
|
|
886
|
-
|
|
617
|
+
By default, client works using `json` protocol. If you want to use binary transfer with Protobuf-based protocol this option must be set to `protobuf`. See more details about Protobuf communication in a special chapter.
|
|
887
618
|
|
|
888
|
-
|
|
619
|
+
### token
|
|
889
620
|
|
|
890
|
-
|
|
621
|
+
Set initial connection token.
|
|
891
622
|
|
|
892
|
-
|
|
893
|
-
var centrifuge = new Centrifuge(address);
|
|
623
|
+
### getToken
|
|
894
624
|
|
|
895
|
-
|
|
896
|
-
const channel = ctx.channel;
|
|
897
|
-
const payload = JSON.stringify(ctx.data);
|
|
898
|
-
console.log('Publication from server-side channel', channel, payload);
|
|
899
|
-
});
|
|
625
|
+
Set function for getting connection token. This may be used for initial token loading and token refresh mechanism (when initial token is going to expire).
|
|
900
626
|
|
|
901
|
-
|
|
902
|
-
|
|
627
|
+
### data
|
|
628
|
+
|
|
629
|
+
Set custom data to send to a server withing every connect command.
|
|
630
|
+
|
|
631
|
+
### name
|
|
632
|
+
|
|
633
|
+
Set custom client name. By default, it's set to `js`. This is useful for analitycs and semantically must identify an environment from which client establishes a connection.
|
|
634
|
+
|
|
635
|
+
### version
|
|
636
|
+
|
|
637
|
+
Version of your application - useful for analitycs.
|
|
638
|
+
|
|
639
|
+
### timeout
|
|
640
|
+
|
|
641
|
+
Timeout for operations.
|
|
903
642
|
|
|
904
|
-
|
|
643
|
+
### websocket
|
|
905
644
|
|
|
906
|
-
|
|
645
|
+
`websocket` option allows to explicitly provide custom WebSocket client to use. By default centrifuge-js will try to use global WebSocket object, so if you are in web browser – it will just use native WebSocket implementation. See notes about using `centrifuge-js` with NodeJS below.
|
|
646
|
+
|
|
647
|
+
### sockjs
|
|
648
|
+
|
|
649
|
+
`sockjs` option allows to explicitly provide SockJS client object to Centrifuge client.
|
|
650
|
+
|
|
651
|
+
For example this can be useful if you develop in ES6 with imports:
|
|
907
652
|
|
|
908
653
|
```javascript
|
|
909
|
-
centrifuge
|
|
910
|
-
|
|
911
|
-
});
|
|
654
|
+
import Centrifuge from 'centrifuge'
|
|
655
|
+
import SockJS from 'sockjs-client'
|
|
912
656
|
|
|
913
|
-
centrifuge
|
|
914
|
-
|
|
657
|
+
const centrifuge = new Centrifuge('https://centrifuge.example.com/connection/sockjs', {
|
|
658
|
+
sockjs: SockJS
|
|
915
659
|
});
|
|
916
660
|
```
|
|
917
661
|
|
|
918
|
-
|
|
662
|
+
### sockjsTransports
|
|
919
663
|
|
|
920
|
-
|
|
664
|
+
In case of using SockJS additional configuration parameter can be used - `sockjsTransports`.
|
|
665
|
+
|
|
666
|
+
It defines allowed SockJS transports.
|
|
921
667
|
|
|
922
668
|
```javascript
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
669
|
+
const centrifuge = new Centrifuge(
|
|
670
|
+
'http://centrifuge.example.com/connection/sockjs',
|
|
671
|
+
{
|
|
672
|
+
sockjsTransports: [
|
|
673
|
+
'websocket',
|
|
674
|
+
'xdr-streaming',
|
|
675
|
+
'xhr-streaming',
|
|
676
|
+
'eventsource',
|
|
677
|
+
'iframe-eventsource',
|
|
678
|
+
'iframe-htmlfile',
|
|
679
|
+
'xdr-polling',
|
|
680
|
+
'xhr-polling',
|
|
681
|
+
'iframe-xhr-polling',
|
|
682
|
+
'jsonp-polling'
|
|
683
|
+
]
|
|
684
|
+
});
|
|
926
685
|
```
|
|
927
686
|
|
|
687
|
+
### sockjsServer
|
|
688
|
+
|
|
689
|
+
`sockjsServer` is SockJS specific option to set server name into connection urls instead
|
|
690
|
+
of random chars. See SockJS docs for more info.
|
|
691
|
+
|
|
928
692
|
## Protobuf support
|
|
929
693
|
|
|
930
694
|
To import client with Protobuf protocol support:
|
|
@@ -936,42 +700,28 @@ To import client with Protobuf protocol support:
|
|
|
936
700
|
Or if you are developing with npm:
|
|
937
701
|
|
|
938
702
|
```javascript
|
|
939
|
-
import Centrifuge from 'centrifuge/
|
|
703
|
+
import Centrifuge from 'centrifuge/build/protobuf';
|
|
940
704
|
```
|
|
941
705
|
|
|
942
706
|
This client uses [protobuf.js](https://github.com/dcodeIO/ProtoBuf.js/) under the hood.
|
|
943
707
|
|
|
944
|
-
Centrifuge client with Protobuf support also works with JSON. To enable binary websocket add `
|
|
945
|
-
|
|
946
|
-
```javascript
|
|
947
|
-
var centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket?format=protobuf');
|
|
948
|
-
```
|
|
949
|
-
|
|
950
|
-
When using Centrifugo v3 or Centrifuge >= v0.18.0 on server side prefer using client options instead of setting format in URL (available in `centrifuge-js` >= v2.8.0):
|
|
708
|
+
Centrifuge client with Protobuf support also works with JSON. To enable binary websocket add `protocol: "protobuf"` option to Centrifuge configuration options:
|
|
951
709
|
|
|
952
710
|
```javascript
|
|
953
|
-
|
|
711
|
+
const centrifuge = new Centrifuge('ws://centrifuge.example.com/connection/websocket", {
|
|
954
712
|
protocol: 'protobuf'
|
|
955
713
|
});
|
|
956
714
|
```
|
|
957
715
|
|
|
958
716
|
## Browser support
|
|
959
717
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
**To support IE 11** you must additionally polyfill `Promise` as this library uses `Promise`.
|
|
963
|
-
|
|
964
|
-
You can easily polyfill `Promise` via CDN (example here uses [es6-promise](https://github.com/stefanpenner/es6-promise) library):
|
|
965
|
-
|
|
966
|
-
```html
|
|
967
|
-
<script src="https://cdn.jsdelivr.net/npm/es6-promise@4/dist/es6-promise.auto.min.js"></script>
|
|
968
|
-
```
|
|
969
|
-
|
|
970
|
-
Or you can explicitly polyfill `Promise` in your code, see [auto-polyfill of es6-promise](https://github.com/stefanpenner/es6-promise#auto-polyfill)
|
|
718
|
+
TODO.
|
|
971
719
|
|
|
972
720
|
## Using with NodeJS
|
|
973
721
|
|
|
974
|
-
NodeJS does not have native WebSocket library in std lib. To use `centrifuge-js` on Node you need to provide WebSocket
|
|
722
|
+
NodeJS does not have native WebSocket library in std lib. To use `centrifuge-js` on Node you need to explicitly provide WebSocket constructor to the library.
|
|
723
|
+
|
|
724
|
+
First, install WebSocket dependency:
|
|
975
725
|
|
|
976
726
|
```
|
|
977
727
|
npm install ws
|
|
@@ -1008,24 +758,7 @@ var centrifuge = new Centrifuge('ws://localhost:8000/connection/sockjs', {
|
|
|
1008
758
|
})
|
|
1009
759
|
```
|
|
1010
760
|
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
To work with private channels you may need to pass `XMLHttpRequest` object to library:
|
|
1014
|
-
|
|
1015
|
-
```javascript
|
|
1016
|
-
const Centrifuge = require('centrifuge');
|
|
1017
|
-
const WebSocket = require('ws');
|
|
1018
|
-
const XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;
|
|
1019
|
-
|
|
1020
|
-
var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
|
|
1021
|
-
websocket: WebSocket,
|
|
1022
|
-
xmlhttprequest: XMLHttpRequest
|
|
1023
|
-
})
|
|
1024
|
-
```
|
|
1025
|
-
|
|
1026
|
-
Or define XMLHttpRequest globally over `global.XMLHttpRequest = require("xmlhttprequest").XMLHttpRequest;`
|
|
1027
|
-
|
|
1028
|
-
### Custom WebSocket constructor
|
|
761
|
+
## Custom WebSocket constructor
|
|
1029
762
|
|
|
1030
763
|
If you are building a client for a non-browser environment and want to pass custom headers then you can use the following approach to wrap a WebSocket constructor and let custom options to be used on connection initialization:
|
|
1031
764
|
|
|
@@ -1049,53 +782,3 @@ var centrifuge = new Centrifuge('ws://localhost:8000/connection/websocket', {
|
|
|
1049
782
|
websocket: myWs({ headers: { Authorization: '<token or key>' } }),
|
|
1050
783
|
});
|
|
1051
784
|
```
|
|
1052
|
-
|
|
1053
|
-
### Subscribe since known position
|
|
1054
|
-
|
|
1055
|
-
Available in `centrifuge-js` >= v2.8.0.
|
|
1056
|
-
|
|
1057
|
-
Subscribe API supports setting known StreamPosition object to use server recovery feature on the connection start (otherwise recovery only used upon client reconnections due to temporary connection problems).
|
|
1058
|
-
|
|
1059
|
-
```javascript
|
|
1060
|
-
centrifuge.subscribe('channel', function(messageCtx) {
|
|
1061
|
-
console.log('new message', messageCtx);
|
|
1062
|
-
}, {'since': {'offset': 0, 'epoch': '<EPOCH>'}});
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
## Feature matrix
|
|
1066
|
-
|
|
1067
|
-
- [x] connect to server using JSON protocol format
|
|
1068
|
-
- [x] connect to server using Protobuf protocol format
|
|
1069
|
-
- [x] connect with token (JWT)
|
|
1070
|
-
- [ ] connect with custom header (not supported by browser API, though [possible for a non-browser target env](https://github.com/centrifugal/centrifuge-js#custom-websocket-constructor))
|
|
1071
|
-
- [x] automatic reconnect in case of errors, network problems etc
|
|
1072
|
-
- [x] an exponential backoff for reconnect
|
|
1073
|
-
- [x] connect and disconnect events
|
|
1074
|
-
- [x] handle disconnect reason
|
|
1075
|
-
- [x] subscribe on a channel and handle asynchronous Publications
|
|
1076
|
-
- [x] handle Join and Leave messages
|
|
1077
|
-
- [x] handle Unsubscribe notifications
|
|
1078
|
-
- [x] reconnect on subscribe timeout
|
|
1079
|
-
- [x] publish method of Subscription
|
|
1080
|
-
- [x] unsubscribe method of Subscription
|
|
1081
|
-
- [x] presence method of Subscription
|
|
1082
|
-
- [x] presence stats method of Subscription
|
|
1083
|
-
- [x] history method of Subscription
|
|
1084
|
-
- [x] top-level publish method
|
|
1085
|
-
- [x] top-level presence method
|
|
1086
|
-
- [x] top-level presence stats method
|
|
1087
|
-
- [x] top-level history method
|
|
1088
|
-
- [ ] top-level unsubscribe method
|
|
1089
|
-
- [x] send asynchronous messages to server
|
|
1090
|
-
- [x] handle asynchronous messages from server
|
|
1091
|
-
- [x] send RPC commands
|
|
1092
|
-
- [x] subscribe to private channels with token (JWT)
|
|
1093
|
-
- [x] connection token (JWT) refresh
|
|
1094
|
-
- [x] private channel subscription token (JWT) refresh
|
|
1095
|
-
- [x] handle connection expired error
|
|
1096
|
-
- [x] handle subscription expired error
|
|
1097
|
-
- [x] ping/pong to find broken connection
|
|
1098
|
-
- [x] message recovery mechanism for client-side subscriptions
|
|
1099
|
-
- [x] server-side subscriptions
|
|
1100
|
-
- [x] message recovery mechanism for server-side subscriptions
|
|
1101
|
-
- [x] history stream pagination
|