@eclipse-glsp/protocol
Version:
The protocol definition for client-server communication in GLSP
157 lines • 6.01 kB
JavaScript
"use strict";
/********************************************************************************
* Copyright (c) 2023 STMicroelectronics and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
Object.defineProperty(exports, "__esModule", { value: true });
exports.listen = exports.createWebSocketConnection = exports.WebSocketMessageWriter = exports.WebSocketMessageReader = exports.wrap = void 0;
// based on https://github.com/TypeFox/monaco-languageclient/blob/vwj-2.0.1/packages/vscode-ws-jsonrpc/src/socket/reader.ts
/* --------------------------------------------------------------------------------------------
* Copyright (c) 2018-2022 TypeFox GmbH (http://www.typefox.io). All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
const vscode_jsonrpc_1 = require("vscode-jsonrpc");
/**
* Creates a {@link WebSocketWrapper} for the given plain WebSocket
* @param socket The socket to wrap
*/
function wrap(socket) {
return {
send: content => socket.send(content),
onMessage: cb => (socket.onmessage = event => cb(event.data)),
onClose: cb => (socket.onclose = event => cb(event.code, event.reason)),
onError: cb => (socket.onerror = event => {
if ('error' in event) {
cb(event.error);
}
}),
dispose: () => socket.close()
};
}
exports.wrap = wrap;
/**
* A `vscode-jsonrpc` {@link MessageReader} that reads messages from an underlying {@link WebSocketWrapper}.
*/
class WebSocketMessageReader extends vscode_jsonrpc_1.AbstractMessageReader {
constructor(socket) {
super();
this.socket = socket;
this.state = 'initial';
this.eventQueue = [];
this.socket.onMessage(message => this.handleMessage(message));
this.socket.onError(error => this.fireError(error));
this.socket.onClose(() => this.fireClose());
}
listen(callback) {
if (this.state === 'initial') {
this.state = 'listening';
this.callback = callback;
this.eventQueue.forEach(event => {
if (event.message) {
this.handleMessage(event.message);
}
else if (event.error) {
this.fireError(event.error);
}
else {
this.fireClose();
}
});
this.eventQueue = [];
}
return vscode_jsonrpc_1.Disposable.create(() => {
this.callback = undefined;
this.eventQueue = [];
});
}
handleMessage(message) {
if (this.state === 'initial') {
this.eventQueue.push({ message });
}
else if (this.state === 'listening') {
const data = JSON.parse(message);
this.callback(data);
}
}
fireError(error) {
if (this.state === 'initial') {
this.eventQueue.push({ error });
}
else if (this.state === 'listening') {
super.fireError(error);
}
}
fireClose() {
if (this.state === 'initial') {
this.eventQueue.push({});
}
else if (this.state === 'listening') {
super.fireClose();
}
this.state = 'closed';
}
}
exports.WebSocketMessageReader = WebSocketMessageReader;
/**
* A `vscode-jsonrpc` {@link MessageReader} that writes messages to an underlying {@link WebSocketWrapper}.
*/
class WebSocketMessageWriter extends vscode_jsonrpc_1.AbstractMessageWriter {
constructor(socket) {
super();
this.socket = socket;
this.errorCount = 0;
}
end() {
/** no-op */
}
async write(msg) {
try {
const content = JSON.stringify(msg);
this.socket.send(content);
}
catch (e) {
this.errorCount++;
this.fireError(e, msg, this.errorCount);
}
}
}
exports.WebSocketMessageWriter = WebSocketMessageWriter;
/**
* Create a `vscode-jsonrpc` {@link MessageConnection} on top of a given {@link WebSocketWrapper}.
*/
function createWebSocketConnection(socket, logger) {
const reader = new WebSocketMessageReader(socket);
const writer = new WebSocketMessageWriter(socket);
return (0, vscode_jsonrpc_1.createMessageConnection)(reader, writer, logger);
}
exports.createWebSocketConnection = createWebSocketConnection;
/**
* Creates a new {@link MessageConnection} on top of the given websocket on open.
* @param webSocket The target webSocket
* @param onConnection Optional callback that is invoked after the connection has been created
* @param logger Optional connection logger
* @returns A promise of the created connection
*/
function listen(webSocket, onConnection, logger) {
return new Promise(resolve => {
webSocket.onopen = () => {
const socket = wrap(webSocket);
const connection = createWebSocketConnection(socket, logger);
onConnection === null || onConnection === void 0 ? void 0 : onConnection(connection);
resolve(connection);
};
});
}
exports.listen = listen;
//# sourceMappingURL=websocket-connection.js.map