@hocuspocus/provider 1.1.0 → 2.0.0-alpha.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/dist/hocuspocus-provider.cjs +352 -217
- package/dist/hocuspocus-provider.cjs.map +1 -1
- package/dist/hocuspocus-provider.esm.js +352 -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 +10 -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/index.d.ts +1 -0
- package/dist/packages/provider/src/types.d.ts +1 -0
- package/dist/packages/server/src/Connection.d.ts +1 -11
- 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/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 +3 -3
- package/src/HocuspocusCloudProvider.ts +8 -1
- package/src/HocuspocusProvider.ts +100 -360
- 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/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 +1 -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
|
}
|
|
@@ -1561,6 +1554,7 @@ class MessageReceiver {
|
|
|
1561
1554
|
apply(provider, emitSynced = true) {
|
|
1562
1555
|
const { message } = this;
|
|
1563
1556
|
const type = message.readVarUint();
|
|
1557
|
+
const emptyMessageLength = message.length();
|
|
1564
1558
|
switch (type) {
|
|
1565
1559
|
case MessageType.Sync:
|
|
1566
1560
|
this.applySyncMessage(provider, emitSynced);
|
|
@@ -1581,7 +1575,7 @@ class MessageReceiver {
|
|
|
1581
1575
|
throw new Error(`Can’t apply message of unknown type: ${type}`);
|
|
1582
1576
|
}
|
|
1583
1577
|
// Reply
|
|
1584
|
-
if (message.length() > 1) {
|
|
1578
|
+
if (message.length() > emptyMessageLength + 1) { // length of documentName (considered in emptyMessageLength plus length of yjs sync type, set in applySyncMessage)
|
|
1585
1579
|
if (this.broadcasted) {
|
|
1586
1580
|
// TODO: Some weird TypeScript error
|
|
1587
1581
|
// @ts-ignore
|
|
@@ -1600,7 +1594,7 @@ class MessageReceiver {
|
|
|
1600
1594
|
// Apply update
|
|
1601
1595
|
const syncMessageType = readSyncMessage(message.decoder, message.encoder, provider.document, provider);
|
|
1602
1596
|
// Synced once we receive Step2
|
|
1603
|
-
if (emitSynced &&
|
|
1597
|
+
if (emitSynced && syncMessageType === messageYjsSyncStep2) {
|
|
1604
1598
|
provider.synced = true;
|
|
1605
1599
|
}
|
|
1606
1600
|
if (syncMessageType === messageYjsUpdate || syncMessageType === messageYjsSyncStep2) {
|
|
@@ -1650,6 +1644,7 @@ class SyncStepOneMessage extends OutgoingMessage {
|
|
|
1650
1644
|
if (typeof args.document === 'undefined') {
|
|
1651
1645
|
throw new Error('The sync step one message requires document as an argument');
|
|
1652
1646
|
}
|
|
1647
|
+
writeVarString(this.encoder, args.documentName);
|
|
1653
1648
|
writeVarUint(this.encoder, this.type);
|
|
1654
1649
|
writeSyncStep1(this.encoder, args.document);
|
|
1655
1650
|
return this.encoder;
|
|
@@ -1666,6 +1661,7 @@ class SyncStepTwoMessage extends OutgoingMessage {
|
|
|
1666
1661
|
if (typeof args.document === 'undefined') {
|
|
1667
1662
|
throw new Error('The sync step two message requires document as an argument');
|
|
1668
1663
|
}
|
|
1664
|
+
writeVarString(this.encoder, args.documentName);
|
|
1669
1665
|
writeVarUint(this.encoder, this.type);
|
|
1670
1666
|
writeSyncStep2(this.encoder, args.document);
|
|
1671
1667
|
return this.encoder;
|
|
@@ -1679,6 +1675,9 @@ class QueryAwarenessMessage extends OutgoingMessage {
|
|
|
1679
1675
|
this.description = 'Queries awareness states';
|
|
1680
1676
|
}
|
|
1681
1677
|
get(args) {
|
|
1678
|
+
console.log('queryAwareness: writing string docName', args.documentName);
|
|
1679
|
+
console.log(this.encoder.cpos);
|
|
1680
|
+
writeVarString(this.encoder, args.documentName);
|
|
1682
1681
|
writeVarUint(this.encoder, this.type);
|
|
1683
1682
|
return this.encoder;
|
|
1684
1683
|
}
|
|
@@ -1694,6 +1693,7 @@ class AuthenticationMessage extends OutgoingMessage {
|
|
|
1694
1693
|
if (typeof args.token === 'undefined') {
|
|
1695
1694
|
throw new Error('The authentication message requires `token` as an argument.');
|
|
1696
1695
|
}
|
|
1696
|
+
writeVarString(this.encoder, args.documentName);
|
|
1697
1697
|
writeVarUint(this.encoder, this.type);
|
|
1698
1698
|
writeAuthentication(this.encoder, args.token);
|
|
1699
1699
|
return this.encoder;
|
|
@@ -1713,6 +1713,7 @@ class AwarenessMessage extends OutgoingMessage {
|
|
|
1713
1713
|
if (typeof args.clients === 'undefined') {
|
|
1714
1714
|
throw new Error('The awareness message requires clients as an argument');
|
|
1715
1715
|
}
|
|
1716
|
+
writeVarString(this.encoder, args.documentName);
|
|
1716
1717
|
writeVarUint(this.encoder, this.type);
|
|
1717
1718
|
let awarenessUpdate;
|
|
1718
1719
|
if (args.states === undefined) {
|
|
@@ -1733,6 +1734,7 @@ class UpdateMessage extends OutgoingMessage {
|
|
|
1733
1734
|
this.description = 'A document update';
|
|
1734
1735
|
}
|
|
1735
1736
|
get(args) {
|
|
1737
|
+
writeVarString(this.encoder, args.documentName);
|
|
1736
1738
|
writeVarUint(this.encoder, this.type);
|
|
1737
1739
|
writeUpdate(this.encoder, args.update);
|
|
1738
1740
|
return this.encoder;
|
|
@@ -1747,6 +1749,7 @@ class StatelessMessage extends OutgoingMessage {
|
|
|
1747
1749
|
}
|
|
1748
1750
|
get(args) {
|
|
1749
1751
|
var _a;
|
|
1752
|
+
writeVarString(this.encoder, args.documentName);
|
|
1750
1753
|
writeVarUint(this.encoder, this.type);
|
|
1751
1754
|
writeVarString(this.encoder, (_a = args.payload) !== null && _a !== void 0 ? _a : '');
|
|
1752
1755
|
return this.encoder;
|
|
@@ -1758,13 +1761,302 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1758
1761
|
super();
|
|
1759
1762
|
this.configuration = {
|
|
1760
1763
|
name: '',
|
|
1764
|
+
// @ts-ignore
|
|
1765
|
+
document: undefined,
|
|
1766
|
+
// @ts-ignore
|
|
1767
|
+
awareness: undefined,
|
|
1768
|
+
token: null,
|
|
1769
|
+
parameters: {},
|
|
1770
|
+
broadcast: true,
|
|
1771
|
+
forceSyncInterval: false,
|
|
1772
|
+
onAuthenticated: () => null,
|
|
1773
|
+
onAuthenticationFailed: () => null,
|
|
1774
|
+
onOpen: () => null,
|
|
1775
|
+
onConnect: () => null,
|
|
1776
|
+
onMessage: () => null,
|
|
1777
|
+
onOutgoingMessage: () => null,
|
|
1778
|
+
onStatus: () => null,
|
|
1779
|
+
onSynced: () => null,
|
|
1780
|
+
onDisconnect: () => null,
|
|
1781
|
+
onClose: () => null,
|
|
1782
|
+
onDestroy: () => null,
|
|
1783
|
+
onAwarenessUpdate: () => null,
|
|
1784
|
+
onAwarenessChange: () => null,
|
|
1785
|
+
onStateless: () => null,
|
|
1786
|
+
quiet: false,
|
|
1787
|
+
};
|
|
1788
|
+
this.subscribedToBroadcastChannel = false;
|
|
1789
|
+
this.isSynced = false;
|
|
1790
|
+
this.unsyncedChanges = 0;
|
|
1791
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1792
|
+
this.isAuthenticated = false;
|
|
1793
|
+
this.mux = createMutex();
|
|
1794
|
+
this.intervals = {
|
|
1795
|
+
forceSync: null,
|
|
1796
|
+
};
|
|
1797
|
+
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1798
|
+
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1799
|
+
this.setConfiguration(configuration);
|
|
1800
|
+
this.configuration.document = configuration.document ? configuration.document : new Y.Doc();
|
|
1801
|
+
this.configuration.awareness = configuration.awareness ? configuration.awareness : new Awareness(this.document);
|
|
1802
|
+
this.on('open', this.configuration.onOpen);
|
|
1803
|
+
this.on('message', this.configuration.onMessage);
|
|
1804
|
+
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1805
|
+
this.on('synced', this.configuration.onSynced);
|
|
1806
|
+
this.on('destroy', this.configuration.onDestroy);
|
|
1807
|
+
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1808
|
+
this.on('awarenessChange', this.configuration.onAwarenessChange);
|
|
1809
|
+
this.on('stateless', this.configuration.onStateless);
|
|
1810
|
+
this.on('authenticated', this.configuration.onAuthenticated);
|
|
1811
|
+
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
1812
|
+
this.configuration.websocketProvider.on('connect', this.configuration.onConnect);
|
|
1813
|
+
this.configuration.websocketProvider.on('connect', (e) => this.emit('connect', e));
|
|
1814
|
+
this.configuration.websocketProvider.on('open', this.onOpen.bind(this));
|
|
1815
|
+
this.configuration.websocketProvider.on('open', (e) => this.emit('open', e));
|
|
1816
|
+
this.configuration.websocketProvider.on('message', this.onMessage.bind(this));
|
|
1817
|
+
this.configuration.websocketProvider.on('close', this.onClose.bind(this));
|
|
1818
|
+
this.configuration.websocketProvider.on('close', this.configuration.onClose);
|
|
1819
|
+
this.configuration.websocketProvider.on('close', (e) => this.emit('close', e));
|
|
1820
|
+
this.configuration.websocketProvider.on('status', this.onStatus.bind(this));
|
|
1821
|
+
this.configuration.websocketProvider.on('disconnect', this.configuration.onDisconnect);
|
|
1822
|
+
this.configuration.websocketProvider.on('disconnect', (e) => this.emit('disconnect', e));
|
|
1823
|
+
this.configuration.websocketProvider.on('destroy', this.configuration.onDestroy);
|
|
1824
|
+
this.configuration.websocketProvider.on('destroy', (e) => this.emit('destroy', e));
|
|
1825
|
+
this.awareness.on('update', () => {
|
|
1826
|
+
this.emit('awarenessUpdate', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1827
|
+
});
|
|
1828
|
+
this.awareness.on('change', () => {
|
|
1829
|
+
this.emit('awarenessChange', { states: awarenessStatesToArray(this.awareness.getStates()) });
|
|
1830
|
+
});
|
|
1831
|
+
this.document.on('update', this.documentUpdateHandler.bind(this));
|
|
1832
|
+
this.awareness.on('update', this.awarenessUpdateHandler.bind(this));
|
|
1833
|
+
this.registerEventListeners();
|
|
1834
|
+
if (this.configuration.forceSyncInterval) {
|
|
1835
|
+
this.intervals.forceSync = setInterval(this.forceSync.bind(this), this.configuration.forceSyncInterval);
|
|
1836
|
+
}
|
|
1837
|
+
this.configuration.websocketProvider.attach(this);
|
|
1838
|
+
}
|
|
1839
|
+
onStatus({ status }) {
|
|
1840
|
+
this.status = status;
|
|
1841
|
+
this.configuration.onStatus({ status });
|
|
1842
|
+
this.emit('status', { status });
|
|
1843
|
+
}
|
|
1844
|
+
setConfiguration(configuration = {}) {
|
|
1845
|
+
this.configuration = { ...this.configuration, ...configuration };
|
|
1846
|
+
}
|
|
1847
|
+
get document() {
|
|
1848
|
+
return this.configuration.document;
|
|
1849
|
+
}
|
|
1850
|
+
get awareness() {
|
|
1851
|
+
return this.configuration.awareness;
|
|
1852
|
+
}
|
|
1853
|
+
get hasUnsyncedChanges() {
|
|
1854
|
+
return this.unsyncedChanges > 0;
|
|
1855
|
+
}
|
|
1856
|
+
forceSync() {
|
|
1857
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1858
|
+
}
|
|
1859
|
+
beforeUnload() {
|
|
1860
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'window unload');
|
|
1861
|
+
}
|
|
1862
|
+
registerEventListeners() {
|
|
1863
|
+
if (typeof window === 'undefined') {
|
|
1864
|
+
return;
|
|
1865
|
+
}
|
|
1866
|
+
window.addEventListener('beforeunload', this.boundBeforeUnload);
|
|
1867
|
+
}
|
|
1868
|
+
sendStateless(payload) {
|
|
1869
|
+
this.send(StatelessMessage, { documentName: this.configuration.name, payload });
|
|
1870
|
+
}
|
|
1871
|
+
documentUpdateHandler(update, origin) {
|
|
1872
|
+
if (origin === this) {
|
|
1873
|
+
return;
|
|
1874
|
+
}
|
|
1875
|
+
this.unsyncedChanges += 1;
|
|
1876
|
+
this.send(UpdateMessage, { update, documentName: this.configuration.name }, true);
|
|
1877
|
+
}
|
|
1878
|
+
awarenessUpdateHandler({ added, updated, removed }, origin) {
|
|
1879
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
1880
|
+
this.send(AwarenessMessage, {
|
|
1881
|
+
awareness: this.awareness,
|
|
1882
|
+
clients: changedClients,
|
|
1883
|
+
documentName: this.configuration.name,
|
|
1884
|
+
}, true);
|
|
1885
|
+
}
|
|
1886
|
+
get synced() {
|
|
1887
|
+
return this.isSynced;
|
|
1888
|
+
}
|
|
1889
|
+
set synced(state) {
|
|
1890
|
+
if (this.isSynced === state) {
|
|
1891
|
+
return;
|
|
1892
|
+
}
|
|
1893
|
+
this.isSynced = state;
|
|
1894
|
+
this.emit('synced', { state });
|
|
1895
|
+
this.emit('sync', { state });
|
|
1896
|
+
}
|
|
1897
|
+
receiveStateless(payload) {
|
|
1898
|
+
this.emit('stateless', { payload });
|
|
1899
|
+
}
|
|
1900
|
+
get isAuthenticationRequired() {
|
|
1901
|
+
return !!this.configuration.token && !this.isAuthenticated;
|
|
1902
|
+
}
|
|
1903
|
+
disconnect() {
|
|
1904
|
+
this.disconnectBroadcastChannel();
|
|
1905
|
+
this.configuration.websocketProvider.detach(this);
|
|
1906
|
+
}
|
|
1907
|
+
async onOpen(event) {
|
|
1908
|
+
this.emit('open', { event });
|
|
1909
|
+
if (this.isAuthenticationRequired) {
|
|
1910
|
+
this.send(AuthenticationMessage, {
|
|
1911
|
+
token: await this.getToken(),
|
|
1912
|
+
documentName: this.configuration.name,
|
|
1913
|
+
});
|
|
1914
|
+
return;
|
|
1915
|
+
}
|
|
1916
|
+
this.startSync();
|
|
1917
|
+
}
|
|
1918
|
+
async getToken() {
|
|
1919
|
+
if (typeof this.configuration.token === 'function') {
|
|
1920
|
+
const token = await this.configuration.token();
|
|
1921
|
+
return token;
|
|
1922
|
+
}
|
|
1923
|
+
return this.configuration.token;
|
|
1924
|
+
}
|
|
1925
|
+
startSync() {
|
|
1926
|
+
this.send(SyncStepOneMessage, { document: this.document, documentName: this.configuration.name });
|
|
1927
|
+
if (this.awareness.getLocalState() !== null) {
|
|
1928
|
+
this.send(AwarenessMessage, {
|
|
1929
|
+
awareness: this.awareness,
|
|
1930
|
+
clients: [this.document.clientID],
|
|
1931
|
+
documentName: this.configuration.name,
|
|
1932
|
+
});
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
send(message, args, broadcast = false) {
|
|
1936
|
+
if (broadcast) {
|
|
1937
|
+
this.mux(() => { this.broadcast(message, args); });
|
|
1938
|
+
}
|
|
1939
|
+
const messageSender = new MessageSender(message, args);
|
|
1940
|
+
this.emit('outgoingMessage', { message: messageSender.message });
|
|
1941
|
+
messageSender.send(this.configuration.websocketProvider);
|
|
1942
|
+
}
|
|
1943
|
+
onMessage(event) {
|
|
1944
|
+
const message = new IncomingMessage(event.data);
|
|
1945
|
+
const documentName = message.readVarString();
|
|
1946
|
+
if (documentName !== this.configuration.name) {
|
|
1947
|
+
return; // message is meant for another provider
|
|
1948
|
+
}
|
|
1949
|
+
message.writeVarString(documentName);
|
|
1950
|
+
this.emit('message', { event, message: new IncomingMessage(event.data) });
|
|
1951
|
+
new MessageReceiver(message).apply(this);
|
|
1952
|
+
}
|
|
1953
|
+
onClose(event) {
|
|
1954
|
+
this.isAuthenticated = false;
|
|
1955
|
+
this.synced = false;
|
|
1956
|
+
// update awareness (all users except local left)
|
|
1957
|
+
removeAwarenessStates(this.awareness, Array.from(this.awareness.getStates().keys()).filter(client => client !== this.document.clientID), this);
|
|
1958
|
+
}
|
|
1959
|
+
destroy() {
|
|
1960
|
+
this.emit('destroy');
|
|
1961
|
+
if (this.intervals.forceSync) {
|
|
1962
|
+
clearInterval(this.intervals.forceSync);
|
|
1963
|
+
}
|
|
1964
|
+
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
1965
|
+
this.disconnect();
|
|
1966
|
+
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
1967
|
+
this.document.off('update', this.documentUpdateHandler);
|
|
1968
|
+
this.removeAllListeners();
|
|
1969
|
+
if (typeof window === 'undefined') {
|
|
1970
|
+
return;
|
|
1971
|
+
}
|
|
1972
|
+
window.removeEventListener('beforeunload', this.boundBeforeUnload);
|
|
1973
|
+
}
|
|
1974
|
+
permissionDeniedHandler(reason) {
|
|
1975
|
+
this.emit('authenticationFailed', { reason });
|
|
1976
|
+
this.isAuthenticated = false;
|
|
1977
|
+
this.disconnect();
|
|
1978
|
+
this.status = WebSocketStatus.Disconnected;
|
|
1979
|
+
}
|
|
1980
|
+
authenticatedHandler() {
|
|
1981
|
+
this.isAuthenticated = true;
|
|
1982
|
+
this.emit('authenticated');
|
|
1983
|
+
this.startSync();
|
|
1984
|
+
}
|
|
1985
|
+
get broadcastChannel() {
|
|
1986
|
+
return `${this.configuration.name}`;
|
|
1987
|
+
}
|
|
1988
|
+
broadcastChannelSubscriber(data) {
|
|
1989
|
+
this.mux(() => {
|
|
1990
|
+
const message = new IncomingMessage(data);
|
|
1991
|
+
const documentName = message.readVarString();
|
|
1992
|
+
message.writeVarString(documentName);
|
|
1993
|
+
new MessageReceiver(message)
|
|
1994
|
+
.setBroadcasted(true)
|
|
1995
|
+
.apply(this, false);
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
subscribeToBroadcastChannel() {
|
|
1999
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2000
|
+
subscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2001
|
+
this.subscribedToBroadcastChannel = true;
|
|
2002
|
+
}
|
|
2003
|
+
this.mux(() => {
|
|
2004
|
+
this.broadcast(SyncStepOneMessage, { document: this.document });
|
|
2005
|
+
this.broadcast(SyncStepTwoMessage, { document: this.document });
|
|
2006
|
+
this.broadcast(QueryAwarenessMessage, { document: this.document });
|
|
2007
|
+
this.broadcast(AwarenessMessage, { awareness: this.awareness, clients: [this.document.clientID], document: this.document });
|
|
2008
|
+
});
|
|
2009
|
+
}
|
|
2010
|
+
disconnectBroadcastChannel() {
|
|
2011
|
+
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
2012
|
+
this.send(AwarenessMessage, {
|
|
2013
|
+
awareness: this.awareness,
|
|
2014
|
+
clients: [this.document.clientID],
|
|
2015
|
+
states: new Map(),
|
|
2016
|
+
documentName: this.configuration.name,
|
|
2017
|
+
}, true);
|
|
2018
|
+
if (this.subscribedToBroadcastChannel) {
|
|
2019
|
+
unsubscribe(this.broadcastChannel, this.boundBroadcastChannelSubscriber);
|
|
2020
|
+
this.subscribedToBroadcastChannel = false;
|
|
2021
|
+
}
|
|
2022
|
+
}
|
|
2023
|
+
broadcast(Message, args) {
|
|
2024
|
+
if (!this.configuration.broadcast) {
|
|
2025
|
+
return;
|
|
2026
|
+
}
|
|
2027
|
+
if (!this.subscribedToBroadcastChannel) {
|
|
2028
|
+
return;
|
|
2029
|
+
}
|
|
2030
|
+
new MessageSender(Message, args).broadcast(this.broadcastChannel);
|
|
2031
|
+
}
|
|
2032
|
+
setAwarenessField(key, value) {
|
|
2033
|
+
this.awareness.setLocalStateField(key, value);
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
|
|
2037
|
+
/**
|
|
2038
|
+
* Utility module to work with urls.
|
|
2039
|
+
*
|
|
2040
|
+
* @module url
|
|
2041
|
+
*/
|
|
2042
|
+
|
|
2043
|
+
/**
|
|
2044
|
+
* @param {Object<string,string>} params
|
|
2045
|
+
* @return {string}
|
|
2046
|
+
*/
|
|
2047
|
+
const encodeQueryParams = params =>
|
|
2048
|
+
map(params, (val, key) => `${encodeURIComponent(key)}=${encodeURIComponent(val)}`).join('&');
|
|
2049
|
+
|
|
2050
|
+
class HocuspocusProviderWebsocket extends EventEmitter {
|
|
2051
|
+
constructor(configuration) {
|
|
2052
|
+
super();
|
|
2053
|
+
this.configuration = {
|
|
1761
2054
|
url: '',
|
|
1762
2055
|
// @ts-ignore
|
|
1763
2056
|
document: undefined,
|
|
1764
2057
|
// @ts-ignore
|
|
1765
2058
|
awareness: undefined,
|
|
1766
2059
|
WebSocketPolyfill: undefined,
|
|
1767
|
-
token: null,
|
|
1768
2060
|
parameters: {},
|
|
1769
2061
|
connect: true,
|
|
1770
2062
|
broadcast: true,
|
|
@@ -1787,29 +2079,22 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1787
2079
|
jitter: true,
|
|
1788
2080
|
// retry forever
|
|
1789
2081
|
timeout: 0,
|
|
1790
|
-
onAuthenticated: () => null,
|
|
1791
|
-
onAuthenticationFailed: () => null,
|
|
1792
2082
|
onOpen: () => null,
|
|
1793
2083
|
onConnect: () => null,
|
|
1794
2084
|
onMessage: () => null,
|
|
1795
2085
|
onOutgoingMessage: () => null,
|
|
1796
2086
|
onStatus: () => null,
|
|
1797
|
-
onSynced: () => null,
|
|
1798
2087
|
onDisconnect: () => null,
|
|
1799
2088
|
onClose: () => null,
|
|
1800
2089
|
onDestroy: () => null,
|
|
1801
2090
|
onAwarenessUpdate: () => null,
|
|
1802
2091
|
onAwarenessChange: () => null,
|
|
1803
|
-
onStateless: () => null,
|
|
1804
2092
|
quiet: false,
|
|
1805
2093
|
};
|
|
1806
2094
|
this.subscribedToBroadcastChannel = false;
|
|
1807
2095
|
this.webSocket = null;
|
|
1808
2096
|
this.shouldConnect = true;
|
|
1809
2097
|
this.status = WebSocketStatus.Disconnected;
|
|
1810
|
-
this.isSynced = false;
|
|
1811
|
-
this.unsyncedChanges = 0;
|
|
1812
|
-
this.isAuthenticated = false;
|
|
1813
2098
|
this.lastMessageReceived = 0;
|
|
1814
2099
|
this.mux = createMutex();
|
|
1815
2100
|
this.intervals = {
|
|
@@ -1817,40 +2102,27 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1817
2102
|
connectionChecker: null,
|
|
1818
2103
|
};
|
|
1819
2104
|
this.connectionAttempt = null;
|
|
2105
|
+
this.receivedOnOpenPayload = undefined;
|
|
2106
|
+
this.receivedOnStatusPayload = undefined;
|
|
1820
2107
|
this.boundConnect = this.connect.bind(this);
|
|
1821
|
-
this.boundBeforeUnload = this.beforeUnload.bind(this);
|
|
1822
|
-
this.boundBroadcastChannelSubscriber = this.broadcastChannelSubscriber.bind(this);
|
|
1823
2108
|
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
2109
|
this.configuration.WebSocketPolyfill = configuration.WebSocketPolyfill ? configuration.WebSocketPolyfill : WebSocket;
|
|
1827
2110
|
this.on('open', this.configuration.onOpen);
|
|
1828
|
-
this.on('
|
|
1829
|
-
this.on('authenticationFailed', this.configuration.onAuthenticationFailed);
|
|
2111
|
+
this.on('open', this.onOpen.bind(this));
|
|
1830
2112
|
this.on('connect', this.configuration.onConnect);
|
|
1831
2113
|
this.on('message', this.configuration.onMessage);
|
|
1832
2114
|
this.on('outgoingMessage', this.configuration.onOutgoingMessage);
|
|
1833
|
-
this.on('synced', this.configuration.onSynced);
|
|
1834
2115
|
this.on('status', this.configuration.onStatus);
|
|
2116
|
+
this.on('status', this.onStatus.bind(this));
|
|
1835
2117
|
this.on('disconnect', this.configuration.onDisconnect);
|
|
1836
2118
|
this.on('close', this.configuration.onClose);
|
|
1837
2119
|
this.on('destroy', this.configuration.onDestroy);
|
|
1838
2120
|
this.on('awarenessUpdate', this.configuration.onAwarenessUpdate);
|
|
1839
2121
|
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));
|
|
2122
|
+
this.on('close', this.onClose.bind(this));
|
|
2123
|
+
this.on('message', this.onMessage.bind(this));
|
|
1849
2124
|
this.registerEventListeners();
|
|
1850
2125
|
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
2126
|
if (typeof configuration.connect !== 'undefined') {
|
|
1855
2127
|
this.shouldConnect = configuration.connect;
|
|
1856
2128
|
}
|
|
@@ -1859,6 +2131,23 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1859
2131
|
}
|
|
1860
2132
|
this.connect();
|
|
1861
2133
|
}
|
|
2134
|
+
async onOpen(event) {
|
|
2135
|
+
this.receivedOnOpenPayload = event;
|
|
2136
|
+
}
|
|
2137
|
+
async onStatus(data) {
|
|
2138
|
+
this.receivedOnStatusPayload = data;
|
|
2139
|
+
}
|
|
2140
|
+
attach(provider) {
|
|
2141
|
+
if (this.receivedOnOpenPayload) {
|
|
2142
|
+
provider.onOpen(this.receivedOnOpenPayload);
|
|
2143
|
+
}
|
|
2144
|
+
if (this.receivedOnStatusPayload) {
|
|
2145
|
+
provider.onStatus(this.receivedOnStatusPayload);
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
detach(provider) {
|
|
2149
|
+
// tell the server to remove the listener
|
|
2150
|
+
}
|
|
1862
2151
|
setConfiguration(configuration = {}) {
|
|
1863
2152
|
this.configuration = { ...this.configuration, ...configuration };
|
|
1864
2153
|
}
|
|
@@ -1871,9 +2160,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1871
2160
|
this.cancelWebsocketRetry();
|
|
1872
2161
|
this.cancelWebsocketRetry = undefined;
|
|
1873
2162
|
}
|
|
1874
|
-
this.unsyncedChanges = 0; // set to 0 in case we got reconnected
|
|
1875
2163
|
this.shouldConnect = true;
|
|
1876
|
-
this.subscribeToBroadcastChannel();
|
|
1877
2164
|
const abortableRetry = () => {
|
|
1878
2165
|
let cancelAttempt = false;
|
|
1879
2166
|
const retryPromise = retry(this.createWebSocketConnection.bind(this), {
|
|
@@ -1917,15 +2204,14 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1917
2204
|
// Init the WebSocket connection
|
|
1918
2205
|
const ws = new this.configuration.WebSocketPolyfill(this.url);
|
|
1919
2206
|
ws.binaryType = 'arraybuffer';
|
|
1920
|
-
ws.onmessage = this.
|
|
1921
|
-
ws.onclose = this.
|
|
1922
|
-
ws.onopen = this.
|
|
2207
|
+
ws.onmessage = (payload) => this.emit('message', payload);
|
|
2208
|
+
ws.onclose = (payload) => this.emit('close', { event: payload });
|
|
2209
|
+
ws.onopen = (payload) => this.emit('open', payload);
|
|
1923
2210
|
ws.onerror = (err) => {
|
|
1924
2211
|
reject(err);
|
|
1925
2212
|
};
|
|
1926
2213
|
this.webSocket = ws;
|
|
1927
2214
|
// Reset the status
|
|
1928
|
-
this.synced = false;
|
|
1929
2215
|
this.status = WebSocketStatus.Connecting;
|
|
1930
2216
|
this.emit('status', { status: WebSocketStatus.Connecting });
|
|
1931
2217
|
// Store resolve/reject for later use
|
|
@@ -1935,13 +2221,17 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1935
2221
|
};
|
|
1936
2222
|
});
|
|
1937
2223
|
}
|
|
2224
|
+
onMessage(event) {
|
|
2225
|
+
this.resolveConnectionAttempt();
|
|
2226
|
+
}
|
|
1938
2227
|
resolveConnectionAttempt() {
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
2228
|
+
if (this.connectionAttempt) {
|
|
2229
|
+
this.connectionAttempt.resolve();
|
|
2230
|
+
this.connectionAttempt = null;
|
|
2231
|
+
this.status = WebSocketStatus.Connected;
|
|
2232
|
+
this.emit('status', { status: WebSocketStatus.Connected });
|
|
2233
|
+
this.emit('connect');
|
|
2234
|
+
}
|
|
1945
2235
|
}
|
|
1946
2236
|
stopConnectionAttempt() {
|
|
1947
2237
|
this.connectionAttempt = null;
|
|
@@ -1951,15 +2241,6 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1951
2241
|
(_a = this.connectionAttempt) === null || _a === void 0 ? void 0 : _a.reject();
|
|
1952
2242
|
this.connectionAttempt = null;
|
|
1953
2243
|
}
|
|
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
2244
|
checkConnection() {
|
|
1964
2245
|
var _a;
|
|
1965
2246
|
// Don’t check the connection when it’s not even established
|
|
@@ -1978,48 +2259,11 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
1978
2259
|
// Awareness updates, which are updated every 15 seconds.
|
|
1979
2260
|
(_a = this.webSocket) === null || _a === void 0 ? void 0 : _a.close();
|
|
1980
2261
|
}
|
|
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
2262
|
registerEventListeners() {
|
|
1991
2263
|
if (typeof window === 'undefined') {
|
|
1992
2264
|
return;
|
|
1993
2265
|
}
|
|
1994
2266
|
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
2267
|
}
|
|
2024
2268
|
// Ensure that the URL always ends with /
|
|
2025
2269
|
get serverUrl() {
|
|
@@ -2030,28 +2274,10 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2030
2274
|
}
|
|
2031
2275
|
get url() {
|
|
2032
2276
|
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;
|
|
2277
|
+
return `${this.serverUrl}${encodedParams.length === 0 ? '' : `?${encodedParams}`}`;
|
|
2051
2278
|
}
|
|
2052
2279
|
disconnect() {
|
|
2053
2280
|
this.shouldConnect = false;
|
|
2054
|
-
this.disconnectBroadcastChannel();
|
|
2055
2281
|
if (this.webSocket === null) {
|
|
2056
2282
|
return;
|
|
2057
2283
|
}
|
|
@@ -2062,58 +2288,15 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2062
2288
|
//
|
|
2063
2289
|
}
|
|
2064
2290
|
}
|
|
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) {
|
|
2291
|
+
send(message) {
|
|
2092
2292
|
var _a;
|
|
2093
|
-
if (broadcast) {
|
|
2094
|
-
this.mux(() => { this.broadcast(Message, args); });
|
|
2095
|
-
}
|
|
2096
2293
|
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);
|
|
2294
|
+
this.webSocket.send(message);
|
|
2100
2295
|
}
|
|
2101
2296
|
}
|
|
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 });
|
|
2297
|
+
onClose({ event }) {
|
|
2111
2298
|
this.webSocket = null;
|
|
2112
|
-
this.isAuthenticated = false;
|
|
2113
|
-
this.synced = false;
|
|
2114
2299
|
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
2300
|
this.status = WebSocketStatus.Disconnected;
|
|
2118
2301
|
this.emit('status', { status: WebSocketStatus.Disconnected });
|
|
2119
2302
|
this.emit('disconnect', { event });
|
|
@@ -2127,6 +2310,7 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2127
2310
|
if (event.code === Forbidden.code) {
|
|
2128
2311
|
if (!this.configuration.quiet) {
|
|
2129
2312
|
console.warn('[HocuspocusProvider] The provided authentication token isn’t allowed to connect to this server. Will try again.');
|
|
2313
|
+
return; // TODO REMOVE ME
|
|
2130
2314
|
}
|
|
2131
2315
|
}
|
|
2132
2316
|
if (this.connectionAttempt) {
|
|
@@ -2156,67 +2340,16 @@ class HocuspocusProvider extends EventEmitter {
|
|
|
2156
2340
|
clearInterval(this.intervals.forceSync);
|
|
2157
2341
|
}
|
|
2158
2342
|
clearInterval(this.intervals.connectionChecker);
|
|
2159
|
-
removeAwarenessStates(this.awareness, [this.document.clientID], 'provider destroy');
|
|
2160
2343
|
// If there is still a connection attempt outstanding then we should stop
|
|
2161
2344
|
// it before calling disconnect, otherwise it will be rejected in the onClose
|
|
2162
2345
|
// handler and trigger a retry
|
|
2163
2346
|
this.stopConnectionAttempt();
|
|
2164
2347
|
this.disconnect();
|
|
2165
|
-
this.awareness.off('update', this.awarenessUpdateHandler);
|
|
2166
|
-
this.document.off('update', this.documentUpdateHandler);
|
|
2167
2348
|
this.removeAllListeners();
|
|
2168
2349
|
if (typeof window === 'undefined') {
|
|
2169
2350
|
return;
|
|
2170
2351
|
}
|
|
2171
2352
|
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
2353
|
}
|
|
2221
2354
|
}
|
|
2222
2355
|
|
|
@@ -2231,9 +2364,10 @@ class HocuspocusCloudProvider extends HocuspocusProvider {
|
|
|
2231
2364
|
}
|
|
2232
2365
|
configuration.parameters.key = configuration.key;
|
|
2233
2366
|
}
|
|
2367
|
+
configuration.websocketProvider = new HocuspocusProviderWebsocket({ url: configuration.url });
|
|
2234
2368
|
super(configuration);
|
|
2235
2369
|
}
|
|
2236
2370
|
}
|
|
2237
2371
|
|
|
2238
|
-
export { HocuspocusCloudProvider, HocuspocusProvider, MessageType, WebSocketStatus };
|
|
2372
|
+
export { HocuspocusCloudProvider, HocuspocusProvider, HocuspocusProviderWebsocket, MessageType, WebSocketStatus };
|
|
2239
2373
|
//# sourceMappingURL=hocuspocus-provider.esm.js.map
|