UNPKG

@eclipse-glsp/protocol

Version:

The protocol definition for client-server communication in GLSP

199 lines 8.74 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.JsonrpcClientProxy = exports.BaseJsonrpcGLSPClient = void 0; /******************************************************************************** * Copyright (c) 2019-2026 EclipseSource 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 ********************************************************************************/ const sprotty_protocol_1 = require("sprotty-protocol"); const event_1 = require("../../utils/event"); const glsp_client_1 = require("../glsp-client"); const glsp_jsonrpc_client_1 = require("./glsp-jsonrpc-client"); class BaseJsonrpcGLSPClient { get onServerInitialized() { return this.onServerInitializedEmitter.event; } get onActionMessageNotification() { return this.onActionMessageNotificationEmitter.event; } get onCurrentStateChanged() { return this.onCurrentStateChangedEmitter.event; } set state(state) { if (this._state !== state) { this._state = state; this.onCurrentStateChangedEmitter.fire(state); } } get state() { return this._state; } get initializeResult() { return this._initializeResult; } constructor(options) { this.onServerInitializedEmitter = new event_1.Emitter(); this.onActionMessageNotificationEmitter = new event_1.Emitter(); this.onCurrentStateChangedEmitter = new event_1.Emitter(); this.connectionProvider = options.connectionProvider; this.state = glsp_client_1.ClientState.Initial; } async start() { if (this.state === glsp_client_1.ClientState.Running || this.state === glsp_client_1.ClientState.StartFailed) { return; } else if (this.state === glsp_client_1.ClientState.Starting) { await event_1.Event.waitUntil(this.onCurrentStateChanged, state => state === glsp_client_1.ClientState.Running || state === glsp_client_1.ClientState.StartFailed); return; } try { this.state = glsp_client_1.ClientState.Starting; const connection = await this.resolveConnection(); connection.listen(); this.resolvedConnection = connection; this.state = glsp_client_1.ClientState.Running; } catch (error) { glsp_jsonrpc_client_1.JsonrpcGLSPClient.error('Failed to start connection to server', error); this.state = glsp_client_1.ClientState.StartFailed; } } async initializeServer(params) { if (this.initializeResult) { return this.initializeResult; } else if (this.pendingServerInitialize) { return this.pendingServerInitialize; } const initializeDeferred = new sprotty_protocol_1.Deferred(); try { this.pendingServerInitialize = initializeDeferred.promise; this._initializeResult = await this.checkedConnection.sendRequest(glsp_jsonrpc_client_1.JsonrpcGLSPClient.InitializeRequest, params); this.onServerInitializedEmitter.fire(this._initializeResult); initializeDeferred.resolve(this._initializeResult); this.pendingServerInitialize = undefined; } catch (error) { initializeDeferred.reject(error); this._initializeResult = undefined; this.pendingServerInitialize = undefined; } return initializeDeferred.promise; } initializeClientSession(params) { return this.checkedConnection.sendRequest(glsp_jsonrpc_client_1.JsonrpcGLSPClient.InitializeClientSessionRequest, params); } disposeClientSession(params) { return this.checkedConnection.sendRequest(glsp_jsonrpc_client_1.JsonrpcGLSPClient.DisposeClientSessionRequest, params); } onActionMessage(handler, clientId) { return this.onActionMessageNotification(msg => { if (!clientId || msg.clientId === clientId) { handler(msg); } }); } sendActionMessage(message) { this.checkedConnection.sendNotification(glsp_jsonrpc_client_1.JsonrpcGLSPClient.ActionMessageNotification, message); } async shutdownServer() { // Await the send so callers can dispose the connection without racing the wire flush. await this.checkedConnection.sendNotification(glsp_jsonrpc_client_1.JsonrpcGLSPClient.ShutdownNotification); } stop() { if (!this.connectionPromise) { this.state = glsp_client_1.ClientState.Stopped; return Promise.resolve(); } if (this.state === glsp_client_1.ClientState.Stopping && this.onStop) { return this.onStop; } this.state = glsp_client_1.ClientState.Stopping; return (this.onStop = this.resolveConnection().then(connection => { connection.dispose(); this.state = glsp_client_1.ClientState.Stopped; this.onStop = undefined; this.onActionMessageNotificationEmitter.dispose(); this.onCurrentStateChangedEmitter.dispose(); this.connectionPromise = undefined; this.resolvedConnection = undefined; })); } get checkedConnection() { if (!this.isConnectionActive()) { throw new Error(glsp_jsonrpc_client_1.JsonrpcGLSPClient.ClientNotReadyMsg); } return this.resolvedConnection; } resolveConnection() { if (!this.connectionPromise) { this.connectionPromise = this.doCreateConnection(); } return this.connectionPromise; } async doCreateConnection() { const connection = typeof this.connectionProvider === 'function' ? await this.connectionProvider() : this.connectionProvider; connection.onError(data => this.handleConnectionError(data[0], data[1], data[2])); connection.onClose(() => this.handleConnectionClosed()); connection.onNotification(glsp_jsonrpc_client_1.JsonrpcGLSPClient.ActionMessageNotification, msg => this.onActionMessageNotificationEmitter.fire(msg)); return connection; } handleConnectionError(error, message, count) { glsp_jsonrpc_client_1.JsonrpcGLSPClient.error('Connection to server is erroring. Shutting down server.', error); this.stop(); this.state = glsp_client_1.ClientState.ServerError; } handleConnectionClosed() { if (this.state === glsp_client_1.ClientState.Stopping || this.state === glsp_client_1.ClientState.Stopped) { return; } try { if (this.resolvedConnection) { this.resolvedConnection.dispose(); this.connectionPromise = undefined; this.resolvedConnection = undefined; } } catch (error) { // Disposing a connection could fail if error cases. } glsp_jsonrpc_client_1.JsonrpcGLSPClient.error('Connection to server got closed. Server will not be restarted.'); this.state = glsp_client_1.ClientState.ServerError; } isConnectionActive() { return this.state === glsp_client_1.ClientState.Running && !!this.resolvedConnection; } get currentState() { return this.state; } } exports.BaseJsonrpcGLSPClient = BaseJsonrpcGLSPClient; /** * Default {@link GLSPClientProxy} implementation for jsonrpc-based client-server communication with typescript based servers. */ class JsonrpcClientProxy { initialize(clientConnection, enableLogging = false) { this.clientConnection = clientConnection; this.enableLogging = enableLogging; } process(message) { var _a; if (this.enableLogging) { console.log(`Send action '${message.action.kind}' to client '${message.clientId}'`); } (_a = this.clientConnection) === null || _a === void 0 ? void 0 : _a.sendNotification(glsp_jsonrpc_client_1.JsonrpcGLSPClient.ActionMessageNotification, message); } } exports.JsonrpcClientProxy = JsonrpcClientProxy; //# sourceMappingURL=base-jsonrpc-glsp-client.js.map