UNPKG

open-collaboration-protocol

Version:

Open Collaboration Protocol implementation, part of the Open Collaboration Tools project

149 lines 6.65 kB
// ****************************************************************************** // Copyright 2024 TypeFox GmbH // This program and the accompanying materials are made available under the // terms of the MIT License, which is available in the project root. // ****************************************************************************** import { AbstractBroadcastConnection } from './messaging/abstract-connection.js'; import { Messages } from './messages.js'; export function createConnection(options) { return new ProtocolBroadcastConnectionImpl(options); } const EMTPY_HANDLER = () => { }; export class ProtocolBroadcastConnectionImpl extends AbstractBroadcastConnection { room = { onJoin: handler => this.onBroadcast(Messages.Room.Joined, (origin, peer) => { this.onDidJoinRoom(peer); handler(origin, peer); }), leave: () => this.sendNotification(Messages.Room.Leave, ''), onLeave: handler => this.onBroadcast(Messages.Room.Left, (origin, peer) => { this.onDidLeaveRoom(peer); handler(origin, peer); }), onClose: handler => this.onBroadcast(Messages.Room.Closed, (origin) => { this.onDidClose(); handler(origin); }), onPermissions: handler => this.onBroadcast(Messages.Room.PermissionsUpdated, handler), updatePermissions: permissions => this.sendBroadcast(Messages.Room.PermissionsUpdated, permissions) }; peer = { onJoinRequest: handler => this.onRequest(Messages.Peer.Join, handler), onInfo: handler => this.onNotification(Messages.Peer.Info, handler), onInit: handler => this.onNotification(Messages.Peer.Init, async (origin, response) => { this.onDidInit(response); handler(origin, response); }), init: (target, request) => this.sendNotification(Messages.Peer.Init, target, request) }; fs = { onReadFile: handler => this.onRequest(Messages.FileSystem.ReadFile, handler), readFile: (target, path) => this.sendRequest(Messages.FileSystem.ReadFile, target, path), onWriteFile: handler => this.onRequest(Messages.FileSystem.WriteFile, handler), writeFile: (target, path, content) => this.sendRequest(Messages.FileSystem.WriteFile, target, path, content), onReaddir: handler => this.onRequest(Messages.FileSystem.ReadDir, handler), readdir: (target, path) => this.sendRequest(Messages.FileSystem.ReadDir, target, path), onStat: handler => this.onRequest(Messages.FileSystem.Stat, handler), stat: (target, path) => this.sendRequest(Messages.FileSystem.Stat, target, path), onMkdir: handler => this.onRequest(Messages.FileSystem.Mkdir, handler), mkdir: (target, path) => this.sendRequest(Messages.FileSystem.Mkdir, target, path), onDelete: handler => this.onRequest(Messages.FileSystem.Delete, handler), delete: (target, path) => this.sendRequest(Messages.FileSystem.Delete, target, path), onRename: handler => this.onRequest(Messages.FileSystem.Rename, handler), rename: (target, from, to) => this.sendRequest(Messages.FileSystem.Rename, target, from, to), onChange: handler => this.onBroadcast(Messages.FileSystem.Change, handler), change: event => this.sendBroadcast(Messages.FileSystem.Change, event) }; editor = { onOpen: handler => this.onNotification(Messages.Editor.Open, handler), open: (target, path) => this.sendNotification(Messages.Editor.Open, target, path), onClose: handler => this.onBroadcast(Messages.Editor.Close, handler), close: path => this.sendBroadcast(Messages.Editor.Close, path) }; sync = { onDataUpdate: handler => { this.onBroadcast(Messages.Sync.DataUpdate, handler); this.onNotification(Messages.Sync.DataNotify, handler); }, dataUpdate: async (target, data) => { if (typeof target === 'object') { await this.sendBroadcast(Messages.Sync.DataUpdate, target); } else { await this.sendNotification(Messages.Sync.DataNotify, target, data); } }, onAwarenessUpdate: handler => { this.onBroadcast(Messages.Sync.AwarenessUpdate, handler); this.onNotification(Messages.Sync.AwarenessNotify, handler); }, awarenessUpdate: async (target, data) => { if (typeof target === 'object') { await this.sendBroadcast(Messages.Sync.AwarenessUpdate, target); } else { await this.sendNotification(Messages.Sync.AwarenessNotify, target, data); } }, onAwarenessQuery: handler => this.onBroadcast(Messages.Sync.AwarenessQuery, handler), awarenessQuery: () => this.sendBroadcast(Messages.Sync.AwarenessQuery) }; // Track peers manually for their public encryption keys peers = new Map(); constructor(options) { super({ privateKey: options.privateKey, transport: options.transport }); if (options.host) { this.onDidJoinRoom(options.host); } else { this.ready(); } // Ensure that the peer handlers are called this.room.onJoin(EMTPY_HANDLER); this.room.onLeave(EMTPY_HANDLER); this.room.onClose(EMTPY_HANDLER); this.peer.onInit(EMTPY_HANDLER); } getPublicKey(origin) { const peer = this.peers.get(origin); if (peer) { return { peerId: peer.id, publicKey: peer.metadata.encryption.publicKey, supportedCompression: peer.metadata.compression.supported }; } else { throw new Error('No public key found for origin ' + origin); } } onDidJoinRoom(peer) { this.peers.set(peer.id, peer); } onDidLeaveRoom(peer) { this.peers.delete(peer.id); } onDidClose() { this.peers.clear(); } onDidInit(response) { for (const peer of [response.host, ...response.guests]) { this.peers.set(peer.id, peer); } this.ready(); } getPublicKeys() { return Array.from(this.peers.values()).map(peer => ({ peerId: peer.id, publicKey: peer.metadata.encryption.publicKey, supportedCompression: peer.metadata.compression.supported })); } getPublicKeysLength() { return this.peers.size; } } //# sourceMappingURL=connection.js.map