@hocuspocus/provider 1.1.1 → 2.0.0-alpha.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/dist/hocuspocus-provider.cjs +370 -217
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +370 -218
- package/dist/hocuspocus-provider.esm.js.map +1 -1
- package/dist/packages/extension-monitor/src/Dashboard.d.ts +1 -1
- package/dist/packages/extension-monitor/src/index.d.ts +1 -1
- package/dist/packages/provider/src/HocuspocusCloudProvider.d.ts +2 -1
- package/dist/packages/provider/src/HocuspocusProvider.d.ts +11 -69
- package/dist/packages/provider/src/HocuspocusProviderWebsocket.d.ts +115 -0
- package/dist/packages/provider/src/IncomingMessage.d.ts +2 -0
- package/dist/packages/provider/src/OutgoingMessages/CloseMessage.d.ts +8 -0
- package/dist/packages/provider/src/index.d.ts +1 -0
- package/dist/packages/provider/src/types.d.ts +3 -1
- package/dist/packages/server/src/Connection.d.ts +6 -12
- package/dist/packages/server/src/Hocuspocus.d.ts +3 -8
- package/dist/packages/server/src/IncomingMessage.d.ts +1 -0
- package/dist/packages/server/src/MessageReceiver.d.ts +1 -2
- package/dist/packages/server/src/OutgoingMessage.d.ts +1 -1
- package/dist/packages/server/src/types.d.ts +2 -1
- package/dist/tests/utils/index.d.ts +1 -0
- package/dist/tests/utils/newHocuspocusProvider.d.ts +2 -2
- package/dist/tests/utils/newHocuspocusProviderWebsocket.d.ts +3 -0
- package/package.json +4 -3
- package/src/HocuspocusCloudProvider.ts +8 -1
- package/src/HocuspocusProvider.ts +108 -361
- package/src/HocuspocusProviderWebsocket.ts +475 -0
- package/src/IncomingMessage.ts +10 -0
- package/src/MessageReceiver.ts +4 -2
- package/src/OutgoingMessages/AuthenticationMessage.ts +2 -1
- package/src/OutgoingMessages/AwarenessMessage.ts +1 -0
- package/src/OutgoingMessages/CloseMessage.ts +16 -0
- package/src/OutgoingMessages/QueryAwarenessMessage.ts +5 -0
- package/src/OutgoingMessages/StatelessMessage.ts +1 -0
- package/src/OutgoingMessages/SyncStepOneMessage.ts +1 -0
- package/src/OutgoingMessages/SyncStepTwoMessage.ts +1 -1
- package/src/OutgoingMessages/UpdateMessage.ts +3 -1
- package/src/index.ts +1 -0
- package/src/types.ts +2 -0
- package/dist/tests/server/getDocumentName.d.ts +0 -1
- /package/dist/tests/{provider → providerwebsocket}/configuration.d.ts +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as Y from 'yjs';
|
|
2
|
-
import { retry } from '@lifeomic/attempt';
|
|
3
2
|
import { readAuthMessage, writeAuthentication, awarenessStatesToArray, WsReadyStates, Unauthorized, Forbidden } from '@hocuspocus/common';
|
|
3
|
+
import { retry } from '@lifeomic/attempt';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Utility module to work with key-value stores.
|
|
@@ -1324,19 +1324,6 @@ const createMutex = () => {
|
|
|
1324
1324
|
}
|
|
1325
1325
|
};
|
|
1326
1326
|
|
|
1327
|
-
/**
|
|
1328
|
-
* Utility module to work with urls.
|
|
1329
|
-
*
|
|
1330
|
-
* @module url
|
|
1331
|
-
*/
|
|
1332
|
-
|
|
1333
|
-
/**
|
|
1334
|
-
* @param {Object<string,string>} params
|
|
1335
|
-
* @return {string}
|
|
1336
|
-
*/
|
|
1337
|
-
const encodeQueryParams = params =>
|
|
1338
|
-
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
1339
|
-
|
|
1340
1327
|
class EventEmitter {
|
|
1341
1328
|
constructor() {
|
|
1342
1329
|
this.callbacks = {};
|
|
@@ -1381,12 +1368,18 @@ class IncomingMessage {
|
|
|
1381
1368
|
readVarUint() {
|
|
1382
1369
|
return readVarUint(this.decoder);
|
|
1383
1370
|
}
|
|
1371
|
+
readVarString() {
|
|
1372
|
+
return readVarString(this.decoder);
|
|
1373
|
+
}
|
|
1384
1374
|
readVarUint8Array() {
|
|
1385
1375
|
return readVarUint8Array(this.decoder);
|
|
1386
1376
|
}
|
|
1387
1377
|
writeVarUint(type) {
|
|
1388
1378
|
return writeVarUint(this.encoder, type);
|
|
1389
1379
|
}
|
|
1380
|
+
writeVarString(string) {
|
|
1381
|
+
return writeVarString(this.encoder, string);
|
|
1382
|
+
}
|
|
1390
1383
|
writeVarUint8Array(data) {
|
|
1391
1384
|
return writeVarUint8Array(this.encoder, data);
|
|
1392
1385
|
}
|
|
@@ -1529,6 +1522,7 @@ var MessageType;
|
|
|
1529
1522
|
MessageType[MessageType["Auth"] = 2] = "Auth";
|
|
1530
1523
|
MessageType[MessageType["QueryAwareness"] = 3] = "QueryAwareness";
|
|
1531
1524
|
MessageType[MessageType["Stateless"] = 5] = "Stateless";
|
|
1525
|
+
MessageType[MessageType["CLOSE"] = 7] = "CLOSE";
|
|
1532
1526
|
})(MessageType || (MessageType = {}));
|
|
1533
1527
|
var WebSocketStatus;
|
|
1534
1528
|
(function (WebSocketStatus) {
|
|
@@ -1561,6 +1555,7 @@ class MessageReceiver {
|
|
|
1561
1555
|
apply(provider, emitSynced = true) {
|
|
1562
1556
|
const { message } = this;
|
|
1563
1557
|
const type = message.readVarUint();
|
|
1558
|
+
const emptyMessageLength = message.length();
|
|
1564
1559
|
switch (type) {
|
|
1565
1560
|
case MessageType.Sync:
|
|
1566
1561
|
this.applySyncMessage(provider, emitSynced);
|
|
@@ -1581,7 +1576,7 @@ class MessageReceiver {
|
|
|
1581
1576
|
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1582
1577
|
}
|
|
1583
1578
|
// Reply
|
|
1584
|
-
if (message.length() > 1) {
|
|
1579
|
+
if (message.length() > emptyMessageLength + 1) { // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
|
|
1585
1580
|
if (this.broadcasted) {
|
|
1586
1581
|
// TODO: Some weird TypeScript error
|
|
1587
1582
|
// @ts-ignore
|
|
@@ -1600,7 +1595,7 @@ class MessageReceiver {
|
|
|
1600
1595
|
// Apply update
|
|
1601
1596
|
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1602
1597
|
// Synced once we receive Step2
|
|
1603
|
-
if (emitSynced &&
|
|
1598
|
+
if (emitSynced && syncMessageType === messageYjsSyncStep2) {
|
|
1604
1599
|
provider.synced = true;
|
|
1605
1600
|
}
|
|
1606
1601
|
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
@@ -1650,6 +1645,7 @@ class SyncStepOneMessage extends OutgoingMessage {
|
|
|
1650
1645
|
if (typeof args.document === 'undefined') {
|
|
1651
1646
|
throw new Error('The sync step one message requires document as an argument');
|
|
1652
1647
|
}
|
|
1648
|
+
writeVarString(this.encoder, args.documentName);
|
|
1653
1649
|
writeVarUint(this.encoder, this.type);
|
|
1654
1650
|
writeSyncStep1(this.encoder, args.document);
|
|
1655
1651
|
return this.encoder;
|
|
@@ -1666,6 +1662,7 @@ class SyncStepTwoMessage extends OutgoingMessage {
|
|
|
1666
1662
|
if (typeof args.document === 'undefined') {
|
|
1667
1663
|
throw new Error('The sync step two message requires document as an argument');
|
|
1668
1664
|
}
|
|
1665
|
+
writeVarString(this.encoder, args.documentName);
|
|
1669
1666
|
writeVarUint(this.encoder, this.type);
|
|
1670
1667
|
writeSyncStep2(this.encoder, args.document);
|
|
1671
1668
|
return this.encoder;
|
|
@@ -1679,6 +1676,9 @@ class QueryAwarenessMessage extends OutgoingMessage {
|
|
|
1679
1676
|
this.description = 'Queries awareness states';
|
|
1680
1677
|
}
|
|
1681
1678
|
get(args) {
|
|
1679
|
+
console.log('queryAwareness: writing string docName', args.documentName);
|
|
1680
|
+
console.log(this.encoder.cpos);
|
|
1681
|
+
writeVarString(this.encoder, args.documentName);
|
|
1682
1682
|
writeVarUint(this.encoder, this.type);
|
|
1683
1683
|
return this.encoder;
|
|
1684
1684
|
}
|
|
@@ -1694,6 +1694,7 @@ class AuthenticationMessage extends OutgoingMessage {
|
|
|
1694
1694
|
if (typeof args.token === 'undefined') {
|
|
1695
1695
|
throw new Error('The authentication message requires `token` as an argument.');
|
|
1696
1696
|
}
|
|
1697
|
+
writeVarString(this.encoder, args.documentName);
|
|
1697
1698
|
writeVarUint(this.encoder, this.type);
|
|
1698
1699
|
writeAuthentication(this.encoder, args.token);
|
|
1699
1700
|
return this.encoder;
|
|
@@ -1713,6 +1714,7 @@ class AwarenessMessage extends OutgoingMessage {
|
|
|
1713
1714
|
if (typeof args.clients === 'undefined') {
|
|
1714
1715
|
throw new Error('The awareness message requires clients as an argument');
|
|
1715
1716
|
}
|
|
1717
|
+
writeVarString(this.encoder, args.documentName);
|
|
1716
1718
|
writeVarUint(this.encoder, this.type);
|
|
1717
1719
|
let awarenessUpdate;
|
|
1718
1720
|
if (args.states === undefined) {
|
|
@@ -1733,6 +1735,7 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1733
1735
|
this.description = 'A document update';
|
|
1734
1736
|
}
|
|
1735
1737
|
get(args) {
|
|
1738
|
+
writeVarString(this.encoder, args.documentName);
|
|
1736
1739
|
writeVarUint(this.encoder, this.type);
|
|
1737
1740
|
writeUpdate(this.encoder, args.update);
|
|
1738
1741
|
return this.encoder;
|
|
@@ -1747,24 +1750,331 @@ class StatelessMessage extends OutgoingMessage {
|
|
|
1747
1750
|
}
|
|
1748
1751
|
get(args) {
|
|
1749
1752
|
var _a;
|
|
1753
|
+
writeVarString(this.encoder, args.documentName);
|
|
1750
1754
|
writeVarUint(this.encoder, this.type);
|
|
1751
1755
|
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
1752
1756
|
return this.encoder;
|
|
1753
1757
|
}
|
|
1754
1758
|
}
|
|
1755
1759
|
|
|
1760
|
+
class CloseMessage extends OutgoingMessage {
|
|
1761
|
+
constructor() {
|
|
1762
|
+
super(...arguments);
|
|
1763
|
+
this.type = MessageType.CLOSE;
|
|
1764
|
+
this.description = 'Ask the server to close the connection';
|
|
1765
|
+
}
|
|
1766
|
+
get(args) {
|
|
1767
|
+
writeVarString(this.encoder, args.documentName);
|
|
1768
|
+
writeVarUint(this.encoder, this.type);
|
|
1769
|
+
return this.encoder;
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1756
1773
|
class HocuspocusProvider extends EventEmitter {
|
|
1757
1774
|
constructor(configuration) {
|
|
1758
1775
|
super();
|
|
1759
1776
|
this.configuration = {
|
|
1760
1777
|
name: '',
|
|
1778
|
+
// @ts-ignore
|
|
1779
|
+
document: undefined,
|
|
1780
|
+
// @ts-ignore
|
|
1781
|
+
awareness: undefined,
|
|
1782
|
+
token: null,
|
|
1783
|
+
parameters: {},
|
|
1784
|
+
broadcast: true,
|
|
1785
|
+
forceSyncInterval: false,
|
|
1786
|
+
onAuthenticated: () => null,
|
|
1787
|
+
onAuthenticationFailed: () => null,
|
|
1788
|
+
onOpen: () => null,
|
|
1789
|
+
onConnect: () => null,
|
|
1790
|
+
onMessage: () => null,
|
|
1791
|
+
onOutgoingMessage: () => null,
|
|
1792
|
+
onStatus: () => null,
|
|
1793
|
+
onSynced: () => null,
|
|
1794
|
+
onDisconnect: () => null,
|
|
1795
|
+
onClose: () => null,
|
|
1796
|
+
onDestroy: () => null,
|
|
1797
|
+
onAwarenessUpdate: () => null,
|
|
1798
|
+
onAwarenessChange: () => null,
|
|
1799
|
+
onStateless: () => null,
|
|
1800
|
+
quiet: false,
|
|
1801
|
+
};
|
|
1802
|
+
this.subscribedToBroadcastChannel = false;
|
|
1803
|
+
this.isSynced = false;
|
|
1804
|
+
this.unsyncedChanges = 0;
|
|
1805
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1806
|
+
this.isAuthenticated = false;
|
|
1807
|
+
this.mux = createMutex();
|
|
1808
|
+
this.intervals = {
|
|
1809
|
+
forceSync: null,
|
|
1810
|
+
};
|
|
1811
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1812
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1813
|
+
this.setConfiguration(configuration);
|
|
1814
|
+
this.configuration.document = configuration.document ? configuration.document : new Y.Doc();
|
|
1815
|
+
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1816
|
+
this.on('open', this.configuration.onOpen);
|
|
1817
|
+
this.on('message', this.configuration.onMessage);
|
|
1818
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1819
|
+
this.on('synced', this.configuration.onSynced);
|
|
1820
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
1821
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1822
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1823
|
+
this.on('stateless', this.configuration.onStateless);
|
|
1824
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
1825
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
1826
|
+
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
1827
|
+
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
1828
|
+
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
1829
|
+
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
1830
|
+
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
1831
|
+
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
1832
|
+
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
1833
|
+
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
1834
|
+
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
1835
|
+
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
1836
|
+
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
1837
|
+
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
1838
|
+
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
1839
|
+
this.awareness.on('update', () => {
|
|
1840
|
+
this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1841
|
+
});
|
|
1842
|
+
this.awareness.on('change', () => {
|
|
1843
|
+
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1844
|
+
});
|
|
1845
|
+
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1846
|
+
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
1847
|
+
this.registerEventListeners();
|
|
1848
|
+
if (this.configuration.forceSyncInterval) {
|
|
1849
|
+
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
1850
|
+
}
|
|
1851
|
+
this.configuration.websocketProvider.attach(this);
|
|
1852
|
+
}
|
|
1853
|
+
onStatus({ status }) {
|
|
1854
|
+
this.status = status;
|
|
1855
|
+
this.configuration.onStatus({ status });
|
|
1856
|
+
this.emit('status', { status });
|
|
1857
|
+
}
|
|
1858
|
+
setConfiguration(configuration = {}) {
|
|
1859
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
1860
|
+
}
|
|
1861
|
+
get document() {
|
|
1862
|
+
return this.configuration.document;
|
|
1863
|
+
}
|
|
1864
|
+
get awareness() {
|
|
1865
|
+
return this.configuration.awareness;
|
|
1866
|
+
}
|
|
1867
|
+
get hasUnsyncedChanges() {
|
|
1868
|
+
return this.unsyncedChanges > 0;
|
|
1869
|
+
}
|
|
1870
|
+
forceSync() {
|
|
1871
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1872
|
+
}
|
|
1873
|
+
beforeUnload() {
|
|
1874
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1875
|
+
}
|
|
1876
|
+
registerEventListeners() {
|
|
1877
|
+
if (typeof window === 'undefined') {
|
|
1878
|
+
return;
|
|
1879
|
+
}
|
|
1880
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1881
|
+
}
|
|
1882
|
+
sendStateless(payload) {
|
|
1883
|
+
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
1884
|
+
}
|
|
1885
|
+
documentUpdateHandler(update, origin) {
|
|
1886
|
+
if (origin === this) {
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
this.unsyncedChanges += 1;
|
|
1890
|
+
this.send(UpdateMessage, { update, documentName: this.configuration.name }, true);
|
|
1891
|
+
}
|
|
1892
|
+
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
1893
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
1894
|
+
this.send(AwarenessMessage, {
|
|
1895
|
+
awareness: this.awareness,
|
|
1896
|
+
clients: changedClients,
|
|
1897
|
+
documentName: this.configuration.name,
|
|
1898
|
+
}, true);
|
|
1899
|
+
}
|
|
1900
|
+
get synced() {
|
|
1901
|
+
return this.isSynced;
|
|
1902
|
+
}
|
|
1903
|
+
set synced(state) {
|
|
1904
|
+
if (this.isSynced === state) {
|
|
1905
|
+
return;
|
|
1906
|
+
}
|
|
1907
|
+
this.isSynced = state;
|
|
1908
|
+
this.emit('synced', { state });
|
|
1909
|
+
this.emit('sync', { state });
|
|
1910
|
+
}
|
|
1911
|
+
receiveStateless(payload) {
|
|
1912
|
+
this.emit('stateless', { payload });
|
|
1913
|
+
}
|
|
1914
|
+
get isAuthenticationRequired() {
|
|
1915
|
+
return !!this.configuration.token && !this.isAuthenticated;
|
|
1916
|
+
}
|
|
1917
|
+
// not needed, but provides backward compatibility with e.g. lexicla/yjs
|
|
1918
|
+
async connect() {
|
|
1919
|
+
return this.configuration.websocketProvider.connect();
|
|
1920
|
+
}
|
|
1921
|
+
disconnect() {
|
|
1922
|
+
this.disconnectBroadcastChannel();
|
|
1923
|
+
this.configuration.websocketProvider.detach(this);
|
|
1924
|
+
}
|
|
1925
|
+
async onOpen(event) {
|
|
1926
|
+
this.emit('open', { event });
|
|
1927
|
+
if (this.isAuthenticationRequired) {
|
|
1928
|
+
this.send(AuthenticationMessage, {
|
|
1929
|
+
token: await this.getToken(),
|
|
1930
|
+
documentName: this.configuration.name,
|
|
1931
|
+
});
|
|
1932
|
+
}
|
|
1933
|
+
this.startSync();
|
|
1934
|
+
}
|
|
1935
|
+
async getToken() {
|
|
1936
|
+
if (typeof this.configuration.token === 'function') {
|
|
1937
|
+
const token = await this.configuration.token();
|
|
1938
|
+
return token;
|
|
1939
|
+
}
|
|
1940
|
+
return this.configuration.token;
|
|
1941
|
+
}
|
|
1942
|
+
startSync() {
|
|
1943
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1944
|
+
if (this.awareness.getLocalState() !== null) {
|
|
1945
|
+
this.send(AwarenessMessage, {
|
|
1946
|
+
awareness: this.awareness,
|
|
1947
|
+
clients: [this.document.clientID],
|
|
1948
|
+
documentName: this.configuration.name,
|
|
1949
|
+
});
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
send(message, args, broadcast = false) {
|
|
1953
|
+
if (broadcast) {
|
|
1954
|
+
this.mux(() => { this.broadcast(message, args); });
|
|
1955
|
+
}
|
|
1956
|
+
const messageSender = new MessageSender(message, args);
|
|
1957
|
+
this.emit('outgoingMessage', { message: messageSender.message });
|
|
1958
|
+
messageSender.send(this.configuration.websocketProvider);
|
|
1959
|
+
}
|
|
1960
|
+
onMessage(event) {
|
|
1961
|
+
const message = new IncomingMessage(event.data);
|
|
1962
|
+
const documentName = message.readVarString();
|
|
1963
|
+
if (documentName !== this.configuration.name) {
|
|
1964
|
+
return; // message is meant for another provider
|
|
1965
|
+
}
|
|
1966
|
+
message.writeVarString(documentName);
|
|
1967
|
+
this.emit('message', { event, message: new IncomingMessage(event.data) });
|
|
1968
|
+
new MessageReceiver(message).apply(this);
|
|
1969
|
+
}
|
|
1970
|
+
onClose(event) {
|
|
1971
|
+
this.isAuthenticated = false;
|
|
1972
|
+
this.synced = false;
|
|
1973
|
+
// update awareness (all users except local left)
|
|
1974
|
+
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
1975
|
+
}
|
|
1976
|
+
destroy() {
|
|
1977
|
+
this.emit('destroy');
|
|
1978
|
+
if (this.intervals.forceSync) {
|
|
1979
|
+
clearInterval(this.intervals.forceSync);
|
|
1980
|
+
}
|
|
1981
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
1982
|
+
this.disconnect();
|
|
1983
|
+
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
1984
|
+
this.document.off('update', this.documentUpdateHandler);
|
|
1985
|
+
this.removeAllListeners();
|
|
1986
|
+
this.send(CloseMessage, { documentName: this.configuration.name });
|
|
1987
|
+
if (typeof window === 'undefined') {
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1990
|
+
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
1991
|
+
}
|
|
1992
|
+
permissionDeniedHandler(reason) {
|
|
1993
|
+
this.emit('authenticationFailed', { reason });
|
|
1994
|
+
this.isAuthenticated = false;
|
|
1995
|
+
this.disconnect();
|
|
1996
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1997
|
+
}
|
|
1998
|
+
authenticatedHandler() {
|
|
1999
|
+
this.isAuthenticated = true;
|
|
2000
|
+
this.emit('authenticated');
|
|
2001
|
+
this.startSync();
|
|
2002
|
+
}
|
|
2003
|
+
get broadcastChannel() {
|
|
2004
|
+
return `${this.configuration.name}`;
|
|
2005
|
+
}
|
|
2006
|
+
broadcastChannelSubscriber(data) {
|
|
2007
|
+
this.mux(() => {
|
|
2008
|
+
const message = new IncomingMessage(data);
|
|
2009
|
+
const documentName = message.readVarString();
|
|
2010
|
+
message.writeVarString(documentName);
|
|
2011
|
+
new MessageReceiver(message)
|
|
2012
|
+
.setBroadcasted(true)
|
|
2013
|
+
.apply(this, false);
|
|
2014
|
+
});
|
|
2015
|
+
}
|
|
2016
|
+
subscribeToBroadcastChannel() {
|
|
2017
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2018
|
+
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2019
|
+
this.subscribedToBroadcastChannel = true;
|
|
2020
|
+
}
|
|
2021
|
+
this.mux(() => {
|
|
2022
|
+
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2023
|
+
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2024
|
+
this.broadcast(QueryAwarenessMessage, { document: this.document });
|
|
2025
|
+
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document });
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2028
|
+
disconnectBroadcastChannel() {
|
|
2029
|
+
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2030
|
+
this.send(AwarenessMessage, {
|
|
2031
|
+
awareness: this.awareness,
|
|
2032
|
+
clients: [this.document.clientID],
|
|
2033
|
+
states: new Map(),
|
|
2034
|
+
documentName: this.configuration.name,
|
|
2035
|
+
}, true);
|
|
2036
|
+
if (this.subscribedToBroadcastChannel) {
|
|
2037
|
+
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2038
|
+
this.subscribedToBroadcastChannel = false;
|
|
2039
|
+
}
|
|
2040
|
+
}
|
|
2041
|
+
broadcast(Message, args) {
|
|
2042
|
+
if (!this.configuration.broadcast) {
|
|
2043
|
+
return;
|
|
2044
|
+
}
|
|
2045
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2046
|
+
return;
|
|
2047
|
+
}
|
|
2048
|
+
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2049
|
+
}
|
|
2050
|
+
setAwarenessField(key, value) {
|
|
2051
|
+
this.awareness.setLocalStateField(key, value);
|
|
2052
|
+
}
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
/**
|
|
2056
|
+
* Utility module to work with urls.
|
|
2057
|
+
*
|
|
2058
|
+
* @module url
|
|
2059
|
+
*/
|
|
2060
|
+
|
|
2061
|
+
/**
|
|
2062
|
+
* @param {Object<string,string>} params
|
|
2063
|
+
* @return {string}
|
|
2064
|
+
*/
|
|
2065
|
+
const encodeQueryParams = params =>
|
|
2066
|
+
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
2067
|
+
|
|
2068
|
+
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
2069
|
+
constructor(configuration) {
|
|
2070
|
+
super();
|
|
2071
|
+
this.configuration = {
|
|
1761
2072
|
url: '',
|
|
1762
2073
|
// @ts-ignore
|
|
1763
2074
|
document: undefined,
|
|
1764
2075
|
// @ts-ignore
|
|
1765
2076
|
awareness: undefined,
|
|
1766
2077
|
WebSocketPolyfill: undefined,
|
|
1767
|
-
token: null,
|
|
1768
2078
|
parameters: {},
|
|
1769
2079
|
connect: true,
|
|
1770
2080
|
broadcast: true,
|
|
@@ -1787,29 +2097,22 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1787
2097
|
jitter: true,
|
|
1788
2098
|
// retry forever
|
|
1789
2099
|
timeout: 0,
|
|
1790
|
-
onAuthenticated: () => null,
|
|
1791
|
-
onAuthenticationFailed: () => null,
|
|
1792
2100
|
onOpen: () => null,
|
|
1793
2101
|
onConnect: () => null,
|
|
1794
2102
|
onMessage: () => null,
|
|
1795
2103
|
onOutgoingMessage: () => null,
|
|
1796
2104
|
onStatus: () => null,
|
|
1797
|
-
onSynced: () => null,
|
|
1798
2105
|
onDisconnect: () => null,
|
|
1799
2106
|
onClose: () => null,
|
|
1800
2107
|
onDestroy: () => null,
|
|
1801
2108
|
onAwarenessUpdate: () => null,
|
|
1802
2109
|
onAwarenessChange: () => null,
|
|
1803
|
-
onStateless: () => null,
|
|
1804
2110
|
quiet: false,
|
|
1805
2111
|
};
|
|
1806
2112
|
this.subscribedToBroadcastChannel = false;
|
|
1807
2113
|
this.webSocket = null;
|
|
1808
2114
|
this.shouldConnect = true;
|
|
1809
2115
|
this.status = WebSocketStatus.Disconnected;
|
|
1810
|
-
this.isSynced = false;
|
|
1811
|
-
this.unsyncedChanges = 0;
|
|
1812
|
-
this.isAuthenticated = false;
|
|
1813
2116
|
this.lastMessageReceived = 0;
|
|
1814
2117
|
this.mux = createMutex();
|
|
1815
2118
|
this.intervals = {
|
|
@@ -1817,40 +2120,27 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1817
2120
|
connectionChecker: null,
|
|
1818
2121
|
};
|
|
1819
2122
|
this.connectionAttempt = null;
|
|
2123
|
+
this.receivedOnOpenPayload = undefined;
|
|
2124
|
+
this.receivedOnStatusPayload = undefined;
|
|
1820
2125
|
this.boundConnect = this.connect.bind(this);
|
|
1821
|
-
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1822
|
-
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1823
2126
|
this.setConfiguration(configuration);
|
|
1824
|
-
this.configuration.document = configuration.document ? configuration.document : new Y.Doc();
|
|
1825
|
-
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1826
2127
|
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
1827
2128
|
this.on('open', this.configuration.onOpen);
|
|
1828
|
-
this.on('
|
|
1829
|
-
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
2129
|
+
this.on('open', this.onOpen.bind(this));
|
|
1830
2130
|
this.on('connect', this.configuration.onConnect);
|
|
1831
2131
|
this.on('message', this.configuration.onMessage);
|
|
1832
2132
|
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1833
|
-
this.on('synced', this.configuration.onSynced);
|
|
1834
2133
|
this.on('status', this.configuration.onStatus);
|
|
2134
|
+
this.on('status', this.onStatus.bind(this));
|
|
1835
2135
|
this.on('disconnect', this.configuration.onDisconnect);
|
|
1836
2136
|
this.on('close', this.configuration.onClose);
|
|
1837
2137
|
this.on('destroy', this.configuration.onDestroy);
|
|
1838
2138
|
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1839
2139
|
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1840
|
-
this.on('
|
|
1841
|
-
this.
|
|
1842
|
-
this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1843
|
-
});
|
|
1844
|
-
this.awareness.on('change', () => {
|
|
1845
|
-
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1846
|
-
});
|
|
1847
|
-
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1848
|
-
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
2140
|
+
this.on('close', this.onClose.bind(this));
|
|
2141
|
+
this.on('message', this.onMessage.bind(this));
|
|
1849
2142
|
this.registerEventListeners();
|
|
1850
2143
|
this.intervals.connectionChecker = setInterval(this.checkConnection.bind(this), this.configuration.messageReconnectTimeout / 10);
|
|
1851
|
-
if (this.configuration.forceSyncInterval) {
|
|
1852
|
-
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
1853
|
-
}
|
|
1854
2144
|
if (typeof configuration.connect !== 'undefined') {
|
|
1855
2145
|
this.shouldConnect = configuration.connect;
|
|
1856
2146
|
}
|
|
@@ -1859,6 +2149,23 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1859
2149
|
}
|
|
1860
2150
|
this.connect();
|
|
1861
2151
|
}
|
|
2152
|
+
async onOpen(event) {
|
|
2153
|
+
this.receivedOnOpenPayload = event;
|
|
2154
|
+
}
|
|
2155
|
+
async onStatus(data) {
|
|
2156
|
+
this.receivedOnStatusPayload = data;
|
|
2157
|
+
}
|
|
2158
|
+
attach(provider) {
|
|
2159
|
+
if (this.receivedOnOpenPayload) {
|
|
2160
|
+
provider.onOpen(this.receivedOnOpenPayload);
|
|
2161
|
+
}
|
|
2162
|
+
if (this.receivedOnStatusPayload) {
|
|
2163
|
+
provider.onStatus(this.receivedOnStatusPayload);
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
detach(provider) {
|
|
2167
|
+
// tell the server to remove the listener
|
|
2168
|
+
}
|
|
1862
2169
|
setConfiguration(configuration = {}) {
|
|
1863
2170
|
this.configuration = { ...this.configuration, ...configuration };
|
|
1864
2171
|
}
|
|
@@ -1871,9 +2178,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1871
2178
|
this.cancelWebsocketRetry();
|
|
1872
2179
|
this.cancelWebsocketRetry = undefined;
|
|
1873
2180
|
}
|
|
1874
|
-
this.unsyncedChanges = 0; // set to 0 in case we got reconnected
|
|
1875
2181
|
this.shouldConnect = true;
|
|
1876
|
-
this.subscribeToBroadcastChannel();
|
|
1877
2182
|
const abortableRetry = () => {
|
|
1878
2183
|
let cancelAttempt = false;
|
|
1879
2184
|
const retryPromise = retry(this.createWebSocketConnection.bind(this), {
|
|
@@ -1917,15 +2222,14 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1917
2222
|
// Init the WebSocket connection
|
|
1918
2223
|
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
1919
2224
|
ws.binaryType = 'arraybuffer';
|
|
1920
|
-
ws.onmessage = this.
|
|
1921
|
-
ws.onclose = this.
|
|
1922
|
-
ws.onopen = this.
|
|
2225
|
+
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2226
|
+
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2227
|
+
ws.onopen = (payload) => this.emit('open', payload);
|
|
1923
2228
|
ws.onerror = (err) => {
|
|
1924
2229
|
reject(err);
|
|
1925
2230
|
};
|
|
1926
2231
|
this.webSocket = ws;
|
|
1927
2232
|
// Reset the status
|
|
1928
|
-
this.synced = false;
|
|
1929
2233
|
this.status = WebSocketStatus.Connecting;
|
|
1930
2234
|
this.emit('status', { status: WebSocketStatus.Connecting });
|
|
1931
2235
|
// Store resolve/reject for later use
|
|
@@ -1935,13 +2239,17 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1935
2239
|
};
|
|
1936
2240
|
});
|
|
1937
2241
|
}
|
|
2242
|
+
onMessage(event) {
|
|
2243
|
+
this.resolveConnectionAttempt();
|
|
2244
|
+
}
|
|
1938
2245
|
resolveConnectionAttempt() {
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2246
|
+
if (this.connectionAttempt) {
|
|
2247
|
+
this.connectionAttempt.resolve();
|
|
2248
|
+
this.connectionAttempt = null;
|
|
2249
|
+
this.status = WebSocketStatus.Connected;
|
|
2250
|
+
this.emit('status', { status: WebSocketStatus.Connected });
|
|
2251
|
+
this.emit('connect');
|
|
2252
|
+
}
|
|
1945
2253
|
}
|
|
1946
2254
|
stopConnectionAttempt() {
|
|
1947
2255
|
this.connectionAttempt = null;
|
|
@@ -1951,15 +2259,6 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1951
2259
|
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
1952
2260
|
this.connectionAttempt = null;
|
|
1953
2261
|
}
|
|
1954
|
-
get document() {
|
|
1955
|
-
return this.configuration.document;
|
|
1956
|
-
}
|
|
1957
|
-
get awareness() {
|
|
1958
|
-
return this.configuration.awareness;
|
|
1959
|
-
}
|
|
1960
|
-
get hasUnsyncedChanges() {
|
|
1961
|
-
return this.unsyncedChanges > 0;
|
|
1962
|
-
}
|
|
1963
2262
|
checkConnection() {
|
|
1964
2263
|
var _a;
|
|
1965
2264
|
// Don’t check the connection when it’s not even established
|
|
@@ -1978,48 +2277,11 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1978
2277
|
// Awareness updates, which are updated every 15 seconds.
|
|
1979
2278
|
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
1980
2279
|
}
|
|
1981
|
-
forceSync() {
|
|
1982
|
-
if (!this.webSocket) {
|
|
1983
|
-
return;
|
|
1984
|
-
}
|
|
1985
|
-
this.send(SyncStepOneMessage, { document: this.document });
|
|
1986
|
-
}
|
|
1987
|
-
beforeUnload() {
|
|
1988
|
-
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1989
|
-
}
|
|
1990
2280
|
registerEventListeners() {
|
|
1991
2281
|
if (typeof window === 'undefined') {
|
|
1992
2282
|
return;
|
|
1993
2283
|
}
|
|
1994
2284
|
window.addEventListener('online', this.boundConnect);
|
|
1995
|
-
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1996
|
-
}
|
|
1997
|
-
sendStateless(payload) {
|
|
1998
|
-
this.send(StatelessMessage, { payload });
|
|
1999
|
-
}
|
|
2000
|
-
documentUpdateHandler(update, origin) {
|
|
2001
|
-
if (origin === this) {
|
|
2002
|
-
return;
|
|
2003
|
-
}
|
|
2004
|
-
this.unsyncedChanges += 1;
|
|
2005
|
-
this.send(UpdateMessage, { update }, true);
|
|
2006
|
-
}
|
|
2007
|
-
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
2008
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
2009
|
-
this.send(AwarenessMessage, {
|
|
2010
|
-
awareness: this.awareness,
|
|
2011
|
-
clients: changedClients,
|
|
2012
|
-
}, true);
|
|
2013
|
-
}
|
|
2014
|
-
permissionDeniedHandler(reason) {
|
|
2015
|
-
this.emit('authenticationFailed', { reason });
|
|
2016
|
-
this.isAuthenticated = false;
|
|
2017
|
-
this.shouldConnect = false;
|
|
2018
|
-
}
|
|
2019
|
-
authenticatedHandler() {
|
|
2020
|
-
this.isAuthenticated = true;
|
|
2021
|
-
this.emit('authenticated');
|
|
2022
|
-
this.startSync();
|
|
2023
2285
|
}
|
|
2024
2286
|
// Ensure that the URL always ends with /
|
|
2025
2287
|
get serverUrl() {
|
|
@@ -2030,28 +2292,10 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2030
2292
|
}
|
|
2031
2293
|
get url() {
|
|
2032
2294
|
const encodedParams = encodeQueryParams(this.configuration.parameters);
|
|
2033
|
-
return `${this.serverUrl}
|
|
2034
|
-
}
|
|
2035
|
-
get synced() {
|
|
2036
|
-
return this.isSynced;
|
|
2037
|
-
}
|
|
2038
|
-
set synced(state) {
|
|
2039
|
-
if (this.isSynced === state) {
|
|
2040
|
-
return;
|
|
2041
|
-
}
|
|
2042
|
-
this.isSynced = state;
|
|
2043
|
-
this.emit('synced', { state });
|
|
2044
|
-
this.emit('sync', { state });
|
|
2045
|
-
}
|
|
2046
|
-
receiveStateless(payload) {
|
|
2047
|
-
this.emit('stateless', { payload });
|
|
2048
|
-
}
|
|
2049
|
-
get isAuthenticationRequired() {
|
|
2050
|
-
return !!this.configuration.token && !this.isAuthenticated;
|
|
2295
|
+
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2051
2296
|
}
|
|
2052
2297
|
disconnect() {
|
|
2053
2298
|
this.shouldConnect = false;
|
|
2054
|
-
this.disconnectBroadcastChannel();
|
|
2055
2299
|
if (this.webSocket === null) {
|
|
2056
2300
|
return;
|
|
2057
2301
|
}
|
|
@@ -2062,58 +2306,15 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2062
2306
|
//
|
|
2063
2307
|
}
|
|
2064
2308
|
}
|
|
2065
|
-
|
|
2066
|
-
this.emit('open', { event });
|
|
2067
|
-
if (this.isAuthenticationRequired) {
|
|
2068
|
-
this.send(AuthenticationMessage, {
|
|
2069
|
-
token: await this.getToken(),
|
|
2070
|
-
});
|
|
2071
|
-
return;
|
|
2072
|
-
}
|
|
2073
|
-
this.startSync();
|
|
2074
|
-
}
|
|
2075
|
-
async getToken() {
|
|
2076
|
-
if (typeof this.configuration.token === 'function') {
|
|
2077
|
-
const token = await this.configuration.token();
|
|
2078
|
-
return token;
|
|
2079
|
-
}
|
|
2080
|
-
return this.configuration.token;
|
|
2081
|
-
}
|
|
2082
|
-
startSync() {
|
|
2083
|
-
this.send(SyncStepOneMessage, { document: this.document });
|
|
2084
|
-
if (this.awareness.getLocalState() !== null) {
|
|
2085
|
-
this.send(AwarenessMessage, {
|
|
2086
|
-
awareness: this.awareness,
|
|
2087
|
-
clients: [this.document.clientID],
|
|
2088
|
-
});
|
|
2089
|
-
}
|
|
2090
|
-
}
|
|
2091
|
-
send(Message, args, broadcast = false) {
|
|
2309
|
+
send(message) {
|
|
2092
2310
|
var _a;
|
|
2093
|
-
if (broadcast) {
|
|
2094
|
-
this.mux(() => { this.broadcast(Message, args); });
|
|
2095
|
-
}
|
|
2096
2311
|
if (((_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.readyState) === WsReadyStates.Open) {
|
|
2097
|
-
|
|
2098
|
-
this.emit('outgoingMessage', { message: messageSender.message });
|
|
2099
|
-
messageSender.send(this.webSocket);
|
|
2312
|
+
this.webSocket.send(message);
|
|
2100
2313
|
}
|
|
2101
2314
|
}
|
|
2102
|
-
|
|
2103
|
-
this.resolveConnectionAttempt();
|
|
2104
|
-
this.lastMessageReceived = getUnixTime();
|
|
2105
|
-
const message = new IncomingMessage(event.data);
|
|
2106
|
-
this.emit('message', { event, message });
|
|
2107
|
-
new MessageReceiver(message).apply(this);
|
|
2108
|
-
}
|
|
2109
|
-
onClose(event) {
|
|
2110
|
-
this.emit('close', { event });
|
|
2315
|
+
onClose({ event }) {
|
|
2111
2316
|
this.webSocket = null;
|
|
2112
|
-
this.isAuthenticated = false;
|
|
2113
|
-
this.synced = false;
|
|
2114
2317
|
if (this.status === WebSocketStatus.Connected) {
|
|
2115
|
-
// update awareness (all users except local left)
|
|
2116
|
-
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
2117
2318
|
this.status = WebSocketStatus.Disconnected;
|
|
2118
2319
|
this.emit('status', { status: WebSocketStatus.Disconnected });
|
|
2119
2320
|
this.emit('disconnect', { event });
|
|
@@ -2127,6 +2328,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2127
2328
|
if (event.code === Forbidden.code) {
|
|
2128
2329
|
if (!this.configuration.quiet) {
|
|
2129
2330
|
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2331
|
+
return; // TODO REMOVE ME
|
|
2130
2332
|
}
|
|
2131
2333
|
}
|
|
2132
2334
|
if (this.connectionAttempt) {
|
|
@@ -2156,67 +2358,16 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2156
2358
|
clearInterval(this.intervals.forceSync);
|
|
2157
2359
|
}
|
|
2158
2360
|
clearInterval(this.intervals.connectionChecker);
|
|
2159
|
-
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
2160
2361
|
// If there is still a connection attempt outstanding then we should stop
|
|
2161
2362
|
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2162
2363
|
// handler and trigger a retry
|
|
2163
2364
|
this.stopConnectionAttempt();
|
|
2164
2365
|
this.disconnect();
|
|
2165
|
-
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
2166
|
-
this.document.off('update', this.documentUpdateHandler);
|
|
2167
2366
|
this.removeAllListeners();
|
|
2168
2367
|
if (typeof window === 'undefined') {
|
|
2169
2368
|
return;
|
|
2170
2369
|
}
|
|
2171
2370
|
window.removeEventListener('online', this.boundConnect);
|
|
2172
|
-
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
2173
|
-
}
|
|
2174
|
-
get broadcastChannel() {
|
|
2175
|
-
return `${this.serverUrl}/${this.configuration.name}`;
|
|
2176
|
-
}
|
|
2177
|
-
broadcastChannelSubscriber(data) {
|
|
2178
|
-
this.mux(() => {
|
|
2179
|
-
const message = new IncomingMessage(data);
|
|
2180
|
-
new MessageReceiver(message)
|
|
2181
|
-
.setBroadcasted(true)
|
|
2182
|
-
.apply(this, false);
|
|
2183
|
-
});
|
|
2184
|
-
}
|
|
2185
|
-
subscribeToBroadcastChannel() {
|
|
2186
|
-
if (!this.subscribedToBroadcastChannel) {
|
|
2187
|
-
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2188
|
-
this.subscribedToBroadcastChannel = true;
|
|
2189
|
-
}
|
|
2190
|
-
this.mux(() => {
|
|
2191
|
-
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2192
|
-
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2193
|
-
this.broadcast(QueryAwarenessMessage);
|
|
2194
|
-
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID] });
|
|
2195
|
-
});
|
|
2196
|
-
}
|
|
2197
|
-
disconnectBroadcastChannel() {
|
|
2198
|
-
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2199
|
-
this.send(AwarenessMessage, {
|
|
2200
|
-
awareness: this.awareness,
|
|
2201
|
-
clients: [this.document.clientID],
|
|
2202
|
-
states: new Map(),
|
|
2203
|
-
}, true);
|
|
2204
|
-
if (this.subscribedToBroadcastChannel) {
|
|
2205
|
-
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2206
|
-
this.subscribedToBroadcastChannel = false;
|
|
2207
|
-
}
|
|
2208
|
-
}
|
|
2209
|
-
broadcast(Message, args) {
|
|
2210
|
-
if (!this.configuration.broadcast) {
|
|
2211
|
-
return;
|
|
2212
|
-
}
|
|
2213
|
-
if (!this.subscribedToBroadcastChannel) {
|
|
2214
|
-
return;
|
|
2215
|
-
}
|
|
2216
|
-
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2217
|
-
}
|
|
2218
|
-
setAwarenessField(key, value) {
|
|
2219
|
-
this.awareness.setLocalStateField(key, value);
|
|
2220
2371
|
}
|
|
2221
2372
|
}
|
|
2222
2373
|
|
|
@@ -2231,9 +2382,10 @@ class HocuspocusCloudProvider extends HocuspocusProvider {
|
|
|
2231
2382
|
}
|
|
2232
2383
|
configuration.parameters.key = configuration.key;
|
|
2233
2384
|
}
|
|
2385
|
+
configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: configuration.url });
|
|
2234
2386
|
super(configuration);
|
|
2235
2387
|
}
|
|
2236
2388
|
}
|
|
2237
2389
|
|
|
2238
|
-
export { HocuspocusCloudProvider, HocuspocusProvider, MessageType, WebSocketStatus };
|
|
2390
|
+
export { HocuspocusCloudProvider, HocuspocusProvider, HocuspocusProviderWebsocket, MessageType, WebSocketStatus };
|
|
2239
2391
|
//# sourceMappingURL=hocuspocus-provider.esm.js.map
|