@styris-ame/y-engineio 1.1.0 → 2.1.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 +18 -15
- package/dist/y-engineio.cjs +133 -29
- package/dist/y-engineio.cjs.map +1 -1
- package/dist/y-engineio.d.ts +49 -5
- package/dist/y-engineio.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/y-engineio.js +130 -29
package/README.md
CHANGED
|
@@ -10,23 +10,23 @@ Why Engine.IO? It negotiates a transport (HTTP long-polling → WebSocket →
|
|
|
10
10
|
WebTransport) and transparently falls back when WebSockets are blocked by a
|
|
11
11
|
proxy, which a raw `WebSocket` cannot do.
|
|
12
12
|
|
|
13
|
-
This is the
|
|
14
|
-
|
|
13
|
+
This is the v4 / `main`-branch port: it targets **Yjs v14** (`@y/y`,
|
|
14
|
+
`@y/protocols`) and includes the `sync-status` feature.
|
|
15
15
|
|
|
16
16
|
## Yjs v13 vs v14
|
|
17
17
|
|
|
18
|
-
This `
|
|
19
|
-
|
|
20
|
-
(dist-tag `
|
|
18
|
+
This `2.x` line (dist-tag `yjs14`) targets **Yjs v14** (`@y/y`, `@y/protocols`).
|
|
19
|
+
For **Yjs v13** (`yjs`, `y-protocols`, `lib0@^0.2`) install the `1.x` line
|
|
20
|
+
(dist-tag `yjs13`): `npm i @styris-ame/y-engineio@yjs13 yjs`.
|
|
21
21
|
|
|
22
22
|
## Quick Start
|
|
23
23
|
|
|
24
24
|
```sh
|
|
25
|
-
npm i @styris-ame/y-engineio@
|
|
25
|
+
npm i @styris-ame/y-engineio@yjs14 engine.io-client @y/y
|
|
26
26
|
```
|
|
27
27
|
|
|
28
28
|
```js
|
|
29
|
-
import * as Y from '
|
|
29
|
+
import * as Y from '@y/y'
|
|
30
30
|
import { EngineIOProvider } from '@styris-ame/y-engineio'
|
|
31
31
|
|
|
32
32
|
const doc = new Y.Doc()
|
|
@@ -49,8 +49,8 @@ provider.on('status', event => {
|
|
|
49
49
|
|
|
50
50
|
Everything else — the `messageSync` / `messageAwareness` / `messageAuth` /
|
|
51
51
|
`messageQueryAwareness` protocol, exponential-backoff reconnect, the
|
|
52
|
-
`socketTimeout` watchdog, `sync` events, and cross-tab
|
|
53
|
-
is unchanged from y-websocket.
|
|
52
|
+
`socketTimeout` watchdog, `sync` / `sync-status` events, and cross-tab
|
|
53
|
+
BroadcastChannel sync — is unchanged from y-websocket.
|
|
54
54
|
|
|
55
55
|
## Wire protocol (for server authors)
|
|
56
56
|
|
|
@@ -59,9 +59,9 @@ Every frame is binary (engine.io binary message) and starts with a
|
|
|
59
59
|
|
|
60
60
|
| type | const | direction | payload |
|
|
61
61
|
|---|---|---|---|
|
|
62
|
-
| `0` | `messageSync` | both |
|
|
62
|
+
| `0` | `messageSync` | both | `@y/protocols/sync` message |
|
|
63
63
|
| `1` | `messageAwareness` | both | `varUint8Array` awareness update |
|
|
64
|
-
| `2` | `messageAuth` | server→client |
|
|
64
|
+
| `2` | `messageAuth` | server→client | `@y/protocols/auth` message |
|
|
65
65
|
| `3` | `messageQueryAwareness` | both | (empty) |
|
|
66
66
|
|
|
67
67
|
### Room handshake
|
|
@@ -115,10 +115,13 @@ following `opts` are supported:
|
|
|
115
115
|
```
|
|
116
116
|
|
|
117
117
|
Instance fields & events match y-websocket, except the `ws`-prefixed fields are
|
|
118
|
-
renamed
|
|
119
|
-
`
|
|
120
|
-
`
|
|
121
|
-
`
|
|
118
|
+
renamed (`connected`, `connecting`, `unsuccessfulReconnects`,
|
|
119
|
+
`lastMessageReceived`): `connected`, `connecting`,
|
|
120
|
+
`shouldConnect`, `bcconnected`, `synced`, `syncStatus`, `params`,
|
|
121
|
+
`connect()`, `disconnect()`, `destroy()`, and the `status`, `sync`,
|
|
122
|
+
`sync-status`, `connection-close`, `connection-error` events. The live socket is
|
|
123
|
+
exposed as `provider.engine` (an engine.io-client `Socket`) rather than
|
|
124
|
+
`provider.ws`.
|
|
122
125
|
|
|
123
126
|
## License
|
|
124
127
|
|
package/dist/y-engineio.cjs
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('
|
|
3
|
+
var Y = require('@y/y');
|
|
4
4
|
var bc = require('lib0/broadcastchannel');
|
|
5
5
|
var time = require('lib0/time');
|
|
6
6
|
var encoding = require('lib0/encoding');
|
|
7
7
|
var decoding = require('lib0/decoding');
|
|
8
|
-
var syncProtocol = require('y
|
|
9
|
-
var authProtocol = require('y
|
|
10
|
-
var awarenessProtocol = require('y
|
|
8
|
+
var syncProtocol = require('@y/protocols/sync');
|
|
9
|
+
var authProtocol = require('@y/protocols/auth');
|
|
10
|
+
var awarenessProtocol = require('@y/protocols/awareness');
|
|
11
11
|
var observable = require('lib0/observable');
|
|
12
12
|
var math = require('lib0/math');
|
|
13
13
|
var url = require('lib0/url');
|
|
14
14
|
var env = require('lib0/environment');
|
|
15
|
+
var array = require('lib0/array');
|
|
15
16
|
var engine_ioClient = require('engine.io-client');
|
|
16
17
|
|
|
17
18
|
function _interopNamespaceDefault(e) {
|
|
@@ -31,6 +32,7 @@ function _interopNamespaceDefault(e) {
|
|
|
31
32
|
return Object.freeze(n);
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
var Y__namespace = /*#__PURE__*/_interopNamespaceDefault(Y);
|
|
34
36
|
var bc__namespace = /*#__PURE__*/_interopNamespaceDefault(bc);
|
|
35
37
|
var time__namespace = /*#__PURE__*/_interopNamespaceDefault(time);
|
|
36
38
|
var encoding__namespace = /*#__PURE__*/_interopNamespaceDefault(encoding);
|
|
@@ -41,6 +43,7 @@ var awarenessProtocol__namespace = /*#__PURE__*/_interopNamespaceDefault(awarene
|
|
|
41
43
|
var math__namespace = /*#__PURE__*/_interopNamespaceDefault(math);
|
|
42
44
|
var url__namespace = /*#__PURE__*/_interopNamespaceDefault(url);
|
|
43
45
|
var env__namespace = /*#__PURE__*/_interopNamespaceDefault(env);
|
|
46
|
+
var array__namespace = /*#__PURE__*/_interopNamespaceDefault(array);
|
|
44
47
|
|
|
45
48
|
/**
|
|
46
49
|
* @module provider/engineio
|
|
@@ -66,6 +69,7 @@ messageHandlers[messageSync] = (
|
|
|
66
69
|
_messageType
|
|
67
70
|
) => {
|
|
68
71
|
encoding__namespace.writeVarUint(encoder, messageSync);
|
|
72
|
+
const readSyncPos = decoder.pos;
|
|
69
73
|
const syncMessageType = syncProtocol__namespace.readSyncMessage(
|
|
70
74
|
decoder,
|
|
71
75
|
encoder,
|
|
@@ -78,6 +82,19 @@ messageHandlers[messageSync] = (
|
|
|
78
82
|
) {
|
|
79
83
|
provider.synced = true;
|
|
80
84
|
}
|
|
85
|
+
// update unconfirmedUpdates
|
|
86
|
+
if (syncMessageType === 1 || syncMessageType === 2) {
|
|
87
|
+
const subdecoder = decoding__namespace.createDecoder(decoder.arr);
|
|
88
|
+
subdecoder.pos = readSyncPos;
|
|
89
|
+
decoding__namespace.readVarUint(subdecoder); // === syncMessageType
|
|
90
|
+
const update = decoding__namespace.readVarUint8Array(subdecoder);
|
|
91
|
+
const receivedIds = Y__namespace.createContentIdsFromUpdate(update);
|
|
92
|
+
provider.unconfirmedUpdates = provider.unconfirmedUpdates.filter(unconfirmed => {
|
|
93
|
+
unconfirmed.ids = Y__namespace.excludeContentIds(unconfirmed.ids, receivedIds);
|
|
94
|
+
return !unconfirmed.ids.inserts.isEmpty() || !unconfirmed.ids.deletes.isEmpty()
|
|
95
|
+
});
|
|
96
|
+
emitSyncStatusEvent(provider);
|
|
97
|
+
}
|
|
81
98
|
};
|
|
82
99
|
|
|
83
100
|
messageHandlers[messageQueryAwareness] = (
|
|
@@ -125,8 +142,6 @@ messageHandlers[messageAuth] = (
|
|
|
125
142
|
);
|
|
126
143
|
};
|
|
127
144
|
|
|
128
|
-
const messageReconnectTimeout = 30000;
|
|
129
|
-
|
|
130
145
|
/**
|
|
131
146
|
* @param {EngineIOProvider} provider
|
|
132
147
|
* @param {string} reason
|
|
@@ -134,15 +149,6 @@ const messageReconnectTimeout = 30000;
|
|
|
134
149
|
const permissionDeniedHandler = (provider, reason) =>
|
|
135
150
|
console.warn(`Permission denied to access ${provider.url}.\n${reason}`);
|
|
136
151
|
|
|
137
|
-
/**
|
|
138
|
-
* @param {ArrayBuffer | ArrayBufferView} data
|
|
139
|
-
* @return {Uint8Array}
|
|
140
|
-
*/
|
|
141
|
-
const toUint8Array = (data) =>
|
|
142
|
-
data instanceof ArrayBuffer
|
|
143
|
-
? new Uint8Array(data)
|
|
144
|
-
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
145
|
-
|
|
146
152
|
/**
|
|
147
153
|
* @param {EngineIOProvider} provider
|
|
148
154
|
* @param {Uint8Array} buf
|
|
@@ -152,14 +158,27 @@ const toUint8Array = (data) =>
|
|
|
152
158
|
const readMessage = (provider, buf, emitSynced) => {
|
|
153
159
|
const decoder = decoding__namespace.createDecoder(buf);
|
|
154
160
|
const encoder = encoding__namespace.createEncoder();
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
161
|
+
while (decoding__namespace.hasContent(decoder)) {
|
|
162
|
+
const messageType = decoding__namespace.readVarUint(decoder);
|
|
163
|
+
const messageHandler = provider.messageHandlers[messageType];
|
|
164
|
+
if (/** @type {any} */ (messageHandler)) {
|
|
165
|
+
messageHandler(encoder, decoder, provider, emitSynced, messageType);
|
|
166
|
+
} else {
|
|
167
|
+
break
|
|
168
|
+
}
|
|
159
169
|
}
|
|
160
170
|
return encoder
|
|
161
171
|
};
|
|
162
172
|
|
|
173
|
+
/**
|
|
174
|
+
* @param {ArrayBuffer | ArrayBufferView} data
|
|
175
|
+
* @return {Uint8Array}
|
|
176
|
+
*/
|
|
177
|
+
const toUint8Array = (data) =>
|
|
178
|
+
data instanceof ArrayBuffer
|
|
179
|
+
? new Uint8Array(data)
|
|
180
|
+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength);
|
|
181
|
+
|
|
163
182
|
/**
|
|
164
183
|
* Outsource this function so that a new engine.io connection is created immediately.
|
|
165
184
|
* I suspect that the `close` event is not always fired if there are network issues.
|
|
@@ -185,13 +204,14 @@ const closeEngineConnection = (provider, engine, event) => {
|
|
|
185
204
|
awarenessProtocol__namespace.removeAwarenessStates(
|
|
186
205
|
provider.awareness,
|
|
187
206
|
Array.from(provider.awareness.getStates().keys()).filter((client) =>
|
|
188
|
-
client !== provider.
|
|
207
|
+
client !== provider.awareness.clientID
|
|
189
208
|
),
|
|
190
209
|
provider
|
|
191
210
|
);
|
|
192
211
|
provider.emit('status', [{
|
|
193
212
|
status: 'disconnected'
|
|
194
213
|
}]);
|
|
214
|
+
emitSyncStatusEvent(provider);
|
|
195
215
|
} else {
|
|
196
216
|
provider.unsuccessfulReconnects++;
|
|
197
217
|
}
|
|
@@ -286,6 +306,7 @@ const setupEngine = (provider) => {
|
|
|
286
306
|
provider.emit('status', [{
|
|
287
307
|
status: 'connecting'
|
|
288
308
|
}]);
|
|
309
|
+
emitSyncStatusEvent(provider);
|
|
289
310
|
}
|
|
290
311
|
};
|
|
291
312
|
|
|
@@ -303,6 +324,39 @@ const broadcastMessage = (provider, buf) => {
|
|
|
303
324
|
}
|
|
304
325
|
};
|
|
305
326
|
|
|
327
|
+
/**
|
|
328
|
+
* This sync status event only works on certain backends (e.g. yhub)
|
|
329
|
+
* @typedef {object} SyncStatus
|
|
330
|
+
* @property {boolean} SyncStatusEvent.connected
|
|
331
|
+
* @property {boolean} SyncStatusEvent.receivedInitialSync
|
|
332
|
+
* @property {boolean} SyncStatusEvent.localUpdatesSynced
|
|
333
|
+
* @property {number} SyncStatusEvent.localUpdatesAge
|
|
334
|
+
* @property {number} SyncStatusEvent.lastMessageAge
|
|
335
|
+
* @property {'green' | 'yellow' | 'red'} SyncStatusEvent.status Distilled sync status: 'green' if synced, connected, there are no unsynced local updates. 'yellow' if last local message age is younger than 8 seconds. 'red' if unsynced or disconnected or if last local message is older than 8 seconds
|
|
336
|
+
*/
|
|
337
|
+
|
|
338
|
+
const acceptableConnectionDelay = 8000;
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* @param {EngineIOProvider} provider
|
|
342
|
+
*/
|
|
343
|
+
const emitSyncStatusEvent = provider => {
|
|
344
|
+
const syncStatus = provider.syncStatus;
|
|
345
|
+
const prevSyncStatus = provider.prevSyncStatus;
|
|
346
|
+
if (
|
|
347
|
+
prevSyncStatus == null ||
|
|
348
|
+
prevSyncStatus.status !== syncStatus.status ||
|
|
349
|
+
prevSyncStatus.connected !== syncStatus.connected ||
|
|
350
|
+
prevSyncStatus.localUpdatesSynced !== syncStatus.localUpdatesSynced ||
|
|
351
|
+
prevSyncStatus.receivedInitialSync !== syncStatus.receivedInitialSync ||
|
|
352
|
+
syncStatus.localUpdatesAge - prevSyncStatus.localUpdatesAge > 1000 ||
|
|
353
|
+
syncStatus.lastMessageAge - prevSyncStatus.lastMessageAge > 1000
|
|
354
|
+
) {
|
|
355
|
+
provider.emit('sync-status', [syncStatus]);
|
|
356
|
+
provider.prevSyncStatus = syncStatus;
|
|
357
|
+
}
|
|
358
|
+
};
|
|
359
|
+
|
|
306
360
|
/**
|
|
307
361
|
* Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared
|
|
308
362
|
* document. Unlike a raw WebSocket, engine.io connects to a single endpoint and
|
|
@@ -311,12 +365,12 @@ const broadcastMessage = (provider, buf) => {
|
|
|
311
365
|
* before any sync frames are exchanged.
|
|
312
366
|
*
|
|
313
367
|
* @example
|
|
314
|
-
* import * as Y from '
|
|
368
|
+
* import * as Y from '@y/y'
|
|
315
369
|
* import { EngineIOProvider } from '@styris-ame/y-engineio'
|
|
316
370
|
* const doc = new Y.Doc()
|
|
317
371
|
* const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)
|
|
318
372
|
*
|
|
319
|
-
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}
|
|
373
|
+
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any, 'sync-status': (syncStatus: SyncStatus) => any }>}
|
|
320
374
|
*/
|
|
321
375
|
class EngineIOProvider extends observable.ObservableV2 {
|
|
322
376
|
/**
|
|
@@ -332,6 +386,7 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
332
386
|
* @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
|
|
333
387
|
* @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
|
|
334
388
|
* @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
|
|
389
|
+
* @param {number} [opts.socketTimeout] If no message is received for this amount of time, client will close the socket and reconnect
|
|
335
390
|
*/
|
|
336
391
|
constructor (serverUrl, roomname, doc, {
|
|
337
392
|
connect = true,
|
|
@@ -341,7 +396,8 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
341
396
|
EngineClass = engine_ioClient.Socket,
|
|
342
397
|
resyncInterval = -1,
|
|
343
398
|
maxBackoffTime = 2500,
|
|
344
|
-
disableBc = false
|
|
399
|
+
disableBc = false,
|
|
400
|
+
socketTimeout = math__namespace.round(awarenessProtocol__namespace.outdatedTimeout * 1.5)
|
|
345
401
|
} = {}) {
|
|
346
402
|
super();
|
|
347
403
|
// ensure that serverUrl does not end with /
|
|
@@ -370,6 +426,7 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
370
426
|
this.connecting = false;
|
|
371
427
|
this.bcconnected = false;
|
|
372
428
|
this.disableBc = disableBc;
|
|
429
|
+
this.socketTimeout = socketTimeout;
|
|
373
430
|
this.unsuccessfulReconnects = 0;
|
|
374
431
|
this.messageHandlers = messageHandlers.slice();
|
|
375
432
|
/**
|
|
@@ -388,6 +445,14 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
388
445
|
*/
|
|
389
446
|
this.shouldConnect = connect;
|
|
390
447
|
|
|
448
|
+
/**
|
|
449
|
+
* @type {Array<{ ids: Y.ContentIds, created: number }>}
|
|
450
|
+
*/
|
|
451
|
+
this.unconfirmedUpdates = [];
|
|
452
|
+
/**
|
|
453
|
+
* @type {SyncStatus?}
|
|
454
|
+
*/
|
|
455
|
+
this.prevSyncStatus = null;
|
|
391
456
|
/**
|
|
392
457
|
* @type {number}
|
|
393
458
|
*/
|
|
@@ -423,6 +488,20 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
423
488
|
*/
|
|
424
489
|
this._updateHandler = (update, origin) => {
|
|
425
490
|
if (origin !== this) {
|
|
491
|
+
const now = time__namespace.getUnixTime();
|
|
492
|
+
const newContentIds = Y__namespace.createContentIdsFromUpdate(update);
|
|
493
|
+
const lastUnconfirmed = this.unconfirmedUpdates.length > 0 ? array__namespace.last(this.unconfirmedUpdates) : null;
|
|
494
|
+
if (lastUnconfirmed != null && now - lastUnconfirmed.created < 500) {
|
|
495
|
+
lastUnconfirmed.ids = Y__namespace.mergeContentIds([lastUnconfirmed.ids, newContentIds]);
|
|
496
|
+
} else {
|
|
497
|
+
this.unconfirmedUpdates.push({
|
|
498
|
+
created: now,
|
|
499
|
+
ids: newContentIds
|
|
500
|
+
});
|
|
501
|
+
if (this.unconfirmedUpdates.length === 1) {
|
|
502
|
+
emitSyncStatusEvent(this);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
426
505
|
const encoder = encoding__namespace.createEncoder();
|
|
427
506
|
encoding__namespace.writeVarUint(encoder, messageSync);
|
|
428
507
|
syncProtocol__namespace.writeUpdate(encoder, update);
|
|
@@ -458,19 +537,43 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
458
537
|
this._checkInterval = /** @type {any} */ (setInterval(() => {
|
|
459
538
|
if (
|
|
460
539
|
this.connected &&
|
|
461
|
-
|
|
540
|
+
this.socketTimeout <
|
|
462
541
|
time__namespace.getUnixTime() - this.lastMessageReceived
|
|
463
542
|
) {
|
|
464
|
-
|
|
465
|
-
// updates (which are updated every 15 seconds)
|
|
543
|
+
console.error('[y-engineio] closing timed-out connection');
|
|
466
544
|
closeEngineConnection(this, /** @type {Engine} */ (this.engine), null);
|
|
467
545
|
}
|
|
468
|
-
|
|
546
|
+
emitSyncStatusEvent(this);
|
|
547
|
+
}, acceptableConnectionDelay / 2));
|
|
469
548
|
if (connect) {
|
|
470
549
|
this.connect();
|
|
471
550
|
}
|
|
472
551
|
}
|
|
473
552
|
|
|
553
|
+
/**
|
|
554
|
+
* @return {SyncStatus}
|
|
555
|
+
*/
|
|
556
|
+
get syncStatus () {
|
|
557
|
+
const {
|
|
558
|
+
unconfirmedUpdates,
|
|
559
|
+
connected,
|
|
560
|
+
synced: receivedInitialSync,
|
|
561
|
+
lastMessageReceived
|
|
562
|
+
} = this;
|
|
563
|
+
const now = time__namespace.getUnixTime();
|
|
564
|
+
const localUpdatesSynced = unconfirmedUpdates.length === 0;
|
|
565
|
+
const localUpdatesAge = localUpdatesSynced ? 0 : now - unconfirmedUpdates[0].created;
|
|
566
|
+
const status = (connected && receivedInitialSync && localUpdatesAge === 0) ? 'green' : (connected && localUpdatesAge < acceptableConnectionDelay ? 'yellow' : 'red');
|
|
567
|
+
return {
|
|
568
|
+
connected,
|
|
569
|
+
receivedInitialSync,
|
|
570
|
+
localUpdatesSynced,
|
|
571
|
+
localUpdatesAge,
|
|
572
|
+
lastMessageAge: now - lastMessageReceived,
|
|
573
|
+
status
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
|
|
474
577
|
get url () {
|
|
475
578
|
const encodedParams = url__namespace.encodeQueryParams({ ...this.params, room: this.roomname });
|
|
476
579
|
return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)
|
|
@@ -539,7 +642,7 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
539
642
|
encoding__namespace.writeVarUint8Array(
|
|
540
643
|
encoderAwarenessState,
|
|
541
644
|
awarenessProtocol__namespace.encodeAwarenessUpdate(this.awareness, [
|
|
542
|
-
this.
|
|
645
|
+
this.awareness.clientID
|
|
543
646
|
])
|
|
544
647
|
);
|
|
545
648
|
bc__namespace.publish(
|
|
@@ -556,7 +659,7 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
556
659
|
encoding__namespace.writeVarUint8Array(
|
|
557
660
|
encoder,
|
|
558
661
|
awarenessProtocol__namespace.encodeAwarenessUpdate(this.awareness, [
|
|
559
|
-
this.
|
|
662
|
+
this.awareness.clientID
|
|
560
663
|
], new Map())
|
|
561
664
|
);
|
|
562
665
|
broadcastMessage(this, encoding__namespace.toUint8Array(encoder));
|
|
@@ -584,6 +687,7 @@ class EngineIOProvider extends observable.ObservableV2 {
|
|
|
584
687
|
}
|
|
585
688
|
|
|
586
689
|
exports.EngineIOProvider = EngineIOProvider;
|
|
690
|
+
exports.acceptableConnectionDelay = acceptableConnectionDelay;
|
|
587
691
|
exports.messageAuth = messageAuth;
|
|
588
692
|
exports.messageAwareness = messageAwareness;
|
|
589
693
|
exports.messageQueryAwareness = messageQueryAwareness;
|
package/dist/y-engineio.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"y-engineio.cjs","sources":["../src/y-engineio.js"],"sourcesContent":["/**\n * @module provider/engineio\n */\n\n/* eslint-env browser */\nimport * as Y from 'yjs' // eslint-disable-line\nimport * as bc from 'lib0/broadcastchannel'\nimport * as time from 'lib0/time'\nimport * as encoding from 'lib0/encoding'\nimport * as decoding from 'lib0/decoding'\nimport * as syncProtocol from 'y-protocols/sync'\nimport * as authProtocol from 'y-protocols/auth'\nimport * as awarenessProtocol from 'y-protocols/awareness'\nimport { ObservableV2 } from 'lib0/observable'\nimport * as math from 'lib0/math'\nimport * as url from 'lib0/url'\nimport * as env from 'lib0/environment'\nimport { Socket as Engine } from 'engine.io-client'\n\nexport const messageSync = 0\nexport const messageQueryAwareness = 3\nexport const messageAwareness = 1\nexport const messageAuth = 2\n\n/**\n * encoder, decoder, provider, emitSynced, messageType\n * @type {Array<function(encoding.Encoder, decoding.Decoder, EngineIOProvider, boolean, number):void>}\n */\nconst messageHandlers = []\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync)\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n )\n if (\n emitSynced && syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true\n }\n}\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n )\n}\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n )\n}\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(\n decoder,\n provider.doc,\n (_ydoc, reason) => permissionDeniedHandler(provider, reason)\n )\n}\n\nconst messageReconnectTimeout = 30000\n\n/**\n * @param {EngineIOProvider} provider\n * @param {string} reason\n */\nconst permissionDeniedHandler = (provider, reason) =>\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`)\n\n/**\n * @param {ArrayBuffer | ArrayBufferView} data\n * @return {Uint8Array}\n */\nconst toUint8Array = (data) =>\n data instanceof ArrayBuffer\n ? new Uint8Array(data)\n : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n * @param {boolean} emitSynced\n * @return {encoding.Encoder}\n */\nconst readMessage = (provider, buf, emitSynced) => {\n const decoder = decoding.createDecoder(buf)\n const encoder = encoding.createEncoder()\n const messageType = decoding.readVarUint(decoder)\n const messageHandler = provider.messageHandlers[messageType]\n if (/** @type {any} */ (messageHandler)) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType)\n }\n return encoder\n}\n\n/**\n * Outsource this function so that a new engine.io connection is created immediately.\n * I suspect that the `close` event is not always fired if there are network issues.\n *\n * @param {EngineIOProvider} provider\n * @param {Engine} engine\n * @param {any} event\n */\nconst closeEngineConnection = (provider, engine, event) => {\n if (engine === provider.engine) {\n provider.emit('connection-close', [event, provider])\n provider.engine = null\n const anyEngine = /** @type {any} */ (engine)\n if (anyEngine._yUnsubscribe) {\n anyEngine._yUnsubscribe()\n }\n engine.close()\n provider.connecting = false\n if (provider.connected) {\n provider.connected = false\n provider.synced = false\n // update awareness (all users except local left)\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys()).filter((client) =>\n client !== provider.doc.clientID\n ),\n provider\n )\n provider.emit('status', [{\n status: 'disconnected'\n }])\n } else {\n provider.unsuccessfulReconnects++\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n setupEngine,\n math.min(\n math.pow(2, provider.unsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n ),\n provider\n )\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n */\nconst setupEngine = (provider) => {\n if (provider.shouldConnect && provider.engine === null) {\n const engine = new provider._Engine(provider.serverUrl, {\n ...provider.engineOptions,\n query: { ...provider.params, room: provider.roomname }\n })\n engine.binaryType = 'arraybuffer'\n provider.engine = engine\n provider.connecting = true\n provider.connected = false\n provider.synced = false\n\n const onMessage = (/** @type {any} */ data) => {\n if (provider.engine !== engine) return\n if (typeof data === 'string') return\n provider.lastMessageReceived = time.getUnixTime()\n const encoder = readMessage(provider, toUint8Array(data), true)\n if (encoding.length(encoder) > 1) {\n engine.send(encoding.toUint8Array(encoder))\n }\n }\n const onError = (/** @type {any} */ event) => {\n if (provider.engine !== engine) return\n provider.emit('connection-error', [event, provider])\n }\n const onPing = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n }\n const onClose = (/** @type {any} */ reason, /** @type {any} */ description) => {\n closeEngineConnection(provider, engine, { reason, description })\n }\n const onOpen = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n provider.connecting = false\n provider.connected = true\n provider.unsuccessfulReconnects = 0\n provider.emit('status', [{\n status: 'connected'\n }])\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, provider.doc)\n engine.send(encoding.toUint8Array(encoder))\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n )\n engine.send(encoding.toUint8Array(encoderAwarenessState))\n }\n }\n engine.on('message', onMessage)\n engine.on('error', onError)\n engine.on('ping', onPing)\n engine.on('close', onClose)\n engine.on('open', onOpen)\n const anyEngine = /** @type {any} */ (engine)\n anyEngine._yUnsubscribe = () => {\n engine.off('message', onMessage)\n engine.off('error', onError)\n engine.off('ping', onPing)\n engine.off('close', onClose)\n engine.off('open', onOpen)\n }\n provider.emit('status', [{\n status: 'connecting'\n }])\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n */\nconst broadcastMessage = (provider, buf) => {\n const engine = provider.engine\n if (provider.connected && engine && engine.readyState === 'open') {\n engine.send(buf)\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider)\n }\n}\n\n/**\n * Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared\n * document. Unlike a raw WebSocket, engine.io connects to a single endpoint and\n * has no document name in the URL, so the room name is sent as the `room`\n * handshake query parameter, letting the server accept or reject the connection\n * before any sync frames are exchanged.\n *\n * @example\n * import * as Y from 'yjs'\n * import { EngineIOProvider } from '@styris-ame/y-engineio'\n * const doc = new Y.Doc()\n * const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}\n */\nexport class EngineIOProvider extends ObservableV2 {\n /**\n * @param {string} serverUrl engine.io server origin, e.g. 'http://localhost:1234'\n * @param {string} roomname\n * @param {Y.Doc} doc\n * @param {object} opts\n * @param {boolean} [opts.connect]\n * @param {awarenessProtocol.Awareness} [opts.awareness]\n * @param {Object<string,string>} [opts.params] url query params, passed to engine.io as `query`\n * @param {object} [opts.engineOptions] options forwarded to the engine.io-client `Socket` (e.g. `path`, `transports`, `withCredentials`, `extraHeaders`)\n * @param {typeof Engine} [opts.EngineClass] override the engine.io `Socket` constructor (e.g. for testing)\n * @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds\n * @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n * @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication\n */\n constructor (serverUrl, roomname, doc, {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n engineOptions = {},\n EngineClass = Engine,\n resyncInterval = -1,\n maxBackoffTime = 2500,\n disableBc = false\n } = {}) {\n super()\n // ensure that serverUrl does not end with /\n while (serverUrl[serverUrl.length - 1] === '/') {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1)\n }\n this.serverUrl = serverUrl\n this.bcChannel = serverUrl + '/' + roomname\n this.maxBackoffTime = maxBackoffTime\n /**\n * The specified url parameters. This can be safely updated. The changed parameters will be used\n * when a new connection is established.\n * @type {Object<string,string>}\n */\n this.params = params\n /**\n * Options forwarded verbatim to the engine.io-client `Socket`.\n * @type {object}\n */\n this.engineOptions = engineOptions\n this.roomname = roomname\n this.doc = doc\n this._Engine = EngineClass\n this.awareness = awareness\n this.connected = false\n this.connecting = false\n this.bcconnected = false\n this.disableBc = disableBc\n this.unsuccessfulReconnects = 0\n this.messageHandlers = messageHandlers.slice()\n /**\n * @type {boolean}\n */\n this._synced = false\n /**\n * The engine.io-client `Socket`, or null when disconnected.\n * @type {Engine?}\n */\n this.engine = null\n this.lastMessageReceived = 0\n /**\n * Whether to connect to other peers or not\n * @type {boolean}\n */\n this.shouldConnect = connect\n\n /**\n * @type {number}\n */\n this._resyncInterval = 0\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ (setInterval(() => {\n if (this.engine && this.engine.readyState === 'open') {\n // resend sync step 1\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, doc)\n this.engine.send(encoding.toUint8Array(encoder))\n }\n }, resyncInterval))\n }\n\n /**\n * @param {ArrayBuffer} data\n * @param {any} origin\n */\n this._bcSubscriber = (data, origin) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false)\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this)\n }\n }\n }\n /**\n * Listens to Yjs updates and sends them to remote peers (engine.io and broadcastchannel)\n * @param {Uint8Array} update\n * @param {any} origin\n */\n this._updateHandler = (update, origin) => {\n if (origin !== this) {\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeUpdate(encoder, update)\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n }\n this.doc.on('update', this._updateHandler)\n /**\n * @param {any} changed\n * @param {any} _origin\n */\n this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {\n const changedClients = added.concat(updated).concat(removed)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n this._exitHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n 'app closed'\n )\n }\n if (env.isNode && typeof process !== 'undefined') {\n process.on('exit', this._exitHandler)\n }\n awareness.on('update', this._awarenessUpdateHandler)\n this._checkInterval = /** @type {any} */ (setInterval(() => {\n if (\n this.connected &&\n messageReconnectTimeout <\n time.getUnixTime() - this.lastMessageReceived\n ) {\n // no message received in a long time - not even your own awareness\n // updates (which are updated every 15 seconds)\n closeEngineConnection(this, /** @type {Engine} */ (this.engine), null)\n }\n }, messageReconnectTimeout / 10))\n if (connect) {\n this.connect()\n }\n }\n\n get url () {\n const encodedParams = url.encodeQueryParams({ ...this.params, room: this.roomname })\n return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)\n }\n\n /**\n * @type {boolean}\n */\n get synced () {\n return this._synced\n }\n\n set synced (state) {\n if (this._synced !== state) {\n this._synced = state\n // @ts-ignore\n this.emit('synced', [state])\n this.emit('sync', [state])\n }\n }\n\n destroy () {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval)\n }\n clearInterval(this._checkInterval)\n this.disconnect()\n if (env.isNode && typeof process !== 'undefined') {\n process.off('exit', this._exitHandler)\n }\n this.awareness.off('update', this._awarenessUpdateHandler)\n this.doc.off('update', this._updateHandler)\n super.destroy()\n }\n\n connectBc () {\n if (this.disableBc) {\n return\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = true\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder()\n encoding.writeVarUint(encoderSync, messageSync)\n syncProtocol.writeSyncStep1(encoderSync, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this)\n // broadcast local state\n const encoderState = encoding.createEncoder()\n encoding.writeVarUint(encoderState, messageSync)\n syncProtocol.writeSyncStep2(encoderState, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this)\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness)\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n )\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ])\n )\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n )\n }\n\n disconnectBc () {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.doc.clientID\n ], new Map())\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = false\n }\n }\n\n disconnect () {\n this.shouldConnect = false\n this.disconnectBc()\n if (this.engine !== null) {\n closeEngineConnection(this, this.engine, null)\n }\n }\n\n connect () {\n this.shouldConnect = true\n if (!this.connected && this.engine === null) {\n setupEngine(this)\n this.connectBc()\n }\n }\n}\n"],"names":["encoding","syncProtocol","awarenessProtocol","decoding","authProtocol","math","time","bc","ObservableV2","Engine","env","url"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"y-engineio.cjs","sources":["../src/y-engineio.js"],"sourcesContent":["/**\n * @module provider/engineio\n */\n\n/* eslint-env browser */\nimport * as Y from '@y/y' // eslint-disable-line\nimport * as bc from 'lib0/broadcastchannel'\nimport * as time from 'lib0/time'\nimport * as encoding from 'lib0/encoding'\nimport * as decoding from 'lib0/decoding'\nimport * as syncProtocol from '@y/protocols/sync'\nimport * as authProtocol from '@y/protocols/auth'\nimport * as awarenessProtocol from '@y/protocols/awareness'\nimport { ObservableV2 } from 'lib0/observable'\nimport * as math from 'lib0/math'\nimport * as url from 'lib0/url'\nimport * as env from 'lib0/environment'\nimport * as array from 'lib0/array'\nimport { Socket as Engine } from 'engine.io-client'\n\nexport const messageSync = 0\nexport const messageQueryAwareness = 3\nexport const messageAwareness = 1\nexport const messageAuth = 2\n\n/**\n * encoder, decoder, provider, emitSynced, messageType\n * @type {Array<function(encoding.Encoder, decoding.Decoder, EngineIOProvider, boolean, number):void>}\n */\nconst messageHandlers = []\n\nmessageHandlers[messageSync] = (\n encoder,\n decoder,\n provider,\n emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageSync)\n const readSyncPos = decoder.pos\n const syncMessageType = syncProtocol.readSyncMessage(\n decoder,\n encoder,\n provider.doc,\n provider\n )\n if (\n emitSynced && syncMessageType === syncProtocol.messageYjsSyncStep2 &&\n !provider.synced\n ) {\n provider.synced = true\n }\n // update unconfirmedUpdates\n if (syncMessageType === 1 || syncMessageType === 2) {\n const subdecoder = decoding.createDecoder(decoder.arr)\n subdecoder.pos = readSyncPos\n decoding.readVarUint(subdecoder) // === syncMessageType\n const update = decoding.readVarUint8Array(subdecoder)\n const receivedIds = Y.createContentIdsFromUpdate(update)\n provider.unconfirmedUpdates = provider.unconfirmedUpdates.filter(unconfirmed => {\n unconfirmed.ids = Y.excludeContentIds(unconfirmed.ids, receivedIds)\n return !unconfirmed.ids.inserts.isEmpty() || !unconfirmed.ids.deletes.isEmpty()\n })\n emitSyncStatusEvent(provider)\n }\n}\n\nmessageHandlers[messageQueryAwareness] = (\n encoder,\n _decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys())\n )\n )\n}\n\nmessageHandlers[messageAwareness] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n awarenessProtocol.applyAwarenessUpdate(\n provider.awareness,\n decoding.readVarUint8Array(decoder),\n provider\n )\n}\n\nmessageHandlers[messageAuth] = (\n _encoder,\n decoder,\n provider,\n _emitSynced,\n _messageType\n) => {\n authProtocol.readAuthMessage(\n decoder,\n provider.doc,\n (_ydoc, reason) => permissionDeniedHandler(provider, reason)\n )\n}\n\n/**\n * @param {EngineIOProvider} provider\n * @param {string} reason\n */\nconst permissionDeniedHandler = (provider, reason) =>\n console.warn(`Permission denied to access ${provider.url}.\\n${reason}`)\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n * @param {boolean} emitSynced\n * @return {encoding.Encoder}\n */\nconst readMessage = (provider, buf, emitSynced) => {\n const decoder = decoding.createDecoder(buf)\n const encoder = encoding.createEncoder()\n while (decoding.hasContent(decoder)) {\n const messageType = decoding.readVarUint(decoder)\n const messageHandler = provider.messageHandlers[messageType]\n if (/** @type {any} */ (messageHandler)) {\n messageHandler(encoder, decoder, provider, emitSynced, messageType)\n } else {\n break\n }\n }\n return encoder\n}\n\n/**\n * @param {ArrayBuffer | ArrayBufferView} data\n * @return {Uint8Array}\n */\nconst toUint8Array = (data) =>\n data instanceof ArrayBuffer\n ? new Uint8Array(data)\n : new Uint8Array(data.buffer, data.byteOffset, data.byteLength)\n\n/**\n * Outsource this function so that a new engine.io connection is created immediately.\n * I suspect that the `close` event is not always fired if there are network issues.\n *\n * @param {EngineIOProvider} provider\n * @param {Engine} engine\n * @param {any} event\n */\nconst closeEngineConnection = (provider, engine, event) => {\n if (engine === provider.engine) {\n provider.emit('connection-close', [event, provider])\n provider.engine = null\n const anyEngine = /** @type {any} */ (engine)\n if (anyEngine._yUnsubscribe) {\n anyEngine._yUnsubscribe()\n }\n engine.close()\n provider.connecting = false\n if (provider.connected) {\n provider.connected = false\n provider.synced = false\n // update awareness (all users except local left)\n awarenessProtocol.removeAwarenessStates(\n provider.awareness,\n Array.from(provider.awareness.getStates().keys()).filter((client) =>\n client !== provider.awareness.clientID\n ),\n provider\n )\n provider.emit('status', [{\n status: 'disconnected'\n }])\n emitSyncStatusEvent(provider)\n } else {\n provider.unsuccessfulReconnects++\n }\n // Start with no reconnect timeout and increase timeout by\n // using exponential backoff starting with 100ms\n setTimeout(\n setupEngine,\n math.min(\n math.pow(2, provider.unsuccessfulReconnects) * 100,\n provider.maxBackoffTime\n ),\n provider\n )\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n */\nconst setupEngine = (provider) => {\n if (provider.shouldConnect && provider.engine === null) {\n const engine = new provider._Engine(provider.serverUrl, {\n ...provider.engineOptions,\n query: { ...provider.params, room: provider.roomname }\n })\n engine.binaryType = 'arraybuffer'\n provider.engine = engine\n provider.connecting = true\n provider.connected = false\n provider.synced = false\n\n const onMessage = (/** @type {any} */ data) => {\n if (provider.engine !== engine) return\n if (typeof data === 'string') return\n provider.lastMessageReceived = time.getUnixTime()\n const encoder = readMessage(provider, toUint8Array(data), true)\n if (encoding.length(encoder) > 1) {\n engine.send(encoding.toUint8Array(encoder))\n }\n }\n const onError = (/** @type {any} */ event) => {\n if (provider.engine !== engine) return\n provider.emit('connection-error', [event, provider])\n }\n const onPing = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n }\n const onClose = (/** @type {any} */ reason, /** @type {any} */ description) => {\n closeEngineConnection(provider, engine, { reason, description })\n }\n const onOpen = () => {\n if (provider.engine !== engine) return\n provider.lastMessageReceived = time.getUnixTime()\n provider.connecting = false\n provider.connected = true\n provider.unsuccessfulReconnects = 0\n provider.emit('status', [{\n status: 'connected'\n }])\n // always send sync step 1 when connected\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, provider.doc)\n engine.send(encoding.toUint8Array(encoder))\n // broadcast local awareness state\n if (provider.awareness.getLocalState() !== null) {\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [\n provider.doc.clientID\n ])\n )\n engine.send(encoding.toUint8Array(encoderAwarenessState))\n }\n }\n engine.on('message', onMessage)\n engine.on('error', onError)\n engine.on('ping', onPing)\n engine.on('close', onClose)\n engine.on('open', onOpen)\n const anyEngine = /** @type {any} */ (engine)\n anyEngine._yUnsubscribe = () => {\n engine.off('message', onMessage)\n engine.off('error', onError)\n engine.off('ping', onPing)\n engine.off('close', onClose)\n engine.off('open', onOpen)\n }\n provider.emit('status', [{\n status: 'connecting'\n }])\n emitSyncStatusEvent(provider)\n }\n}\n\n/**\n * @param {EngineIOProvider} provider\n * @param {Uint8Array} buf\n */\nconst broadcastMessage = (provider, buf) => {\n const engine = provider.engine\n if (provider.connected && engine && engine.readyState === 'open') {\n engine.send(buf)\n }\n if (provider.bcconnected) {\n bc.publish(provider.bcChannel, buf, provider)\n }\n}\n\n/**\n * This sync status event only works on certain backends (e.g. yhub)\n * @typedef {object} SyncStatus\n * @property {boolean} SyncStatusEvent.connected\n * @property {boolean} SyncStatusEvent.receivedInitialSync\n * @property {boolean} SyncStatusEvent.localUpdatesSynced\n * @property {number} SyncStatusEvent.localUpdatesAge\n * @property {number} SyncStatusEvent.lastMessageAge\n * @property {'green' | 'yellow' | 'red'} SyncStatusEvent.status Distilled sync status: 'green' if synced, connected, there are no unsynced local updates. 'yellow' if last local message age is younger than 8 seconds. 'red' if unsynced or disconnected or if last local message is older than 8 seconds\n */\n\nexport const acceptableConnectionDelay = 8000\n\n/**\n * @param {EngineIOProvider} provider\n */\nconst emitSyncStatusEvent = provider => {\n const syncStatus = provider.syncStatus\n const prevSyncStatus = provider.prevSyncStatus\n if (\n prevSyncStatus == null ||\n prevSyncStatus.status !== syncStatus.status ||\n prevSyncStatus.connected !== syncStatus.connected ||\n prevSyncStatus.localUpdatesSynced !== syncStatus.localUpdatesSynced ||\n prevSyncStatus.receivedInitialSync !== syncStatus.receivedInitialSync ||\n syncStatus.localUpdatesAge - prevSyncStatus.localUpdatesAge > 1000 ||\n syncStatus.lastMessageAge - prevSyncStatus.lastMessageAge > 1000\n ) {\n provider.emit('sync-status', [syncStatus])\n provider.prevSyncStatus = syncStatus\n }\n}\n\n/**\n * Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared\n * document. Unlike a raw WebSocket, engine.io connects to a single endpoint and\n * has no document name in the URL, so the room name is sent as the `room`\n * handshake query parameter, letting the server accept or reject the connection\n * before any sync frames are exchanged.\n *\n * @example\n * import * as Y from '@y/y'\n * import { EngineIOProvider } from '@styris-ame/y-engineio'\n * const doc = new Y.Doc()\n * const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)\n *\n * @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any, 'sync-status': (syncStatus: SyncStatus) => any }>}\n */\nexport class EngineIOProvider extends ObservableV2 {\n /**\n * @param {string} serverUrl engine.io server origin, e.g. 'http://localhost:1234'\n * @param {string} roomname\n * @param {Y.Doc} doc\n * @param {object} opts\n * @param {boolean} [opts.connect]\n * @param {awarenessProtocol.Awareness} [opts.awareness]\n * @param {Object<string,string>} [opts.params] url query params, passed to engine.io as `query`\n * @param {object} [opts.engineOptions] options forwarded to the engine.io-client `Socket` (e.g. `path`, `transports`, `withCredentials`, `extraHeaders`)\n * @param {typeof Engine} [opts.EngineClass] override the engine.io `Socket` constructor (e.g. for testing)\n * @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds\n * @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)\n * @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication\n * @param {number} [opts.socketTimeout] If no message is received for this amount of time, client will close the socket and reconnect\n */\n constructor (serverUrl, roomname, doc, {\n connect = true,\n awareness = new awarenessProtocol.Awareness(doc),\n params = {},\n engineOptions = {},\n EngineClass = Engine,\n resyncInterval = -1,\n maxBackoffTime = 2500,\n disableBc = false,\n socketTimeout = math.round(awarenessProtocol.outdatedTimeout * 1.5)\n } = {}) {\n super()\n // ensure that serverUrl does not end with /\n while (serverUrl[serverUrl.length - 1] === '/') {\n serverUrl = serverUrl.slice(0, serverUrl.length - 1)\n }\n this.serverUrl = serverUrl\n this.bcChannel = serverUrl + '/' + roomname\n this.maxBackoffTime = maxBackoffTime\n /**\n * The specified url parameters. This can be safely updated. The changed parameters will be used\n * when a new connection is established.\n * @type {Object<string,string>}\n */\n this.params = params\n /**\n * Options forwarded verbatim to the engine.io-client `Socket`.\n * @type {object}\n */\n this.engineOptions = engineOptions\n this.roomname = roomname\n this.doc = doc\n this._Engine = EngineClass\n this.awareness = awareness\n this.connected = false\n this.connecting = false\n this.bcconnected = false\n this.disableBc = disableBc\n this.socketTimeout = socketTimeout\n this.unsuccessfulReconnects = 0\n this.messageHandlers = messageHandlers.slice()\n /**\n * @type {boolean}\n */\n this._synced = false\n /**\n * The engine.io-client `Socket`, or null when disconnected.\n * @type {Engine?}\n */\n this.engine = null\n this.lastMessageReceived = 0\n /**\n * Whether to connect to other peers or not\n * @type {boolean}\n */\n this.shouldConnect = connect\n\n /**\n * @type {Array<{ ids: Y.ContentIds, created: number }>}\n */\n this.unconfirmedUpdates = []\n /**\n * @type {SyncStatus?}\n */\n this.prevSyncStatus = null\n /**\n * @type {number}\n */\n this._resyncInterval = 0\n if (resyncInterval > 0) {\n this._resyncInterval = /** @type {any} */ (setInterval(() => {\n if (this.engine && this.engine.readyState === 'open') {\n // resend sync step 1\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeSyncStep1(encoder, doc)\n this.engine.send(encoding.toUint8Array(encoder))\n }\n }, resyncInterval))\n }\n\n /**\n * @param {ArrayBuffer} data\n * @param {any} origin\n */\n this._bcSubscriber = (data, origin) => {\n if (origin !== this) {\n const encoder = readMessage(this, new Uint8Array(data), false)\n if (encoding.length(encoder) > 1) {\n bc.publish(this.bcChannel, encoding.toUint8Array(encoder), this)\n }\n }\n }\n /**\n * Listens to Yjs updates and sends them to remote peers (engine.io and broadcastchannel)\n * @param {Uint8Array} update\n * @param {any} origin\n */\n this._updateHandler = (update, origin) => {\n if (origin !== this) {\n const now = time.getUnixTime()\n const newContentIds = Y.createContentIdsFromUpdate(update)\n const lastUnconfirmed = this.unconfirmedUpdates.length > 0 ? array.last(this.unconfirmedUpdates) : null\n if (lastUnconfirmed != null && now - lastUnconfirmed.created < 500) {\n lastUnconfirmed.ids = Y.mergeContentIds([lastUnconfirmed.ids, newContentIds])\n } else {\n this.unconfirmedUpdates.push({\n created: now,\n ids: newContentIds\n })\n if (this.unconfirmedUpdates.length === 1) {\n emitSyncStatusEvent(this)\n }\n }\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageSync)\n syncProtocol.writeUpdate(encoder, update)\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n }\n this.doc.on('update', this._updateHandler)\n /**\n * @param {any} changed\n * @param {any} _origin\n */\n this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {\n const changedClients = added.concat(updated).concat(removed)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(awareness, changedClients)\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n }\n this._exitHandler = () => {\n awarenessProtocol.removeAwarenessStates(\n this.awareness,\n [doc.clientID],\n 'app closed'\n )\n }\n if (env.isNode && typeof process !== 'undefined') {\n process.on('exit', this._exitHandler)\n }\n awareness.on('update', this._awarenessUpdateHandler)\n this._checkInterval = /** @type {any} */ (setInterval(() => {\n if (\n this.connected &&\n this.socketTimeout <\n time.getUnixTime() - this.lastMessageReceived\n ) {\n console.error('[y-engineio] closing timed-out connection')\n closeEngineConnection(this, /** @type {Engine} */ (this.engine), null)\n }\n emitSyncStatusEvent(this)\n }, acceptableConnectionDelay / 2))\n if (connect) {\n this.connect()\n }\n }\n\n /**\n * @return {SyncStatus}\n */\n get syncStatus () {\n const {\n unconfirmedUpdates,\n connected,\n synced: receivedInitialSync,\n lastMessageReceived\n } = this\n const now = time.getUnixTime()\n const localUpdatesSynced = unconfirmedUpdates.length === 0\n const localUpdatesAge = localUpdatesSynced ? 0 : now - unconfirmedUpdates[0].created\n const status = (connected && receivedInitialSync && localUpdatesAge === 0) ? 'green' : (connected && localUpdatesAge < acceptableConnectionDelay ? 'yellow' : 'red')\n return {\n connected,\n receivedInitialSync,\n localUpdatesSynced,\n localUpdatesAge,\n lastMessageAge: now - lastMessageReceived,\n status\n }\n }\n\n get url () {\n const encodedParams = url.encodeQueryParams({ ...this.params, room: this.roomname })\n return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)\n }\n\n /**\n * @type {boolean}\n */\n get synced () {\n return this._synced\n }\n\n set synced (state) {\n if (this._synced !== state) {\n this._synced = state\n // @ts-ignore\n this.emit('synced', [state])\n this.emit('sync', [state])\n }\n }\n\n destroy () {\n if (this._resyncInterval !== 0) {\n clearInterval(this._resyncInterval)\n }\n clearInterval(this._checkInterval)\n this.disconnect()\n if (env.isNode && typeof process !== 'undefined') {\n process.off('exit', this._exitHandler)\n }\n this.awareness.off('update', this._awarenessUpdateHandler)\n this.doc.off('update', this._updateHandler)\n super.destroy()\n }\n\n connectBc () {\n if (this.disableBc) {\n return\n }\n if (!this.bcconnected) {\n bc.subscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = true\n }\n // send sync step1 to bc\n // write sync step 1\n const encoderSync = encoding.createEncoder()\n encoding.writeVarUint(encoderSync, messageSync)\n syncProtocol.writeSyncStep1(encoderSync, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderSync), this)\n // broadcast local state\n const encoderState = encoding.createEncoder()\n encoding.writeVarUint(encoderState, messageSync)\n syncProtocol.writeSyncStep2(encoderState, this.doc)\n bc.publish(this.bcChannel, encoding.toUint8Array(encoderState), this)\n // write queryAwareness\n const encoderAwarenessQuery = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness)\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessQuery),\n this\n )\n // broadcast local awareness state\n const encoderAwarenessState = encoding.createEncoder()\n encoding.writeVarUint(encoderAwarenessState, messageAwareness)\n encoding.writeVarUint8Array(\n encoderAwarenessState,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.awareness.clientID\n ])\n )\n bc.publish(\n this.bcChannel,\n encoding.toUint8Array(encoderAwarenessState),\n this\n )\n }\n\n disconnectBc () {\n // broadcast message with local awareness state set to null (indicating disconnect)\n const encoder = encoding.createEncoder()\n encoding.writeVarUint(encoder, messageAwareness)\n encoding.writeVarUint8Array(\n encoder,\n awarenessProtocol.encodeAwarenessUpdate(this.awareness, [\n this.awareness.clientID\n ], new Map())\n )\n broadcastMessage(this, encoding.toUint8Array(encoder))\n if (this.bcconnected) {\n bc.unsubscribe(this.bcChannel, this._bcSubscriber)\n this.bcconnected = false\n }\n }\n\n disconnect () {\n this.shouldConnect = false\n this.disconnectBc()\n if (this.engine !== null) {\n closeEngineConnection(this, this.engine, null)\n }\n }\n\n connect () {\n this.shouldConnect = true\n if (!this.connected && this.engine === null) {\n setupEngine(this)\n this.connectBc()\n }\n }\n}\n"],"names":["encoding","syncProtocol","decoding","Y","awarenessProtocol","authProtocol","math","time","bc","ObservableV2","Engine","array","env","url"],"mappings":"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"}
|
package/dist/y-engineio.d.ts
CHANGED
|
@@ -2,6 +2,17 @@ export const messageSync: 0;
|
|
|
2
2
|
export const messageQueryAwareness: 3;
|
|
3
3
|
export const messageAwareness: 1;
|
|
4
4
|
export const messageAuth: 2;
|
|
5
|
+
/**
|
|
6
|
+
* This sync status event only works on certain backends (e.g. yhub)
|
|
7
|
+
* @typedef {object} SyncStatus
|
|
8
|
+
* @property {boolean} SyncStatusEvent.connected
|
|
9
|
+
* @property {boolean} SyncStatusEvent.receivedInitialSync
|
|
10
|
+
* @property {boolean} SyncStatusEvent.localUpdatesSynced
|
|
11
|
+
* @property {number} SyncStatusEvent.localUpdatesAge
|
|
12
|
+
* @property {number} SyncStatusEvent.lastMessageAge
|
|
13
|
+
* @property {'green' | 'yellow' | 'red'} SyncStatusEvent.status Distilled sync status: 'green' if synced, connected, there are no unsynced local updates. 'yellow' if last local message age is younger than 8 seconds. 'red' if unsynced or disconnected or if last local message is older than 8 seconds
|
|
14
|
+
*/
|
|
15
|
+
export const acceptableConnectionDelay: 8000;
|
|
5
16
|
/**
|
|
6
17
|
* Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared
|
|
7
18
|
* document. Unlike a raw WebSocket, engine.io connects to a single endpoint and
|
|
@@ -10,12 +21,12 @@ export const messageAuth: 2;
|
|
|
10
21
|
* before any sync frames are exchanged.
|
|
11
22
|
*
|
|
12
23
|
* @example
|
|
13
|
-
* import * as Y from '
|
|
24
|
+
* import * as Y from '@y/y'
|
|
14
25
|
* import { EngineIOProvider } from '@styris-ame/y-engineio'
|
|
15
26
|
* const doc = new Y.Doc()
|
|
16
27
|
* const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)
|
|
17
28
|
*
|
|
18
|
-
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}
|
|
29
|
+
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any, 'sync-status': (syncStatus: SyncStatus) => any }>}
|
|
19
30
|
*/
|
|
20
31
|
export class EngineIOProvider extends ObservableV2<{
|
|
21
32
|
'connection-close': (event: any, provider: EngineIOProvider) => any;
|
|
@@ -25,6 +36,7 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
25
36
|
'connection-error': (event: any, provider: EngineIOProvider) => any;
|
|
26
37
|
sync: (state: boolean) => any;
|
|
27
38
|
synced: (state: boolean) => any;
|
|
39
|
+
'sync-status': (syncStatus: SyncStatus) => any;
|
|
28
40
|
}> {
|
|
29
41
|
/**
|
|
30
42
|
* @param {string} serverUrl engine.io server origin, e.g. 'http://localhost:1234'
|
|
@@ -39,8 +51,9 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
39
51
|
* @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
|
|
40
52
|
* @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
|
|
41
53
|
* @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
|
|
54
|
+
* @param {number} [opts.socketTimeout] If no message is received for this amount of time, client will close the socket and reconnect
|
|
42
55
|
*/
|
|
43
|
-
constructor(serverUrl: string, roomname: string, doc: Y.Doc, { connect, awareness, params, engineOptions, EngineClass, resyncInterval, maxBackoffTime, disableBc }?: {
|
|
56
|
+
constructor(serverUrl: string, roomname: string, doc: Y.Doc, { connect, awareness, params, engineOptions, EngineClass, resyncInterval, maxBackoffTime, disableBc, socketTimeout }?: {
|
|
44
57
|
connect?: boolean | undefined;
|
|
45
58
|
awareness?: awarenessProtocol.Awareness | undefined;
|
|
46
59
|
params?: {
|
|
@@ -51,6 +64,7 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
51
64
|
resyncInterval?: number | undefined;
|
|
52
65
|
maxBackoffTime?: number | undefined;
|
|
53
66
|
disableBc?: boolean | undefined;
|
|
67
|
+
socketTimeout?: number | undefined;
|
|
54
68
|
});
|
|
55
69
|
serverUrl: string;
|
|
56
70
|
bcChannel: string;
|
|
@@ -76,6 +90,7 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
76
90
|
connecting: boolean;
|
|
77
91
|
bcconnected: boolean;
|
|
78
92
|
disableBc: boolean;
|
|
93
|
+
socketTimeout: number;
|
|
79
94
|
unsuccessfulReconnects: number;
|
|
80
95
|
messageHandlers: ((arg0: encoding.Encoder, arg1: decoding.Decoder, arg2: EngineIOProvider, arg3: boolean, arg4: number) => void)[];
|
|
81
96
|
/**
|
|
@@ -93,6 +108,17 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
93
108
|
* @type {boolean}
|
|
94
109
|
*/
|
|
95
110
|
shouldConnect: boolean;
|
|
111
|
+
/**
|
|
112
|
+
* @type {Array<{ ids: Y.ContentIds, created: number }>}
|
|
113
|
+
*/
|
|
114
|
+
unconfirmedUpdates: Array<{
|
|
115
|
+
ids: Y.ContentIds;
|
|
116
|
+
created: number;
|
|
117
|
+
}>;
|
|
118
|
+
/**
|
|
119
|
+
* @type {SyncStatus?}
|
|
120
|
+
*/
|
|
121
|
+
prevSyncStatus: SyncStatus | null;
|
|
96
122
|
/**
|
|
97
123
|
* @type {number}
|
|
98
124
|
*/
|
|
@@ -115,6 +141,10 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
115
141
|
_awarenessUpdateHandler: ({ added, updated, removed }: any, _origin: any) => void;
|
|
116
142
|
_exitHandler: () => void;
|
|
117
143
|
_checkInterval: any;
|
|
144
|
+
/**
|
|
145
|
+
* @return {SyncStatus}
|
|
146
|
+
*/
|
|
147
|
+
get syncStatus(): SyncStatus;
|
|
118
148
|
get url(): string;
|
|
119
149
|
set synced(state: boolean);
|
|
120
150
|
/**
|
|
@@ -126,10 +156,24 @@ export class EngineIOProvider extends ObservableV2<{
|
|
|
126
156
|
disconnect(): void;
|
|
127
157
|
connect(): void;
|
|
128
158
|
}
|
|
159
|
+
/**
|
|
160
|
+
* This sync status event only works on certain backends (e.g. yhub)
|
|
161
|
+
*/
|
|
162
|
+
export type SyncStatus = {
|
|
163
|
+
connected: boolean;
|
|
164
|
+
receivedInitialSync: boolean;
|
|
165
|
+
localUpdatesSynced: boolean;
|
|
166
|
+
localUpdatesAge: number;
|
|
167
|
+
lastMessageAge: number;
|
|
168
|
+
/**
|
|
169
|
+
* Distilled sync status: 'green' if synced, connected, there are no unsynced local updates. 'yellow' if last local message age is younger than 8 seconds. 'red' if unsynced or disconnected or if last local message is older than 8 seconds
|
|
170
|
+
*/
|
|
171
|
+
status: "green" | "yellow" | "red";
|
|
172
|
+
};
|
|
129
173
|
import { ObservableV2 } from 'lib0/observable';
|
|
130
|
-
import * as Y from '
|
|
174
|
+
import * as Y from '@y/y';
|
|
131
175
|
import { Socket as Engine } from 'engine.io-client';
|
|
132
|
-
import * as awarenessProtocol from 'y
|
|
176
|
+
import * as awarenessProtocol from '@y/protocols/awareness';
|
|
133
177
|
import * as encoding from 'lib0/encoding';
|
|
134
178
|
import * as decoding from 'lib0/decoding';
|
|
135
179
|
//# sourceMappingURL=y-engineio.d.ts.map
|
package/dist/y-engineio.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"y-engineio.d.ts","sourceRoot":"","sources":["../src/y-engineio.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"y-engineio.d.ts","sourceRoot":"","sources":["../src/y-engineio.js"],"names":[],"mappings":"AAoBA,0BAA2B,CAAC,CAAA;AAC5B,oCAAqC,CAAC,CAAA;AACtC,+BAAgC,CAAC,CAAA;AACjC,0BAA2B,CAAC,CAAA;AA+Q5B;;;;;;;;;GASG;AAEH,wCAAyC,IAAI,CAAA;AAsB7C;;;;;;;;;;;;;;GAcG;AACH;wBAFgD,CAAC,KAAK,EAAE,GAAG,EAAG,QAAQ,EAAE,gBAAgB,KAAK,GAAG;YAAY,CAAC,KAAK,EAAE;QAAE,MAAM,EAAE,WAAW,GAAG,cAAc,GAAG,YAAY,CAAA;KAAE,KAAK,GAAG;wBAAsB,CAAC,KAAK,EAAE,GAAG,EAAE,QAAQ,EAAE,gBAAgB,KAAK,GAAG;UAAU,CAAC,KAAK,EAAE,OAAO,KAAK,GAAG;YAAY,CAAC,KAAK,EAAE,OAAO,KAAK,GAAG;mBAAiB,CAAC,UAAU,EAAE,UAAU,KAAK,GAAG;;IAG1W;;;;;;;;;;;;;;OAcG;IACH,uBAdW,MAAM,YACN,MAAM,OACN,CAAC,CAAC,GAAG,yHAEb;QAAuB,OAAO;QACa,SAAS;QACf,MAAM;;;QACrB,aAAa;QACN,WAAW;QAClB,cAAc;QACd,cAAc;QACb,SAAS;QACV,aAAa;KACrC,EAiKA;IAhJC,kBAA0B;IAC1B,kBAA2C;IAC3C,uBAAoC;IACpC;;;;OAIG;IACH;;MAAoB;IACpB;;;OAGG;IACH,eAFU,MAAM,CAEkB;IAClC,iBAAwB;IACxB,WAAc;IACd,uBAA0B;IAC1B,uCAA0B;IAC1B,mBAAsB;IACtB,oBAAuB;IACvB,qBAAwB;IACxB,mBAA0B;IAC1B,sBAAkC;IAClC,+BAA+B;IAC/B,yBAnXqB,QAAQ,CAAC,OAAO,QAAE,QAAQ,CAAC,OAAO,QAAE,gBAAgB,QAAE,OAAO,QAAK,MAAM,KAAE,IAAI,IAmXrD;IAC9C;;OAEG;IACH,SAFU,OAAO,CAEG;IACpB;;;OAGG;IACH,QAFU,MAAM,OAAC,CAEC;IAClB,4BAA4B;IAC5B;;;OAGG;IACH,eAFU,OAAO,CAEW;IAE5B;;OAEG;IACH,oBAFU,KAAK,CAAC;QAAE,GAAG,EAAE,CAAC,CAAC,UAAU,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,CAE3B;IAC5B;;OAEG;IACH,gBAFU,UAAU,OAAC,CAEK;IAC1B;;OAEG;IACH,iBAFU,MAAM,CAEQ;IAaxB;;;OAGG;IACH,sBAHW,WAAW,UACX,GAAG,UASb;IACD;;;;OAIG;IACH,yBAHW,UAAU,UACV,GAAG,UAuBb;IAED;;;OAGG;IACH,uDAHW,GAAG,WACH,GAAG,UAWb;IACD,yBAMC;IAKD,oBAUkC;IAMpC;;OAEG;IACH,kBAFY,UAAU,CAqBrB;IAED,kBAGC;IASD,kBANU,OAAO,EAahB;IAdD;;OAEG;IACH,cAFU,OAAO,CAIhB;IAyBD,kBAyCC;IAED,qBAeC;IAED,mBAMC;IAED,gBAMC;CACF;;;;;eArWa,OAAO;yBACP,OAAO;wBACP,OAAO;qBACP,MAAM;oBACN,MAAM;;;;YACN,OAAO,GAAG,QAAQ,GAAG,KAAK;;6BAjSX,iBAAiB;mBAR3B,MAAM;iCAaQ,kBAAkB;mCANhB,wBAAwB;0BAJjC,eAAe;0BACf,eAAe"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@styris-ame/y-engineio",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Engine.IO provider for Yjs (Yjs
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "Engine.IO provider for Yjs (Yjs v14 line)",
|
|
5
5
|
"main": "./dist/y-engineio.cjs",
|
|
6
6
|
"module": "./src/y-engineio.js",
|
|
7
7
|
"types": "./dist/y-engineio.d.ts",
|
|
@@ -40,19 +40,19 @@
|
|
|
40
40
|
]
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
+
"@y/protocols": "^1.0.6-rc.1",
|
|
43
44
|
"engine.io-client": "^6.6.5",
|
|
44
|
-
"lib0": "^0.
|
|
45
|
-
"y-protocols": "^1.0.6"
|
|
45
|
+
"lib0": "^1.0.0-rc.1"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@types/node": "^22.14.0",
|
|
49
|
+
"@y/y": "^14.0.0-22",
|
|
49
50
|
"rollup": "^4.43.0",
|
|
50
51
|
"standard": "^17.1.2",
|
|
51
|
-
"typescript": "^5.8.3"
|
|
52
|
-
"yjs": "^13.6.0"
|
|
52
|
+
"typescript": "^5.8.3"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
|
-
"
|
|
55
|
+
"@y/y": "*"
|
|
56
56
|
},
|
|
57
57
|
"engines": {
|
|
58
58
|
"npm": ">=8.0.0",
|
package/src/y-engineio.js
CHANGED
|
@@ -3,18 +3,19 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* eslint-env browser */
|
|
6
|
-
import * as Y from '
|
|
6
|
+
import * as Y from '@y/y' // eslint-disable-line
|
|
7
7
|
import * as bc from 'lib0/broadcastchannel'
|
|
8
8
|
import * as time from 'lib0/time'
|
|
9
9
|
import * as encoding from 'lib0/encoding'
|
|
10
10
|
import * as decoding from 'lib0/decoding'
|
|
11
|
-
import * as syncProtocol from 'y
|
|
12
|
-
import * as authProtocol from 'y
|
|
13
|
-
import * as awarenessProtocol from 'y
|
|
11
|
+
import * as syncProtocol from '@y/protocols/sync'
|
|
12
|
+
import * as authProtocol from '@y/protocols/auth'
|
|
13
|
+
import * as awarenessProtocol from '@y/protocols/awareness'
|
|
14
14
|
import { ObservableV2 } from 'lib0/observable'
|
|
15
15
|
import * as math from 'lib0/math'
|
|
16
16
|
import * as url from 'lib0/url'
|
|
17
17
|
import * as env from 'lib0/environment'
|
|
18
|
+
import * as array from 'lib0/array'
|
|
18
19
|
import { Socket as Engine } from 'engine.io-client'
|
|
19
20
|
|
|
20
21
|
export const messageSync = 0
|
|
@@ -36,6 +37,7 @@ messageHandlers[messageSync] = (
|
|
|
36
37
|
_messageType
|
|
37
38
|
) => {
|
|
38
39
|
encoding.writeVarUint(encoder, messageSync)
|
|
40
|
+
const readSyncPos = decoder.pos
|
|
39
41
|
const syncMessageType = syncProtocol.readSyncMessage(
|
|
40
42
|
decoder,
|
|
41
43
|
encoder,
|
|
@@ -48,6 +50,19 @@ messageHandlers[messageSync] = (
|
|
|
48
50
|
) {
|
|
49
51
|
provider.synced = true
|
|
50
52
|
}
|
|
53
|
+
// update unconfirmedUpdates
|
|
54
|
+
if (syncMessageType === 1 || syncMessageType === 2) {
|
|
55
|
+
const subdecoder = decoding.createDecoder(decoder.arr)
|
|
56
|
+
subdecoder.pos = readSyncPos
|
|
57
|
+
decoding.readVarUint(subdecoder) // === syncMessageType
|
|
58
|
+
const update = decoding.readVarUint8Array(subdecoder)
|
|
59
|
+
const receivedIds = Y.createContentIdsFromUpdate(update)
|
|
60
|
+
provider.unconfirmedUpdates = provider.unconfirmedUpdates.filter(unconfirmed => {
|
|
61
|
+
unconfirmed.ids = Y.excludeContentIds(unconfirmed.ids, receivedIds)
|
|
62
|
+
return !unconfirmed.ids.inserts.isEmpty() || !unconfirmed.ids.deletes.isEmpty()
|
|
63
|
+
})
|
|
64
|
+
emitSyncStatusEvent(provider)
|
|
65
|
+
}
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
messageHandlers[messageQueryAwareness] = (
|
|
@@ -95,8 +110,6 @@ messageHandlers[messageAuth] = (
|
|
|
95
110
|
)
|
|
96
111
|
}
|
|
97
112
|
|
|
98
|
-
const messageReconnectTimeout = 30000
|
|
99
|
-
|
|
100
113
|
/**
|
|
101
114
|
* @param {EngineIOProvider} provider
|
|
102
115
|
* @param {string} reason
|
|
@@ -104,15 +117,6 @@ const messageReconnectTimeout = 30000
|
|
|
104
117
|
const permissionDeniedHandler = (provider, reason) =>
|
|
105
118
|
console.warn(`Permission denied to access ${provider.url}.\n${reason}`)
|
|
106
119
|
|
|
107
|
-
/**
|
|
108
|
-
* @param {ArrayBuffer | ArrayBufferView} data
|
|
109
|
-
* @return {Uint8Array}
|
|
110
|
-
*/
|
|
111
|
-
const toUint8Array = (data) =>
|
|
112
|
-
data instanceof ArrayBuffer
|
|
113
|
-
? new Uint8Array(data)
|
|
114
|
-
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
|
|
115
|
-
|
|
116
120
|
/**
|
|
117
121
|
* @param {EngineIOProvider} provider
|
|
118
122
|
* @param {Uint8Array} buf
|
|
@@ -122,14 +126,27 @@ const toUint8Array = (data) =>
|
|
|
122
126
|
const readMessage = (provider, buf, emitSynced) => {
|
|
123
127
|
const decoder = decoding.createDecoder(buf)
|
|
124
128
|
const encoder = encoding.createEncoder()
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
+
while (decoding.hasContent(decoder)) {
|
|
130
|
+
const messageType = decoding.readVarUint(decoder)
|
|
131
|
+
const messageHandler = provider.messageHandlers[messageType]
|
|
132
|
+
if (/** @type {any} */ (messageHandler)) {
|
|
133
|
+
messageHandler(encoder, decoder, provider, emitSynced, messageType)
|
|
134
|
+
} else {
|
|
135
|
+
break
|
|
136
|
+
}
|
|
129
137
|
}
|
|
130
138
|
return encoder
|
|
131
139
|
}
|
|
132
140
|
|
|
141
|
+
/**
|
|
142
|
+
* @param {ArrayBuffer | ArrayBufferView} data
|
|
143
|
+
* @return {Uint8Array}
|
|
144
|
+
*/
|
|
145
|
+
const toUint8Array = (data) =>
|
|
146
|
+
data instanceof ArrayBuffer
|
|
147
|
+
? new Uint8Array(data)
|
|
148
|
+
: new Uint8Array(data.buffer, data.byteOffset, data.byteLength)
|
|
149
|
+
|
|
133
150
|
/**
|
|
134
151
|
* Outsource this function so that a new engine.io connection is created immediately.
|
|
135
152
|
* I suspect that the `close` event is not always fired if there are network issues.
|
|
@@ -155,13 +172,14 @@ const closeEngineConnection = (provider, engine, event) => {
|
|
|
155
172
|
awarenessProtocol.removeAwarenessStates(
|
|
156
173
|
provider.awareness,
|
|
157
174
|
Array.from(provider.awareness.getStates().keys()).filter((client) =>
|
|
158
|
-
client !== provider.
|
|
175
|
+
client !== provider.awareness.clientID
|
|
159
176
|
),
|
|
160
177
|
provider
|
|
161
178
|
)
|
|
162
179
|
provider.emit('status', [{
|
|
163
180
|
status: 'disconnected'
|
|
164
181
|
}])
|
|
182
|
+
emitSyncStatusEvent(provider)
|
|
165
183
|
} else {
|
|
166
184
|
provider.unsuccessfulReconnects++
|
|
167
185
|
}
|
|
@@ -256,6 +274,7 @@ const setupEngine = (provider) => {
|
|
|
256
274
|
provider.emit('status', [{
|
|
257
275
|
status: 'connecting'
|
|
258
276
|
}])
|
|
277
|
+
emitSyncStatusEvent(provider)
|
|
259
278
|
}
|
|
260
279
|
}
|
|
261
280
|
|
|
@@ -273,6 +292,39 @@ const broadcastMessage = (provider, buf) => {
|
|
|
273
292
|
}
|
|
274
293
|
}
|
|
275
294
|
|
|
295
|
+
/**
|
|
296
|
+
* This sync status event only works on certain backends (e.g. yhub)
|
|
297
|
+
* @typedef {object} SyncStatus
|
|
298
|
+
* @property {boolean} SyncStatusEvent.connected
|
|
299
|
+
* @property {boolean} SyncStatusEvent.receivedInitialSync
|
|
300
|
+
* @property {boolean} SyncStatusEvent.localUpdatesSynced
|
|
301
|
+
* @property {number} SyncStatusEvent.localUpdatesAge
|
|
302
|
+
* @property {number} SyncStatusEvent.lastMessageAge
|
|
303
|
+
* @property {'green' | 'yellow' | 'red'} SyncStatusEvent.status Distilled sync status: 'green' if synced, connected, there are no unsynced local updates. 'yellow' if last local message age is younger than 8 seconds. 'red' if unsynced or disconnected or if last local message is older than 8 seconds
|
|
304
|
+
*/
|
|
305
|
+
|
|
306
|
+
export const acceptableConnectionDelay = 8000
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* @param {EngineIOProvider} provider
|
|
310
|
+
*/
|
|
311
|
+
const emitSyncStatusEvent = provider => {
|
|
312
|
+
const syncStatus = provider.syncStatus
|
|
313
|
+
const prevSyncStatus = provider.prevSyncStatus
|
|
314
|
+
if (
|
|
315
|
+
prevSyncStatus == null ||
|
|
316
|
+
prevSyncStatus.status !== syncStatus.status ||
|
|
317
|
+
prevSyncStatus.connected !== syncStatus.connected ||
|
|
318
|
+
prevSyncStatus.localUpdatesSynced !== syncStatus.localUpdatesSynced ||
|
|
319
|
+
prevSyncStatus.receivedInitialSync !== syncStatus.receivedInitialSync ||
|
|
320
|
+
syncStatus.localUpdatesAge - prevSyncStatus.localUpdatesAge > 1000 ||
|
|
321
|
+
syncStatus.lastMessageAge - prevSyncStatus.lastMessageAge > 1000
|
|
322
|
+
) {
|
|
323
|
+
provider.emit('sync-status', [syncStatus])
|
|
324
|
+
provider.prevSyncStatus = syncStatus
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
276
328
|
/**
|
|
277
329
|
* Engine.IO Provider for Yjs. Creates an engine.io connection to sync the shared
|
|
278
330
|
* document. Unlike a raw WebSocket, engine.io connects to a single endpoint and
|
|
@@ -281,12 +333,12 @@ const broadcastMessage = (provider, buf) => {
|
|
|
281
333
|
* before any sync frames are exchanged.
|
|
282
334
|
*
|
|
283
335
|
* @example
|
|
284
|
-
* import * as Y from '
|
|
336
|
+
* import * as Y from '@y/y'
|
|
285
337
|
* import { EngineIOProvider } from '@styris-ame/y-engineio'
|
|
286
338
|
* const doc = new Y.Doc()
|
|
287
339
|
* const provider = new EngineIOProvider('http://localhost:1234', 'my-document-name', doc)
|
|
288
340
|
*
|
|
289
|
-
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any }>}
|
|
341
|
+
* @extends {ObservableV2<{ 'connection-close': (event: any, provider: EngineIOProvider) => any, 'status': (event: { status: 'connected' | 'disconnected' | 'connecting' }) => any, 'connection-error': (event: any, provider: EngineIOProvider) => any, 'sync': (state: boolean) => any, 'synced': (state: boolean) => any, 'sync-status': (syncStatus: SyncStatus) => any }>}
|
|
290
342
|
*/
|
|
291
343
|
export class EngineIOProvider extends ObservableV2 {
|
|
292
344
|
/**
|
|
@@ -302,6 +354,7 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
302
354
|
* @param {number} [opts.resyncInterval] Request server state every `resyncInterval` milliseconds
|
|
303
355
|
* @param {number} [opts.maxBackoffTime] Maximum amount of time to wait before trying to reconnect (we try to reconnect using exponential backoff)
|
|
304
356
|
* @param {boolean} [opts.disableBc] Disable cross-tab BroadcastChannel communication
|
|
357
|
+
* @param {number} [opts.socketTimeout] If no message is received for this amount of time, client will close the socket and reconnect
|
|
305
358
|
*/
|
|
306
359
|
constructor (serverUrl, roomname, doc, {
|
|
307
360
|
connect = true,
|
|
@@ -311,7 +364,8 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
311
364
|
EngineClass = Engine,
|
|
312
365
|
resyncInterval = -1,
|
|
313
366
|
maxBackoffTime = 2500,
|
|
314
|
-
disableBc = false
|
|
367
|
+
disableBc = false,
|
|
368
|
+
socketTimeout = math.round(awarenessProtocol.outdatedTimeout * 1.5)
|
|
315
369
|
} = {}) {
|
|
316
370
|
super()
|
|
317
371
|
// ensure that serverUrl does not end with /
|
|
@@ -340,6 +394,7 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
340
394
|
this.connecting = false
|
|
341
395
|
this.bcconnected = false
|
|
342
396
|
this.disableBc = disableBc
|
|
397
|
+
this.socketTimeout = socketTimeout
|
|
343
398
|
this.unsuccessfulReconnects = 0
|
|
344
399
|
this.messageHandlers = messageHandlers.slice()
|
|
345
400
|
/**
|
|
@@ -358,6 +413,14 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
358
413
|
*/
|
|
359
414
|
this.shouldConnect = connect
|
|
360
415
|
|
|
416
|
+
/**
|
|
417
|
+
* @type {Array<{ ids: Y.ContentIds, created: number }>}
|
|
418
|
+
*/
|
|
419
|
+
this.unconfirmedUpdates = []
|
|
420
|
+
/**
|
|
421
|
+
* @type {SyncStatus?}
|
|
422
|
+
*/
|
|
423
|
+
this.prevSyncStatus = null
|
|
361
424
|
/**
|
|
362
425
|
* @type {number}
|
|
363
426
|
*/
|
|
@@ -393,6 +456,20 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
393
456
|
*/
|
|
394
457
|
this._updateHandler = (update, origin) => {
|
|
395
458
|
if (origin !== this) {
|
|
459
|
+
const now = time.getUnixTime()
|
|
460
|
+
const newContentIds = Y.createContentIdsFromUpdate(update)
|
|
461
|
+
const lastUnconfirmed = this.unconfirmedUpdates.length > 0 ? array.last(this.unconfirmedUpdates) : null
|
|
462
|
+
if (lastUnconfirmed != null && now - lastUnconfirmed.created < 500) {
|
|
463
|
+
lastUnconfirmed.ids = Y.mergeContentIds([lastUnconfirmed.ids, newContentIds])
|
|
464
|
+
} else {
|
|
465
|
+
this.unconfirmedUpdates.push({
|
|
466
|
+
created: now,
|
|
467
|
+
ids: newContentIds
|
|
468
|
+
})
|
|
469
|
+
if (this.unconfirmedUpdates.length === 1) {
|
|
470
|
+
emitSyncStatusEvent(this)
|
|
471
|
+
}
|
|
472
|
+
}
|
|
396
473
|
const encoder = encoding.createEncoder()
|
|
397
474
|
encoding.writeVarUint(encoder, messageSync)
|
|
398
475
|
syncProtocol.writeUpdate(encoder, update)
|
|
@@ -428,19 +505,43 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
428
505
|
this._checkInterval = /** @type {any} */ (setInterval(() => {
|
|
429
506
|
if (
|
|
430
507
|
this.connected &&
|
|
431
|
-
|
|
508
|
+
this.socketTimeout <
|
|
432
509
|
time.getUnixTime() - this.lastMessageReceived
|
|
433
510
|
) {
|
|
434
|
-
|
|
435
|
-
// updates (which are updated every 15 seconds)
|
|
511
|
+
console.error('[y-engineio] closing timed-out connection')
|
|
436
512
|
closeEngineConnection(this, /** @type {Engine} */ (this.engine), null)
|
|
437
513
|
}
|
|
438
|
-
|
|
514
|
+
emitSyncStatusEvent(this)
|
|
515
|
+
}, acceptableConnectionDelay / 2))
|
|
439
516
|
if (connect) {
|
|
440
517
|
this.connect()
|
|
441
518
|
}
|
|
442
519
|
}
|
|
443
520
|
|
|
521
|
+
/**
|
|
522
|
+
* @return {SyncStatus}
|
|
523
|
+
*/
|
|
524
|
+
get syncStatus () {
|
|
525
|
+
const {
|
|
526
|
+
unconfirmedUpdates,
|
|
527
|
+
connected,
|
|
528
|
+
synced: receivedInitialSync,
|
|
529
|
+
lastMessageReceived
|
|
530
|
+
} = this
|
|
531
|
+
const now = time.getUnixTime()
|
|
532
|
+
const localUpdatesSynced = unconfirmedUpdates.length === 0
|
|
533
|
+
const localUpdatesAge = localUpdatesSynced ? 0 : now - unconfirmedUpdates[0].created
|
|
534
|
+
const status = (connected && receivedInitialSync && localUpdatesAge === 0) ? 'green' : (connected && localUpdatesAge < acceptableConnectionDelay ? 'yellow' : 'red')
|
|
535
|
+
return {
|
|
536
|
+
connected,
|
|
537
|
+
receivedInitialSync,
|
|
538
|
+
localUpdatesSynced,
|
|
539
|
+
localUpdatesAge,
|
|
540
|
+
lastMessageAge: now - lastMessageReceived,
|
|
541
|
+
status
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
444
545
|
get url () {
|
|
445
546
|
const encodedParams = url.encodeQueryParams({ ...this.params, room: this.roomname })
|
|
446
547
|
return this.serverUrl + (encodedParams.length === 0 ? '' : '?' + encodedParams)
|
|
@@ -509,7 +610,7 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
509
610
|
encoding.writeVarUint8Array(
|
|
510
611
|
encoderAwarenessState,
|
|
511
612
|
awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
512
|
-
this.
|
|
613
|
+
this.awareness.clientID
|
|
513
614
|
])
|
|
514
615
|
)
|
|
515
616
|
bc.publish(
|
|
@@ -526,7 +627,7 @@ export class EngineIOProvider extends ObservableV2 {
|
|
|
526
627
|
encoding.writeVarUint8Array(
|
|
527
628
|
encoder,
|
|
528
629
|
awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
529
|
-
this.
|
|
630
|
+
this.awareness.clientID
|
|
530
631
|
], new Map())
|
|
531
632
|
)
|
|
532
633
|
broadcastMessage(this, encoding.toUint8Array(encoder))
|