forked from eclipse-glsp/glsp-client
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
…on protocol (eclipse-glsp#79) * eclipse-glsp#94 eclipse-glsp#104 eclipse-glsp#96 Clean up communication protocol - Clean up communication and move implementation into glsp client - Define a "clean" `GLSPClient` interface that is independent from the underlying communication protocol - Provide a base implementation for a jsonrpc-based `GLSPClient` - Update dependencies to sprotty 0.9.0 - Align dependency versions with Theia versions - Add new DisposeClientAction to notify the server if a specific diagram client/widget can be disposed (e.g. on editor tab close) Part of: - eclipse-glsp/glsp/issues/104 - eclipse-glsp/glsp/issues/94 - eclipse-glsp/glsp/issues/96 * Fix minors * Adapt copyright headers Co-authored-by: Philip Langer <[email protected]>
- Loading branch information
1 parent
d597f7a
commit 1237187
Showing
8 changed files
with
345 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2020 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 { injectable } from "inversify"; | ||
import { Action } from "sprotty"; | ||
|
||
/** | ||
* Send to the server if the graphical representation (diagram) for a specific | ||
* client/widget id is no longer needed. e.g. the tab containing the diagram has been closed. | ||
*/ | ||
@injectable() | ||
export class DisposeClientAction implements Action { | ||
static readonly KIND = "disposeClient"; | ||
readonly kind = DisposeClientAction.KIND; | ||
} | ||
|
||
export function isDisposeClientAction(action: Action): action is DisposeClientAction { | ||
return action.kind === DisposeClientAction.KIND; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2020 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 { ActionMessage } from "sprotty"; | ||
import * as uuid from "uuid"; | ||
|
||
export interface InitializeParameters<> { | ||
/** | ||
* Unique identifier for the current client application | ||
*/ | ||
applicationId: string; | ||
options?: any | ||
} | ||
export class ApplicationIdProvider { | ||
private static _applicationId?: string; | ||
static get(): string { | ||
if (!ApplicationIdProvider._applicationId) { | ||
ApplicationIdProvider._applicationId = uuid.v4(); | ||
} | ||
return ApplicationIdProvider._applicationId; | ||
} | ||
} | ||
export type ActionMessageHandler = (message: ActionMessage) => void; | ||
|
||
export enum ClientState { | ||
Initial, | ||
Starting, | ||
StartFailed, | ||
Running, | ||
Stopping, | ||
Stopped, | ||
ServerError | ||
} | ||
|
||
export interface GLSPClient { | ||
readonly id: string; | ||
readonly name: string; | ||
currentState(): ClientState; | ||
/** | ||
* Initialize the client and the server connection. | ||
* | ||
*/ | ||
start(): Promise<void>; | ||
/** | ||
* Send an initalize request to ther server. The server needs to be initialized | ||
* in order to accept and process action messages | ||
* @param params Initialize parameter | ||
* @returns true if the initialization was successfull | ||
*/ | ||
initializeServer(params: InitializeParameters): Promise<Boolean>; | ||
/** | ||
* Send a shutdown notification to the server | ||
*/ | ||
shutdownServer(): void | ||
/** | ||
* Stop the client and cleanup/dispose resources | ||
*/ | ||
stop(): Promise<void>; | ||
/** | ||
* Set a handler/listener for action messages received from the server | ||
* @param handler The action message handler | ||
*/ | ||
onActionMessage(handler: ActionMessageHandler): void; | ||
/** | ||
* Send an action message to the server | ||
* @param message The message | ||
*/ | ||
sendActionMessage(message: ActionMessage): void; | ||
} | ||
|
||
export namespace GLSPClient { | ||
export interface Options { | ||
id: string; | ||
name: string; | ||
} | ||
|
||
export function isOptions(object: any): object is Options { | ||
return object !== undefined && "id" in object && typeof object["id"] === "string" | ||
&& "name" in object && typeof object["name"] === "string"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2019-2020 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 { ActionMessage } from "sprotty"; | ||
import { Message, MessageConnection, NotificationType, RequestType } from "vscode-jsonrpc"; | ||
import { NotificationType0 } from "vscode-ws-jsonrpc"; | ||
|
||
import { ActionMessageHandler, ClientState, GLSPClient, InitializeParameters } from "./glsp-client"; | ||
|
||
export type MaybePromise<T> = T | Promise<T> | PromiseLike<T>; | ||
export type ConnectionProvider = MessageConnection | (() => MaybePromise<MessageConnection>); | ||
|
||
export namespace JsonrpcGLSPClient { | ||
export interface Options extends GLSPClient.Options { | ||
connectionProvider: ConnectionProvider; | ||
} | ||
|
||
export function isOptions(object: any): object is Options { | ||
return GLSPClient.isOptions(object) && "connectionProvider" in object; | ||
} | ||
|
||
export const ActionMessageNotification = new NotificationType<ActionMessage, void>('process'); | ||
export const InitializeRequest = new RequestType<InitializeParameters, Boolean, void, void>('initialize'); | ||
export const ShutdownNotification = new NotificationType0<void>('shutdown'); | ||
export const ClientNotReadyMsg = 'JsonrpcGLSPClient is not ready yet'; | ||
} | ||
export class BaseJsonrpcGLSPClient implements GLSPClient { | ||
|
||
readonly name: string; | ||
readonly id: string; | ||
protected readonly connectionProvider: ConnectionProvider; | ||
protected connectionPromise?: Promise<MessageConnection>; | ||
protected resolvedConnection?: MessageConnection; | ||
protected state: ClientState; | ||
protected onStop?: Promise<void>; | ||
|
||
constructor(options: JsonrpcGLSPClient.Options) { | ||
Object.assign(this, options); | ||
this.state = ClientState.Initial; | ||
} | ||
|
||
shutdownServer(): void { | ||
if (this.checkConnectionState()) { | ||
this.resolvedConnection!.sendNotification(JsonrpcGLSPClient.ShutdownNotification); | ||
} | ||
} | ||
|
||
initializeServer(params: InitializeParameters): Promise<Boolean> { | ||
if (this.checkConnectionState()) { | ||
return this.resolvedConnection!.sendRequest(JsonrpcGLSPClient.InitializeRequest, params); | ||
} | ||
return Promise.resolve(false); | ||
} | ||
|
||
onActionMessage(handler: ActionMessageHandler): void { | ||
if (this.checkConnectionState()) { | ||
this.resolvedConnection!.onNotification(JsonrpcGLSPClient.ActionMessageNotification, handler); | ||
} | ||
} | ||
|
||
sendActionMessage(message: ActionMessage): void { | ||
if (this.checkConnectionState()) { | ||
this.resolvedConnection!.sendNotification(JsonrpcGLSPClient.ActionMessageNotification, message); | ||
} | ||
} | ||
|
||
protected checkConnectionState(): boolean { | ||
if (!this.isConnectionActive()) { | ||
throw new Error(JsonrpcGLSPClient.ClientNotReadyMsg); | ||
} | ||
return true; | ||
} | ||
|
||
async start(): Promise<void> { | ||
try { | ||
this.state = ClientState.Starting; | ||
const connection = await this.resolveConnection(); | ||
connection.listen(); | ||
this.resolvedConnection = connection; | ||
this.state = ClientState.Running; | ||
} catch (error) { | ||
this.error('Failed to start connection to server', error); | ||
this.state = ClientState.StartFailed; | ||
} | ||
} | ||
|
||
stop(): Promise<void> { | ||
if (!this.connectionPromise) { | ||
this.state = ClientState.Stopped; | ||
return Promise.resolve(); | ||
} | ||
if (this.state === ClientState.Stopping && this.onStop) { | ||
return this.onStop; | ||
} | ||
this.state = ClientState.Stopping; | ||
return this.onStop = this.resolveConnection().then(connection => { | ||
connection.dispose(); | ||
this.state = ClientState.Stopped; | ||
this.onStop = undefined; | ||
this.connectionPromise = undefined; | ||
this.resolvedConnection = undefined; | ||
}); | ||
} | ||
|
||
private resolveConnection(): Promise<MessageConnection> { | ||
if (!this.connectionPromise) { | ||
this.connectionPromise = this.doCreateConnection(); | ||
} | ||
return this.connectionPromise; | ||
} | ||
|
||
protected async doCreateConnection(): Promise<MessageConnection> { | ||
const connection = typeof this.connectionProvider === 'function' ? await this.connectionProvider() : this.connectionProvider; | ||
connection.onError((data: [Error, Message, number]) => this.handleConnectionError(data[0], data[1], data[2])); | ||
connection.onClose(() => this.handleConnectionClosed()); | ||
return connection; | ||
} | ||
|
||
protected handleConnectionError(error: Error, message: Message, count: number): void { | ||
this.error('Connection to server is erroring. Shutting down server.', error); | ||
this.stop(); | ||
this.state = ClientState.ServerError; | ||
} | ||
|
||
protected handleConnectionClosed(): void { | ||
if (this.state === ClientState.Stopping || this.state === 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. | ||
} | ||
|
||
this.error('Connection to server got closed. Server will not be restarted.'); | ||
this.state = ClientState.ServerError; | ||
} | ||
|
||
protected error(message: string, ...optionalParams: any[]): void { | ||
console.error(`[JsonrpcGLSPClient] ${message}`, optionalParams); | ||
} | ||
|
||
protected isConnectionActive(): boolean { | ||
return this.state === ClientState.Running && !!this.resolvedConnection; | ||
} | ||
|
||
currentState(): ClientState { | ||
return this.state; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/******************************************************************************** | ||
* Copyright (c) 2020 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 | ||
********************************************************************************/ | ||
export * from './glsp-client'; | ||
export * from './glsp-jsonrpc-client'; |
Oops, something went wrong.