@eclipse-glsp/server 2.8.0-next.9 → 2.9.0-next.1

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.
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2022-2023 STMicroelectronics and others.
2
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -26,6 +26,13 @@ export declare abstract class GLSPServerLauncher<T> implements Disposable {
26
26
  configure(serverModule: ServerModule, ...additionalModules: ContainerModule[]): void;
27
27
  createContainer(...additionalModules: ContainerModule[]): Container;
28
28
  start(startParams: T): MaybePromise<void>;
29
+ /**
30
+ * Registers what {@link shutdown} has to release for the launch that is about to start.
31
+ *
32
+ * Called once per launch, because {@link dispose} empties the collection it registers into. A subclass that holds
33
+ * resources for the duration of a launch overrides this instead of registering them in its constructor.
34
+ */
35
+ protected registerDisposables(): void;
29
36
  protected abstract run(startParams: T): MaybePromise<void>;
30
37
  shutdown(): MaybePromise<void>;
31
38
  protected stop(): MaybePromise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"glsp-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/common/launch/glsp-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAClF,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAgC,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,8BACsB,kBAAkB,CAAC,CAAC,CAAE,YAAW,UAAU;IAC7C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzC,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAM;IAC3C,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,SAAS,uBAA8B;IAET,SAAS,CAAC,eAAe,CAAC,EAAE,SAAS,CAAC;IAE9E,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,iBAAiB,EAAE,eAAe,EAAE,GAAG,IAAI;IAIpF,eAAe,CAAC,GAAG,iBAAiB,EAAE,eAAe,EAAE,GAAG,SAAS;IAMnE,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC;IAQzC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC;IAE1D,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC;IAU9B,SAAS,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC;IAIpC,OAAO,IAAI,IAAI;IAIf,IAAI,OAAO,IAAI,eAAe,EAAE,CAK/B;CACJ"}
