Skip to content

Commit

Permalink
GLSP-975 Move glsp-server types into protocol packages (#245)
Browse files Browse the repository at this point in the history
Ensures that the `@eclipse-glsp/protocol` package also provides the glsp server interfaces.
This allows type reusage in usecases where the GLSP server is not connected via JSON-RPC and is instead accessed directly.

Contributed on behalf of STMicroelectronics
Part of eclipse-glsp/glsp#975
  • Loading branch information
tortmayr authored May 3, 2023
1 parent d9a27cd commit 15c2f6f
Show file tree
Hide file tree
Showing 7 changed files with 307 additions and 79 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2020-2022 EclipseSource and others.
* Copyright (c) 2020-2023 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
Expand All @@ -15,76 +15,8 @@
********************************************************************************/
import * as uuid from 'uuid';

import { ActionMessage } from './action-protocol';
import { Args } from './action-protocol/types';

/**
* A key-value pair structure to map a diagramType to its server-handled action kinds.
*/
export interface ServerActions {
[key: string]: string[];
}

export interface InitializeParameters {
/**
* Unique identifier for the current client application.
*/
applicationId: string;

/**
* GLSP protocol version that this client is implementing.
*/
protocolVersion: string;

/**
* Additional custom arguments e.g. application specific parameters.
*/
args?: Args;
}

export interface InitializeResult {
/**
* GLSP protocol version that the server is implementing.
*/
protocolVersion: string;

/**
* The actions (grouped by diagramType) that the server can handle.
*/
serverActions: ServerActions;
}

/**
* Known server actions i.e. action kinds that the server can handle for a specific diagram type.
*/
export interface InitializeClientSessionParameters {
/**
* Unique identifier for the new client session.
*/
clientSessionId: string;

/**
* Unique identifier of the diagram type for which the session should be configured.
*/
diagramType: string;

/**
* Additional custom arguments.
*/
args?: Args;
}

export interface DisposeClientSessionParameters {
/**
* Unique identifier of the client session that should be disposed.
*/
clientSessionId: string;

/**
* Additional custom arguments.
*/
args?: Args;
}
import { ActionMessage } from '../action-protocol';
import { DisposeClientSessionParameters, InitializeClientSessionParameters, InitializeParameters, InitializeResult } from './types';

export class ApplicationIdProvider {
private static _applicationId?: string;
Expand Down
149 changes: 149 additions & 0 deletions packages/protocol/src/client-server-protocol/glsp-server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
/********************************************************************************
* Copyright (c) 2022-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
********************************************************************************/

import { ActionMessage } from '../action-protocol';
import { DisposeClientSessionParameters, InitializeClientSessionParameters, InitializeParameters, InitializeResult } from './types';

/**
* Interface for implementations of a server component using json-rpc for client-server communication.
* Based on the specification of the Graphical Language Server Protocol:
* https://github.com/eclipse-glsp/glsp/blob/master/PROTOCOL.md
*/
export interface GLSPServer {
/**
*
* The `initialize` request has to be the first request from the client to the server. Until the server has responded
* with an {@link InitializeResult} no other request or notification can be handled and is expected to throw an
* error. A client is uniquely identified by an `applicationId` and has to specify on which `protocolVersion` it is
* based on. In addition, custom arguments can be provided in the `args` map to allow for custom initialization
* behavior on the server.
*
* After successfully initialization all {@link GLSPServerListener}s are notified via the
* {@link GLSPServerListener.serverInitialized} method.
*
* @param params the {@link InitializeParameters}.
* @returns A promise of the {@link InitializeResult} .
*
* @throws {@link Error} Subsequent initialize requests return the {@link InitializeResult} of the initial request
* if the given application id and protocol version are matching, otherwise the promise rejects with an error.
*
*/
initialize(params: InitializeParameters): Promise<InitializeResult>;

/**
* The `initializeClientSession` request is sent to the server whenever a new graphical representation (diagram) is
* created. Each individual diagram on the client side counts as one session and has to provide a unique
* `clientSessionId` and its `diagramType`. In addition, custom arguments can be provided in the `args` map to allow
* for custom initialization behavior on the server. Subsequent `initializeClientSession` requests for the same
* client id and diagram type are expected to resolve successfully but don't have an actual effect because the
* corresponding client session is already initialized.
*
* @param params the {@link InitializeClientSessionParameters}.
* @returns A promise that completes when the initialization was successful.
*/
initializeClientSession(params: InitializeClientSessionParameters): Promise<void>;

/**
* The 'DisposeClientSession' request is sent to the server when a graphical representation (diagram) is no longer
* needed, e.g. the tab containing the diagram widget has been closed. The session is identified by its unique
* `clientSessionId`. In addition, custom arguments can be provided in the `args` map to allow for custom dispose
* behavior on the server.
*
* @param params the {@link DisposeClientSessionParameters}.
* @returns A `void` promise that completes if the disposal was successful.
*
*/
disposeClientSession(params: DisposeClientSessionParameters): Promise<void>;

/**
* A `process` notification is sent from the client to server when the server should handle i.e. process a specific
* {@link ActionMessage}. Any communication that is performed between initialization and shutdown is handled by
* sending action messages, either from the client to the server or from the server to the client. This is the core
* part of the Graphical Language Server Protocol.
*
* @param message The {@link ActionMessage} that should be processed.
*/
process(message: ActionMessage): void;

/**
* The `shutdown` notification is sent from the client to the server if the client disconnects from the server (e.g.
* the client application has been closed).
* This gives the server a chance to clean up and dispose any resources dedicated to the client and its sessions.
* All {@link GLSPServerListener}s are notified via the {@link GLSPServerListener.serverShutDown} method.
* Afterwards the server instance is considered to be disposed and can no longer be used for handling requests.
*
*/
shutdown(): void;

/**
* Register a new {@link GLSPServerListener}.
*
* @param listener The listener that should be registered.
* @returns `true` if the listener was registered successfully, `false` otherwise (e.g. listener is already
* registered).
*/
addListener(listener: GLSPServerListener): boolean;

/**
* Unregister a {@link GLSPServerListener}.
*
* @param listener The listener that should be removed
* @returns 'true' if the listener was unregistered successfully, `false` otherwise (e.g. listener is was not
* registered in the first place).
*/
removeListener(listener: GLSPServerListener): boolean;
}

export const GLSPServer = Symbol('GLSPServer');

/**
* A listener to track the connection status of {@link GLSPClient}s (i.e. client applications).
* Gets notified when a new GLSP client connects or disconnects.
*/
export interface GLSPServerListener {
/**
* Triggered after a GLSPServer has been initialized via the {@link GLSPServer.initialize()}
* method.
*
* @param server The GLSPServer which has been initialized.
*/
serverInitialized?(server: GLSPServer): void;

/**
* Triggered after the {@link GLSPServer.shutdown()} method has been invoked.
*
* @param glspServer The glspServer which has been shut down.
*/
serverShutDown?(server: GLSPServer): void;
}
export const GLSPServerListener = Symbol('GLSPServerListener');

/**
* Communication proxy interface used by the GLSP servers to send action messages to clients.
* The default `JsonrpcClientProxy` used an underlying jsonrpc message connection for sending the action messages.
*/
export interface GLSPClientProxy {
/**
* A `process` notification is sent from the server to server to the client when the client should handle i.e.
* process a specific {@link ActionMessage}. Any communication that is performed between initialization and shutdown
* is handled by sending action messages, either from the client to the server or from the server to the client. This
* is the core part of the Graphical Language Server Protocol.
*
* @param message The {@link ActionMessage} that should be processed.
*/
process(message: ActionMessage): void;
}
export const GLSPClientProxy = Symbol('GLSPClientProxy');
85 changes: 85 additions & 0 deletions packages/protocol/src/client-server-protocol/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/********************************************************************************
* Copyright (c) 2023 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
********************************************************************************/

import { Args } from '../action-protocol';

/**
* A key-value pair structure to map a diagramType to its server-handled action kinds.
*/
export interface ServerActions {
[key: string]: string[];
}

export interface InitializeParameters {
/**
* Unique identifier for the current client application.
*/
applicationId: string;

/**
* GLSP protocol version that this client is implementing.
*/
protocolVersion: string;

/**
* Additional custom arguments e.g. application specific parameters.
*/
args?: Args;
}

export interface InitializeResult {
/**
* GLSP protocol version that the server is implementing.
*/
protocolVersion: string;

/**
* The actions (grouped by diagramType) that the server can handle.
*/
serverActions: ServerActions;
}

/**
* Known server actions i.e. action kinds that the server can handle for a specific diagram type.
*/
export interface InitializeClientSessionParameters {
/**
* Unique identifier for the new client session.
*/
clientSessionId: string;

/**
* Unique identifier of the diagram type for which the session should be configured.
*/
diagramType: string;

/**
* Additional custom arguments.
*/
args?: Args;
}

export interface DisposeClientSessionParameters {
/**
* Unique identifier of the client session that should be disposed.
*/
clientSessionId: string;

/**
* Additional custom arguments.
*/
args?: Args;
}
5 changes: 4 additions & 1 deletion packages/protocol/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ export * from 'sprotty-protocol/lib/utils/json';
export * from 'sprotty-protocol/lib/utils/model-utils';
// Default export of @eclipse-glsp/protocol
export * from './action-protocol';
export * from './client-server-protocol/glsp-client';
export * from './client-server-protocol/glsp-server';
export * from './client-server-protocol/types';
export * from './disposable/disposable';
export * from './glsp-client';
export * from './jsonrpc/base-jsonrpc-glsp-client';
export * from './jsonrpc/glsp-jsonrpc-client';
export * from './jsonrpc/glsp-jsonrpc-server';
export * from './jsonrpc/websocket-connection';
export * from './model/default-types';
export * from './model/model-schema';
Expand Down
31 changes: 26 additions & 5 deletions packages/protocol/src/jsonrpc/base-jsonrpc-glsp-client.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (c) 2019-2022 EclipseSource and others.
* Copyright (c) 2019-2023 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
Expand All @@ -13,17 +13,17 @@
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/
import { injectable } from 'inversify';
import { Message, MessageConnection } from 'vscode-jsonrpc';
import { GLSPClientProxy } from '..';
import { ActionMessage } from '../action-protocol';
import { ActionMessageHandler, ClientState, GLSPClient } from '../client-server-protocol/glsp-client';
import {
ActionMessageHandler,
ClientState,
DisposeClientSessionParameters,
GLSPClient,
InitializeClientSessionParameters,
InitializeParameters,
InitializeResult
} from '../glsp-client';
} from '../client-server-protocol/types';
import { ConnectionProvider, JsonrpcGLSPClient } from './glsp-jsonrpc-client';

export class BaseJsonrpcGLSPClient implements GLSPClient {
Expand Down Expand Up @@ -162,3 +162,24 @@ export class BaseJsonrpcGLSPClient implements GLSPClient {
return this.state;
}
}

/**
* Default {@link GLSPClientProxy} implementation for jsonrpc-based client-server communication with typescript based servers.
*/
@injectable()
export class JsonrpcClientProxy implements GLSPClientProxy {
protected clientConnection?: MessageConnection;
protected enableLogging: boolean;

initialize(clientConnection: MessageConnection, enableLogging = true): void {
this.clientConnection = clientConnection;
this.enableLogging = enableLogging;
}

process(message: ActionMessage): void {
if (this.enableLogging) {
console.log(`Send action '${message.action.kind}' to client '${message.clientId}'`);
}
this.clientConnection?.sendNotification(JsonrpcGLSPClient.ActionMessageNotification, message);
}
}
Loading

0 comments on commit 15c2f6f

Please sign in to comment.