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