@kapeta/local-cluster-service 0.64.1 → 0.64.2

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/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## [0.64.2](https://github.com/kapetacom/local-cluster-service/compare/v0.64.1...v0.64.2) (2024-08-22)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * handle port detection on multiple interfaces ([#222](https://github.com/kapetacom/local-cluster-service/issues/222)) ([6635cc2](https://github.com/kapetacom/local-cluster-service/commit/6635cc207355b2083edbb380f0ba83227c6a16e1))
7
+
1
8
  ## [0.64.1](https://github.com/kapetacom/local-cluster-service/compare/v0.64.0...v0.64.1) (2024-08-21)
2
9
 
3
10
 
@@ -16,7 +16,7 @@ declare class ClusterService {
16
16
  * Gets next available port
17
17
  */
18
18
  getNextAvailablePort(startPort?: number): Promise<number>;
19
- _checkIfPortIsUsed(port: number, host?: string): Promise<unknown>;
19
+ private resolveWithAvailablePort;
20
20
  /**
21
21
  * The port of this local cluster service itself
22
22
  */
@@ -42,10 +42,13 @@ class ClusterService {
42
42
  }
43
43
  async _findClusterServicePort() {
44
44
  for (; this._port <= 65535; this._port++) {
45
- const isUsed = await this._checkIfPortIsUsed(this._port);
46
- if (!isUsed) {
45
+ try {
46
+ await this.resolveWithAvailablePort(this._port);
47
47
  return;
48
48
  }
49
+ catch (e) {
50
+ // try again
51
+ }
49
52
  }
50
53
  throw new Error('No available ports');
51
54
  }
@@ -54,28 +57,33 @@ class ClusterService {
54
57
  */
55
58
  async getNextAvailablePort(startPort = -1) {
56
59
  for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
57
- if (this._reservedPorts.indexOf(startPort) > -1) {
60
+ if (this._reservedPorts.indexOf(nextPort) > -1) {
58
61
  continue;
59
62
  }
60
- const isUsed = await this._checkIfPortIsUsed(nextPort);
61
- if (!isUsed) {
63
+ try {
64
+ // Try both IPv4 and IPv6 addresses
65
+ await this.resolveWithAvailablePort(nextPort);
66
+ await this.resolveWithAvailablePort(nextPort, '0.0.0.0');
62
67
  // Save the state if we're looking for a system port for the cluster itself
63
68
  if (startPort <= 0) {
64
69
  this._currentPort = nextPort;
65
70
  }
66
71
  return nextPort;
67
72
  }
73
+ catch (e) {
74
+ // try again }
75
+ }
68
76
  }
69
77
  throw new Error('No available ports');
70
78
  }
71
- _checkIfPortIsUsed(port, host = this._host) {
79
+ async resolveWithAvailablePort(port, host = this._host) {
72
80
  return new Promise((resolve, reject) => {
73
81
  const server = net_1.default.createServer();
74
82
  server.unref();
75
- server.on('error', () => resolve(true));
76
- server.listen({ port, host }, () => {
83
+ server.on('error', reject);
84
+ server.listen({ port, host }, (...args) => {
77
85
  server.close(() => {
78
- resolve(false);
86
+ resolve(port);
79
87
  });
80
88
  });
81
89
  });
@@ -1,13 +1,5 @@
1
- /// <reference types="node" />
2
- import { Server } from 'http';
3
1
  import { StormEventPage } from './events';
4
- declare module 'express-serve-static-core' {
5
- interface Application {
6
- listen(port: number, callback?: (err?: Error) => void): Server;
7
- }
8
- }
9
2
  export declare class UIServer {
10
- private readonly express;
11
3
  private readonly systemId;
12
4
  private port;
13
5
  private server;
@@ -11,34 +11,31 @@ exports.UIServer = void 0;
11
11
  const express_1 = __importDefault(require("express"));
12
12
  const page_utils_1 = require("./page-utils");
13
13
  const clusterService_1 = require("../clusterService");
14
+ const http_1 = require("http");
14
15
  class UIServer {
15
- express;
16
16
  systemId;
17
17
  port = 50000;
18
18
  server;
19
19
  constructor(systemId) {
20
20
  this.systemId = systemId;
21
- this.express = (0, express_1.default)();
22
21
  }
23
22
  async start() {
24
- this.port = await clusterService_1.clusterService.getNextAvailablePort(this.port);
25
- this.express.get('/_reset', (req, res) => {
23
+ const app = (0, express_1.default)();
24
+ app.get('/_reset', (req, res) => {
26
25
  res.send(`
27
26
  <script>
28
27
  window.localStorage.clear();
29
28
  window.sessionStorage.clear();
30
29
  </script>`);
31
30
  });
32
- this.express.all('/*', (req, res) => {
31
+ app.all('/*', (req, res) => {
33
32
  (0, page_utils_1.readPageFromDisk)(this.systemId, req.params[0], req.method, res);
34
33
  });
34
+ this.port = await clusterService_1.clusterService.getNextAvailablePort(this.port);
35
35
  return new Promise((resolve, reject) => {
36
- this.server = this.express.listen(this.port, (err) => {
37
- if (err) {
38
- console.error('Failed to start UI server', err);
39
- reject(err);
40
- return;
41
- }
36
+ this.server = (0, http_1.createServer)(app);
37
+ this.server.on('error', reject);
38
+ this.server.listen(this.port, () => {
42
39
  console.log(`UI Server started on port ${this.port}`);
43
40
  resolve();
44
41
  });
@@ -16,7 +16,7 @@ declare class ClusterService {
16
16
  * Gets next available port
17
17
  */
18
18
  getNextAvailablePort(startPort?: number): Promise<number>;
19
- _checkIfPortIsUsed(port: number, host?: string): Promise<unknown>;
19
+ private resolveWithAvailablePort;
20
20
  /**
21
21
  * The port of this local cluster service itself
22
22
  */
@@ -42,10 +42,13 @@ class ClusterService {
42
42
  }
43
43
  async _findClusterServicePort() {
44
44
  for (; this._port <= 65535; this._port++) {
45
- const isUsed = await this._checkIfPortIsUsed(this._port);
46
- if (!isUsed) {
45
+ try {
46
+ await this.resolveWithAvailablePort(this._port);
47
47
  return;
48
48
  }
49
+ catch (e) {
50
+ // try again
51
+ }
49
52
  }
50
53
  throw new Error('No available ports');
51
54
  }
@@ -54,28 +57,33 @@ class ClusterService {
54
57
  */
55
58
  async getNextAvailablePort(startPort = -1) {
56
59
  for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
57
- if (this._reservedPorts.indexOf(startPort) > -1) {
60
+ if (this._reservedPorts.indexOf(nextPort) > -1) {
58
61
  continue;
59
62
  }
60
- const isUsed = await this._checkIfPortIsUsed(nextPort);
61
- if (!isUsed) {
63
+ try {
64
+ // Try both IPv4 and IPv6 addresses
65
+ await this.resolveWithAvailablePort(nextPort);
66
+ await this.resolveWithAvailablePort(nextPort, '0.0.0.0');
62
67
  // Save the state if we're looking for a system port for the cluster itself
63
68
  if (startPort <= 0) {
64
69
  this._currentPort = nextPort;
65
70
  }
66
71
  return nextPort;
67
72
  }
73
+ catch (e) {
74
+ // try again }
75
+ }
68
76
  }
69
77
  throw new Error('No available ports');
70
78
  }
71
- _checkIfPortIsUsed(port, host = this._host) {
79
+ async resolveWithAvailablePort(port, host = this._host) {
72
80
  return new Promise((resolve, reject) => {
73
81
  const server = net_1.default.createServer();
74
82
  server.unref();
75
- server.on('error', () => resolve(true));
76
- server.listen({ port, host }, () => {
83
+ server.on('error', reject);
84
+ server.listen({ port, host }, (...args) => {
77
85
  server.close(() => {
78
- resolve(false);
86
+ resolve(port);
79
87
  });
80
88
  });
81
89
  });
@@ -1,13 +1,5 @@
1
- /// <reference types="node" />
2
- import { Server } from 'http';
3
1
  import { StormEventPage } from './events';
4
- declare module 'express-serve-static-core' {
5
- interface Application {
6
- listen(port: number, callback?: (err?: Error) => void): Server;
7
- }
8
- }
9
2
  export declare class UIServer {
10
- private readonly express;
11
3
  private readonly systemId;
12
4
  private port;
13
5
  private server;
@@ -11,34 +11,31 @@ exports.UIServer = void 0;
11
11
  const express_1 = __importDefault(require("express"));
12
12
  const page_utils_1 = require("./page-utils");
13
13
  const clusterService_1 = require("../clusterService");
14
+ const http_1 = require("http");
14
15
  class UIServer {
15
- express;
16
16
  systemId;
17
17
  port = 50000;
18
18
  server;
19
19
  constructor(systemId) {
20
20
  this.systemId = systemId;
21
- this.express = (0, express_1.default)();
22
21
  }
23
22
  async start() {
24
- this.port = await clusterService_1.clusterService.getNextAvailablePort(this.port);
25
- this.express.get('/_reset', (req, res) => {
23
+ const app = (0, express_1.default)();
24
+ app.get('/_reset', (req, res) => {
26
25
  res.send(`
27
26
  <script>
28
27
  window.localStorage.clear();
29
28
  window.sessionStorage.clear();
30
29
  </script>`);
31
30
  });
32
- this.express.all('/*', (req, res) => {
31
+ app.all('/*', (req, res) => {
33
32
  (0, page_utils_1.readPageFromDisk)(this.systemId, req.params[0], req.method, res);
34
33
  });
34
+ this.port = await clusterService_1.clusterService.getNextAvailablePort(this.port);
35
35
  return new Promise((resolve, reject) => {
36
- this.server = this.express.listen(this.port, (err) => {
37
- if (err) {
38
- console.error('Failed to start UI server', err);
39
- reject(err);
40
- return;
41
- }
36
+ this.server = (0, http_1.createServer)(app);
37
+ this.server.on('error', reject);
38
+ this.server.listen(this.port, () => {
42
39
  console.log(`UI Server started on port ${this.port}`);
43
40
  resolve();
44
41
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kapeta/local-cluster-service",
3
- "version": "0.64.1",
3
+ "version": "0.64.2",
4
4
  "description": "Manages configuration, ports and service discovery for locally running Kapeta systems",
5
5
  "type": "commonjs",
6
6
  "exports": {
@@ -45,9 +45,11 @@ class ClusterService {
45
45
 
46
46
  async _findClusterServicePort() {
47
47
  for (; this._port <= 65535; this._port++) {
48
- const isUsed = await this._checkIfPortIsUsed(this._port);
49
- if (!isUsed) {
48
+ try {
49
+ await this.resolveWithAvailablePort(this._port);
50
50
  return;
51
+ } catch (e) {
52
+ // try again
51
53
  }
52
54
  }
53
55
  throw new Error('No available ports');
@@ -58,31 +60,35 @@ class ClusterService {
58
60
  */
59
61
  public async getNextAvailablePort(startPort: number = -1) {
60
62
  for (let nextPort = startPort > 0 ? startPort : this._currentPort; nextPort <= 65535; nextPort++) {
61
- if (this._reservedPorts.indexOf(startPort) > -1) {
63
+ if (this._reservedPorts.indexOf(nextPort) > -1) {
62
64
  continue;
63
65
  }
64
66
 
65
- const isUsed = await this._checkIfPortIsUsed(nextPort);
66
- if (!isUsed) {
67
+ try {
68
+ // Try both IPv4 and IPv6 addresses
69
+ await this.resolveWithAvailablePort(nextPort);
70
+ await this.resolveWithAvailablePort(nextPort, '0.0.0.0');
67
71
  // Save the state if we're looking for a system port for the cluster itself
68
72
  if (startPort <= 0) {
69
73
  this._currentPort = nextPort;
70
74
  }
71
75
  return nextPort;
76
+ } catch (e) {
77
+ // try again }
72
78
  }
73
79
  }
74
80
  throw new Error('No available ports');
75
81
  }
76
82
 
77
- _checkIfPortIsUsed(port: number, host: string = this._host) {
83
+ private async resolveWithAvailablePort(port: number, host: string = this._host) {
78
84
  return new Promise((resolve, reject) => {
79
85
  const server = net.createServer();
80
86
  server.unref();
81
- server.on('error', () => resolve(true));
87
+ server.on('error', reject);
82
88
 
83
- server.listen({ port, host }, () => {
89
+ server.listen({ port, host }, (...args) => {
84
90
  server.close(() => {
85
- resolve(false);
91
+ resolve(port);
86
92
  });
87
93
  });
88
94
  });
@@ -5,20 +5,10 @@
5
5
  import express, { Express, Request, Response } from 'express';
6
6
  import { readPageFromDisk } from './page-utils';
7
7
  import { clusterService } from '../clusterService';
8
- import { Server } from 'http';
8
+ import { createServer, Server } from 'http';
9
9
  import { StormEventPage } from './events';
10
10
 
11
- declare module 'express-serve-static-core' {
12
- interface Application {
13
- // Adds error callback support
14
- // From the docs:
15
- // All the forms of Node’s http.Server.listen() method are in fact actually supported.
16
- listen(port: number, callback?: (err?: Error) => void): Server;
17
- }
18
- }
19
-
20
11
  export class UIServer {
21
- private readonly express: Express;
22
12
  private readonly systemId: string;
23
13
 
24
14
  private port: number = 50000;
@@ -26,13 +16,11 @@ export class UIServer {
26
16
 
27
17
  constructor(systemId: string) {
28
18
  this.systemId = systemId;
29
- this.express = express();
30
19
  }
31
20
 
32
21
  public async start() {
33
- this.port = await clusterService.getNextAvailablePort(this.port);
34
-
35
- this.express.get('/_reset', (req: Request, res: Response) => {
22
+ const app = express();
23
+ app.get('/_reset', (req: Request, res: Response) => {
36
24
  res.send(
37
25
  `
38
26
  <script>
@@ -42,17 +30,16 @@ export class UIServer {
42
30
  );
43
31
  });
44
32
 
45
- this.express.all('/*', (req: Request, res: Response) => {
33
+ app.all('/*', (req: Request, res: Response) => {
46
34
  readPageFromDisk(this.systemId, req.params[0], req.method, res);
47
35
  });
48
36
 
37
+ this.port = await clusterService.getNextAvailablePort(this.port);
49
38
  return new Promise<void>((resolve, reject) => {
50
- this.server = this.express.listen(this.port, (err) => {
51
- if (err) {
52
- console.error('Failed to start UI server', err);
53
- reject(err);
54
- return;
55
- }
39
+ this.server = createServer(app);
40
+ this.server.on('error', reject);
41
+
42
+ this.server.listen(this.port, () => {
56
43
  console.log(`UI Server started on port ${this.port}`);
57
44
  resolve();
58
45
  });