@tramvai/cli 3.21.0 → 3.24.0
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/di/providers/network.d.ts.map +1 -1
- package/lib/di/providers/network.js +1 -12
- package/lib/di/providers/network.js.map +1 -1
- package/lib/models/port-manager.d.ts +2 -1
- package/lib/models/port-manager.d.ts.map +1 -1
- package/lib/models/port-manager.js +84 -67
- package/lib/models/port-manager.js.map +1 -1
- package/package.json +4 -4
- package/src/di/providers/network.ts +1 -14
- package/src/models/port-manager.ts +98 -79
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../src/di/providers/network.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM/C,eAAO,MAAM,gBAAgB,EAAE,SAAS,QAAQ,
|
|
1
|
+
{"version":3,"file":"network.d.ts","sourceRoot":"","sources":["../../../src/di/providers/network.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAM/C,eAAO,MAAM,gBAAgB,EAAE,SAAS,QAAQ,EActC,CAAC"}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.networkProviders = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
4
|
const dippy_1 = require("@tinkoff/dippy");
|
|
6
5
|
const tokens_1 = require("../tokens");
|
|
7
6
|
const port_manager_1 = require("../../models/port-manager");
|
|
@@ -14,17 +13,7 @@ exports.networkProviders = [
|
|
|
14
13
|
logger: 'network logger',
|
|
15
14
|
},
|
|
16
15
|
provide: tokens_1.PORT_MANAGER_TOKEN,
|
|
17
|
-
|
|
18
|
-
// @ts-expect-error
|
|
19
|
-
const portManager = new port_manager_1.PortManager(deps);
|
|
20
|
-
['SIGINT', 'SIGTERM'].forEach((signal) => {
|
|
21
|
-
process.on(signal, () => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
-
yield portManager.cleanup();
|
|
23
|
-
process.exit();
|
|
24
|
-
}));
|
|
25
|
-
});
|
|
26
|
-
return portManager;
|
|
27
|
-
},
|
|
16
|
+
useClass: port_manager_1.PortManager,
|
|
28
17
|
}),
|
|
29
18
|
(0, dippy_1.provide)({
|
|
30
19
|
provide: 'network logger',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/di/providers/network.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../../../src/di/providers/network.ts"],"names":[],"mappings":";;;AAAA,0CAAyC;AAGzC,sCAA6F;AAC7F,4DAAwD;AACxD,gDAA6C;AAEhC,QAAA,gBAAgB,GAAwB;IACnD,IAAA,eAAO,EAAC;QACN,IAAI,EAAE;YACJ,WAAW,EAAE,2BAAkB;YAC/B,aAAa,EAAE,iCAAwB;YACvC,MAAM,EAAE,gBAAgB;SACzB;QACD,OAAO,EAAE,2BAAkB;QAC3B,QAAQ,EAAE,0BAAW;KACtB,CAAC;IACF,IAAA,eAAO,EAAC;QACN,OAAO,EAAE,gBAAgB;QACzB,QAAQ,EAAE,eAAM;KACjB,CAAC;CACM,CAAC"}
|
|
@@ -12,13 +12,14 @@ export declare class PortManager {
|
|
|
12
12
|
static readonly DEFAULT_MODULE_PORT = 3040;
|
|
13
13
|
static readonly DEFAULT_STATIC_PORT = 4000;
|
|
14
14
|
static readonly DEFAULT_MODULE_STATIC_PORT = 4040;
|
|
15
|
+
private static readonly cachePath;
|
|
15
16
|
private readonly configEntry;
|
|
16
17
|
private readonly commandParams;
|
|
17
|
-
private readonly cachePath;
|
|
18
18
|
private readonly logger;
|
|
19
19
|
port: number | null;
|
|
20
20
|
staticPort: number | null;
|
|
21
21
|
constructor({ configEntry, commandParams, logger }: NetworkConstructorPayload);
|
|
22
|
+
private handleConfigValues;
|
|
22
23
|
/**
|
|
23
24
|
* Try to detect port considering the fact, that if user requests
|
|
24
25
|
* a port explicitly, we should not try to detect a free one.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-manager.d.ts","sourceRoot":"","sources":["../../src/models/port-manager.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"port-manager.d.ts","sourceRoot":"","sources":["../../src/models/port-manager.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,KAAK,EAAE,MAAM,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAC1D,OAAO,KAAK,EAAE,MAAM,IAAI,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,UAAU,yBAAyB;IACjC,WAAW,EAAE,WAAW,CAAC;IACzB,aAAa,EAAE,WAAW,GAAG,eAAe,CAAC;IAC7C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBAAa,WAAW;IACtB,MAAM,CAAC,QAAQ,CAAC,YAAY,QAAQ;IACpC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,QAAQ;IAC3C,MAAM,CAAC,QAAQ,CAAC,mBAAmB,QAAQ;IAC3C,MAAM,CAAC,QAAQ,CAAC,0BAA0B,QAAQ;IAClD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAG/B;IAEF,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAgC;IAC9D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEzB,IAAI,EAAE,MAAM,GAAG,IAAI,CAAQ;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;gBAE5B,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,EAAE,EAAE,yBAAyB;YAM/D,kBAAkB;IA6BhC;;;;;;OAMG;IACU,qBAAqB;IA0BlC;;OAEG;IACU,OAAO;YA8BN,cAAc;YAMd,SAAS;YAMT,WAAW;IAMzB,OAAO,CAAC,aAAa;YAIP,eAAe;YAQf,aAAa;YAUb,cAAc;YAId,eAAe;YAIf,eAAe;CAgC9B"}
|
|
@@ -7,6 +7,7 @@ const path_1 = require("path");
|
|
|
7
7
|
const find_cache_dir_1 = tslib_1.__importDefault(require("find-cache-dir"));
|
|
8
8
|
const detect_port_1 = tslib_1.__importDefault(require("detect-port"));
|
|
9
9
|
const proper_lockfile_1 = require("proper-lockfile");
|
|
10
|
+
const noop_1 = tslib_1.__importDefault(require("@tinkoff/utils/function/noop"));
|
|
10
11
|
class PortManager {
|
|
11
12
|
constructor({ configEntry, commandParams, logger }) {
|
|
12
13
|
this.port = null;
|
|
@@ -14,7 +15,31 @@ class PortManager {
|
|
|
14
15
|
this.configEntry = configEntry;
|
|
15
16
|
this.commandParams = commandParams;
|
|
16
17
|
this.logger = logger;
|
|
17
|
-
|
|
18
|
+
}
|
|
19
|
+
handleConfigValues() {
|
|
20
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
21
|
+
if (this.commandParams.port !== undefined && this.commandParams.port !== 0) {
|
|
22
|
+
// @ts-expect-error There is a string actually
|
|
23
|
+
this.port = parseInt(this.commandParams.port, 10);
|
|
24
|
+
}
|
|
25
|
+
if (this.commandParams.staticPort !== undefined && this.commandParams.staticPort !== 0) {
|
|
26
|
+
// @ts-expect-error There is a string actually
|
|
27
|
+
this.staticPort = parseInt(this.commandParams.staticPort, 10);
|
|
28
|
+
}
|
|
29
|
+
switch (this.configEntry.type) {
|
|
30
|
+
case 'child-app':
|
|
31
|
+
yield this.forChildApp();
|
|
32
|
+
break;
|
|
33
|
+
case 'module':
|
|
34
|
+
yield this.forModule();
|
|
35
|
+
break;
|
|
36
|
+
case 'application':
|
|
37
|
+
yield this.forApplication();
|
|
38
|
+
break;
|
|
39
|
+
default:
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
});
|
|
18
43
|
}
|
|
19
44
|
/**
|
|
20
45
|
* Try to detect port considering the fact, that if user requests
|
|
@@ -26,43 +51,27 @@ class PortManager {
|
|
|
26
51
|
computeAvailablePorts() {
|
|
27
52
|
var _a;
|
|
28
53
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
this.port
|
|
54
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
55
|
+
yield this.createCacheFile();
|
|
56
|
+
const release = yield this.lockCacheFile();
|
|
57
|
+
try {
|
|
58
|
+
yield this.handleConfigValues();
|
|
59
|
+
yield this.appendCacheFile([this.port, this.staticPort].join(','));
|
|
35
60
|
}
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
61
|
+
catch (error) {
|
|
62
|
+
this.logger.event({
|
|
63
|
+
type: 'warning',
|
|
64
|
+
event: 'PORT_MANAGER:GET_AVAILABLE_PORTS',
|
|
65
|
+
message: `Can't get free ports for ${this.configEntry.type}:`,
|
|
66
|
+
payload: (_a = error.message) !== null && _a !== void 0 ? _a : '',
|
|
67
|
+
});
|
|
39
68
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
yield this.forChildApp();
|
|
43
|
-
break;
|
|
44
|
-
case 'module':
|
|
45
|
-
yield this.forModule();
|
|
46
|
-
break;
|
|
47
|
-
case 'application':
|
|
48
|
-
yield this.forApplication();
|
|
49
|
-
break;
|
|
50
|
-
default:
|
|
51
|
-
break;
|
|
69
|
+
finally {
|
|
70
|
+
yield release();
|
|
52
71
|
}
|
|
53
|
-
|
|
54
|
-
}
|
|
55
|
-
catch (error) {
|
|
56
|
-
this.logger.event({
|
|
57
|
-
type: 'warning',
|
|
58
|
-
event: 'PORT_MANAGER:GET_AVAILABLE_PORTS',
|
|
59
|
-
message: `Can't get free ports for ${this.configEntry.type}:`,
|
|
60
|
-
payload: (_a = error.message) !== null && _a !== void 0 ? _a : '',
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
finally {
|
|
64
|
-
yield release();
|
|
72
|
+
return;
|
|
65
73
|
}
|
|
74
|
+
yield this.handleConfigValues();
|
|
66
75
|
});
|
|
67
76
|
}
|
|
68
77
|
/**
|
|
@@ -71,25 +80,29 @@ class PortManager {
|
|
|
71
80
|
cleanup() {
|
|
72
81
|
var _a;
|
|
73
82
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
84
|
+
const release = yield this.lockCacheFile();
|
|
85
|
+
try {
|
|
86
|
+
const cache = yield this.readCacheFile();
|
|
87
|
+
yield this.writeCacheFile(cache
|
|
88
|
+
.filter(Boolean)
|
|
89
|
+
.filter((port) => port !== this.port.toString() && port !== this.staticPort.toString())
|
|
90
|
+
.join(','));
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
this.logger.event({
|
|
94
|
+
type: 'warning',
|
|
95
|
+
event: 'PORT_MANAGER:CLEANUP',
|
|
96
|
+
message: "Can't perform a cleanup of previously used ports:",
|
|
97
|
+
payload: (_a = error.message) !== null && _a !== void 0 ? _a : '',
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
finally {
|
|
101
|
+
yield release();
|
|
102
|
+
}
|
|
103
|
+
return;
|
|
92
104
|
}
|
|
105
|
+
(0, noop_1.default)();
|
|
93
106
|
});
|
|
94
107
|
}
|
|
95
108
|
forApplication() {
|
|
@@ -117,22 +130,22 @@ class PortManager {
|
|
|
117
130
|
});
|
|
118
131
|
}
|
|
119
132
|
lockCacheFile() {
|
|
120
|
-
return (0, proper_lockfile_1.lock)(
|
|
133
|
+
return (0, proper_lockfile_1.lock)(PortManager.cachePath, { retries: 10 });
|
|
121
134
|
}
|
|
122
135
|
createCacheFile() {
|
|
123
136
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
124
137
|
try {
|
|
125
|
-
yield (0, fs_extra_1.access)(
|
|
138
|
+
yield (0, fs_extra_1.access)(PortManager.cachePath);
|
|
126
139
|
}
|
|
127
140
|
catch (error) {
|
|
128
|
-
yield (0, fs_extra_1.outputFile)(
|
|
141
|
+
yield (0, fs_extra_1.outputFile)(PortManager.cachePath, '');
|
|
129
142
|
}
|
|
130
143
|
});
|
|
131
144
|
}
|
|
132
145
|
readCacheFile() {
|
|
133
146
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
134
147
|
try {
|
|
135
|
-
const content = yield (0, fs_extra_1.readFile)(
|
|
148
|
+
const content = yield (0, fs_extra_1.readFile)(PortManager.cachePath, { encoding: 'utf-8' });
|
|
136
149
|
return content.split(',');
|
|
137
150
|
}
|
|
138
151
|
catch (error) {
|
|
@@ -142,29 +155,32 @@ class PortManager {
|
|
|
142
155
|
}
|
|
143
156
|
writeCacheFile(content) {
|
|
144
157
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
145
|
-
yield (0, fs_extra_1.outputFile)(
|
|
158
|
+
yield (0, fs_extra_1.outputFile)(PortManager.cachePath, content);
|
|
146
159
|
});
|
|
147
160
|
}
|
|
148
161
|
appendCacheFile(content) {
|
|
149
162
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
150
|
-
yield (0, fs_extra_1.appendFile)(
|
|
163
|
+
yield (0, fs_extra_1.appendFile)(PortManager.cachePath, `,${content}`);
|
|
151
164
|
});
|
|
152
165
|
}
|
|
153
166
|
resolveFreePort(initial) {
|
|
154
167
|
var _a;
|
|
155
168
|
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
156
169
|
try {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
170
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
171
|
+
const cache = yield this.readCacheFile();
|
|
172
|
+
let port = yield (0, detect_port_1.default)(initial);
|
|
173
|
+
let attempts = 1;
|
|
174
|
+
while (cache.includes(port.toString())) {
|
|
175
|
+
if (attempts >= 3) {
|
|
176
|
+
throw new Error(`Max attempts exceeded (${attempts})`);
|
|
177
|
+
}
|
|
178
|
+
port = yield (0, detect_port_1.default)(0);
|
|
179
|
+
attempts++;
|
|
163
180
|
}
|
|
164
|
-
port
|
|
165
|
-
attempts++;
|
|
181
|
+
return port;
|
|
166
182
|
}
|
|
167
|
-
return
|
|
183
|
+
return (0, detect_port_1.default)(initial);
|
|
168
184
|
}
|
|
169
185
|
catch (error) {
|
|
170
186
|
this.logger.event({
|
|
@@ -183,4 +199,5 @@ PortManager.DEFAULT_PORT = 3000;
|
|
|
183
199
|
PortManager.DEFAULT_MODULE_PORT = 3040;
|
|
184
200
|
PortManager.DEFAULT_STATIC_PORT = 4000;
|
|
185
201
|
PortManager.DEFAULT_MODULE_STATIC_PORT = 4040;
|
|
202
|
+
PortManager.cachePath = (0, path_1.join)((0, find_cache_dir_1.default)({ cwd: __dirname, create: true, name: 'tramvai' }), 'used-ports');
|
|
186
203
|
//# sourceMappingURL=port-manager.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"port-manager.js","sourceRoot":"","sources":["../../src/models/port-manager.ts"],"names":[],"mappings":";;;;AAAA,uCAAoE;AACpE,+BAA4B;AAC5B,4EAA0C;AAC1C,sEAAqC;AACrC,qDAAuC;
|
|
1
|
+
{"version":3,"file":"port-manager.js","sourceRoot":"","sources":["../../src/models/port-manager.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tramvai/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.24.0",
|
|
4
4
|
"description": "Cli инструмент для сборки и запуска приложений",
|
|
5
5
|
"files": [
|
|
6
6
|
"src",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"@sentry/node": "^6.2.5",
|
|
62
62
|
"@svgr/webpack": "^8.1.0",
|
|
63
63
|
"@tinkoff/browserslist-config": "0.3.2",
|
|
64
|
-
"@tinkoff/dippy": "0.9.
|
|
64
|
+
"@tinkoff/dippy": "0.9.2",
|
|
65
65
|
"@tinkoff/is-modern-lib": "3.0.2",
|
|
66
66
|
"@tinkoff/logger": "0.10.170",
|
|
67
67
|
"@tinkoff/minicss-class-generator": "0.3.1",
|
|
@@ -71,7 +71,7 @@
|
|
|
71
71
|
"@tinkoff/utils": "^2.1.3",
|
|
72
72
|
"@tinkoff/webpack-dedupe-plugin": "2.0.2",
|
|
73
73
|
"@tramvai/build": "4.1.0",
|
|
74
|
-
"@tramvai/react": "3.
|
|
74
|
+
"@tramvai/react": "3.24.0",
|
|
75
75
|
"@tramvai/tools-check-versions": "0.5.3",
|
|
76
76
|
"@tramvai/tools-migrate": "0.7.3",
|
|
77
77
|
"ajv": "^8.12.0",
|
|
@@ -160,11 +160,11 @@
|
|
|
160
160
|
"validate-npm-package-name": "^3.0.0",
|
|
161
161
|
"wait-on": "^5.3.0",
|
|
162
162
|
"webpack": "5.87.0",
|
|
163
|
-
"webpack-sources": "^3.2.3",
|
|
164
163
|
"webpack-bundle-analyzer": "^4.9.0",
|
|
165
164
|
"webpack-chain": "^6.5.1",
|
|
166
165
|
"webpack-dev-middleware": "^6.1.1",
|
|
167
166
|
"webpack-hot-middleware": "^2.25.4",
|
|
167
|
+
"webpack-sources": "^3.2.3",
|
|
168
168
|
"webpack-stats-plugin": "^1.1.3",
|
|
169
169
|
"webpackbar": "^5.0.2",
|
|
170
170
|
"workbox-build": "^6.6.1",
|
|
@@ -13,20 +13,7 @@ export const networkProviders: readonly Provider[] = [
|
|
|
13
13
|
logger: 'network logger',
|
|
14
14
|
},
|
|
15
15
|
provide: PORT_MANAGER_TOKEN,
|
|
16
|
-
|
|
17
|
-
// @ts-expect-error
|
|
18
|
-
const portManager = new PortManager(deps);
|
|
19
|
-
|
|
20
|
-
['SIGINT', 'SIGTERM'].forEach((signal) => {
|
|
21
|
-
process.on(signal, async () => {
|
|
22
|
-
await portManager.cleanup();
|
|
23
|
-
|
|
24
|
-
process.exit();
|
|
25
|
-
});
|
|
26
|
-
});
|
|
27
|
-
|
|
28
|
-
return portManager;
|
|
29
|
-
},
|
|
16
|
+
useClass: PortManager,
|
|
30
17
|
}),
|
|
31
18
|
provide({
|
|
32
19
|
provide: 'network logger',
|
|
@@ -3,6 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import findCacheDir from 'find-cache-dir';
|
|
4
4
|
import detectPort from 'detect-port';
|
|
5
5
|
import { lock } from 'proper-lockfile';
|
|
6
|
+
import noop from '@tinkoff/utils/function/noop';
|
|
6
7
|
|
|
7
8
|
import type { ConfigEntry } from '../typings/configEntry/common';
|
|
8
9
|
import type { Params as StartParams } from '../api/start';
|
|
@@ -20,10 +21,13 @@ export class PortManager {
|
|
|
20
21
|
static readonly DEFAULT_MODULE_PORT = 3040;
|
|
21
22
|
static readonly DEFAULT_STATIC_PORT = 4000;
|
|
22
23
|
static readonly DEFAULT_MODULE_STATIC_PORT = 4040;
|
|
24
|
+
private static readonly cachePath = join(
|
|
25
|
+
findCacheDir({ cwd: __dirname, create: true, name: 'tramvai' }),
|
|
26
|
+
'used-ports'
|
|
27
|
+
);
|
|
23
28
|
|
|
24
29
|
private readonly configEntry: ConfigEntry;
|
|
25
30
|
private readonly commandParams: StartParams | StartProdParams;
|
|
26
|
-
private readonly cachePath: string;
|
|
27
31
|
private readonly logger: Logger;
|
|
28
32
|
|
|
29
33
|
public port: number | null = null;
|
|
@@ -33,11 +37,35 @@ export class PortManager {
|
|
|
33
37
|
this.configEntry = configEntry;
|
|
34
38
|
this.commandParams = commandParams;
|
|
35
39
|
this.logger = logger;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private async handleConfigValues() {
|
|
43
|
+
if (this.commandParams.port !== undefined && this.commandParams.port !== 0) {
|
|
44
|
+
// @ts-expect-error There is a string actually
|
|
45
|
+
this.port = parseInt(this.commandParams.port, 10);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (this.commandParams.staticPort !== undefined && this.commandParams.staticPort !== 0) {
|
|
49
|
+
// @ts-expect-error There is a string actually
|
|
50
|
+
this.staticPort = parseInt(this.commandParams.staticPort, 10);
|
|
51
|
+
}
|
|
36
52
|
|
|
37
|
-
this.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
switch (this.configEntry.type) {
|
|
54
|
+
case 'child-app':
|
|
55
|
+
await this.forChildApp();
|
|
56
|
+
break;
|
|
57
|
+
|
|
58
|
+
case 'module':
|
|
59
|
+
await this.forModule();
|
|
60
|
+
break;
|
|
61
|
+
|
|
62
|
+
case 'application':
|
|
63
|
+
await this.forApplication();
|
|
64
|
+
break;
|
|
65
|
+
|
|
66
|
+
default:
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
41
69
|
}
|
|
42
70
|
|
|
43
71
|
/**
|
|
@@ -48,75 +76,62 @@ export class PortManager {
|
|
|
48
76
|
* because we must pass a final number to the config manager.
|
|
49
77
|
*/
|
|
50
78
|
public async computeAvailablePorts() {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
79
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
80
|
+
await this.createCacheFile();
|
|
81
|
+
const release = await this.lockCacheFile();
|
|
82
|
+
|
|
83
|
+
try {
|
|
84
|
+
await this.handleConfigValues();
|
|
85
|
+
|
|
86
|
+
await this.appendCacheFile([this.port, this.staticPort].join(','));
|
|
87
|
+
} catch (error) {
|
|
88
|
+
this.logger.event({
|
|
89
|
+
type: 'warning',
|
|
90
|
+
event: 'PORT_MANAGER:GET_AVAILABLE_PORTS',
|
|
91
|
+
message: `Can't get free ports for ${this.configEntry.type}:`,
|
|
92
|
+
payload: error.message ?? '',
|
|
93
|
+
});
|
|
94
|
+
} finally {
|
|
95
|
+
await release();
|
|
63
96
|
}
|
|
64
97
|
|
|
65
|
-
|
|
66
|
-
case 'child-app':
|
|
67
|
-
await this.forChildApp();
|
|
68
|
-
break;
|
|
69
|
-
|
|
70
|
-
case 'module':
|
|
71
|
-
await this.forModule();
|
|
72
|
-
break;
|
|
73
|
-
|
|
74
|
-
case 'application':
|
|
75
|
-
await this.forApplication();
|
|
76
|
-
break;
|
|
77
|
-
|
|
78
|
-
default:
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
await this.appendCacheFile([this.port, this.staticPort].join(','));
|
|
83
|
-
} catch (error) {
|
|
84
|
-
this.logger.event({
|
|
85
|
-
type: 'warning',
|
|
86
|
-
event: 'PORT_MANAGER:GET_AVAILABLE_PORTS',
|
|
87
|
-
message: `Can't get free ports for ${this.configEntry.type}:`,
|
|
88
|
-
payload: error.message ?? '',
|
|
89
|
-
});
|
|
90
|
-
} finally {
|
|
91
|
-
await release();
|
|
98
|
+
return;
|
|
92
99
|
}
|
|
100
|
+
|
|
101
|
+
await this.handleConfigValues();
|
|
93
102
|
}
|
|
94
103
|
|
|
95
104
|
/**
|
|
96
105
|
* Cleanup a cache file by removing ports were written previously.
|
|
97
106
|
*/
|
|
98
107
|
public async cleanup() {
|
|
99
|
-
|
|
108
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
109
|
+
const release = await this.lockCacheFile();
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
const cache = await this.readCacheFile();
|
|
113
|
+
|
|
114
|
+
await this.writeCacheFile(
|
|
115
|
+
cache
|
|
116
|
+
.filter(Boolean)
|
|
117
|
+
.filter((port) => port !== this.port.toString() && port !== this.staticPort.toString())
|
|
118
|
+
.join(',')
|
|
119
|
+
);
|
|
120
|
+
} catch (error) {
|
|
121
|
+
this.logger.event({
|
|
122
|
+
type: 'warning',
|
|
123
|
+
event: 'PORT_MANAGER:CLEANUP',
|
|
124
|
+
message: "Can't perform a cleanup of previously used ports:",
|
|
125
|
+
payload: error.message ?? '',
|
|
126
|
+
});
|
|
127
|
+
} finally {
|
|
128
|
+
await release();
|
|
129
|
+
}
|
|
100
130
|
|
|
101
|
-
|
|
102
|
-
const cache = await this.readCacheFile();
|
|
103
|
-
|
|
104
|
-
await this.writeCacheFile(
|
|
105
|
-
cache
|
|
106
|
-
.filter(Boolean)
|
|
107
|
-
.filter((port) => port !== this.port.toString() && port !== this.staticPort.toString())
|
|
108
|
-
.join(',')
|
|
109
|
-
);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
this.logger.event({
|
|
112
|
-
type: 'warning',
|
|
113
|
-
event: 'PORT_MANAGER:CLEANUP',
|
|
114
|
-
message: "Can't perform a cleanup of previously used ports:",
|
|
115
|
-
payload: error.message ?? '',
|
|
116
|
-
});
|
|
117
|
-
} finally {
|
|
118
|
-
await release();
|
|
131
|
+
return;
|
|
119
132
|
}
|
|
133
|
+
|
|
134
|
+
noop();
|
|
120
135
|
}
|
|
121
136
|
|
|
122
137
|
private async forApplication() {
|
|
@@ -138,20 +153,20 @@ export class PortManager {
|
|
|
138
153
|
}
|
|
139
154
|
|
|
140
155
|
private lockCacheFile() {
|
|
141
|
-
return lock(
|
|
156
|
+
return lock(PortManager.cachePath, { retries: 10 });
|
|
142
157
|
}
|
|
143
158
|
|
|
144
159
|
private async createCacheFile() {
|
|
145
160
|
try {
|
|
146
|
-
await access(
|
|
161
|
+
await access(PortManager.cachePath);
|
|
147
162
|
} catch (error) {
|
|
148
|
-
await outputFile(
|
|
163
|
+
await outputFile(PortManager.cachePath, '');
|
|
149
164
|
}
|
|
150
165
|
}
|
|
151
166
|
|
|
152
167
|
private async readCacheFile() {
|
|
153
168
|
try {
|
|
154
|
-
const content = await readFile(
|
|
169
|
+
const content = await readFile(PortManager.cachePath, { encoding: 'utf-8' });
|
|
155
170
|
|
|
156
171
|
return content.split(',');
|
|
157
172
|
} catch (error) {
|
|
@@ -160,30 +175,34 @@ export class PortManager {
|
|
|
160
175
|
}
|
|
161
176
|
|
|
162
177
|
private async writeCacheFile(content: string) {
|
|
163
|
-
await outputFile(
|
|
178
|
+
await outputFile(PortManager.cachePath, content);
|
|
164
179
|
}
|
|
165
180
|
|
|
166
181
|
private async appendCacheFile(content: string) {
|
|
167
|
-
await appendFile(
|
|
182
|
+
await appendFile(PortManager.cachePath, `,${content}`);
|
|
168
183
|
}
|
|
169
184
|
|
|
170
185
|
private async resolveFreePort(initial: number) {
|
|
171
186
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
187
|
+
if (process.env.USE_CONCURRENT_PORT_DETECTING === 'true') {
|
|
188
|
+
const cache = await this.readCacheFile();
|
|
189
|
+
let port = await detectPort(initial);
|
|
190
|
+
let attempts = 1;
|
|
175
191
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
192
|
+
while (cache.includes(port.toString())) {
|
|
193
|
+
if (attempts >= 3) {
|
|
194
|
+
throw new Error(`Max attempts exceeded (${attempts})`);
|
|
195
|
+
}
|
|
180
196
|
|
|
181
|
-
|
|
197
|
+
port = await detectPort(0);
|
|
198
|
+
|
|
199
|
+
attempts++;
|
|
200
|
+
}
|
|
182
201
|
|
|
183
|
-
|
|
202
|
+
return port;
|
|
184
203
|
}
|
|
185
204
|
|
|
186
|
-
return
|
|
205
|
+
return detectPort(initial);
|
|
187
206
|
} catch (error) {
|
|
188
207
|
this.logger.event({
|
|
189
208
|
type: 'info',
|