UNPKG

y-socket.io-provider

Version:

Socket IO Provider for Yjs (Inspired by y-websocket and y-socket.io)

216 lines (215 loc) 8.81 kB
/** * SocketIOProvider instance configuration. Here you can configure: * - autoConnect: (Optional) Will try to connect to the server when the instance is created if true; otherwise you have to call `provider.connect()` manually * - awareness: (Optional) Give an existing awareness * - resyncInterval: (Optional) Specify the number of milliseconds to set an interval to synchronize the document, * if it is greater than 0 enable the synchronization interval (by default is -1) * - disableBc: (Optional) This boolean disable the broadcast channel functionality, by default is false (broadcast channel enabled) * - onConnect: (Optional) Set a callback that will triggered immediately when the socket is connected * - onDisconnect: (Optional) Set a callback that will triggered immediately when the socket is disconnected * - onConnectError: (Optional) Set a callback that will triggered immediately when the occurs a socket connection error */ /** * The socket io provider class to sync a document */ export class SocketIOProvider extends Observable<any> { /** * SocketIOProvider constructor * @constructor * @param {string} url The connection url from server * @param {string} roomName The document's room name * @param {Y.Doc} doc The yjs document * @param options Configuration options to the SocketIOProvider */ constructor(url: string, roomName: string, doc: Y.Doc, { autoConnect, awareness, resyncInterval, disableBc, auth, }: { autoConnect?: boolean; awareness?: AwarenessProtocol.Awareness; resyncInterval?: number; disableBc?: boolean; auth?: {}; }); /** * The connection url to server. Example: `ws://localhost:3001` * @type {string} */ _url: string; /** * The name of the document room * @type {string} */ roomName: string; /** * The broadcast channel room * @type {string} * @private */ private _broadcastChannel; /** * The socket connection * @type {Socket} */ socket: Socket; /** * The yjs document * @type {Y.Doc} */ doc: Y.Doc; /** * The awareness * @type {AwarenessProtocol.Awareness} */ awareness: AwarenessProtocol.Awareness; /** * Disable broadcast channel, by default is false * @type {boolean} */ disableBc: boolean; /** * The broadcast channel connection status indicator * @type {boolean} */ bcconnected: boolean; /** * The document's sync status indicator * @type {boolean} * @private */ private _synced; /** * Interval to emit `sync-step-1` to sync changes * @type {NodeJS.Timer | null} * @private */ private resyncInterval; /** * Broadcast channel room getter * @type {string} */ get broadcastChannel(): string; /** * URL getter * @type {string} */ get url(): string; /** * Synchronized state flag setter */ set synced(arg: boolean); /** * Synchronized state flag getter * @type {boolean} */ get synced(): boolean; /** * This function initializes the socket event listeners to synchronize document changes. * * The synchronization protocol is as follows: * - A server emits the sync step one event (`sync-step-1`) which sends the document as a state vector * and the sync step two callback as an acknowledgment according to the socket io acknowledgments. * - When the client receives the `sync-step-1` event, it executes the `syncStep2` acknowledgment callback and sends * the difference between the received state vector and the local document (this difference is called an update). * - The second step of the sync is to apply the update sent in the `syncStep2` callback parameters from the client * to the document on the server side. * - There is another event (`sync-update`) that is emitted from the server, which sends an update for the document, * and when the client receives this event, it applies the received update to the local document. * - When an update is applied to a document, it will fire the document's "update" event, which * sends the update to the server. * @type {() => void} * @private */ private initSyncListeners; /** * This function initializes socket event listeners to synchronize awareness changes. * * The awareness protocol is as follows: * - The server emits the `awareness-update` event by sending the awareness update. * - The client receives that event and applies the received update to the local awareness. * - When an update is applied to awareness, the awareness "update" event will fire, which * sends the update to the server. * @type {() => void} * @private */ private initAwarenessListeners; /** * This function initialize the window or process events listener. Specifically set ups the * window `beforeunload` and process `exit` events to remove the client from the awareness. * @type {() => void} */ initSystemListeners: () => void; connect(): void; /** * This function runs when the socket connects and reconnects and emits the `sync-step-1` * and `awareness-update` socket events to start synchronization. * * Also starts the resync interval if is enabled. * @private * @param onConnect (Optional) A callback that will be triggered every time that socket is connected or reconnected * @param resyncInterval (Optional) A number of milliseconds for interval of synchronize */ private onSocketConnection; disconnect(): void; /** * This function runs when the socket is disconnected and emits the socket event `awareness-update` * which removes this client from awareness. */ onSocketDisconnection: (event: any) => void; /** * This function is executed when the socket connection fails. */ onSocketConnectionError: (error: any) => void; /** * This function is executed when the document is updated, if the instance that * emit the change is not this, it emit the changes by socket and broadcast channel. * @private * @param {Uint8Array} update Document update * @param {SocketIOProvider} origin The SocketIOProvider instance that emits the change. * @type {(update: Uint8Array, origin: SocketIOProvider) => void} */ private onUpdateDoc; /** * This function is called when the server emits the `sync-update` event and applies the received update to the local document. * @private * @param {Uint8Array}update A document update received by the `sync-update` socket event * @type {(update: Uint8Array) => void} */ private onSocketSyncUpdate; /** * This function is executed when the local awareness changes and this broadcasts the changes per socket and broadcast channel. * @private * @param {{ added: number[], updated: number[], removed: number[] }} awarenessChanges The clients added, updated and removed * @param {SocketIOProvider | null} origin The SocketIOProvider instance that emits the change. * @type {({ added, updated, removed }: { added: number[], updated: number[], removed: number[] }, origin: SocketIOProvider | null) => void} */ private awarenessUpdate; /** * This function is executed when the windows will be unloaded or the process will be closed and this * will remove the local client from awareness. * @private * @type {() => void} */ private beforeUnloadHandler; /** * This function subscribes the provider to the broadcast channel and initiates synchronization by broadcast channel. * @type {() => void} */ connectBc: () => void; /** * This function unsubscribes the provider from the broadcast channel and before unsubscribing, updates the awareness. * @type {() => void} */ disconnectBc: () => void; /** * This method handles messages received by the broadcast channel and responds to them. * @param {{ type: string, data: any }} message The object message received by broadcast channel * @param {SocketIOProvider} origin The SocketIOProvider instance that emits the change * @type {(message: { type: string, data: any }, origin: SocketIOProvider) => void} */ onBroadcastChannelMessage: (message: { type: string; data: any; }, origin: SocketIOProvider) => void; } import { Observable } from "lib0/observable"; import { Socket } from "socket.io-client"; import * as Y from "yjs"; import * as AwarenessProtocol from "y-protocols/awareness";