open-collaboration-protocol
Version:
Open Collaboration Protocol implementation, part of the Open Collaboration Tools project
88 lines • 3.05 kB
JavaScript
// ******************************************************************************
// 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 { Emitter } from '../utils/event.js';
import { Deferred } from '../utils/promise.js';
import { io } from 'socket.io-client';
export const SocketIoTransportProvider = {
id: 'socket.io',
createTransport: (url, headers) => {
const parsedUrl = new URL(url);
let path = parsedUrl.pathname;
if (path && !path.endsWith('/')) {
path += '/';
}
// Path always ends in .../socket.io
path += 'socket.io';
const socket = io(url, {
path,
extraHeaders: headers
});
const transport = new SocketIoTransport(socket);
return transport;
}
};
export class SocketIoTransport {
socket;
id = 'socket.io';
onReconnectEmitter = new Emitter();
onDisconnectEmitter = new Emitter();
onErrorEmitter = new Emitter();
disconnectTimeout;
ready = new Deferred();
get onDisconnect() {
return this.onDisconnectEmitter.event;
}
get onReconnect() {
return this.onReconnectEmitter.event;
}
get onError() {
return this.onErrorEmitter.event;
}
constructor(socket) {
this.socket = socket;
this.socket.on('disconnect', (_reason, _description) => {
this.ready.reject();
this.ready = new Deferred();
// Give it 30 seconds to reconnect before firing the disconnect event
this.disconnectTimeout = setTimeout(() => {
this.onDisconnectEmitter.fire();
this.disconnectTimeout = undefined;
}, 30_000);
});
this.socket.io.on('reconnect', () => {
if (this.disconnectTimeout) {
clearTimeout(this.disconnectTimeout);
this.disconnectTimeout = undefined;
this.ready.resolve();
}
this.onReconnectEmitter.fire();
});
const timeout = setTimeout(() => {
this.onErrorEmitter.fire('Websocket connection timed out.');
this.ready.reject();
}, 30_000);
this.socket.on('error', () => {
this.onErrorEmitter.fire('Websocket connection closed unexpectedly.');
this.ready.reject();
clearTimeout(timeout);
});
this.socket.on('connect', () => {
this.ready.resolve();
clearTimeout(timeout);
});
}
async write(data) {
await this.ready.promise.then(() => this.socket.send(data));
}
read(cb) {
this.socket.on('message', data => cb(data));
}
dispose() {
this.onDisconnectEmitter.dispose();
this.socket.close();
}
}
//# sourceMappingURL=socket-io-transport.js.map