1
+ {"version":3,"file":"glsp-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/common/launch/glsp-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAClF,OAAO,EAAE,UAAU,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,SAAS,EAAE,eAAe,EAAgC,MAAM,WAAW,CAAC;AACrF,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,8BACsB,kBAAkB,CAAC,CAAC,CAAE,YAAW,UAAU;IAC7C,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;IAEzC,SAAS,CAAC,QAAQ,EAAE,eAAe,EAAE,CAAM;IAC3C,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC;IAC3B,SAAS,CAAC,SAAS,uBAA8B;IAET,SAAS,CAAC,eAAe,CAAC,EAAE,SAAS,CAAC;IAE9E,SAAS,CAAC,YAAY,EAAE,YAAY,EAAE,GAAG,iBAAiB,EAAE,eAAe,EAAE,GAAG,IAAI;IAIpF,eAAe,CAAC,GAAG,iBAAiB,EAAE,eAAe,EAAE,GAAG,SAAS;IAMnE,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC;IASzC;;;;;OAKG;IACH,SAAS,CAAC,mBAAmB,IAAI,IAAI;IAIrC,SAAS,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,GAAG,YAAY,CAAC,IAAI,CAAC;IAE1D,QAAQ,IAAI,YAAY,CAAC,IAAI,CAAC;IAU9B,SAAS,CAAC,IAAI,IAAI,YAAY,CAAC,IAAI,CAAC;IAIpC,OAAO,IAAI,IAAI;IAIf,IAAI,OAAO,IAAI,eAAe,EAAE,CAK/B;CACJ"}
@@ -11,7 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.GLSPServerLauncher = void 0;
13
13
  /********************************************************************************
14
- * Copyright (c) 2022-2023 STMicroelectronics and others.
14
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
15
15
  *
16
16
  * This program and the accompanying materials are made available under the
17
17
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -45,10 +45,20 @@ let GLSPServerLauncher = class GLSPServerLauncher {
45
45
  start(startParams) {
46
46
  if (!this.running) {
47
47
  this.running = true;
48
+ this.registerDisposables();
48
49
  return this.run(startParams);
49
50
  }
50
51
  this.logger.warn('Could not start launcher. Launcher is already running!');
51
52
  }
53
+ /**
54
+ * Registers what {@link shutdown} has to release for the launch that is about to start.
55
+ *
56
+ * Called once per launch, because {@link dispose} empties the collection it registers into. A subclass that holds
57
+ * resources for the duration of a launch overrides this instead of registering them in its constructor.
58
+ */
59
+ registerDisposables() {
60
+ // nothing to release by default
61
+ }
52
62
  shutdown() {
53
63
  if (this.running) {
54
64
  this.logger.info('Shutdown GLSPServerLauncher');
@@ -1 +1 @@
1
- {"version":3,"file":"glsp-server-launcher.js","sourceRoot":"","sources":["../../../src/common/launch/glsp-server-launcher.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;;;;;kFAckF;AAClF,qDAAwF;AACxF,yCAAqF;AAErF,mEAA+D;AAC/D,4CAAyC;AAGlC,IAAe,kBAAkB,GAAjC,MAAe,kBAAkB;IAAjC;QAGO,aAAQ,GAAsB,EAAE,CAAC;QAEjC,cAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IAgDrD,CAAC;IA5CG,SAAS,CAAC,YAA0B,EAAE,GAAG,iBAAoC;QACzE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,iBAAiB,CAAC,CAAC;IAC3D,CAAC;IAED,eAAe,CAAC,GAAG,iBAAoC;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,qBAAS,EAAE,CAAC;QAC9F,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,iBAAiB,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,WAAc;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAC/E,CAAC;IAID,QAAQ;QACJ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAC1E,CAAC;IAES,IAAI;QACV,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,OAAO;QACH,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO;QACP,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;CACJ,CAAA;AArDqB,gDAAkB;AACV;IAAzB,IAAA,kBAAM,EAAC,eAAM,CAAC;8BAAmB,eAAM;kDAAC;AAMS;IAAjD,IAAA,kBAAM,EAAC,wCAAkB,CAAC;IAAE,IAAA,oBAAQ,GAAE;8BAA6B,qBAAS;2DAAC;6BAP5D,kBAAkB;IADvC,IAAA,sBAAU,GAAE;GACS,kBAAkB,CAqDvC"}
1
+ {"version":3,"file":"glsp-server-launcher.js","sourceRoot":"","sources":["../../../src/common/launch/glsp-server-launcher.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;;;;;kFAckF;AAClF,qDAAwF;AACxF,yCAAqF;AAErF,mEAA+D;AAC/D,4CAAyC;AAGlC,IAAe,kBAAkB,GAAjC,MAAe,kBAAkB;IAAjC;QAGO,aAAQ,GAAsB,EAAE,CAAC;QAEjC,cAAS,GAAG,IAAI,+BAAoB,EAAE,CAAC;IA2DrD,CAAC;IAvDG,SAAS,CAAC,YAA0B,EAAE,GAAG,iBAAoC;QACzE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,YAAY,EAAE,GAAG,iBAAiB,CAAC,CAAC;IAC3D,CAAC;IAED,eAAe,CAAC,GAAG,iBAAoC;QACnD,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,IAAI,qBAAS,EAAE,CAAC;QAC9F,SAAS,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,GAAG,iBAAiB,CAAC,CAAC;QACvD,OAAO,SAAS,CAAC;IACrB,CAAC;IAED,KAAK,CAAC,WAAc;QAChB,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,mBAAmB,EAAE,CAAC;YAC3B,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC;QACjC,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,wDAAwD,CAAC,CAAC;IAC/E,CAAC;IAED;;;;;OAKG;IACO,mBAAmB;QACzB,gCAAgC;IACpC,CAAC;IAID,QAAQ;QACJ,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;YAChD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,OAAO,MAAM,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IAC1E,CAAC;IAES,IAAI;QACV,IAAI,CAAC,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,OAAO;QACH,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO;QACP,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,oDAAoD,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC,QAAQ,CAAC;IACzB,CAAC;CACJ,CAAA;AAhEqB,gDAAkB;AACV;IAAzB,IAAA,kBAAM,EAAC,eAAM,CAAC;8BAAmB,eAAM;kDAAC;AAMS;IAAjD,IAAA,kBAAM,EAAC,wCAAkB,CAAC;IAAE,IAAA,oBAAQ,GAAE;8BAA6B,qBAAS;2DAAC;6BAP5D,kBAAkB;IADvC,IAAA,sBAAU,GAAE;GACS,kBAAkB,CAgEvC"}
@@ -13,8 +13,9 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { GLSPClientProxy, GLSPServer } from '@eclipse-glsp/protocol';
16
+ import { Deferred, GLSPClientProxy, GLSPServer } from '@eclipse-glsp/protocol';
17
17
  import { Container, ContainerModule } from 'inversify';
18
+ import * as net from 'net';
18
19
  import * as jsonrpc from 'vscode-jsonrpc';
19
20
  import { Logger } from '../utils/logger';
20
21
  import { GLSPServerLauncher } from './glsp-server-launcher';
@@ -28,7 +29,55 @@ export declare abstract class JsonRpcGLSPServerLauncher<T> extends GLSPServerLau
28
29
  protected logger: Logger;
29
30
  protected serverInstances: Map<jsonrpc.MessageConnection, JsonRpcServerInstance>;
30
31
  protected startupCompleteMessage: string;
31
- constructor();
32
+ protected listeningAddress: Deferred<net.AddressInfo>;
33
+ /**
34
+ * Resolves with the address the server bound to once it is listening, and rejects if it never gets there.
35
+ *
36
+ * Launching with port `0` lets the operating system pick a free port, so the bound address is not necessarily the
37
+ * requested one. Settles once per launch and keeps that value, so use {@link port} for the current state. Reading
38
+ * this before {@link start} is fine, the promise handed out is the one that launch settles.
39
+ */
40
+ get listening(): Promise<net.AddressInfo>;
41
+ /**
42
+ * The port the server is currently listening on, or `undefined` if it is not.
43
+ *
44
+ * Await {@link listening} rather than polling this while the server is still starting up.
45
+ */
46
+ get port(): number | undefined;
47
+ /**
48
+ * The socket that {@link port} reports on, or `undefined` before the first launch.
49
+ *
50
+ * A launcher that binds a socket overrides this, the default reports no address at all.
51
+ */
52
+ protected getServerSocket(): net.Server | undefined;
53
+ /**
54
+ * Arms {@link listening} for a launch.
55
+ *
56
+ * An unresolved promise is kept, so a caller that grabbed {@link listening} before {@link start} gets the one this
57
+ * launch settles. A settled one is replaced, so a restart is not handed the previous result.
58
+ */
59
+ protected resetListening(): void;
60
+ /**
61
+ * Resolves {@link listening} with the address the given server bound to.
62
+ *
63
+ * @param server The server that reported itself as listening.
64
+ * @returns The bound address, or `undefined` if it cannot be used, in which case the launcher is shut down.
65
+ */
66
+ protected settleListening(server: net.Server): net.AddressInfo | undefined;
67
+ /**
68
+ * Invoked when the server socket fails, e.g. because the requested port is already in use.
69
+ *
70
+ * @param error The reason the socket failed.
71
+ */
72
+ protected handleError(error: Error): void;
73
+ /**
74
+ * Reports that the server will not accept requests, rejects {@link listening} and shuts the launcher down.
75
+ *
76
+ * @param message The reason the server is not usable.
77
+ * @param cause The underlying error, if the reason was one.
78
+ */
79
+ protected failToListen(message: string, cause?: Error): void;
80
+ protected registerDisposables(): void;
32
81
  protected disposeServerInstance(instance: JsonRpcServerInstance): void;
33
82
  protected createServerInstance(clientConnection: jsonrpc.MessageConnection): void;
34
83
  protected createJsonRpcModule(clientConnection: jsonrpc.MessageConnection): ContainerModule;
@@ -1 +1 @@
1
- {"version":3,"file":"jsonrpc-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/common/launch/jsonrpc-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAElF,OAAO,EAEH,eAAe,EACf,UAAU,EAIb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAsB,MAAM,WAAW,CAAC;AAC3E,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,eAAO,MAAM,qBAAqB,iEAAiE,CAAC;AAEpG,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAC5C,SAAS,EAAE,SAAS,CAAC;CACxB;AAED,8BACsB,yBAAyB,CAAC,CAAC,CAAE,SAAQ,kBAAkB,CAAC,CAAC,CAAC;IAC5E,UACmB,MAAM,EAAE,MAAM,CAAC;IAElC,SAAS,CAAC,eAAe,wDAA+D;IACxF,SAAS,CAAC,sBAAsB,SAAyB;;IAWzD,SAAS,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI;IAOtE,SAAS,CAAC,oBAAoB,CAAC,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,GAAG,IAAI;IAQjF,SAAS,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,GAAG,eAAe;IAU3F,SAAS,CAAC,yBAAyB,CAAC,cAAc,EAAE,qBAAqB,GAAG,IAAI;IAahF,SAAS,CAAC,iBAAiB,CAAC,cAAc,EAAE,qBAAqB,GAAG,eAAe;CAKtF"}
1
+ {"version":3,"file":"jsonrpc-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/common/launch/jsonrpc-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAElF,OAAO,EACH,QAAQ,EAER,eAAe,EACf,UAAU,EAIb,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,SAAS,EAAE,eAAe,EAAsB,MAAM,WAAW,CAAC;AAC3E,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,eAAO,MAAM,qBAAqB,iEAAiE,CAAC;AAEpG,MAAM,WAAW,qBAAqB;IAClC,MAAM,EAAE,UAAU,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAC5C,SAAS,EAAE,SAAS,CAAC;CACxB;AAED,8BACsB,yBAAyB,CAAC,CAAC,CAAE,SAAQ,kBAAkB,CAAC,CAAC,CAAC;IAC5E,UACmB,MAAM,EAAE,MAAM,CAAC;IAElC,SAAS,CAAC,eAAe,wDAA+D;IACxF,SAAS,CAAC,sBAAsB,SAAyB;IAEzD,SAAS,CAAC,gBAAgB,4BAAmC;IAE7D;;;;;;OAMG;IACH,IAAI,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,CAExC;IAED;;;;OAIG;IACH,IAAI,IAAI,IAAI,MAAM,GAAG,SAAS,CAG7B;IAED;;;;OAIG;IACH,SAAS,CAAC,eAAe,IAAI,GAAG,CAAC,MAAM,GAAG,SAAS;IAInD;;;;;OAKG;IACH,SAAS,CAAC,cAAc,IAAI,IAAI;IAMhC;;;;;OAKG;IACH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,WAAW,GAAG,SAAS;IAc1E;;;;OAIG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAIzC;;;;;OAKG;IACH,SAAS,CAAC,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI;cAMzC,mBAAmB,IAAI,IAAI;IAS9C,SAAS,CAAC,qBAAqB,CAAC,QAAQ,EAAE,qBAAqB,GAAG,IAAI;IAOtE,SAAS,CAAC,oBAAoB,CAAC,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,GAAG,IAAI;IAQjF,SAAS,CAAC,mBAAmB,CAAC,gBAAgB,EAAE,OAAO,CAAC,iBAAiB,GAAG,eAAe;IAU3F,SAAS,CAAC,yBAAyB,CAAC,cAAc,EAAE,qBAAqB,GAAG,IAAI;IAahF,SAAS,CAAC,iBAAiB,CAAC,cAAc,EAAE,qBAAqB,GAAG,eAAe;CAKtF"}
@@ -32,9 +32,89 @@ const glsp_server_launcher_1 = require("./glsp-server-launcher");
32
32
  exports.START_UP_COMPLETE_MSG = '[GLSP-Server]:Startup completed. Accepting requests on port:';
33
33
  let JsonRpcGLSPServerLauncher = class JsonRpcGLSPServerLauncher extends glsp_server_launcher_1.GLSPServerLauncher {
34
34
  constructor() {
35
- super();
35
+ super(...arguments);
36
36
  this.serverInstances = new Map();
37
37
  this.startupCompleteMessage = exports.START_UP_COMPLETE_MSG;
38
+ this.listeningAddress = new protocol_1.Deferred();
39
+ }
40
+ /**
41
+ * Resolves with the address the server bound to once it is listening, and rejects if it never gets there.
42
+ *
43
+ * Launching with port `0` lets the operating system pick a free port, so the bound address is not necessarily the
44
+ * requested one. Settles once per launch and keeps that value, so use {@link port} for the current state. Reading
45
+ * this before {@link start} is fine, the promise handed out is the one that launch settles.
46
+ */
47
+ get listening() {
48
+ return this.listeningAddress.promise;
49
+ }
50
+ /**
51
+ * The port the server is currently listening on, or `undefined` if it is not.
52
+ *
53
+ * Await {@link listening} rather than polling this while the server is still starting up.
54
+ */
55
+ get port() {
56
+ const address = this.getServerSocket()?.address();
57
+ return address && typeof address !== 'string' ? address.port : undefined;
58
+ }
59
+ /**
60
+ * The socket that {@link port} reports on, or `undefined` before the first launch.
61
+ *
62
+ * A launcher that binds a socket overrides this, the default reports no address at all.
63
+ */
64
+ getServerSocket() {
65
+ return undefined;
66
+ }
67
+ /**
68
+ * Arms {@link listening} for a launch.
69
+ *
70
+ * An unresolved promise is kept, so a caller that grabbed {@link listening} before {@link start} gets the one this
71
+ * launch settles. A settled one is replaced, so a restart is not handed the previous result.
72
+ */
73
+ resetListening() {
74
+ if (this.listeningAddress.state !== 'unresolved') {
75
+ this.listeningAddress = new protocol_1.Deferred();
76
+ }
77
+ }
78
+ /**
79
+ * Resolves {@link listening} with the address the given server bound to.
80
+ *
81
+ * @param server The server that reported itself as listening.
82
+ * @returns The bound address, or `undefined` if it cannot be used, in which case the launcher is shut down.
83
+ */
84
+ settleListening(server) {
85
+ const addressInfo = server.address();
86
+ if (!addressInfo) {
87
+ this.failToListen('Could not resolve GLSP Server address info.');
88
+ return undefined;
89
+ }
90
+ if (typeof addressInfo === 'string') {
91
+ this.failToListen(`GLSP Server is unexpectedly listening to pipe or domain socket "${addressInfo}".`);
92
+ return undefined;
93
+ }
94
+ this.listeningAddress.resolve(addressInfo);
95
+ return addressInfo;
96
+ }
97
+ /**
98
+ * Invoked when the server socket fails, e.g. because the requested port is already in use.
99
+ *
100
+ * @param error The reason the socket failed.
101
+ */
102
+ handleError(error) {
103
+ this.failToListen(`GLSP server socket error. ${error.message}`, error);
104
+ }
105
+ /**
106
+ * Reports that the server will not accept requests, rejects {@link listening} and shuts the launcher down.
107
+ *
108
+ * @param message The reason the server is not usable.
109
+ * @param cause The underlying error, if the reason was one.
110
+ */
111
+ failToListen(message, cause) {
112
+ this.logger.error(`${message} Shutting down.`);
113
+ this.listeningAddress.reject(cause ?? new Error(message));
114
+ this.shutdown();
115
+ }
116
+ registerDisposables() {
117
+ super.registerDisposables();
38
118
  this.toDispose.push(protocol_1.Disposable.create(() => {
39
119
  this.serverInstances.forEach(instance => this.disposeServerInstance(instance));
40
120
  }));
@@ -81,7 +161,6 @@ __decorate([
81
161
  __metadata("design:type", logger_1.Logger)
82
162
  ], JsonRpcGLSPServerLauncher.prototype, "logger", void 0);
83
163
  exports.JsonRpcGLSPServerLauncher = JsonRpcGLSPServerLauncher = __decorate([
84
- (0, inversify_1.injectable)(),
85
- __metadata("design:paramtypes", [])
164
+ (0, inversify_1.injectable)()
86
165
  ], JsonRpcGLSPServerLauncher);
87
166
  //# sourceMappingURL=jsonrpc-server-launcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsonrpc-server-launcher.js","sourceRoot":"","sources":["../../../src/common/launch/jsonrpc-server-launcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jsonrpc-server-launcher.js","sourceRoot":"","sources":["../../../src/common/launch/jsonrpc-server-launcher.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,49 @@
1
+ /********************************************************************************
2
+ * Copyright (c) 2022-2026 STMicroelectronics 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
+ import { Emitter } from '@eclipse-glsp/protocol';
1
17
  import * as net from 'net';
2
18
  import * as jsonrpc from 'vscode-jsonrpc/node';
3
19
  import { JsonRpcGLSPServerLauncher } from '../../common/launch/jsonrpc-server-launcher';
4
20
  import { Logger } from '../../common/utils/logger';
5
21
  export declare class SocketServerLauncher extends JsonRpcGLSPServerLauncher<net.TcpSocketConnectOpts> {
6
22
  protected logger: Logger;
7
- protected netServer: net.Server;
8
- constructor();
23
+ protected netServer?: net.Server;
24
+ protected onConnectionEmitter: Emitter<net.Socket>;
25
+ /**
26
+ * Fires for every socket the server accepts, before the JSON-RPC connection is built on it.
27
+ *
28
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
29
+ * subscription outlives an individual launch and is disposed by the caller.
30
+ */
31
+ readonly onConnection: import("@eclipse-glsp/protocol").Event<net.Socket>;
32
+ protected getServerSocket(): net.Server | undefined;
33
+ protected registerDisposables(): void;
9
34
  protected run(opts: net.TcpSocketConnectOpts): Promise<void>;
35
+ /**
36
+ * Takes up a socket the server accepted. Observers are notified before the socket is read from.
37
+ *
38
+ * @param socket The accepted socket.
39
+ */
40
+ protected acceptConnection(socket: net.Socket): void;
41
+ /**
42
+ * Reports the server as ready and resolves {@link listening}.
43
+ *
44
+ * @param server The server that reported itself as listening.
45
+ */
46
+ protected handleListening(server: net.Server): void;
10
47
  protected createConnection(socket: net.Socket): jsonrpc.MessageConnection;
11
48
  }
12
49
  //# sourceMappingURL=socket-server-launcher.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/node/launch/socket-server-launcher.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEnD,qBACa,oBAAqB,SAAQ,yBAAyB,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACzF,UAAmC,MAAM,EAAE,MAAM,CAAC;IAElD,SAAS,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC;;IAWhC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+B5D,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,iBAAiB;CAG5E"}
1
+ {"version":3,"file":"socket-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/node/launch/socket-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAClF,OAAO,EAAc,OAAO,EAAE,MAAM,wBAAwB,CAAC;AAE7D,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,KAAK,OAAO,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEnD,qBACa,oBAAqB,SAAQ,yBAAyB,CAAC,GAAG,CAAC,oBAAoB,CAAC;IACzF,UAAmC,MAAM,EAAE,MAAM,CAAC;IAElD,SAAS,CAAC,SAAS,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC;IAEjC,SAAS,CAAC,mBAAmB,sBAA6B;IAE1D;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,qDAAkC;cAEpC,eAAe,IAAI,GAAG,CAAC,MAAM,GAAG,SAAS;cAIzC,mBAAmB,IAAI,IAAI;IAS9C,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc5D;;;;OAIG;IACH,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI;IAKpD;;;;OAIG;IACH,SAAS,CAAC,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,IAAI;IAWnD,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,OAAO,CAAC,iBAAiB;CAG5E"}
@@ -11,7 +11,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.SocketServerLauncher = void 0;
13
13
  /********************************************************************************
14
- * Copyright (c) 2022-2024 STMicroelectronics and others.
14
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
15
15
  *
16
16
  * This program and the accompanying materials are made available under the
17
17
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -33,41 +33,61 @@ const jsonrpc_server_launcher_1 = require("../../common/launch/jsonrpc-server-la
33
33
  const logger_1 = require("../../common/utils/logger");
34
34
  let SocketServerLauncher = class SocketServerLauncher extends jsonrpc_server_launcher_1.JsonRpcGLSPServerLauncher {
35
35
  constructor() {
36
- super();
36
+ super(...arguments);
37
+ this.onConnectionEmitter = new protocol_1.Emitter();
38
+ /**
39
+ * Fires for every socket the server accepts, before the JSON-RPC connection is built on it.
40
+ *
41
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
42
+ * subscription outlives an individual launch and is disposed by the caller.
43
+ */
44
+ this.onConnection = this.onConnectionEmitter.event;
45
+ }
46
+ getServerSocket() {
47
+ return this.netServer;
48
+ }
49
+ registerDisposables() {
50
+ super.registerDisposables();
37
51
  this.toDispose.push(protocol_1.Disposable.create(() => {
38
- this.netServer.close();
52
+ this.netServer?.close();
39
53
  }));
40
54
  }
41
55
  run(opts) {
42
- this.netServer = net.createServer(socket => {
43
- const connection = this.createConnection(socket);
44
- this.createServerInstance(connection);
45
- });
46
- this.netServer.listen(opts.port, opts.host);
47
- this.netServer.on('listening', () => {
48
- const addressInfo = this.netServer.address();
49
- if (!addressInfo) {
50
- this.logger.error('Could not resolve GLSP Server address info. Shutting down.');
51
- this.shutdown();
52
- return;
53
- }
54
- else if (typeof addressInfo === 'string') {
55
- this.logger.error(`GLSP Server is unexpectedly listening to pipe or domain socket "${addressInfo}". Shutting down.`);
56
- this.shutdown();
57
- return;
58
- }
59
- const currentPort = addressInfo.port;
60
- this.logger.info(`The GLSP server is ready to accept new client requests on port: ${currentPort}`);
61
- // Print a message to the output stream that indicates that the start is completed.
62
- // This indicates to the client that the server process is ready (in an embedded scenario).
63
- console.log(this.startupCompleteMessage.concat(currentPort.toString()));
64
- });
65
- this.netServer.on('error', () => this.shutdown());
56
+ this.resetListening();
57
+ const netServer = net.createServer(socket => this.acceptConnection(socket));
58
+ this.netServer = netServer;
59
+ netServer.listen(opts.port, opts.host);
60
+ netServer.on('listening', () => this.handleListening(netServer));
61
+ netServer.on('error', error => this.handleError(error));
66
62
  return new Promise((resolve, reject) => {
67
- this.netServer.on('close', () => resolve(undefined));
68
- this.netServer.on('error', error => reject(error));
63
+ netServer.on('close', () => resolve(undefined));
64
+ netServer.on('error', error => reject(error));
69
65
  });
70
66
  }
67
+ /**
68
+ * Takes up a socket the server accepted. Observers are notified before the socket is read from.
69
+ *
70
+ * @param socket The accepted socket.
71
+ */
72
+ acceptConnection(socket) {
73
+ this.onConnectionEmitter.fire(socket);
74
+ this.createServerInstance(this.createConnection(socket));
75
+ }
76
+ /**
77
+ * Reports the server as ready and resolves {@link listening}.
78
+ *
79
+ * @param server The server that reported itself as listening.
80
+ */
81
+ handleListening(server) {
82
+ const addressInfo = this.settleListening(server);
83
+ if (!addressInfo) {
84
+ return;
85
+ }
86
+ this.logger.info(`The GLSP server is ready to accept new client requests on port: ${addressInfo.port}`);
87
+ // Print a message to the output stream that indicates that the start is completed.
88
+ // This indicates to the client that the server process is ready (in an embedded scenario).
89
+ console.log(this.startupCompleteMessage.concat(addressInfo.port.toString()));
90
+ }
71
91
  createConnection(socket) {
72
92
  return jsonrpc.createMessageConnection(new jsonrpc.SocketMessageReader(socket), new jsonrpc.SocketMessageWriter(socket), console);
73
93
  }
@@ -78,7 +98,6 @@ __decorate([
78
98
  __metadata("design:type", logger_1.Logger)
79
99
  ], SocketServerLauncher.prototype, "logger", void 0);
80
100
  exports.SocketServerLauncher = SocketServerLauncher = __decorate([
81
- (0, inversify_1.injectable)(),
82
- __metadata("design:paramtypes", [])
101
+ (0, inversify_1.injectable)()
83
102
  ], SocketServerLauncher);
84
103
  //# sourceMappingURL=socket-server-launcher.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"socket-server-launcher.js","sourceRoot":"","sources":["../../../src/node/launch/socket-server-launcher.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;;;;;kFAckF;AAClF,qDAAoD;AACpD,yCAA+C;AAC/C,2BAA2B;AAC3B,+CAA+C;AAC/C,yFAAwF;AACxF,sDAAmD;AAG5C,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,mDAAmD;IAKzF;QACI,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,SAAS,CAAC,IAAI,CACf,qBAAU,CAAC,MAAM,CAAC,GAAG,EAAE;YACnB,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;QAC3B,CAAC,CAAC,CACL,CAAC;IACN,CAAC;IAES,GAAG,CAAC,IAA8B;QACxC,IAAI,CAAC,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE;YACvC,MAAM,UAAU,GAAG,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC;YACjD,IAAI,CAAC,oBAAoB,CAAC,UAAU,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE;YAChC,MAAM,WAAW,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;YAC7C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4DAA4D,CAAC,CAAC;gBAChF,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,OAAO;YACX,CAAC;iBAAM,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE,CAAC;gBACzC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,mEAAmE,WAAW,mBAAmB,CAAC,CAAC;gBACrH,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,OAAO;YACX,CAAC;YACD,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC;YACrC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mEAAmE,WAAW,EAAE,CAAC,CAAC;YACnG,mFAAmF;YACnF,2FAA2F;YAC3F,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QAC5E,CAAC,CAAC,CAAC;QACH,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;QAClD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YACrD,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC,CAAC;IACP,CAAC;IAES,gBAAgB,CAAC,MAAkB;QACzC,OAAO,OAAO,CAAC,uBAAuB,CAAC,IAAI,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACtI,CAAC;CACJ,CAAA;AAhDY,oDAAoB;AACM;IAAlC,IAAA,kBAAM,EAAC,eAAM,CAAC;8BAA4B,eAAM;oDAAC;+BADzC,oBAAoB;IADhC,IAAA,sBAAU,GAAE;;GACA,oBAAoB,CAgDhC"}
1
+ {"version":3,"file":"socket-server-launcher.js","sourceRoot":"","sources":["../../../src/node/launch/socket-server-launcher.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA;;;;;;;;;;;;;;kFAckF;AAClF,qDAA6D;AAC7D,yCAA+C;AAC/C,2BAA2B;AAC3B,+CAA+C;AAC/C,yFAAwF;AACxF,sDAAmD;AAG5C,IAAM,oBAAoB,GAA1B,MAAM,oBAAqB,SAAQ,mDAAmD;IAAtF;;QAKO,wBAAmB,GAAG,IAAI,kBAAO,EAAc,CAAC;QAE1D;;;;;WAKG;QACM,iBAAY,GAAG,IAAI,CAAC,mBAAmB,CAAC,KAAK,CAAC;IA0D3D,CAAC;IAxDsB,eAAe;QAC9B,OAAO,IAAI,CAAC,SAAS,CAAC;IAC1B,CAAC;IAEkB,mBAAmB;QAClC,KAAK,CAAC,mBAAmB,EAAE,CAAC;QAC5B,IAAI,CAAC,SAAS,CAAC,IAAI,CACf,qBAAU,CAAC,MAAM,CAAC,GAAG,EAAE;YACnB,IAAI,CAAC,SAAS,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC,CAAC,CACL,CAAC;IACN,CAAC;IAES,GAAG,CAAC,IAA8B;QACxC,IAAI,CAAC,cAAc,EAAE,CAAC;QACtB,MAAM,SAAS,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;QAC5E,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAE3B,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,SAAS,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC,CAAC;QACjE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC;YAChD,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClD,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;;;OAIG;IACO,gBAAgB,CAAC,MAAkB;QACzC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACO,eAAe,CAAC,MAAkB;QACxC,MAAM,WAAW,GAAG,IAAI,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;QACjD,IAAI,CAAC,WAAW,EAAE,CAAC;YACf,OAAO;QACX,CAAC;QACD,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mEAAmE,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QACxG,mFAAmF;QACnF,2FAA2F;QAC3F,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,sBAAsB,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACjF,CAAC;IAES,gBAAgB,CAAC,MAAkB;QACzC,OAAO,OAAO,CAAC,uBAAuB,CAAC,IAAI,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,IAAI,OAAO,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IACtI,CAAC;CACJ,CAAA;AAvEY,oDAAoB;AACM;IAAlC,IAAA,kBAAM,EAAC,eAAM,CAAC;8BAA4B,eAAM;oDAAC;+BADzC,oBAAoB;IADhC,IAAA,sBAAU,GAAE;GACA,oBAAoB,CAuEhC"}
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,10 +13,11 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { MaybePromise, WebSocketWrapper } from '@eclipse-glsp/protocol';
16
+ import { Emitter, MaybePromise, WebSocketWrapper } from '@eclipse-glsp/protocol';
17
17
  import * as http from 'http';
18
+ import * as net from 'net';
18
19
  import * as jsonrpc from 'vscode-jsonrpc';
19
- import { Server, WebSocket } from 'ws';
20
+ import { WebSocket, WebSocketServer } from 'ws';
20
21
  import { JsonRpcGLSPServerLauncher } from '../../common/launch/jsonrpc-server-launcher';
21
22
  import { Logger } from '../../common/utils/logger';
22
23
  export interface WebSocketServerOptions {
@@ -34,11 +35,41 @@ export interface WebsocketConnectionData {
34
35
  socket: WebSocket;
35
36
  connection: jsonrpc.MessageConnection;
36
37
  }
38
+ /** An accepted web socket together with the upgrade request it was negotiated with. */
39
+ export interface AcceptedWebSocket {
40
+ socket: WebSocket;
41
+ /** The handshake request, the only place where its headers and query are still available. */
42
+ request: http.IncomingMessage;
43
+ }
37
44
  export declare class WebSocketServerLauncher extends JsonRpcGLSPServerLauncher<WebSocketServerOptions> {
38
45
  protected logger: Logger;
39
- protected server: Server;
40
- constructor();
46
+ protected server?: WebSocketServer;
47
+ /**
48
+ * The HTTP server the web socket server is mounted on.
49
+ *
50
+ * Held separately because `ws` only closes an HTTP server it created itself, so releasing the socket is up to us.
51
+ */
52
+ protected httpServer?: http.Server;
53
+ protected onConnectionEmitter: Emitter<AcceptedWebSocket>;
54
+ /**
55
+ * Fires for every web socket the server accepts, before the JSON-RPC connection is built on it.
56
+ *
57
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
58
+ * subscription outlives an individual launch and is disposed by the caller.
59
+ */
60
+ readonly onConnection: import("@eclipse-glsp/protocol").Event<AcceptedWebSocket>;
61
+ protected getServerSocket(): net.Server | undefined;
62
+ protected registerDisposables(): void;
41
63
  protected run(options: WebSocketServerOptions): Promise<void>;
64
+ /** Settles {@link listening} from the HTTP server, which may already be bound by the time we get here. */
65
+ protected observeListening(server: http.Server): void;
66
+ /**
67
+ * Takes up a web socket the server accepted. Observers are notified before the socket is read from.
68
+ *
69
+ * @param socket The accepted web socket.
70
+ * @param request The upgrade request the socket was negotiated with.
71
+ */
72
+ protected acceptConnection(socket: WebSocket, request: http.IncomingMessage): void;
42
73
  protected createConnection(socket: WebSocket): jsonrpc.MessageConnection;
43
74
  protected resolveOptions(options: WebSocketServerOptions): Promise<ResolvedWebSocketServerOptions>;
44
75
  protected createHttpServer(port: number, host?: string): http.Server;
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/node/launch/websocket-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAElF,OAAO,EAAyC,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC/G,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAG7B,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACvC,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEnD,MAAM,WAAW,sBAAsB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACpC,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC,iBAAiB,CAAC;CACzC;AAID,qBACa,uBAAwB,SAAQ,yBAAyB,CAAC,sBAAsB,CAAC;IAC1F,UACmB,MAAM,EAAE,MAAM,CAAC;IAElC,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;;cAWT,GAAG,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBnE,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,iBAAiB;cAIxD,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAQxG,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM;IAgB3D,KAAK,CAAC,OAAO,EAAE,sBAAsB,GAAG,YAAY,CAAC,IAAI,CAAC;CAGtE;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,CAQjE"}
1
+ {"version":3,"file":"websocket-server-launcher.d.ts","sourceRoot":"","sources":["../../../src/node/launch/websocket-server-launcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;kFAckF;AAElF,OAAO,EAAyC,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AACxH,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAC3B,OAAO,KAAK,OAAO,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,IAAI,CAAC;AAChD,OAAO,EAAE,yBAAyB,EAAE,MAAM,6CAA6C,CAAC;AACxF,OAAO,EAAE,MAAM,EAAE,MAAM,2BAA2B,CAAC;AAEnD,MAAM,WAAW,sBAAsB;IACnC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,8BAA8B;IAC3C,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,uBAAuB;IACpC,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,OAAO,CAAC,iBAAiB,CAAC;CACzC;AAED,uFAAuF;AACvF,MAAM,WAAW,iBAAiB;IAC9B,MAAM,EAAE,SAAS,CAAC;IAClB,6FAA6F;IAC7F,OAAO,EAAE,IAAI,CAAC,eAAe,CAAC;CACjC;AAID,qBACa,uBAAwB,SAAQ,yBAAyB,CAAC,sBAAsB,CAAC;IAC1F,UACmB,MAAM,EAAE,MAAM,CAAC;IAElC,SAAS,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAEnC;;;;OAIG;IACH,SAAS,CAAC,UAAU,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC;IAEnC,SAAS,CAAC,mBAAmB,6BAAoC;IAEjE;;;;;OAKG;IACH,QAAQ,CAAC,YAAY,4DAAkC;cAEpC,eAAe,IAAI,GAAG,CAAC,MAAM,GAAG,SAAS;cAIzC,mBAAmB,IAAI,IAAI;cAY9B,GAAG,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,IAAI,CAAC;IAwBnE,0GAA0G;IAC1G,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,IAAI;IASrD;;;;;OAKG;IACH,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,eAAe,GAAG,IAAI;IAKlF,SAAS,CAAC,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,iBAAiB;cAIxD,cAAc,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAQxG,SAAS,CAAC,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC,MAAM;IAgB3D,KAAK,CAAC,OAAO,EAAE,sBAAsB,GAAG,YAAY,CAAC,IAAI,CAAC;CAGtE;AAeD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,GAAG,gBAAgB,CAQjE"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  /********************************************************************************
3
- * Copyright (c) 2023 EclipseSource and others.
3
+ * Copyright (c) 2023-2026 EclipseSource and others.
4
4
  *
5
5
  * This program and the accompanying materials are made available under the
6
6
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -36,26 +36,68 @@ const logger_1 = require("../../common/utils/logger");
36
36
  const STATUS_UPGRADE_REQUIRED = 426;
37
37
  let WebSocketServerLauncher = class WebSocketServerLauncher extends jsonrpc_server_launcher_1.JsonRpcGLSPServerLauncher {
38
38
  constructor() {
39
- super();
39
+ super(...arguments);
40
+ this.onConnectionEmitter = new protocol_1.Emitter();
41
+ /**
42
+ * Fires for every web socket the server accepts, before the JSON-RPC connection is built on it.
43
+ *
44
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
45
+ * subscription outlives an individual launch and is disposed by the caller.
46
+ */
47
+ this.onConnection = this.onConnectionEmitter.event;
48
+ }
49
+ getServerSocket() {
50
+ return this.httpServer;
51
+ }
52
+ registerDisposables() {
53
+ super.registerDisposables();
40
54
  this.toDispose.push(protocol_1.Disposable.create(() => {
41
- this.server.close();
55
+ this.server?.close();
56
+ // `ws` leaves an HTTP server it did not create itself listening, so close ours explicitly.
57
+ this.httpServer?.close();
58
+ this.httpServer = undefined;
42
59
  }));
43
60
  }
44
61
  async run(options) {
62
+ this.resetListening();
45
63
  const resolvedOptions = await this.resolveOptions(options);
46
- this.server = new ws_1.Server({ server: resolvedOptions.server, path: resolvedOptions.path });
64
+ if (!this.running) {
65
+ // Shut down while the options were being resolved, so release the socket they already bound.
66
+ resolvedOptions.server.close();
67
+ return;
68
+ }
69
+ this.httpServer = resolvedOptions.server;
70
+ this.server = new ws_1.WebSocketServer({ server: resolvedOptions.server, path: resolvedOptions.path });
47
71
  const endpoint = `ws://${resolvedOptions.host}:${resolvedOptions.port}:${resolvedOptions.path}`;
48
72
  this.logger.info(`The GLSP Websocket launcher is ready to accept new client requests on endpoint '${endpoint}'`);
49
73
  console.log(this.startupCompleteMessage.concat(resolvedOptions.port.toString()));
50
- this.server.on('connection', (ws, req) => {
51
- const connection = this.createConnection(ws);
52
- this.createServerInstance(connection);
53
- });
74
+ this.observeListening(resolvedOptions.server);
75
+ this.server.on('connection', (ws, request) => this.acceptConnection(ws, request));
76
+ const server = this.server;
54
77
  return new Promise((resolve, reject) => {
55
- this.server.on('close', () => resolve(undefined));
56
- this.server.on('error', error => reject(error));
78
+ server.on('close', () => resolve(undefined));
79
+ server.on('error', error => reject(error));
57
80
  });
58
81
  }
82
+ /** Settles {@link listening} from the HTTP server, which may already be bound by the time we get here. */
83
+ observeListening(server) {
84
+ if (server.listening) {
85
+ this.settleListening(server);
86
+ return;
87
+ }
88
+ server.on('listening', () => this.settleListening(server));
89
+ server.on('error', error => this.handleError(error));
90
+ }
91
+ /**
92
+ * Takes up a web socket the server accepted. Observers are notified before the socket is read from.
93
+ *
94
+ * @param socket The accepted web socket.
95
+ * @param request The upgrade request the socket was negotiated with.
96
+ */
97
+ acceptConnection(socket, request) {
98
+ this.onConnectionEmitter.fire({ socket, request });
99
+ this.createServerInstance(this.createConnection(socket));
100
+ }
59
101
  createConnection(socket) {
60
102
  return (0, protocol_1.createWebSocketConnection)(wrapWebSocket(socket));
61
103
  }
@@ -89,8 +131,7 @@ __decorate([
89
131
  __metadata("design:type", logger_1.Logger)
90
132
  ], WebSocketServerLauncher.prototype, "logger", void 0);
91
133
  exports.WebSocketServerLauncher = WebSocketServerLauncher = __decorate([
92
- (0, inversify_1.injectable)(),
93
- __metadata("design:paramtypes", [])
134
+ (0, inversify_1.injectable)()
94
135
  ], WebSocketServerLauncher);
95
136
  async function getFreePort() {
96
137
  return new Promise((resolve, reject) => {
@@ -1 +1 @@
1
- {"version":3,"file":"websocket-server-launcher.js","sourceRoot":"","sources":["../../../src/node/launch/websocket-server-launcher.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"websocket-server-launcher.js","sourceRoot":"","sources":["../../../src/node/launch/websocket-server-launcher.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eclipse-glsp/server",
3
- "version": "2.8.0-next.9",
3
+ "version": "2.9.0-next.1",
4
4
  "description": "A js server framework for Eclipse GLSP",
5
5
  "keywords": [
6
6
  "eclipse",
@@ -57,7 +57,7 @@
57
57
  "vscode-jsonrpc": "8.2.0",
58
58
  "winston": "^3.3.3",
59
59
  "ws": "^8.12.1",
60
- "@eclipse-glsp/graph": "2.8.0-next.9"
60
+ "@eclipse-glsp/graph": "2.9.0-next.1"
61
61
  },
62
62
  "devDependencies": {
63
63
  "@types/ws": "^8.5.4"
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2022-2023 STMicroelectronics and others.
2
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -42,11 +42,22 @@ export abstract class GLSPServerLauncher<T> implements Disposable {
42
42
  start(startParams: T): MaybePromise<void> {
43
43
  if (!this.running) {
44
44
  this.running = true;
45
+ this.registerDisposables();
45
46
  return this.run(startParams);
46
47
  }
47
48
  this.logger.warn('Could not start launcher. Launcher is already running!');
48
49
  }
49
50
 
51
+ /**
52
+ * Registers what {@link shutdown} has to release for the launch that is about to start.
53
+ *
54
+ * Called once per launch, because {@link dispose} empties the collection it registers into. A subclass that holds
55
+ * resources for the duration of a launch overrides this instead of registering them in its constructor.
56
+ */
57
+ protected registerDisposables(): void {
58
+ // nothing to release by default
59
+ }
60
+
50
61
  protected abstract run(startParams: T): MaybePromise<void>;
51
62
 
52
63
  shutdown(): MaybePromise<void> {
@@ -15,6 +15,7 @@
15
15
  ********************************************************************************/
16
16
 
17
17
  import {
18
+ Deferred,
18
19
  Disposable,
19
20
  GLSPClientProxy,
20
21
  GLSPServer,
@@ -23,6 +24,7 @@ import {
23
24
  configureClientConnection
24
25
  } from '@eclipse-glsp/protocol';
25
26
  import { Container, ContainerModule, inject, injectable } from 'inversify';
27
+ import * as net from 'net';
26
28
  import * as jsonrpc from 'vscode-jsonrpc';
27
29
  import { Logger } from '../utils/logger';
28
30
  import { GLSPServerLauncher } from './glsp-server-launcher';
@@ -43,8 +45,93 @@ export abstract class JsonRpcGLSPServerLauncher<T> extends GLSPServerLauncher<T>
43
45
  protected serverInstances = new Map<jsonrpc.MessageConnection, JsonRpcServerInstance>();
44
46
  protected startupCompleteMessage = START_UP_COMPLETE_MSG;
45
47
 
46
- constructor() {
47
- super();
48
+ protected listeningAddress = new Deferred<net.AddressInfo>();
49
+
50
+ /**
51
+ * Resolves with the address the server bound to once it is listening, and rejects if it never gets there.
52
+ *
53
+ * Launching with port `0` lets the operating system pick a free port, so the bound address is not necessarily the
54
+ * requested one. Settles once per launch and keeps that value, so use {@link port} for the current state. Reading
55
+ * this before {@link start} is fine, the promise handed out is the one that launch settles.
56
+ */
57
+ get listening(): Promise<net.AddressInfo> {
58
+ return this.listeningAddress.promise;
59
+ }
60
+
61
+ /**
62
+ * The port the server is currently listening on, or `undefined` if it is not.
63
+ *
64
+ * Await {@link listening} rather than polling this while the server is still starting up.
65
+ */
66
+ get port(): number | undefined {
67
+ const address = this.getServerSocket()?.address();
68
+ return address && typeof address !== 'string' ? address.port : undefined;
69
+ }
70
+
71
+ /**
72
+ * The socket that {@link port} reports on, or `undefined` before the first launch.
73
+ *
74
+ * A launcher that binds a socket overrides this, the default reports no address at all.
75
+ */
76
+ protected getServerSocket(): net.Server | undefined {
77
+ return undefined;
78
+ }
79
+
80
+ /**
81
+ * Arms {@link listening} for a launch.
82
+ *
83
+ * An unresolved promise is kept, so a caller that grabbed {@link listening} before {@link start} gets the one this
84
+ * launch settles. A settled one is replaced, so a restart is not handed the previous result.
85
+ */
86
+ protected resetListening(): void {
87
+ if (this.listeningAddress.state !== 'unresolved') {
88
+ this.listeningAddress = new Deferred<net.AddressInfo>();
89
+ }
90
+ }
91
+
92
+ /**
93
+ * Resolves {@link listening} with the address the given server bound to.
94
+ *
95
+ * @param server The server that reported itself as listening.
96
+ * @returns The bound address, or `undefined` if it cannot be used, in which case the launcher is shut down.
97
+ */
98
+ protected settleListening(server: net.Server): net.AddressInfo | undefined {
99
+ const addressInfo = server.address();
100
+ if (!addressInfo) {
101
+ this.failToListen('Could not resolve GLSP Server address info.');
102
+ return undefined;
103
+ }
104
+ if (typeof addressInfo === 'string') {
105
+ this.failToListen(`GLSP Server is unexpectedly listening to pipe or domain socket "${addressInfo}".`);
106
+ return undefined;
107
+ }
108
+ this.listeningAddress.resolve(addressInfo);
109
+ return addressInfo;
110
+ }
111
+
112
+ /**
113
+ * Invoked when the server socket fails, e.g. because the requested port is already in use.
114
+ *
115
+ * @param error The reason the socket failed.
116
+ */
117
+ protected handleError(error: Error): void {
118
+ this.failToListen(`GLSP server socket error. ${error.message}`, error);
119
+ }
120
+
121
+ /**
122
+ * Reports that the server will not accept requests, rejects {@link listening} and shuts the launcher down.
123
+ *
124
+ * @param message The reason the server is not usable.
125
+ * @param cause The underlying error, if the reason was one.
126
+ */
127
+ protected failToListen(message: string, cause?: Error): void {
128
+ this.logger.error(`${message} Shutting down.`);
129
+ this.listeningAddress.reject(cause ?? new Error(message));
130
+ this.shutdown();
131
+ }
132
+
133
+ protected override registerDisposables(): void {
134
+ super.registerDisposables();
48
135
  this.toDispose.push(
49
136
  Disposable.create(() => {
50
137
  this.serverInstances.forEach(instance => this.disposeServerInstance(instance));
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2022-2024 STMicroelectronics and others.
2
+ * Copyright (c) 2022-2026 STMicroelectronics and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -13,7 +13,7 @@
13
13
  *
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
- import { Disposable } from '@eclipse-glsp/protocol';
16
+ import { Disposable, Emitter } from '@eclipse-glsp/protocol';
17
17
  import { inject, injectable } from 'inversify';
18
18
  import * as net from 'net';
19
19
  import * as jsonrpc from 'vscode-jsonrpc/node';
@@ -24,48 +24,71 @@ import { Logger } from '../../common/utils/logger';
24
24
  export class SocketServerLauncher extends JsonRpcGLSPServerLauncher<net.TcpSocketConnectOpts> {
25
25
  @inject(Logger) protected override logger: Logger;
26
26
 
27
- protected netServer: net.Server;
27
+ protected netServer?: net.Server;
28
28
 
29
- constructor() {
30
- super();
29
+ protected onConnectionEmitter = new Emitter<net.Socket>();
30
+
31
+ /**
32
+ * Fires for every socket the server accepts, before the JSON-RPC connection is built on it.
33
+ *
34
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
35
+ * subscription outlives an individual launch and is disposed by the caller.
36
+ */
37
+ readonly onConnection = this.onConnectionEmitter.event;
38
+
39
+ protected override getServerSocket(): net.Server | undefined {
40
+ return this.netServer;
41
+ }
42
+
43
+ protected override registerDisposables(): void {
44
+ super.registerDisposables();
31
45
  this.toDispose.push(
32
46
  Disposable.create(() => {
33
- this.netServer.close();
47
+ this.netServer?.close();
34
48
  })
35
49
  );
36
50
  }
37
51
 
38
52
  protected run(opts: net.TcpSocketConnectOpts): Promise<void> {
39
- this.netServer = net.createServer(socket => {
40
- const connection = this.createConnection(socket);
41
- this.createServerInstance(connection);
42
- });
53
+ this.resetListening();
54
+ const netServer = net.createServer(socket => this.acceptConnection(socket));
55
+ this.netServer = netServer;
43
56
 
44
- this.netServer.listen(opts.port, opts.host);
45
- this.netServer.on('listening', () => {
46
- const addressInfo = this.netServer.address();
47
- if (!addressInfo) {
48
- this.logger.error('Could not resolve GLSP Server address info. Shutting down.');
49
- this.shutdown();
50
- return;
51
- } else if (typeof addressInfo === 'string') {
52
- this.logger.error(`GLSP Server is unexpectedly listening to pipe or domain socket "${addressInfo}". Shutting down.`);
53
- this.shutdown();
54
- return;
55
- }
56
- const currentPort = addressInfo.port;
57
- this.logger.info(`The GLSP server is ready to accept new client requests on port: ${currentPort}`);
58
- // Print a message to the output stream that indicates that the start is completed.
59
- // This indicates to the client that the server process is ready (in an embedded scenario).
60
- console.log(this.startupCompleteMessage.concat(currentPort.toString()));
61
- });
62
- this.netServer.on('error', () => this.shutdown());
57
+ netServer.listen(opts.port, opts.host);
58
+ netServer.on('listening', () => this.handleListening(netServer));
59
+ netServer.on('error', error => this.handleError(error));
63
60
  return new Promise((resolve, reject) => {
64
- this.netServer.on('close', () => resolve(undefined));
65
- this.netServer.on('error', error => reject(error));
61
+ netServer.on('close', () => resolve(undefined));
62
+ netServer.on('error', error => reject(error));
66
63
  });
67
64
  }
68
65
 
66
+ /**
67
+ * Takes up a socket the server accepted. Observers are notified before the socket is read from.
68
+ *
69
+ * @param socket The accepted socket.
70
+ */
71
+ protected acceptConnection(socket: net.Socket): void {
72
+ this.onConnectionEmitter.fire(socket);
73
+ this.createServerInstance(this.createConnection(socket));
74
+ }
75
+
76
+ /**
77
+ * Reports the server as ready and resolves {@link listening}.
78
+ *
79
+ * @param server The server that reported itself as listening.
80
+ */
81
+ protected handleListening(server: net.Server): void {
82
+ const addressInfo = this.settleListening(server);
83
+ if (!addressInfo) {
84
+ return;
85
+ }
86
+ this.logger.info(`The GLSP server is ready to accept new client requests on port: ${addressInfo.port}`);
87
+ // Print a message to the output stream that indicates that the start is completed.
88
+ // This indicates to the client that the server process is ready (in an embedded scenario).
89
+ console.log(this.startupCompleteMessage.concat(addressInfo.port.toString()));
90
+ }
91
+
69
92
  protected createConnection(socket: net.Socket): jsonrpc.MessageConnection {
70
93
  return jsonrpc.createMessageConnection(new jsonrpc.SocketMessageReader(socket), new jsonrpc.SocketMessageWriter(socket), console);
71
94
  }
@@ -1,5 +1,5 @@
1
1
  /********************************************************************************
2
- * Copyright (c) 2023 EclipseSource and others.
2
+ * Copyright (c) 2023-2026 EclipseSource and others.
3
3
  *
4
4
  * This program and the accompanying materials are made available under the
5
5
  * terms of the Eclipse Public License v. 2.0 which is available at
@@ -14,12 +14,12 @@
14
14
  * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15
15
  ********************************************************************************/
16
16
 
17
- import { createWebSocketConnection, Disposable, MaybePromise, WebSocketWrapper } from '@eclipse-glsp/protocol';
17
+ import { createWebSocketConnection, Disposable, Emitter, MaybePromise, WebSocketWrapper } from '@eclipse-glsp/protocol';
18
18
  import * as http from 'http';
19
19
  import { inject, injectable } from 'inversify';
20
20
  import * as net from 'net';
21
21
  import * as jsonrpc from 'vscode-jsonrpc';
22
- import { Server, WebSocket } from 'ws';
22
+ import { WebSocket, WebSocketServer } from 'ws';
23
23
  import { JsonRpcGLSPServerLauncher } from '../../common/launch/jsonrpc-server-launcher';
24
24
  import { Logger } from '../../common/utils/logger';
25
25
 
@@ -41,6 +41,13 @@ export interface WebsocketConnectionData {
41
41
  connection: jsonrpc.MessageConnection;
42
42
  }
43
43
 
44
+ /** An accepted web socket together with the upgrade request it was negotiated with. */
45
+ export interface AcceptedWebSocket {
46
+ socket: WebSocket;
47
+ /** The handshake request, the only place where its headers and query are still available. */
48
+ request: http.IncomingMessage;
49
+ }
50
+
44
51
  const STATUS_UPGRADE_REQUIRED = 426;
45
52
 
46
53
  @injectable()
@@ -48,35 +55,86 @@ export class WebSocketServerLauncher extends JsonRpcGLSPServerLauncher<WebSocket
48
55
  @inject(Logger)
49
56
  protected override logger: Logger;
50
57
 
51
- protected server: Server;
58
+ protected server?: WebSocketServer;
59
+
60
+ /**
61
+ * The HTTP server the web socket server is mounted on.
62
+ *
63
+ * Held separately because `ws` only closes an HTTP server it created itself, so releasing the socket is up to us.
64
+ */
65
+ protected httpServer?: http.Server;
52
66
 
53
- constructor() {
54
- super();
67
+ protected onConnectionEmitter = new Emitter<AcceptedWebSocket>();
68
+
69
+ /**
70
+ * Fires for every web socket the server accepts, before the JSON-RPC connection is built on it.
71
+ *
72
+ * A listener must not consume the socket. Subscribe before {@link start} to observe the first connection; the
73
+ * subscription outlives an individual launch and is disposed by the caller.
74
+ */
75
+ readonly onConnection = this.onConnectionEmitter.event;
76
+
77
+ protected override getServerSocket(): net.Server | undefined {
78
+ return this.httpServer;
79
+ }
80
+
81
+ protected override registerDisposables(): void {
82
+ super.registerDisposables();
55
83
  this.toDispose.push(
56
84
  Disposable.create(() => {
57
- this.server.close();
85
+ this.server?.close();
86
+ // `ws` leaves an HTTP server it did not create itself listening, so close ours explicitly.
87
+ this.httpServer?.close();
88
+ this.httpServer = undefined;
58
89
  })
59
90
  );
60
91
  }
61
92
 
62
93
  protected async run(options: WebSocketServerOptions): Promise<void> {
94
+ this.resetListening();
63
95
  const resolvedOptions = await this.resolveOptions(options);
64
- this.server = new Server({ server: resolvedOptions.server, path: resolvedOptions.path });
96
+ if (!this.running) {
97
+ // Shut down while the options were being resolved, so release the socket they already bound.
98
+ resolvedOptions.server.close();
99
+ return;
100
+ }
101
+ this.httpServer = resolvedOptions.server;
102
+ this.server = new WebSocketServer({ server: resolvedOptions.server, path: resolvedOptions.path });
65
103
  const endpoint = `ws://${resolvedOptions.host}:${resolvedOptions.port}:${resolvedOptions.path}`;
66
104
  this.logger.info(`The GLSP Websocket launcher is ready to accept new client requests on endpoint '${endpoint}'`);
67
105
  console.log(this.startupCompleteMessage.concat(resolvedOptions.port.toString()));
68
106
 
69
- this.server.on('connection', (ws, req) => {
70
- const connection = this.createConnection(ws);
71
- this.createServerInstance(connection);
72
- });
107
+ this.observeListening(resolvedOptions.server);
108
+ this.server.on('connection', (ws, request) => this.acceptConnection(ws, request));
73
109
 
110
+ const server = this.server;
74
111
  return new Promise((resolve, reject) => {
75
- this.server.on('close', () => resolve(undefined));
76
- this.server.on('error', error => reject(error));
112
+ server.on('close', () => resolve(undefined));
113
+ server.on('error', error => reject(error));
77
114
  });
78
115
  }
79
116
 
117
+ /** Settles {@link listening} from the HTTP server, which may already be bound by the time we get here. */
118
+ protected observeListening(server: http.Server): void {
119
+ if (server.listening) {
120
+ this.settleListening(server);
121
+ return;
122
+ }
123
+ server.on('listening', () => this.settleListening(server));
124
+ server.on('error', error => this.handleError(error));
125
+ }
126
+
127
+ /**
128
+ * Takes up a web socket the server accepted. Observers are notified before the socket is read from.
129
+ *
130
+ * @param socket The accepted web socket.
131
+ * @param request The upgrade request the socket was negotiated with.
132
+ */
133
+ protected acceptConnection(socket: WebSocket, request: http.IncomingMessage): void {
134
+ this.onConnectionEmitter.fire({ socket, request });
135
+ this.createServerInstance(this.createConnection(socket));
136
+ }
137
+
80
138
  protected createConnection(socket: WebSocket): jsonrpc.MessageConnection {
81
139
  return createWebSocketConnection(wrapWebSocket(socket));
82
140
  }