@eclipse-glsp/server 1.1.0-RC05 → 1.1.0-RC06
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/browser/launch/worker-server-launcher.d.ts +8 -5
- package/lib/browser/launch/worker-server-launcher.d.ts.map +1 -1
- package/lib/browser/launch/worker-server-launcher.js +9 -11
- package/lib/browser/launch/worker-server-launcher.js.map +1 -1
- package/lib/common/command/command-stack.d.ts +7 -6
- package/lib/common/command/command-stack.d.ts.map +1 -1
- package/lib/common/command/command-stack.js +6 -6
- package/lib/common/command/command-stack.js.map +1 -1
- package/lib/common/command/command-stack.spec.js +31 -31
- package/lib/common/command/command-stack.spec.js.map +1 -1
- package/lib/common/command/command.d.ts +7 -6
- package/lib/common/command/command.d.ts.map +1 -1
- package/lib/common/command/command.js +19 -15
- package/lib/common/command/command.js.map +1 -1
- package/lib/common/command/command.spec.js +8 -8
- package/lib/common/command/command.spec.js.map +1 -1
- package/lib/common/command/recording-command.d.ts +15 -15
- package/lib/common/command/recording-command.d.ts.map +1 -1
- package/lib/common/command/recording-command.js +10 -10
- package/lib/common/command/recording-command.js.map +1 -1
- package/lib/common/command/recording-command.spec.js +8 -8
- package/lib/common/command/recording-command.spec.js.map +1 -1
- package/lib/common/command/undo-redo-action-handler.d.ts +2 -2
- package/lib/common/command/undo-redo-action-handler.d.ts.map +1 -1
- package/lib/common/command/undo-redo-action-handler.js +4 -4
- package/lib/common/command/undo-redo-action-handler.js.map +1 -1
- package/lib/common/features/layout/computed-bounds-action-handler.js +1 -1
- package/lib/common/features/layout/computed-bounds-action-handler.js.map +1 -1
- package/lib/common/index.d.ts +3 -1
- package/lib/common/index.d.ts.map +1 -1
- package/lib/common/index.js +3 -1
- package/lib/common/index.js.map +1 -1
- package/lib/common/launch/glsp-server-launcher.d.ts +7 -6
- package/lib/common/launch/glsp-server-launcher.d.ts.map +1 -1
- package/lib/common/launch/glsp-server-launcher.js +25 -2
- package/lib/common/launch/glsp-server-launcher.js.map +1 -1
- package/lib/common/operations/operation-action-handler.d.ts +1 -1
- package/lib/common/operations/operation-action-handler.d.ts.map +1 -1
- package/lib/common/operations/operation-action-handler.js +3 -3
- package/lib/common/operations/operation-action-handler.js.map +1 -1
- package/lib/common/test/mock-util.d.ts +7 -1
- package/lib/common/test/mock-util.d.ts.map +1 -1
- package/lib/common/test/mock-util.js +23 -1
- package/lib/common/test/mock-util.js.map +1 -1
- package/lib/common/utils/layout-util.d.ts +1 -1
- package/lib/common/utils/layout-util.d.ts.map +1 -1
- package/lib/common/utils/layout-util.js +3 -3
- package/lib/common/utils/layout-util.js.map +1 -1
- package/lib/node/index.d.ts +1 -0
- package/lib/node/index.d.ts.map +1 -1
- package/lib/node/index.js +1 -0
- package/lib/node/index.js.map +1 -1
- package/lib/node/launch/socket-server-launcher.d.ts +2 -1
- package/lib/node/launch/socket-server-launcher.d.ts.map +1 -1
- package/lib/node/launch/socket-server-launcher.js +11 -10
- package/lib/node/launch/socket-server-launcher.js.map +1 -1
- package/lib/node/launch/websocket-server-launcher.d.ts +59 -0
- package/lib/node/launch/websocket-server-launcher.d.ts.map +1 -0
- package/lib/node/launch/websocket-server-launcher.js +145 -0
- package/lib/node/launch/websocket-server-launcher.js.map +1 -0
- package/package.json +8 -6
- package/src/browser/launch/worker-server-launcher.ts +16 -12
- package/src/common/command/command-stack.spec.ts +32 -32
- package/src/common/command/command-stack.ts +10 -9
- package/src/common/command/command.spec.ts +9 -10
- package/src/common/command/command.ts +23 -19
- package/src/common/command/recording-command.spec.ts +8 -8
- package/src/common/command/recording-command.ts +19 -19
- package/src/common/command/undo-redo-action-handler.ts +4 -4
- package/src/common/features/layout/computed-bounds-action-handler.ts +2 -2
- package/src/common/index.ts +3 -1
- package/src/common/launch/glsp-server-launcher.ts +13 -7
- package/src/common/operations/operation-action-handler.ts +3 -3
- package/src/common/test/mock-util.ts +21 -0
- package/src/common/utils/layout-util.ts +1 -1
- package/src/node/index.ts +1 -0
- package/src/node/launch/socket-server-launcher.ts +13 -7
- package/src/node/launch/websocket-server-launcher.ts +164 -0
|
@@ -13,20 +13,19 @@
|
|
|
13
13
|
*
|
|
14
14
|
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
15
|
********************************************************************************/
|
|
16
|
-
import { MaybePromise } from '@eclipse-glsp/protocol';
|
|
16
|
+
import { Disposable, DisposableCollection, MaybePromise } from '@eclipse-glsp/protocol';
|
|
17
17
|
import { Container, ContainerModule, inject, injectable, optional } from 'inversify';
|
|
18
18
|
import { ServerModule } from '../di/server-module';
|
|
19
19
|
import { InjectionContainer } from '../di/service-identifiers';
|
|
20
20
|
import { Logger } from '../utils/logger';
|
|
21
21
|
|
|
22
|
-
export const START_UP_COMPLETE_MSG = '[GLSP-Server]:Startup completed';
|
|
23
|
-
|
|
24
22
|
@injectable()
|
|
25
|
-
export abstract class GLSPServerLauncher<T
|
|
23
|
+
export abstract class GLSPServerLauncher<T> implements Disposable {
|
|
26
24
|
@inject(Logger) protected logger: Logger;
|
|
27
25
|
|
|
28
26
|
protected _modules: ContainerModule[] = [];
|
|
29
27
|
protected running: boolean;
|
|
28
|
+
protected toDispose = new DisposableCollection();
|
|
30
29
|
|
|
31
30
|
@inject(InjectionContainer) @optional() protected parentContainer?: Container;
|
|
32
31
|
|
|
@@ -40,7 +39,7 @@ export abstract class GLSPServerLauncher<T = undefined> {
|
|
|
40
39
|
return container;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
start(startParams
|
|
42
|
+
start(startParams: T): MaybePromise<void> {
|
|
44
43
|
if (!this.running) {
|
|
45
44
|
this.running = true;
|
|
46
45
|
return this.run(startParams);
|
|
@@ -48,10 +47,11 @@ export abstract class GLSPServerLauncher<T = undefined> {
|
|
|
48
47
|
this.logger.warn('Could not start launcher. Launcher is already running!');
|
|
49
48
|
}
|
|
50
49
|
|
|
51
|
-
protected abstract run(startParams
|
|
50
|
+
protected abstract run(startParams: T): MaybePromise<void>;
|
|
52
51
|
|
|
53
52
|
shutdown(): MaybePromise<void> {
|
|
54
53
|
if (this.running) {
|
|
54
|
+
this.logger.info('Shutdown GLSPServerLauncher');
|
|
55
55
|
const result = this.stop();
|
|
56
56
|
this.running = false;
|
|
57
57
|
return result;
|
|
@@ -59,7 +59,13 @@ export abstract class GLSPServerLauncher<T = undefined> {
|
|
|
59
59
|
this.logger.warn('Could not stop launcher. Launcher is not running!');
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
protected
|
|
62
|
+
protected stop(): MaybePromise<void> {
|
|
63
|
+
this.dispose();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
dispose(): void {
|
|
67
|
+
this.toDispose.dispose();
|
|
68
|
+
}
|
|
63
69
|
|
|
64
70
|
get modules(): ContainerModule[] {
|
|
65
71
|
if (!this._modules) {
|
|
@@ -66,13 +66,13 @@ export class OperationActionHandler implements ActionHandler {
|
|
|
66
66
|
protected async executeHandler(operation: Operation, handler: OperationHandler): Promise<Action[]> {
|
|
67
67
|
const command = await handler.execute(operation);
|
|
68
68
|
if (command) {
|
|
69
|
-
this.executeCommand(command);
|
|
69
|
+
await this.executeCommand(command);
|
|
70
70
|
}
|
|
71
71
|
return this.modelSubmissionHandler.submitModel('operation');
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
protected executeCommand(command: Command): void {
|
|
75
|
-
this.commandStack.execute(command);
|
|
74
|
+
protected async executeCommand(command: Command): Promise<void> {
|
|
75
|
+
return this.commandStack.execute(command);
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
protected submitModel(): MaybePromise<Action[]> {
|
|
@@ -25,11 +25,13 @@ import {
|
|
|
25
25
|
EdgeTypeHint,
|
|
26
26
|
InitializeClientSessionParameters,
|
|
27
27
|
MaybeArray,
|
|
28
|
+
MaybePromise,
|
|
28
29
|
Point,
|
|
29
30
|
RequestEditValidationAction,
|
|
30
31
|
ShapeTypeHint,
|
|
31
32
|
ValidationStatus
|
|
32
33
|
} from '@eclipse-glsp/protocol';
|
|
34
|
+
import { expect } from 'chai';
|
|
33
35
|
import { Container } from 'inversify';
|
|
34
36
|
import { MessageConnection } from 'vscode-jsonrpc';
|
|
35
37
|
import { ActionDispatcher } from '../actions/action-dispatcher';
|
|
@@ -53,6 +55,25 @@ export async function delay(ms: number): Promise<void> {
|
|
|
53
55
|
return new Promise(resolve => setTimeout(resolve, ms));
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
/**
|
|
59
|
+
* Consumes a maybe async function and checks for error
|
|
60
|
+
* @param method - The function to check
|
|
61
|
+
* @param message - Optional message to match with error message
|
|
62
|
+
*/
|
|
63
|
+
export async function expectToThrowAsync(toEvaluate: () => MaybePromise<void>, message?: string): Promise<void> {
|
|
64
|
+
let err: Error | undefined = undefined;
|
|
65
|
+
try {
|
|
66
|
+
await toEvaluate();
|
|
67
|
+
} catch (error: any) {
|
|
68
|
+
err = error;
|
|
69
|
+
}
|
|
70
|
+
if (message) {
|
|
71
|
+
expect(err?.message).to.be.equal(message);
|
|
72
|
+
} else {
|
|
73
|
+
expect(err).to.be.an('Error');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
56
77
|
export function createClientSession(
|
|
57
78
|
id: string,
|
|
58
79
|
diagramType: string,
|
|
@@ -27,7 +27,7 @@ import { getOrThrow, GLSPServerError } from './glsp-server-error';
|
|
|
27
27
|
* @param index The model index.
|
|
28
28
|
* @returns The changed element.
|
|
29
29
|
*/
|
|
30
|
-
export function
|
|
30
|
+
export function applyElementAndBounds(bounds: ElementAndBounds, index: GModelIndex): GBoundsAware | undefined {
|
|
31
31
|
const element = getOrThrow(index.get(bounds.elementId), 'Model element not found! ID: ' + bounds.elementId);
|
|
32
32
|
if (isGBoundsAware(element)) {
|
|
33
33
|
if (bounds.newPosition !== undefined) {
|
package/src/node/index.ts
CHANGED
|
@@ -16,11 +16,13 @@
|
|
|
16
16
|
import { Container, inject, injectable } from 'inversify';
|
|
17
17
|
import * as net from 'net';
|
|
18
18
|
import * as jsonrpc from 'vscode-jsonrpc/node';
|
|
19
|
+
import { Disposable } from '..';
|
|
19
20
|
import { GLSPServerLauncher } from '../../common/launch/glsp-server-launcher';
|
|
20
21
|
import { GLSPServer, JsonRpcGLSPServer } from '../../common/protocol/glsp-server';
|
|
21
22
|
import { Logger } from '../../common/utils/logger';
|
|
22
23
|
|
|
23
|
-
const START_UP_COMPLETE_MSG = '[GLSP-Server]:Startup completed. Accepting requests on port:';
|
|
24
|
+
export const START_UP_COMPLETE_MSG = '[GLSP-Server]:Startup completed. Accepting requests on port:';
|
|
25
|
+
|
|
24
26
|
@injectable()
|
|
25
27
|
export class SocketServerLauncher extends GLSPServerLauncher<net.TcpSocketConnectOpts> {
|
|
26
28
|
@inject(Logger) protected override logger: Logger;
|
|
@@ -29,6 +31,16 @@ export class SocketServerLauncher extends GLSPServerLauncher<net.TcpSocketConnec
|
|
|
29
31
|
protected startupCompleteMessage = START_UP_COMPLETE_MSG;
|
|
30
32
|
protected netServer: net.Server;
|
|
31
33
|
|
|
34
|
+
constructor() {
|
|
35
|
+
super();
|
|
36
|
+
this.toDispose.push(
|
|
37
|
+
Disposable.create(() => {
|
|
38
|
+
this.currentConnections.forEach(connection => connection.dispose());
|
|
39
|
+
this.netServer.close();
|
|
40
|
+
})
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
protected run(opts: net.TcpSocketConnectOpts): Promise<void> {
|
|
33
45
|
this.netServer = net.createServer(socket => this.createClientConnection(socket));
|
|
34
46
|
|
|
@@ -81,10 +93,4 @@ export class SocketServerLauncher extends GLSPServerLauncher<net.TcpSocketConnec
|
|
|
81
93
|
protected createConnection(socket: net.Socket): jsonrpc.MessageConnection {
|
|
82
94
|
return jsonrpc.createMessageConnection(new jsonrpc.SocketMessageReader(socket), new jsonrpc.SocketMessageWriter(socket), console);
|
|
83
95
|
}
|
|
84
|
-
|
|
85
|
-
protected stop(): void {
|
|
86
|
-
this.logger.info('Shutdown SocketServerLauncher');
|
|
87
|
-
this.currentConnections.forEach(connection => connection.dispose());
|
|
88
|
-
this.netServer.close();
|
|
89
|
-
}
|
|
90
96
|
}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/********************************************************************************
|
|
2
|
+
* Copyright (c) 2023 EclipseSource and others.
|
|
3
|
+
*
|
|
4
|
+
* This program and the accompanying materials are made available under the
|
|
5
|
+
* terms of the Eclipse Public License v. 2.0 which is available at
|
|
6
|
+
* http://www.eclipse.org/legal/epl-2.0.
|
|
7
|
+
*
|
|
8
|
+
* This Source Code may also be made available under the following Secondary
|
|
9
|
+
* Licenses when the conditions for such availability set forth in the Eclipse
|
|
10
|
+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
|
|
11
|
+
* with the GNU Classpath Exception which is available at
|
|
12
|
+
* https://www.gnu.org/software/classpath/license.html.
|
|
13
|
+
*
|
|
14
|
+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
|
15
|
+
********************************************************************************/
|
|
16
|
+
|
|
17
|
+
import { createWebSocketConnection, Disposable, MaybePromise, WebSocketWrapper } from '@eclipse-glsp/protocol';
|
|
18
|
+
import * as http from 'http';
|
|
19
|
+
import { Container, inject, injectable } from 'inversify';
|
|
20
|
+
import * as net from 'net';
|
|
21
|
+
import * as jsonrpc from 'vscode-jsonrpc';
|
|
22
|
+
import { Server, WebSocket } from 'ws';
|
|
23
|
+
import { GLSPServerLauncher } from '../../common/launch/glsp-server-launcher';
|
|
24
|
+
import { GLSPServer, JsonRpcGLSPServer } from '../../common/protocol/glsp-server';
|
|
25
|
+
import { Logger } from '../../common/utils/logger';
|
|
26
|
+
import { START_UP_COMPLETE_MSG } from './socket-server-launcher';
|
|
27
|
+
|
|
28
|
+
export interface WebSocketServerOptions {
|
|
29
|
+
host?: string;
|
|
30
|
+
port?: number;
|
|
31
|
+
path: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface ResolvedWebSocketServerOptions {
|
|
35
|
+
host?: string;
|
|
36
|
+
port: number;
|
|
37
|
+
path: string;
|
|
38
|
+
server: http.Server;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface WebsocketConnectionData {
|
|
42
|
+
socket: WebSocket;
|
|
43
|
+
connection: jsonrpc.MessageConnection;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const STATUS_UPGRADE_REQUIRED = 426;
|
|
47
|
+
|
|
48
|
+
@injectable()
|
|
49
|
+
export class WebSocketServerLauncher extends GLSPServerLauncher<WebSocketServerOptions> {
|
|
50
|
+
@inject(Logger)
|
|
51
|
+
protected override logger: Logger;
|
|
52
|
+
|
|
53
|
+
protected server: Server;
|
|
54
|
+
protected startupCompleteMessage = START_UP_COMPLETE_MSG;
|
|
55
|
+
protected currentConnections: jsonrpc.MessageConnection[] = [];
|
|
56
|
+
|
|
57
|
+
constructor() {
|
|
58
|
+
super();
|
|
59
|
+
this.toDispose.push(
|
|
60
|
+
Disposable.create(() => {
|
|
61
|
+
this.currentConnections.forEach(connection => connection.dispose());
|
|
62
|
+
this.server.close();
|
|
63
|
+
})
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
protected async run(options: WebSocketServerOptions): Promise<void> {
|
|
68
|
+
const resolvedOptions = await this.resolveOptions(options);
|
|
69
|
+
this.server = new Server({ server: resolvedOptions.server, path: resolvedOptions.path });
|
|
70
|
+
const endpoint = `ws://${resolvedOptions.host}:${resolvedOptions.port}:${resolvedOptions.path}`;
|
|
71
|
+
this.logger.info(`The GLSP Websocket launcher is ready to accept new client requests on endpoint '${endpoint}'`);
|
|
72
|
+
console.log(this.startupCompleteMessage.concat(resolvedOptions.port.toString()));
|
|
73
|
+
|
|
74
|
+
this.server.on('connection', (ws, req) => {
|
|
75
|
+
this.createClientConnection(ws);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return new Promise((resolve, reject) => {
|
|
79
|
+
this.server.on('close', () => resolve(undefined));
|
|
80
|
+
this.server.on('error', error => reject(error));
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
protected async createClientConnection(socket: WebSocket): Promise<void> {
|
|
85
|
+
const container = this.createContainer();
|
|
86
|
+
const connection = this.createConnection(socket);
|
|
87
|
+
this.currentConnections.push(connection);
|
|
88
|
+
const glspServer = container.get<JsonRpcGLSPServer>(JsonRpcGLSPServer);
|
|
89
|
+
glspServer.connect(connection);
|
|
90
|
+
this.logger.info('Starting GLSP server connection');
|
|
91
|
+
connection.listen();
|
|
92
|
+
connection.onDispose(() => this.disposeClientConnection(container, glspServer));
|
|
93
|
+
socket.on('close', () => this.disposeClientConnection(container, glspServer));
|
|
94
|
+
connection.onClose(() => console.log('GOD dam'));
|
|
95
|
+
return new Promise((resolve, rejects) => {
|
|
96
|
+
connection.onClose(() => resolve(undefined));
|
|
97
|
+
connection.onError(error => rejects(error));
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
protected disposeClientConnection(container: Container, glspServer: GLSPServer): void {
|
|
102
|
+
glspServer.shutdown();
|
|
103
|
+
container.unbindAll();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
protected createConnection(socket: WebSocket): jsonrpc.MessageConnection {
|
|
107
|
+
return createWebSocketConnection(wrapWebSocket(socket));
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
protected async resolveOptions(options: WebSocketServerOptions): Promise<ResolvedWebSocketServerOptions> {
|
|
111
|
+
const port = !options.port || options.port === 0 ? await getFreePort() : options.port;
|
|
112
|
+
const path = options.path.startsWith('/') ? options.path : `/${options.path}`;
|
|
113
|
+
const server = this.createHttpServer(port, options.host);
|
|
114
|
+
|
|
115
|
+
return { ...options, port, path, server };
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
protected createHttpServer(port: number, host?: string): http.Server {
|
|
119
|
+
const server = http.createServer((req, res) => {
|
|
120
|
+
const body = http.STATUS_CODES[STATUS_UPGRADE_REQUIRED];
|
|
121
|
+
|
|
122
|
+
res.writeHead(426, {
|
|
123
|
+
'Content-Length': body?.length,
|
|
124
|
+
'Content-Type': 'text/plain'
|
|
125
|
+
});
|
|
126
|
+
res.end(body);
|
|
127
|
+
});
|
|
128
|
+
server.listen(port, host);
|
|
129
|
+
// Set server timeout to infinite
|
|
130
|
+
server.setTimeout(0);
|
|
131
|
+
return server;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
override start(options: WebSocketServerOptions): MaybePromise<void> {
|
|
135
|
+
super.start(options);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async function getFreePort(): Promise<number> {
|
|
140
|
+
return new Promise((resolve, reject) => {
|
|
141
|
+
const srv = net.createServer();
|
|
142
|
+
srv.listen(0, () => {
|
|
143
|
+
const address = srv.address();
|
|
144
|
+
if (!address || typeof address === 'string') {
|
|
145
|
+
reject(new Error('Could not address to compute a free port'));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
srv.close(() => resolve(address.port));
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Creates a {@link WebSocketWrapper} for the given plain WebSocket
|
|
154
|
+
* @param socket The socket to wrap
|
|
155
|
+
*/
|
|
156
|
+
export function wrapWebSocket(socket: WebSocket): WebSocketWrapper {
|
|
157
|
+
return {
|
|
158
|
+
send: content => socket.send(content),
|
|
159
|
+
onMessage: cb => socket.on('message', cb),
|
|
160
|
+
onClose: cb => socket.on('close', cb),
|
|
161
|
+
onError: cb => socket.on('error', cb),
|
|
162
|
+
dispose: () => socket.close()
|
|
163
|
+
};
|
|
164
|
+
}
|