@kapeta/local-cluster-service 0.6.1 → 0.7.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/.eslintrc.cjs +17 -0
- package/.github/workflows/main.yml +22 -22
- package/.prettierignore +4 -0
- package/.vscode/launch.json +2 -4
- package/CHANGELOG.md +7 -0
- package/definitions.d.ts +17 -35
- package/dist/cjs/index.d.ts +27 -0
- package/dist/cjs/index.js +126 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/src/assetManager.d.ts +31 -0
- package/dist/cjs/src/assetManager.js +153 -0
- package/dist/cjs/src/assets/routes.d.ts +3 -0
- package/dist/cjs/src/assets/routes.js +117 -0
- package/dist/cjs/src/clusterService.d.ts +40 -0
- package/dist/cjs/src/clusterService.js +114 -0
- package/dist/cjs/src/codeGeneratorManager.d.ts +8 -0
- package/dist/cjs/src/codeGeneratorManager.js +53 -0
- package/dist/cjs/src/config/routes.d.ts +3 -0
- package/dist/cjs/src/config/routes.js +126 -0
- package/dist/cjs/src/configManager.d.ts +36 -0
- package/dist/cjs/src/configManager.js +110 -0
- package/dist/cjs/src/containerManager.d.ts +89 -0
- package/dist/cjs/src/containerManager.js +365 -0
- package/dist/cjs/src/filesystem/routes.d.ts +3 -0
- package/dist/cjs/src/filesystem/routes.js +69 -0
- package/dist/cjs/src/filesystemManager.d.ts +15 -0
- package/dist/cjs/src/filesystemManager.js +87 -0
- package/dist/cjs/src/identities/routes.d.ts +3 -0
- package/dist/cjs/src/identities/routes.js +18 -0
- package/dist/cjs/src/instanceManager.d.ts +56 -0
- package/dist/cjs/src/instanceManager.js +424 -0
- package/dist/cjs/src/instances/routes.d.ts +3 -0
- package/dist/cjs/src/instances/routes.js +134 -0
- package/dist/cjs/src/middleware/cors.d.ts +2 -0
- package/dist/cjs/src/middleware/cors.js +10 -0
- package/dist/cjs/src/middleware/kapeta.d.ts +11 -0
- package/dist/cjs/src/middleware/kapeta.js +17 -0
- package/dist/cjs/src/middleware/stringBody.d.ts +5 -0
- package/dist/cjs/src/middleware/stringBody.js +14 -0
- package/dist/cjs/src/networkManager.d.ts +32 -0
- package/dist/cjs/src/networkManager.js +109 -0
- package/dist/cjs/src/operatorManager.d.ts +36 -0
- package/dist/cjs/src/operatorManager.js +165 -0
- package/dist/cjs/src/progressListener.d.ts +20 -0
- package/dist/cjs/src/progressListener.js +91 -0
- package/dist/cjs/src/providerManager.d.ts +9 -0
- package/dist/cjs/src/providerManager.js +51 -0
- package/dist/cjs/src/providers/routes.d.ts +3 -0
- package/dist/cjs/src/providers/routes.js +42 -0
- package/dist/cjs/src/proxy/routes.d.ts +3 -0
- package/dist/cjs/src/proxy/routes.js +111 -0
- package/dist/cjs/src/proxy/types/rest.d.ts +4 -0
- package/dist/cjs/src/proxy/types/rest.js +114 -0
- package/dist/cjs/src/proxy/types/web.d.ts +4 -0
- package/dist/cjs/src/proxy/types/web.js +53 -0
- package/dist/cjs/src/repositoryManager.d.ts +17 -0
- package/dist/cjs/src/repositoryManager.js +215 -0
- package/dist/cjs/src/serviceManager.d.ts +29 -0
- package/dist/cjs/src/serviceManager.js +99 -0
- package/dist/cjs/src/socketManager.d.ts +14 -0
- package/dist/cjs/src/socketManager.js +53 -0
- package/dist/cjs/src/storageService.d.ts +17 -0
- package/dist/cjs/src/storageService.js +74 -0
- package/dist/cjs/src/traffic/routes.d.ts +3 -0
- package/dist/cjs/src/traffic/routes.js +18 -0
- package/dist/cjs/src/types.d.ts +88 -0
- package/dist/cjs/src/types.js +2 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +468 -0
- package/dist/cjs/src/utils/LogData.d.ts +19 -0
- package/dist/cjs/src/utils/LogData.js +43 -0
- package/dist/cjs/src/utils/pathTemplateParser.d.ts +26 -0
- package/dist/cjs/src/utils/pathTemplateParser.js +121 -0
- package/dist/cjs/src/utils/utils.d.ts +1 -0
- package/dist/cjs/src/utils/utils.js +18 -0
- package/dist/cjs/start.d.ts +1 -0
- package/dist/cjs/start.js +12 -0
- package/dist/esm/index.d.ts +27 -0
- package/dist/esm/index.js +121 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/src/assetManager.d.ts +31 -0
- package/{src → dist/esm/src}/assetManager.js +22 -60
- package/dist/esm/src/assets/routes.d.ts +3 -0
- package/{src → dist/esm/src}/assets/routes.js +21 -36
- package/dist/esm/src/clusterService.d.ts +40 -0
- package/{src → dist/esm/src}/clusterService.js +14 -37
- package/dist/esm/src/codeGeneratorManager.d.ts +8 -0
- package/{src → dist/esm/src}/codeGeneratorManager.js +15 -24
- package/dist/esm/src/config/routes.d.ts +3 -0
- package/{src → dist/esm/src}/config/routes.js +40 -89
- package/dist/esm/src/configManager.d.ts +36 -0
- package/{src → dist/esm/src}/configManager.js +11 -40
- package/dist/esm/src/containerManager.d.ts +89 -0
- package/{src → dist/esm/src}/containerManager.js +81 -182
- package/dist/esm/src/filesystem/routes.d.ts +3 -0
- package/dist/esm/src/filesystem/routes.js +64 -0
- package/dist/esm/src/filesystemManager.d.ts +15 -0
- package/{src → dist/esm/src}/filesystemManager.js +20 -28
- package/dist/esm/src/identities/routes.d.ts +3 -0
- package/dist/esm/src/identities/routes.js +13 -0
- package/dist/esm/src/instanceManager.d.ts +56 -0
- package/{src → dist/esm/src}/instanceManager.js +88 -179
- package/dist/esm/src/instances/routes.d.ts +3 -0
- package/{src → dist/esm/src}/instances/routes.js +31 -70
- package/dist/esm/src/middleware/cors.d.ts +2 -0
- package/{src → dist/esm/src}/middleware/cors.js +2 -3
- package/dist/esm/src/middleware/kapeta.d.ts +11 -0
- package/{src → dist/esm/src}/middleware/kapeta.js +3 -7
- package/dist/esm/src/middleware/stringBody.d.ts +5 -0
- package/{src → dist/esm/src}/middleware/stringBody.js +2 -3
- package/dist/esm/src/networkManager.d.ts +32 -0
- package/{src → dist/esm/src}/networkManager.js +16 -33
- package/dist/esm/src/operatorManager.d.ts +36 -0
- package/{src → dist/esm/src}/operatorManager.js +35 -91
- package/dist/esm/src/progressListener.d.ts +20 -0
- package/dist/esm/src/progressListener.js +88 -0
- package/dist/esm/src/providerManager.d.ts +9 -0
- package/dist/esm/src/providerManager.js +45 -0
- package/dist/esm/src/providers/routes.d.ts +3 -0
- package/{src → dist/esm/src}/providers/routes.js +10 -16
- package/dist/esm/src/proxy/routes.d.ts +3 -0
- package/dist/esm/src/proxy/routes.js +106 -0
- package/dist/esm/src/proxy/types/rest.d.ts +4 -0
- package/dist/esm/src/proxy/types/rest.js +107 -0
- package/dist/esm/src/proxy/types/web.d.ts +4 -0
- package/{src → dist/esm/src}/proxy/types/web.js +13 -35
- package/dist/esm/src/repositoryManager.d.ts +17 -0
- package/dist/esm/src/repositoryManager.js +209 -0
- package/dist/esm/src/serviceManager.d.ts +29 -0
- package/{src → dist/esm/src}/serviceManager.js +12 -42
- package/dist/esm/src/socketManager.d.ts +14 -0
- package/{src → dist/esm/src}/socketManager.js +19 -23
- package/dist/esm/src/storageService.d.ts +17 -0
- package/{src → dist/esm/src}/storageService.js +8 -27
- package/dist/esm/src/traffic/routes.d.ts +3 -0
- package/{src → dist/esm/src}/traffic/routes.js +4 -9
- package/dist/esm/src/types.d.ts +88 -0
- package/dist/esm/src/types.js +1 -0
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +29 -0
- package/{src → dist/esm/src}/utils/BlockInstanceRunner.js +137 -256
- package/dist/esm/src/utils/LogData.d.ts +19 -0
- package/{src → dist/esm/src}/utils/LogData.js +11 -22
- package/dist/esm/src/utils/pathTemplateParser.d.ts +26 -0
- package/{src → dist/esm/src}/utils/pathTemplateParser.js +21 -40
- package/dist/esm/src/utils/utils.d.ts +1 -0
- package/dist/esm/src/utils/utils.js +11 -0
- package/dist/esm/start.d.ts +1 -0
- package/dist/esm/start.js +7 -0
- package/index.ts +147 -0
- package/package.json +106 -74
- package/src/assetManager.ts +191 -0
- package/src/assets/routes.ts +132 -0
- package/src/clusterService.ts +134 -0
- package/src/codeGeneratorManager.ts +57 -0
- package/src/config/routes.ts +159 -0
- package/src/configManager.ts +148 -0
- package/src/containerManager.ts +466 -0
- package/src/filesystem/routes.ts +74 -0
- package/src/filesystemManager.ts +93 -0
- package/src/identities/routes.ts +20 -0
- package/src/instanceManager.ts +503 -0
- package/src/instances/routes.ts +164 -0
- package/src/middleware/cors.ts +9 -0
- package/src/middleware/kapeta.ts +27 -0
- package/src/middleware/stringBody.ts +16 -0
- package/src/networkManager.ts +137 -0
- package/src/operatorManager.ts +221 -0
- package/src/progressListener.ts +102 -0
- package/src/{providerManager.js → providerManager.ts} +15 -31
- package/src/providers/routes.ts +46 -0
- package/src/proxy/routes.ts +148 -0
- package/src/proxy/types/{rest.js → rest.ts} +30 -30
- package/src/proxy/types/web.ts +60 -0
- package/src/{repositoryManager.js → repositoryManager.ts} +45 -73
- package/src/serviceManager.ts +120 -0
- package/src/socketManager.ts +57 -0
- package/src/storageService.ts +88 -0
- package/src/traffic/routes.ts +18 -0
- package/src/types.ts +97 -0
- package/src/utils/BlockInstanceRunner.ts +555 -0
- package/src/utils/LogData.ts +47 -0
- package/src/utils/pathTemplateParser.ts +138 -0
- package/src/utils/utils.ts +12 -0
- package/start.ts +8 -0
- package/tsconfig.json +13 -0
- package/index.js +0 -127
- package/src/filesystem/routes.js +0 -74
- package/src/identities/routes.js +0 -19
- package/src/progressListener.js +0 -82
- package/src/proxy/routes.js +0 -126
- package/src/utils/utils.js +0 -13
- package/start.js +0 -7
@@ -0,0 +1,107 @@
|
|
1
|
+
import _ from 'lodash';
|
2
|
+
import request from 'request';
|
3
|
+
import Path from 'path';
|
4
|
+
import { pathTemplateParser } from '../../utils/pathTemplateParser';
|
5
|
+
import { networkManager } from '../../networkManager';
|
6
|
+
import { socketManager } from '../../socketManager';
|
7
|
+
function getRestMethodId(restResource, httpMethod, httpPath) {
|
8
|
+
return _.findKey(restResource.spec.methods, (method) => {
|
9
|
+
let methodType = method.method ? method.method.toUpperCase() : 'GET';
|
10
|
+
if (methodType.toUpperCase() !== httpMethod.toUpperCase()) {
|
11
|
+
return false;
|
12
|
+
}
|
13
|
+
let path = method.path;
|
14
|
+
if (restResource.spec.basePath) {
|
15
|
+
path = Path.join(restResource.spec.basePath, path);
|
16
|
+
}
|
17
|
+
const pathTemplate = pathTemplateParser(path);
|
18
|
+
return pathTemplate.matches(httpPath);
|
19
|
+
});
|
20
|
+
}
|
21
|
+
/**
|
22
|
+
*
|
23
|
+
* @param req {Request}
|
24
|
+
* @param opts {ProxyRequestInfo}
|
25
|
+
* @return {{consumerMethod: *, providerMethod: *}}
|
26
|
+
*/
|
27
|
+
function resolveMethods(req, opts) {
|
28
|
+
const consumerMethodId = getRestMethodId(opts.consumerResource, req.method, opts.consumerPath);
|
29
|
+
if (!consumerMethodId) {
|
30
|
+
throw new Error(`Consumer method not found for path "${req.method} ${opts.consumerPath}" in resource "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`);
|
31
|
+
}
|
32
|
+
const consumerMethod = _.cloneDeep(opts.consumerResource.spec.methods[consumerMethodId]);
|
33
|
+
if (!consumerMethod) {
|
34
|
+
throw new Error(`Consumer method not found for path "${req.method} ${opts.consumerPath}" in resource "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`);
|
35
|
+
}
|
36
|
+
consumerMethod.id = consumerMethodId;
|
37
|
+
const providerMethodId = _.findKey(opts.connection.mapping, (mapping) => {
|
38
|
+
return mapping.targetId === consumerMethodId;
|
39
|
+
});
|
40
|
+
if (!providerMethodId) {
|
41
|
+
throw new Error(`Connection contained no mapping for consumer method "${consumerMethodId}`);
|
42
|
+
}
|
43
|
+
const providerMethod = _.cloneDeep(opts.providerResource.spec.methods[providerMethodId]);
|
44
|
+
if (!providerMethod) {
|
45
|
+
throw new Error(`Provider method not found "${providerMethodId}" in resource "${opts.connection.provider.blockId}::${opts.connection.provider.resourceName}`);
|
46
|
+
}
|
47
|
+
providerMethod.id = providerMethodId;
|
48
|
+
return {
|
49
|
+
consumerMethod,
|
50
|
+
providerMethod,
|
51
|
+
};
|
52
|
+
}
|
53
|
+
export function proxyRestRequest(req, res, opts) {
|
54
|
+
let { consumerMethod, providerMethod } = resolveMethods(req, opts);
|
55
|
+
const consumerPathTemplate = pathTemplateParser(consumerMethod.path);
|
56
|
+
const providerPathTemplate = pathTemplateParser(providerMethod.path);
|
57
|
+
const pathVariables = consumerPathTemplate.parse(opts.consumerPath);
|
58
|
+
if (!pathVariables) {
|
59
|
+
res.status(400).send({
|
60
|
+
error: `Path did not match any patterns: "${opts.consumerPath}"`,
|
61
|
+
});
|
62
|
+
return;
|
63
|
+
}
|
64
|
+
let providerPath = providerPathTemplate.create(pathVariables);
|
65
|
+
if (!providerPath.startsWith('/')) {
|
66
|
+
providerPath = '/' + providerPath;
|
67
|
+
}
|
68
|
+
const requestHeaders = _.clone(req.headers);
|
69
|
+
delete requestHeaders['content-length'];
|
70
|
+
delete requestHeaders['content-encoding'];
|
71
|
+
delete requestHeaders['connection'];
|
72
|
+
delete requestHeaders['host'];
|
73
|
+
delete requestHeaders['origin'];
|
74
|
+
console.log('Proxy request to provider: %s => %s [rest]', opts.consumerPath, opts.address + providerPath);
|
75
|
+
const reqOpts = {
|
76
|
+
method: providerMethod.method || 'GET',
|
77
|
+
url: opts.address + providerPath,
|
78
|
+
body: req.stringBody,
|
79
|
+
headers: requestHeaders,
|
80
|
+
};
|
81
|
+
const traffic = networkManager.addRequest(req.params.systemId, opts.connection, reqOpts, consumerMethod.id, providerMethod.id);
|
82
|
+
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
83
|
+
request(reqOpts, function (err, response, responseBody) {
|
84
|
+
if (err) {
|
85
|
+
traffic.asError(err);
|
86
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
87
|
+
res.status(500).send({ error: '' + err });
|
88
|
+
return;
|
89
|
+
}
|
90
|
+
const responseHeaders = _.clone(response.headers);
|
91
|
+
delete responseHeaders['content-length'];
|
92
|
+
delete responseHeaders['content-encoding'];
|
93
|
+
delete responseHeaders['connection'];
|
94
|
+
res.set(responseHeaders);
|
95
|
+
res.status(response.statusCode);
|
96
|
+
traffic.withResponse({
|
97
|
+
code: response.statusCode,
|
98
|
+
headers: response.headers,
|
99
|
+
body: responseBody,
|
100
|
+
});
|
101
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
102
|
+
if (responseBody) {
|
103
|
+
res.write(responseBody);
|
104
|
+
}
|
105
|
+
res.end();
|
106
|
+
});
|
107
|
+
}
|
@@ -1,68 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
/**
|
8
|
-
*
|
9
|
-
* @param req {Request}
|
10
|
-
* @param res {Response}
|
11
|
-
* @param opts {ProxyRequestInfo}
|
12
|
-
*/
|
13
|
-
module.exports = function proxyWebRequest(req, res, opts) {
|
14
|
-
|
1
|
+
import request from 'request';
|
2
|
+
import _ from 'lodash';
|
3
|
+
import { networkManager } from '../../networkManager';
|
4
|
+
import { socketManager } from '../../socketManager';
|
5
|
+
export function proxyWebRequest(req, res, opts) {
|
15
6
|
const requestHeaders = _.clone(req.headers);
|
16
|
-
|
17
7
|
delete requestHeaders['content-length'];
|
18
8
|
delete requestHeaders['content-encoding'];
|
19
9
|
delete requestHeaders['connection'];
|
20
10
|
delete requestHeaders['host'];
|
21
11
|
delete requestHeaders['origin'];
|
22
|
-
|
23
12
|
const sourceBasePath = opts.consumerResource.spec.path;
|
24
13
|
const targetBasePath = opts.providerResource.spec.path;
|
25
14
|
let path = opts.consumerPath;
|
26
15
|
if (opts.consumerPath.startsWith(sourceBasePath)) {
|
27
16
|
path = path.replace(sourceBasePath, targetBasePath);
|
28
17
|
}
|
29
|
-
|
30
18
|
console.log('Proxy request to provider: %s => %s%s [web]', opts.consumerPath, opts.address, path);
|
31
|
-
|
32
19
|
const reqOpts = {
|
33
20
|
method: req.method,
|
34
21
|
url: opts.address + path,
|
35
22
|
headers: requestHeaders,
|
36
|
-
body: req.stringBody
|
23
|
+
body: req.stringBody,
|
37
24
|
};
|
38
|
-
|
39
|
-
const traffic = networkManager.addRequest(
|
40
|
-
req.params.systemId,
|
41
|
-
opts.connection,
|
42
|
-
reqOpts
|
43
|
-
);
|
44
|
-
|
25
|
+
const traffic = networkManager.addRequest(req.params.systemId, opts.connection, reqOpts);
|
45
26
|
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
46
27
|
const proxyReq = request(reqOpts);
|
47
|
-
|
48
|
-
proxyReq.on('error', function(err) {
|
28
|
+
proxyReq.on('error', function (err) {
|
49
29
|
traffic.asError(err);
|
50
30
|
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
51
31
|
if (!res.headersSent) {
|
52
|
-
res.status(500).send({error: '' + err});
|
32
|
+
res.status(500).send({ error: '' + err });
|
53
33
|
}
|
54
34
|
});
|
55
|
-
|
56
|
-
proxyReq.on('response', function(response) {
|
35
|
+
proxyReq.on('response', function (response) {
|
57
36
|
//TODO: Include the response body in the traffic object when it is not a stream
|
58
37
|
traffic.withResponse({
|
59
38
|
code: response.statusCode,
|
60
|
-
headers: response.headers
|
39
|
+
headers: response.headers,
|
40
|
+
body: null,
|
61
41
|
});
|
62
|
-
|
63
42
|
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
64
43
|
});
|
65
|
-
|
66
44
|
//We need to pipe the proxy response to the client response to handle sockets and event streams
|
67
45
|
proxyReq.pipe(res);
|
68
|
-
}
|
46
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
declare class RepositoryManager {
|
2
|
+
private changeEventsEnabled;
|
3
|
+
private _registryService;
|
4
|
+
private _cache;
|
5
|
+
private watcher?;
|
6
|
+
private _installQueue;
|
7
|
+
private _processing;
|
8
|
+
constructor();
|
9
|
+
setChangeEventsEnabled(enabled: boolean): void;
|
10
|
+
listenForChanges(): void;
|
11
|
+
stopListening(): void;
|
12
|
+
private _install;
|
13
|
+
_processNext(): Promise<void>;
|
14
|
+
ensureAsset(handle: string, name: string, version: string): Promise<void>;
|
15
|
+
}
|
16
|
+
export declare const repositoryManager: RepositoryManager;
|
17
|
+
export {};
|
@@ -0,0 +1,209 @@
|
|
1
|
+
import FS from 'node:fs';
|
2
|
+
import os from 'node:os';
|
3
|
+
import Path from 'node:path';
|
4
|
+
import FSExtra from 'fs-extra';
|
5
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
6
|
+
import { parseKapetaUri } from '@kapeta/nodejs-utils';
|
7
|
+
import { socketManager } from './socketManager';
|
8
|
+
import { progressListener } from './progressListener';
|
9
|
+
import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
|
10
|
+
const INSTALL_ATTEMPTED = {};
|
11
|
+
class RepositoryManager {
|
12
|
+
changeEventsEnabled;
|
13
|
+
_registryService;
|
14
|
+
_cache;
|
15
|
+
watcher;
|
16
|
+
_installQueue;
|
17
|
+
_processing = false;
|
18
|
+
constructor() {
|
19
|
+
this.changeEventsEnabled = true;
|
20
|
+
this.listenForChanges();
|
21
|
+
this._registryService = new RegistryService(Config.data.registry.url);
|
22
|
+
this._cache = {};
|
23
|
+
this._installQueue = [];
|
24
|
+
}
|
25
|
+
setChangeEventsEnabled(enabled) {
|
26
|
+
this.changeEventsEnabled = enabled;
|
27
|
+
}
|
28
|
+
listenForChanges() {
|
29
|
+
const baseDir = ClusterConfiguration.getRepositoryBasedir();
|
30
|
+
if (!FS.existsSync(baseDir)) {
|
31
|
+
FSExtra.mkdirpSync(baseDir);
|
32
|
+
}
|
33
|
+
let allDefinitions = ClusterConfiguration.getDefinitions();
|
34
|
+
console.log('Watching local repository for provider changes: %s', baseDir);
|
35
|
+
try {
|
36
|
+
this.watcher = FS.watch(baseDir, { recursive: true });
|
37
|
+
}
|
38
|
+
catch (e) {
|
39
|
+
// Fallback to run without watch mode due to potential platform issues.
|
40
|
+
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
41
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.');
|
42
|
+
return;
|
43
|
+
}
|
44
|
+
this.watcher.on('change', (eventType, filename) => {
|
45
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
46
|
+
if (!name || !version) {
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
if (!this.changeEventsEnabled) {
|
50
|
+
return;
|
51
|
+
}
|
52
|
+
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
53
|
+
const newDefinitions = ClusterConfiguration.getDefinitions();
|
54
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
55
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
56
|
+
const ymlExists = FS.existsSync(ymlPath);
|
57
|
+
let type;
|
58
|
+
if (ymlExists) {
|
59
|
+
if (currentDefinition) {
|
60
|
+
type = 'updated';
|
61
|
+
}
|
62
|
+
else if (newDefinition) {
|
63
|
+
type = 'added';
|
64
|
+
currentDefinition = newDefinition;
|
65
|
+
}
|
66
|
+
else {
|
67
|
+
//Other definition was added / updated - ignore
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
else {
|
72
|
+
if (currentDefinition) {
|
73
|
+
const ref = parseKapetaUri(`${currentDefinition.definition.metadata.name}:${currentDefinition.version}`).id;
|
74
|
+
delete INSTALL_ATTEMPTED[ref];
|
75
|
+
//Something was removed
|
76
|
+
type = 'removed';
|
77
|
+
}
|
78
|
+
else {
|
79
|
+
//Other definition was removed - ignore
|
80
|
+
return;
|
81
|
+
}
|
82
|
+
}
|
83
|
+
const payload = {
|
84
|
+
type,
|
85
|
+
definition: currentDefinition?.definition,
|
86
|
+
asset: { handle, name, version },
|
87
|
+
};
|
88
|
+
allDefinitions = newDefinitions;
|
89
|
+
socketManager.emit(`assets`, 'changed', payload);
|
90
|
+
});
|
91
|
+
}
|
92
|
+
stopListening() {
|
93
|
+
if (!this.watcher) {
|
94
|
+
return;
|
95
|
+
}
|
96
|
+
this.watcher.close();
|
97
|
+
this.watcher = undefined;
|
98
|
+
}
|
99
|
+
async _install(refs) {
|
100
|
+
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
101
|
+
const out = new Promise((resolve, reject) => {
|
102
|
+
this._installQueue.push(async () => {
|
103
|
+
try {
|
104
|
+
const normalizedRefs = refs.map((ref) => parseKapetaUri(ref).id);
|
105
|
+
const filteredRefs = normalizedRefs.filter((ref) => !INSTALL_ATTEMPTED[ref]);
|
106
|
+
console.log(filteredRefs);
|
107
|
+
if (filteredRefs.length > 0) {
|
108
|
+
filteredRefs.forEach((ref) => (INSTALL_ATTEMPTED[ref] = true));
|
109
|
+
//Auto-install missing asset
|
110
|
+
try {
|
111
|
+
//We change to a temp dir to avoid issues with the current working directory
|
112
|
+
process.chdir(os.tmpdir());
|
113
|
+
//Disable change events while installing
|
114
|
+
this.setChangeEventsEnabled(false);
|
115
|
+
socketManager.emit(`install`, 'install:action', {
|
116
|
+
type: 'start',
|
117
|
+
refs,
|
118
|
+
});
|
119
|
+
await Actions.install(progressListener, normalizedRefs, {});
|
120
|
+
socketManager.emit(`install`, 'install:action', {
|
121
|
+
type: 'done',
|
122
|
+
refs,
|
123
|
+
});
|
124
|
+
}
|
125
|
+
catch (e) {
|
126
|
+
socketManager.emit(`install`, 'install:action', {
|
127
|
+
type: 'failed',
|
128
|
+
refs,
|
129
|
+
error: e.message,
|
130
|
+
});
|
131
|
+
}
|
132
|
+
finally {
|
133
|
+
this.setChangeEventsEnabled(true);
|
134
|
+
}
|
135
|
+
}
|
136
|
+
resolve();
|
137
|
+
}
|
138
|
+
catch (e) {
|
139
|
+
reject(e);
|
140
|
+
}
|
141
|
+
finally {
|
142
|
+
this._processNext().catch((e) => console.error(e));
|
143
|
+
}
|
144
|
+
});
|
145
|
+
});
|
146
|
+
this._processNext().catch((e) => console.error(e));
|
147
|
+
return out;
|
148
|
+
}
|
149
|
+
async _processNext() {
|
150
|
+
if (this._processing) {
|
151
|
+
return;
|
152
|
+
}
|
153
|
+
this._processing = true;
|
154
|
+
try {
|
155
|
+
while (this._installQueue.length > 0) {
|
156
|
+
const item = this._installQueue.shift();
|
157
|
+
if (item) {
|
158
|
+
await item();
|
159
|
+
}
|
160
|
+
}
|
161
|
+
}
|
162
|
+
finally {
|
163
|
+
this._processing = false;
|
164
|
+
}
|
165
|
+
}
|
166
|
+
async ensureAsset(handle, name, version) {
|
167
|
+
const fullName = `${handle}/${name}`;
|
168
|
+
const ref = `${fullName}:${version}`;
|
169
|
+
if (version === 'local') {
|
170
|
+
//TODO: Get dependencies for local asset
|
171
|
+
return;
|
172
|
+
}
|
173
|
+
const definitions = ClusterConfiguration.getDefinitions();
|
174
|
+
const installedAsset = definitions.find((d) => d.definition.metadata.name === fullName && d.version === version);
|
175
|
+
if (installedAsset && this._cache[ref] === true) {
|
176
|
+
return;
|
177
|
+
}
|
178
|
+
if (!installedAsset && this._cache[ref] === false) {
|
179
|
+
return;
|
180
|
+
}
|
181
|
+
let assetVersion;
|
182
|
+
try {
|
183
|
+
assetVersion = await this._registryService.getVersion(fullName, version);
|
184
|
+
if (!assetVersion) {
|
185
|
+
this._cache[ref] = false;
|
186
|
+
return;
|
187
|
+
}
|
188
|
+
}
|
189
|
+
catch (e) {
|
190
|
+
console.warn(`Unable to resolve asset: ${ref}`, e);
|
191
|
+
if (installedAsset) {
|
192
|
+
return;
|
193
|
+
}
|
194
|
+
throw e;
|
195
|
+
}
|
196
|
+
this._cache[ref] = true;
|
197
|
+
if (!installedAsset) {
|
198
|
+
console.log(`Auto-installing missing asset: ${ref}`);
|
199
|
+
await this._install([ref]);
|
200
|
+
}
|
201
|
+
else {
|
202
|
+
//Ensure dependencies are installed
|
203
|
+
const refs = assetVersion.dependencies.map((dep) => dep.name);
|
204
|
+
console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
|
205
|
+
await this._install(refs);
|
206
|
+
}
|
207
|
+
}
|
208
|
+
}
|
209
|
+
export const repositoryManager = new RepositoryManager();
|
@@ -0,0 +1,29 @@
|
|
1
|
+
import { EnvironmentType } from './types';
|
2
|
+
declare class ServiceManager {
|
3
|
+
private _systems;
|
4
|
+
constructor();
|
5
|
+
_forLocal(port: string | number, path?: string, environmentType?: EnvironmentType): string;
|
6
|
+
_ensureSystem(systemId: string): any;
|
7
|
+
_ensureService(systemId: string, serviceId: string): any;
|
8
|
+
ensureServicePort(systemId: string, blockInstanceId: string, portType?: string): Promise<any>;
|
9
|
+
_save(): void;
|
10
|
+
/**
|
11
|
+
* Gets the consumable address of a service block resource
|
12
|
+
*
|
13
|
+
* This returns a local proxy path to allow traffic inspection and control.
|
14
|
+
*
|
15
|
+
*/
|
16
|
+
getConsumerAddress(systemId: string, consumerInstanceId: string, consumerResourceName: string, portType: string, environmentType?: EnvironmentType): string;
|
17
|
+
/**
|
18
|
+
* Gets the direct address of a service block
|
19
|
+
*
|
20
|
+
* This returns the actual endpoint address of a service that we're talking to.
|
21
|
+
* For local services this address will be on localhost - for remote services it will
|
22
|
+
* be their remotely available address.
|
23
|
+
*
|
24
|
+
*/
|
25
|
+
getProviderAddress(systemId: string, providerInstanceId: string, portType: string): Promise<string>;
|
26
|
+
getServices(): any;
|
27
|
+
}
|
28
|
+
export declare const serviceManager: ServiceManager;
|
29
|
+
export {};
|
@@ -1,17 +1,14 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import _ from 'lodash';
|
2
|
+
import { clusterService } from './clusterService';
|
3
|
+
import { storageService } from './storageService';
|
5
4
|
const DEFAULT_PORT_TYPE = 'rest';
|
6
|
-
|
7
5
|
class ServiceManager {
|
8
|
-
|
6
|
+
_systems;
|
9
7
|
constructor() {
|
10
|
-
this._systems = storageService.get(
|
8
|
+
this._systems = storageService.get('services');
|
11
9
|
if (!this._systems) {
|
12
10
|
this._systems = {};
|
13
11
|
}
|
14
|
-
|
15
12
|
_.forEach(this._systems, (system) => {
|
16
13
|
_.forEach(system, (services) => {
|
17
14
|
_.forEach(services, (portInfo) => {
|
@@ -20,7 +17,6 @@ class ServiceManager {
|
|
20
17
|
});
|
21
18
|
});
|
22
19
|
}
|
23
|
-
|
24
20
|
_forLocal(port, path, environmentType) {
|
25
21
|
if (!path) {
|
26
22
|
path = '';
|
@@ -29,75 +25,55 @@ class ServiceManager {
|
|
29
25
|
if (environmentType === 'docker') {
|
30
26
|
//We're inside a docker container, so we can use this special host name to access the host machine
|
31
27
|
host = 'host.docker.internal';
|
32
|
-
}
|
28
|
+
}
|
29
|
+
else {
|
33
30
|
host = clusterService.getClusterServiceHost();
|
34
31
|
}
|
35
|
-
|
36
32
|
if (path.startsWith('/')) {
|
37
33
|
path = path.substring(1);
|
38
34
|
}
|
39
35
|
return `http://${host}:${port}/${path}`;
|
40
36
|
}
|
41
|
-
|
42
37
|
_ensureSystem(systemId) {
|
43
38
|
if (!this._systems[systemId]) {
|
44
39
|
this._systems[systemId] = {};
|
45
40
|
}
|
46
|
-
|
47
41
|
return this._systems[systemId];
|
48
42
|
}
|
49
|
-
|
50
43
|
_ensureService(systemId, serviceId) {
|
51
|
-
|
52
44
|
const system = this._ensureSystem(systemId);
|
53
|
-
|
54
45
|
if (!system[serviceId]) {
|
55
46
|
system[serviceId] = {};
|
56
47
|
}
|
57
|
-
|
58
48
|
return system[serviceId];
|
59
49
|
}
|
60
|
-
|
61
|
-
async ensureServicePort(systemId, blockInstanceId, portType) {
|
50
|
+
async ensureServicePort(systemId, blockInstanceId, portType = DEFAULT_PORT_TYPE) {
|
62
51
|
if (!portType) {
|
63
52
|
portType = DEFAULT_PORT_TYPE;
|
64
53
|
}
|
65
|
-
|
66
54
|
const service = this._ensureService(systemId, blockInstanceId);
|
67
|
-
|
68
55
|
if (!service[portType]) {
|
69
56
|
const port = await clusterService.getNextAvailablePort();
|
70
|
-
service[portType] = {port};
|
57
|
+
service[portType] = { port };
|
71
58
|
this._save();
|
72
59
|
}
|
73
|
-
|
74
60
|
const portTypeSection = service[portType];
|
75
|
-
|
76
61
|
return portTypeSection.port;
|
77
62
|
}
|
78
|
-
|
79
63
|
_save() {
|
80
|
-
storageService.put(
|
64
|
+
storageService.put('services', this._systems);
|
81
65
|
}
|
82
|
-
|
83
66
|
/**
|
84
67
|
* Gets the consumable address of a service block resource
|
85
68
|
*
|
86
69
|
* This returns a local proxy path to allow traffic inspection and control.
|
87
70
|
*
|
88
|
-
* @param {string} systemId
|
89
|
-
* @param {string} consumerInstanceId
|
90
|
-
* @param {string} consumerResourceName
|
91
|
-
* @param {string} portType
|
92
|
-
* @param {'docker'|'process'} environmentType
|
93
|
-
* @return {string}
|
94
71
|
*/
|
95
72
|
getConsumerAddress(systemId, consumerInstanceId, consumerResourceName, portType, environmentType) {
|
96
73
|
const port = clusterService.getClusterServicePort();
|
97
74
|
const path = clusterService.getProxyPath(systemId, consumerInstanceId, consumerResourceName, portType);
|
98
75
|
return this._forLocal(port, path, environmentType);
|
99
76
|
}
|
100
|
-
|
101
77
|
/**
|
102
78
|
* Gets the direct address of a service block
|
103
79
|
*
|
@@ -105,19 +81,13 @@ class ServiceManager {
|
|
105
81
|
* For local services this address will be on localhost - for remote services it will
|
106
82
|
* be their remotely available address.
|
107
83
|
*
|
108
|
-
* @param {string} systemId
|
109
|
-
* @param {string} providerInstanceId
|
110
|
-
* @param {string} portType
|
111
|
-
* @return {Promise<string>}
|
112
84
|
*/
|
113
85
|
async getProviderAddress(systemId, providerInstanceId, portType) {
|
114
86
|
const port = await this.ensureServicePort(systemId, providerInstanceId, portType);
|
115
|
-
return this._forLocal(port)
|
87
|
+
return this._forLocal(port);
|
116
88
|
}
|
117
|
-
|
118
89
|
getServices() {
|
119
90
|
return this._systems;
|
120
91
|
}
|
121
92
|
}
|
122
|
-
|
123
|
-
module.exports = new ServiceManager();
|
93
|
+
export const serviceManager = new ServiceManager();
|
@@ -0,0 +1,14 @@
|
|
1
|
+
import { Socket, Server } from 'socket.io';
|
2
|
+
export declare class SocketManager {
|
3
|
+
private _io;
|
4
|
+
private _sockets;
|
5
|
+
constructor();
|
6
|
+
setIo(io: Server): void;
|
7
|
+
private get io();
|
8
|
+
emit(context: string, type: string, payload: any): void;
|
9
|
+
_bindIO(): void;
|
10
|
+
_handleSocketCreated(socket: Socket): void;
|
11
|
+
_bindSocket(socket: Socket): void;
|
12
|
+
_handleSocketDestroyed(socket: Socket): void;
|
13
|
+
}
|
14
|
+
export declare const socketManager: SocketManager;
|
@@ -1,50 +1,46 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
import _ from 'lodash';
|
2
|
+
export class SocketManager {
|
3
|
+
_io;
|
4
|
+
_sockets;
|
5
5
|
constructor() {
|
6
6
|
this._io = null;
|
7
7
|
this._sockets = [];
|
8
8
|
return this;
|
9
9
|
}
|
10
|
-
|
11
10
|
setIo(io) {
|
12
|
-
console.log(
|
11
|
+
console.log('Socket server ready');
|
13
12
|
this._io = io;
|
14
|
-
|
15
13
|
this._bindIO();
|
16
14
|
}
|
17
|
-
|
15
|
+
get io() {
|
16
|
+
if (!this._io) {
|
17
|
+
throw new Error('Socket server not ready');
|
18
|
+
}
|
19
|
+
return this._io;
|
20
|
+
}
|
18
21
|
emit(context, type, payload) {
|
19
|
-
this.
|
22
|
+
this.io.to(context).emit(type, { context, payload });
|
20
23
|
}
|
21
|
-
|
22
24
|
_bindIO() {
|
23
|
-
this.
|
25
|
+
this.io.on('connection', (socket) => this._handleSocketCreated(socket));
|
24
26
|
}
|
25
|
-
|
26
27
|
_handleSocketCreated(socket) {
|
27
28
|
this._bindSocket(socket);
|
28
29
|
this._sockets.push(socket);
|
29
30
|
}
|
30
|
-
|
31
31
|
_bindSocket(socket) {
|
32
|
-
socket.on('disconnect', () => this._handleSocketDestroyed(socket))
|
32
|
+
socket.on('disconnect', () => this._handleSocketDestroyed(socket));
|
33
33
|
socket.on('join', (id) => {
|
34
|
-
console.log(
|
34
|
+
console.log('socket joined ', id);
|
35
35
|
socket.join(id);
|
36
|
-
})
|
36
|
+
});
|
37
37
|
socket.on('leave', (id) => {
|
38
|
-
console.log(
|
38
|
+
console.log('socket left ', id);
|
39
39
|
socket.leave(id);
|
40
|
-
})
|
40
|
+
});
|
41
41
|
}
|
42
|
-
|
43
42
|
_handleSocketDestroyed(socket) {
|
44
43
|
_.pull(this._sockets, socket);
|
45
44
|
}
|
46
|
-
|
47
45
|
}
|
48
|
-
|
49
|
-
|
50
|
-
module.exports = new SocketManager();
|
46
|
+
export const socketManager = new SocketManager();
|