@kapeta/local-cluster-service 0.6.1 → 0.7.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.
- 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 +14 -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 +218 -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 +212 -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} +49 -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
@@ -1,52 +1,36 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
import Path from 'path';
|
2
|
+
import FSExtra from 'fs-extra';
|
3
|
+
import { repositoryManager } from './repositoryManager';
|
4
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
5
|
+
import { StringMap } from './types';
|
6
6
|
|
7
7
|
class ProviderManager {
|
8
|
+
private _webAssetCache: StringMap;
|
8
9
|
constructor() {
|
9
10
|
this._webAssetCache = {};
|
10
11
|
}
|
11
12
|
|
12
13
|
getWebProviders() {
|
13
|
-
return ClusterConfiguration.getProviderDefinitions().filter(
|
14
|
-
(providerDefinition) => providerDefinition.hasWeb
|
15
|
-
);
|
14
|
+
return ClusterConfiguration.getProviderDefinitions().filter((providerDefinition) => providerDefinition.hasWeb);
|
16
15
|
}
|
17
16
|
|
18
|
-
async getAsset(handle, name, version, sourceMap = false) {
|
17
|
+
async getAsset(handle: string, name: string, version: string, sourceMap: boolean = false) {
|
19
18
|
const fullName = `${handle}/${name}`;
|
20
|
-
const id = `${handle}/${name}/${version}/web.js${
|
21
|
-
sourceMap ? '.map' : ''
|
22
|
-
}`;
|
19
|
+
const id = `${handle}/${name}/${version}/web.js${sourceMap ? '.map' : ''}`;
|
23
20
|
|
24
|
-
if (
|
25
|
-
this._webAssetCache[id] &&
|
26
|
-
(await FSExtra.pathExists(this._webAssetCache[id]))
|
27
|
-
) {
|
21
|
+
if (this._webAssetCache[id] && (await FSExtra.pathExists(this._webAssetCache[id]))) {
|
28
22
|
return FSExtra.readFile(this._webAssetCache[id], 'utf8');
|
29
23
|
}
|
30
24
|
|
31
25
|
await repositoryManager.ensureAsset(handle, name, version);
|
32
26
|
|
33
|
-
const installedProvider = this.getWebProviders().find(
|
34
|
-
|
35
|
-
|
36
|
-
providerDefinition.definition.metadata.name === fullName &&
|
37
|
-
providerDefinition.version === version
|
38
|
-
);
|
39
|
-
}
|
40
|
-
);
|
27
|
+
const installedProvider = this.getWebProviders().find((providerDefinition) => {
|
28
|
+
return providerDefinition.definition.metadata.name === fullName && providerDefinition.version === version;
|
29
|
+
});
|
41
30
|
|
42
31
|
if (installedProvider) {
|
43
32
|
//Check locally installed providers
|
44
|
-
const path = Path.join(
|
45
|
-
installedProvider.path,
|
46
|
-
'web',
|
47
|
-
handle,
|
48
|
-
`${name}.js${sourceMap ? '.map' : ''}`
|
49
|
-
);
|
33
|
+
const path = Path.join(installedProvider.path, 'web', handle, `${name}.js${sourceMap ? '.map' : ''}`);
|
50
34
|
if (await FSExtra.pathExists(path)) {
|
51
35
|
this._webAssetCache[id] = path;
|
52
36
|
|
@@ -75,4 +59,4 @@ if (providerDefinitions.length > 0) {
|
|
75
59
|
console.log('## No providers found ##');
|
76
60
|
}
|
77
61
|
|
78
|
-
|
62
|
+
export const providerManager = new ProviderManager();
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import Router from 'express-promise-router';
|
2
|
+
import { providerManager } from '../providerManager';
|
3
|
+
|
4
|
+
import { corsHandler } from '../middleware/cors';
|
5
|
+
import { Request, Response } from 'express';
|
6
|
+
|
7
|
+
const router = Router();
|
8
|
+
|
9
|
+
router.use('/', corsHandler);
|
10
|
+
|
11
|
+
router.get('/', async (req: Request, res: Response) => {
|
12
|
+
const result = await providerManager.getWebProviders();
|
13
|
+
|
14
|
+
res.send(result);
|
15
|
+
});
|
16
|
+
|
17
|
+
router.get('/asset/:handle/:name/:version/web.js', async (req: Request, res: Response) => {
|
18
|
+
const { handle, name, version } = req.params;
|
19
|
+
let result = await providerManager.getAsset(handle, name, version);
|
20
|
+
|
21
|
+
if (!result) {
|
22
|
+
res.status(404).send('');
|
23
|
+
} else {
|
24
|
+
if (version !== 'local') {
|
25
|
+
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
|
26
|
+
}
|
27
|
+
res.send(result.toString().replace(`${name}.js.map`, 'web.js.map'));
|
28
|
+
}
|
29
|
+
});
|
30
|
+
|
31
|
+
router.get('/asset/:handle/:name/:version/web.js.map', async (req: Request, res: Response) => {
|
32
|
+
const { handle, name, version } = req.params;
|
33
|
+
const result = await providerManager.getAsset(handle, name, version, true);
|
34
|
+
|
35
|
+
if (!result) {
|
36
|
+
res.status(404).send('');
|
37
|
+
} else {
|
38
|
+
// Only cache successful requests
|
39
|
+
if (version !== 'local') {
|
40
|
+
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
|
41
|
+
}
|
42
|
+
res.send(result);
|
43
|
+
}
|
44
|
+
});
|
45
|
+
|
46
|
+
export default router;
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import Router from 'express-promise-router';
|
2
|
+
import { Request, Response } from 'express';
|
3
|
+
import { Resource } from '@kapeta/schemas';
|
4
|
+
import { proxyRestRequest } from './types/rest';
|
5
|
+
import { proxyWebRequest } from './types/web';
|
6
|
+
import { ProxyRequestHandler } from '../types';
|
7
|
+
import { stringBody, StringBodyRequest } from '../middleware/stringBody';
|
8
|
+
import { serviceManager } from '../serviceManager';
|
9
|
+
import { clusterService } from '../clusterService';
|
10
|
+
import { assetManager } from '../assetManager';
|
11
|
+
|
12
|
+
import _ from 'lodash';
|
13
|
+
|
14
|
+
const router = Router();
|
15
|
+
/**
|
16
|
+
* @var {{[key:string]:ProxyRequestHandler}}
|
17
|
+
*/
|
18
|
+
const TYPE_HANDLERS: { [p: string]: ProxyRequestHandler } = {
|
19
|
+
rest: proxyRestRequest,
|
20
|
+
web: proxyWebRequest,
|
21
|
+
};
|
22
|
+
|
23
|
+
function getResource(resources: Resource[], resourceName: string) {
|
24
|
+
return resources.find((resource) => {
|
25
|
+
return resource.metadata.name.toLowerCase() === resourceName.toLowerCase();
|
26
|
+
});
|
27
|
+
}
|
28
|
+
|
29
|
+
router.use('/:systemId/:consumerInstanceId/:consumerResourceName', stringBody);
|
30
|
+
|
31
|
+
router.all(
|
32
|
+
'/:systemId/:consumerInstanceId/:consumerResourceName/:type/*',
|
33
|
+
async (req: StringBodyRequest, res: Response) => {
|
34
|
+
try {
|
35
|
+
const typeHandler = TYPE_HANDLERS[req.params.type.toLowerCase()];
|
36
|
+
if (!typeHandler) {
|
37
|
+
res.status(401).send({ error: 'Unknown connection type: ' + req.params.type });
|
38
|
+
return;
|
39
|
+
}
|
40
|
+
|
41
|
+
const plan = await assetManager.getPlan(req.params.systemId);
|
42
|
+
|
43
|
+
// We can find the connection by the consumer information alone since
|
44
|
+
// only 1 provider can be connected to a consumer resource at a time
|
45
|
+
const connection = _.find(plan.spec.connections, (connection) => {
|
46
|
+
return (
|
47
|
+
connection.consumer.blockId.toLowerCase() === req.params.consumerInstanceId.toLowerCase() &&
|
48
|
+
connection.consumer.resourceName.toLowerCase() === req.params.consumerResourceName.toLowerCase()
|
49
|
+
);
|
50
|
+
});
|
51
|
+
|
52
|
+
if (!connection) {
|
53
|
+
res.status(401).send({
|
54
|
+
error: `No connection found for consumer "${req.params.consumerInstanceId}::${req.params.consumerResourceName}"`,
|
55
|
+
});
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
const toBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
60
|
+
return blockInstance.id.toLowerCase() === connection.consumer.blockId.toLowerCase();
|
61
|
+
});
|
62
|
+
|
63
|
+
if (!toBlockInstance) {
|
64
|
+
res.status(401).send({ error: `Block instance not found "${req.params.consumerInstanceId}` });
|
65
|
+
return;
|
66
|
+
}
|
67
|
+
|
68
|
+
const toBlockAsset = await assetManager.getAsset(toBlockInstance.block.ref);
|
69
|
+
|
70
|
+
if (!toBlockAsset) {
|
71
|
+
res.status(401).send({ error: `Block asset not found "${toBlockInstance.block.ref}` });
|
72
|
+
return;
|
73
|
+
}
|
74
|
+
|
75
|
+
const consumerResource = getResource(toBlockAsset.data.spec.consumers, req.params.consumerResourceName);
|
76
|
+
|
77
|
+
if (!consumerResource) {
|
78
|
+
res.status(401).send({
|
79
|
+
error: `Block resource not found "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`,
|
80
|
+
});
|
81
|
+
return;
|
82
|
+
}
|
83
|
+
|
84
|
+
const basePath = clusterService.getProxyPath(
|
85
|
+
req.params.systemId,
|
86
|
+
req.params.consumerInstanceId,
|
87
|
+
req.params.consumerResourceName,
|
88
|
+
req.params.type
|
89
|
+
);
|
90
|
+
|
91
|
+
const fromBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
92
|
+
return blockInstance.id.toLowerCase() === connection.provider.blockId.toLowerCase();
|
93
|
+
});
|
94
|
+
|
95
|
+
if (!fromBlockInstance) {
|
96
|
+
res.status(401).send({ error: `Block instance not found "${connection.provider.blockId}` });
|
97
|
+
return;
|
98
|
+
}
|
99
|
+
|
100
|
+
const fromBlockAsset = await assetManager.getAsset(fromBlockInstance.block.ref);
|
101
|
+
|
102
|
+
if (!fromBlockAsset) {
|
103
|
+
res.status(401).send({ error: `Block asset not found "${fromBlockInstance.block.ref}` });
|
104
|
+
return;
|
105
|
+
}
|
106
|
+
|
107
|
+
const providerResource = getResource(fromBlockAsset.data.spec.providers, connection.provider.resourceName);
|
108
|
+
|
109
|
+
if (!providerResource) {
|
110
|
+
res.status(401).send({
|
111
|
+
error: `Block resource not found "${connection.provider.blockId}::${connection.provider.resourceName}`,
|
112
|
+
});
|
113
|
+
return;
|
114
|
+
}
|
115
|
+
|
116
|
+
//Get target address
|
117
|
+
let address = await serviceManager.getProviderAddress(
|
118
|
+
req.params.systemId,
|
119
|
+
connection.provider.blockId,
|
120
|
+
req.params.type
|
121
|
+
);
|
122
|
+
|
123
|
+
while (address.endsWith('/')) {
|
124
|
+
address = address.substring(0, address.length - 1);
|
125
|
+
}
|
126
|
+
|
127
|
+
/*
|
128
|
+
Get the path the consumer requested.
|
129
|
+
Note that this might not match the path the destination is expecting so we need to identify the method
|
130
|
+
that is being called and identify the destination path from the connection.
|
131
|
+
*/
|
132
|
+
const consumerPath = req.originalUrl.substring(basePath.length - 1);
|
133
|
+
|
134
|
+
typeHandler(req, res, {
|
135
|
+
consumerPath,
|
136
|
+
address,
|
137
|
+
consumerResource,
|
138
|
+
providerResource,
|
139
|
+
connection,
|
140
|
+
});
|
141
|
+
} catch (err: any) {
|
142
|
+
console.warn('Failed to process proxy request', err);
|
143
|
+
res.status(400).send({ error: err.message });
|
144
|
+
}
|
145
|
+
}
|
146
|
+
);
|
147
|
+
|
148
|
+
export default router;
|
@@ -1,13 +1,16 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
+
|
7
|
+
import { socketManager } from '../../socketManager';
|
8
|
+
import { Request, Response } from 'express';
|
9
|
+
import { ProxyRequestInfo, SimpleRequest, StringMap } from '../../types';
|
10
|
+
import { StringBodyRequest } from '../../middleware/stringBody';
|
11
|
+
import { Resource } from '@kapeta/schemas';
|
12
|
+
|
13
|
+
function getRestMethodId(restResource: Resource, httpMethod: string, httpPath: string) {
|
11
14
|
return _.findKey(restResource.spec.methods, (method) => {
|
12
15
|
let methodType = method.method ? method.method.toUpperCase() : 'GET';
|
13
16
|
|
@@ -24,7 +27,6 @@ function getRestMethodId(restResource, httpMethod, httpPath) {
|
|
24
27
|
const pathTemplate = pathTemplateParser(path);
|
25
28
|
|
26
29
|
return pathTemplate.matches(httpPath);
|
27
|
-
|
28
30
|
});
|
29
31
|
}
|
30
32
|
|
@@ -34,7 +36,7 @@ function getRestMethodId(restResource, httpMethod, httpPath) {
|
|
34
36
|
* @param opts {ProxyRequestInfo}
|
35
37
|
* @return {{consumerMethod: *, providerMethod: *}}
|
36
38
|
*/
|
37
|
-
function resolveMethods(req, opts) {
|
39
|
+
function resolveMethods(req: Request, opts: ProxyRequestInfo) {
|
38
40
|
const consumerMethodId = getRestMethodId(opts.consumerResource, req.method, opts.consumerPath);
|
39
41
|
|
40
42
|
if (!consumerMethodId) {
|
@@ -73,24 +75,23 @@ function resolveMethods(req, opts) {
|
|
73
75
|
|
74
76
|
return {
|
75
77
|
consumerMethod,
|
76
|
-
providerMethod
|
78
|
+
providerMethod,
|
77
79
|
};
|
78
80
|
}
|
79
81
|
|
80
|
-
|
81
|
-
|
82
|
-
* @param req {Request}
|
83
|
-
* @param res {Response}
|
84
|
-
* @param opts {ProxyRequestInfo}
|
85
|
-
*/
|
86
|
-
module.exports = function proxyRestRequest(req, res, opts) {
|
87
|
-
|
88
|
-
let {consumerMethod, providerMethod} = resolveMethods(req, opts);
|
82
|
+
export function proxyRestRequest(req: StringBodyRequest, res: Response, opts: ProxyRequestInfo) {
|
83
|
+
let { consumerMethod, providerMethod } = resolveMethods(req, opts);
|
89
84
|
|
90
85
|
const consumerPathTemplate = pathTemplateParser(consumerMethod.path);
|
91
86
|
const providerPathTemplate = pathTemplateParser(providerMethod.path);
|
92
87
|
|
93
88
|
const pathVariables = consumerPathTemplate.parse(opts.consumerPath);
|
89
|
+
if (!pathVariables) {
|
90
|
+
res.status(400).send({
|
91
|
+
error: `Path did not match any patterns: "${opts.consumerPath}"`,
|
92
|
+
});
|
93
|
+
return;
|
94
|
+
}
|
94
95
|
|
95
96
|
let providerPath = providerPathTemplate.create(pathVariables);
|
96
97
|
|
@@ -108,11 +109,11 @@ module.exports = function proxyRestRequest(req, res, opts) {
|
|
108
109
|
|
109
110
|
console.log('Proxy request to provider: %s => %s [rest]', opts.consumerPath, opts.address + providerPath);
|
110
111
|
|
111
|
-
const reqOpts = {
|
112
|
+
const reqOpts: SimpleRequest = {
|
112
113
|
method: providerMethod.method || 'GET',
|
113
114
|
url: opts.address + providerPath,
|
114
115
|
body: req.stringBody,
|
115
|
-
headers: requestHeaders
|
116
|
+
headers: requestHeaders as StringMap,
|
116
117
|
};
|
117
118
|
|
118
119
|
const traffic = networkManager.addRequest(
|
@@ -125,12 +126,12 @@ module.exports = function proxyRestRequest(req, res, opts) {
|
|
125
126
|
|
126
127
|
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
127
128
|
|
128
|
-
request(reqOpts, function(err, response, responseBody) {
|
129
|
+
request(reqOpts, function (err, response, responseBody) {
|
129
130
|
if (err) {
|
130
131
|
traffic.asError(err);
|
131
132
|
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
132
133
|
|
133
|
-
res.status(500).send({error: '' + err});
|
134
|
+
res.status(500).send({ error: '' + err });
|
134
135
|
return;
|
135
136
|
}
|
136
137
|
|
@@ -146,8 +147,8 @@ module.exports = function proxyRestRequest(req, res, opts) {
|
|
146
147
|
|
147
148
|
traffic.withResponse({
|
148
149
|
code: response.statusCode,
|
149
|
-
headers: response.headers,
|
150
|
-
body: responseBody
|
150
|
+
headers: response.headers as StringMap,
|
151
|
+
body: responseBody,
|
151
152
|
});
|
152
153
|
|
153
154
|
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
@@ -158,5 +159,4 @@ module.exports = function proxyRestRequest(req, res, opts) {
|
|
158
159
|
|
159
160
|
res.end();
|
160
161
|
});
|
161
|
-
|
162
|
-
};
|
162
|
+
}
|
@@ -0,0 +1,60 @@
|
|
1
|
+
import request from 'request';
|
2
|
+
import _ from 'lodash';
|
3
|
+
import { networkManager } from '../../networkManager';
|
4
|
+
import { socketManager } from '../../socketManager';
|
5
|
+
import { Request, Response } from 'express';
|
6
|
+
import { ProxyRequestInfo, SimpleRequest, StringMap } from '../../types';
|
7
|
+
import { StringBodyRequest } from '../../middleware/stringBody';
|
8
|
+
|
9
|
+
export function proxyWebRequest(req: StringBodyRequest, res: Response, opts: ProxyRequestInfo) {
|
10
|
+
const requestHeaders = _.clone(req.headers);
|
11
|
+
|
12
|
+
delete requestHeaders['content-length'];
|
13
|
+
delete requestHeaders['content-encoding'];
|
14
|
+
delete requestHeaders['connection'];
|
15
|
+
delete requestHeaders['host'];
|
16
|
+
delete requestHeaders['origin'];
|
17
|
+
|
18
|
+
const sourceBasePath = opts.consumerResource.spec.path;
|
19
|
+
const targetBasePath = opts.providerResource.spec.path;
|
20
|
+
let path = opts.consumerPath;
|
21
|
+
if (opts.consumerPath.startsWith(sourceBasePath)) {
|
22
|
+
path = path.replace(sourceBasePath, targetBasePath);
|
23
|
+
}
|
24
|
+
|
25
|
+
console.log('Proxy request to provider: %s => %s%s [web]', opts.consumerPath, opts.address, path);
|
26
|
+
|
27
|
+
const reqOpts: SimpleRequest = {
|
28
|
+
method: req.method,
|
29
|
+
url: opts.address + path,
|
30
|
+
headers: requestHeaders as StringMap,
|
31
|
+
body: req.stringBody,
|
32
|
+
};
|
33
|
+
|
34
|
+
const traffic = networkManager.addRequest(req.params.systemId, opts.connection, reqOpts);
|
35
|
+
|
36
|
+
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
37
|
+
const proxyReq = request(reqOpts);
|
38
|
+
|
39
|
+
proxyReq.on('error', function (err) {
|
40
|
+
traffic.asError(err);
|
41
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
42
|
+
if (!res.headersSent) {
|
43
|
+
res.status(500).send({ error: '' + err });
|
44
|
+
}
|
45
|
+
});
|
46
|
+
|
47
|
+
proxyReq.on('response', function (response) {
|
48
|
+
//TODO: Include the response body in the traffic object when it is not a stream
|
49
|
+
traffic.withResponse({
|
50
|
+
code: response.statusCode,
|
51
|
+
headers: response.headers as StringMap,
|
52
|
+
body: null,
|
53
|
+
});
|
54
|
+
|
55
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
56
|
+
});
|
57
|
+
|
58
|
+
//We need to pipe the proxy response to the client response to handle sockets and event streams
|
59
|
+
proxyReq.pipe(res);
|
60
|
+
}
|
@@ -1,21 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
}
|
11
|
-
|
12
|
-
const
|
13
|
-
const { parseKapetaUri } = require('@kapeta/nodejs-utils');
|
14
|
-
const INSTALL_ATTEMPTED = {};
|
1
|
+
import FS from 'node:fs';
|
2
|
+
import os from 'node:os';
|
3
|
+
import Path from 'node:path';
|
4
|
+
import FSExtra, { FSWatcher } 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 { Dependency } from '@kapeta/schemas';
|
10
|
+
import { Actions, Config, RegistryService } from '@kapeta/nodejs-registry-utils';
|
11
|
+
|
12
|
+
const INSTALL_ATTEMPTED: { [p: string]: boolean } = {};
|
15
13
|
|
16
14
|
class RepositoryManager {
|
15
|
+
private changeEventsEnabled: boolean;
|
16
|
+
private _registryService: RegistryService;
|
17
|
+
private _cache: { [key: string]: boolean };
|
18
|
+
private watcher?: FSWatcher;
|
19
|
+
private _installQueue: (() => Promise<void>)[];
|
20
|
+
private _processing: boolean = false;
|
17
21
|
constructor() {
|
18
|
-
this.watcher = null;
|
19
22
|
this.changeEventsEnabled = true;
|
20
23
|
this.listenForChanges();
|
21
24
|
this._registryService = new RegistryService(Config.data.registry.url);
|
@@ -23,7 +26,7 @@ class RepositoryManager {
|
|
23
26
|
this._installQueue = [];
|
24
27
|
}
|
25
28
|
|
26
|
-
setChangeEventsEnabled(enabled) {
|
29
|
+
setChangeEventsEnabled(enabled: boolean) {
|
27
30
|
this.changeEventsEnabled = enabled;
|
28
31
|
}
|
29
32
|
|
@@ -35,22 +38,21 @@ class RepositoryManager {
|
|
35
38
|
|
36
39
|
let allDefinitions = ClusterConfiguration.getDefinitions();
|
37
40
|
|
38
|
-
console.log(
|
39
|
-
'Watching local repository for provider changes: %s',
|
40
|
-
baseDir
|
41
|
-
);
|
41
|
+
console.log('Watching local repository for provider changes: %s', baseDir);
|
42
42
|
try {
|
43
43
|
this.watcher = FS.watch(baseDir, { recursive: true });
|
44
44
|
} catch (e) {
|
45
45
|
// Fallback to run without watch mode due to potential platform issues.
|
46
46
|
// https://nodejs.org/docs/latest/api/fs.html#caveats
|
47
|
-
console.log(
|
48
|
-
'Unable to watch for changes. Changes to assets will not update automatically.'
|
49
|
-
);
|
47
|
+
console.log('Unable to watch for changes. Changes to assets will not update automatically.');
|
50
48
|
return;
|
51
49
|
}
|
52
50
|
this.watcher.on('change', (eventType, filename) => {
|
53
|
-
|
51
|
+
if (!filename) {
|
52
|
+
return;
|
53
|
+
}
|
54
|
+
|
55
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
54
56
|
if (!name || !version) {
|
55
57
|
return;
|
56
58
|
}
|
@@ -59,21 +61,11 @@ class RepositoryManager {
|
|
59
61
|
return;
|
60
62
|
}
|
61
63
|
|
62
|
-
const ymlPath = Path.join(
|
63
|
-
baseDir,
|
64
|
-
handle,
|
65
|
-
name,
|
66
|
-
version,
|
67
|
-
'kapeta.yml'
|
68
|
-
);
|
64
|
+
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
69
65
|
const newDefinitions = ClusterConfiguration.getDefinitions();
|
70
66
|
|
71
|
-
const newDefinition = newDefinitions.find(
|
72
|
-
|
73
|
-
);
|
74
|
-
let currentDefinition = allDefinitions.find(
|
75
|
-
(d) => d.ymlPath === ymlPath
|
76
|
-
);
|
67
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
68
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
77
69
|
const ymlExists = FS.existsSync(ymlPath);
|
78
70
|
let type;
|
79
71
|
if (ymlExists) {
|
@@ -112,32 +104,23 @@ class RepositoryManager {
|
|
112
104
|
}
|
113
105
|
|
114
106
|
stopListening() {
|
107
|
+
if (!this.watcher) {
|
108
|
+
return;
|
109
|
+
}
|
115
110
|
this.watcher.close();
|
116
|
-
this.watcher =
|
111
|
+
this.watcher = undefined;
|
117
112
|
}
|
118
113
|
|
119
|
-
|
120
|
-
*
|
121
|
-
* @param {string[]} refs
|
122
|
-
* @return {Promise<void>}
|
123
|
-
* @private
|
124
|
-
*/
|
125
|
-
async _install(refs) {
|
114
|
+
private async _install(refs: string[]): Promise<void> {
|
126
115
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
127
|
-
const out = new Promise((resolve, reject) => {
|
116
|
+
const out = new Promise<void>((resolve, reject) => {
|
128
117
|
this._installQueue.push(async () => {
|
129
118
|
try {
|
130
|
-
const normalizedRefs = refs.map(
|
131
|
-
|
132
|
-
);
|
133
|
-
const filteredRefs = normalizedRefs.filter(
|
134
|
-
(ref) => !INSTALL_ATTEMPTED[ref]
|
135
|
-
);
|
119
|
+
const normalizedRefs = refs.map((ref) => parseKapetaUri(ref).id);
|
120
|
+
const filteredRefs = normalizedRefs.filter((ref) => !INSTALL_ATTEMPTED[ref]);
|
136
121
|
console.log(filteredRefs);
|
137
122
|
if (filteredRefs.length > 0) {
|
138
|
-
filteredRefs.forEach(
|
139
|
-
(ref) => (INSTALL_ATTEMPTED[ref] = true)
|
140
|
-
);
|
123
|
+
filteredRefs.forEach((ref) => (INSTALL_ATTEMPTED[ref] = true));
|
141
124
|
//Auto-install missing asset
|
142
125
|
try {
|
143
126
|
//We change to a temp dir to avoid issues with the current working directory
|
@@ -148,16 +131,12 @@ class RepositoryManager {
|
|
148
131
|
type: 'start',
|
149
132
|
refs,
|
150
133
|
});
|
151
|
-
await Actions.install(
|
152
|
-
progressListener,
|
153
|
-
normalizedRefs,
|
154
|
-
{}
|
155
|
-
);
|
134
|
+
await Actions.install(progressListener, normalizedRefs, {});
|
156
135
|
socketManager.emit(`install`, 'install:action', {
|
157
136
|
type: 'done',
|
158
137
|
refs,
|
159
138
|
});
|
160
|
-
} catch (e) {
|
139
|
+
} catch (e: any) {
|
161
140
|
socketManager.emit(`install`, 'install:action', {
|
162
141
|
type: 'failed',
|
163
142
|
refs,
|
@@ -189,27 +168,27 @@ class RepositoryManager {
|
|
189
168
|
try {
|
190
169
|
while (this._installQueue.length > 0) {
|
191
170
|
const item = this._installQueue.shift();
|
192
|
-
|
193
|
-
|
171
|
+
if (item) {
|
172
|
+
await item();
|
173
|
+
}
|
194
174
|
}
|
195
175
|
} finally {
|
196
176
|
this._processing = false;
|
197
177
|
}
|
198
178
|
}
|
199
179
|
|
200
|
-
async ensureAsset(handle, name, version) {
|
180
|
+
async ensureAsset(handle: string, name: string, version: string) {
|
201
181
|
const fullName = `${handle}/${name}`;
|
202
182
|
const ref = `${fullName}:${version}`;
|
203
183
|
|
204
184
|
if (version === 'local') {
|
205
185
|
//TODO: Get dependencies for local asset
|
206
|
-
return
|
186
|
+
return;
|
207
187
|
}
|
208
188
|
|
209
189
|
const definitions = ClusterConfiguration.getDefinitions();
|
210
190
|
const installedAsset = definitions.find(
|
211
|
-
(d) =>
|
212
|
-
d.definition.metadata.name === fullName && d.version === version
|
191
|
+
(d) => d.definition.metadata.name === fullName && d.version === version
|
213
192
|
);
|
214
193
|
|
215
194
|
if (installedAsset && this._cache[ref] === true) {
|
@@ -222,10 +201,7 @@ class RepositoryManager {
|
|
222
201
|
|
223
202
|
let assetVersion;
|
224
203
|
try {
|
225
|
-
assetVersion = await this._registryService.getVersion(
|
226
|
-
fullName,
|
227
|
-
version
|
228
|
-
);
|
204
|
+
assetVersion = await this._registryService.getVersion(fullName, version);
|
229
205
|
if (!assetVersion) {
|
230
206
|
this._cache[ref] = false;
|
231
207
|
return;
|
@@ -244,11 +220,11 @@ class RepositoryManager {
|
|
244
220
|
await this._install([ref]);
|
245
221
|
} else {
|
246
222
|
//Ensure dependencies are installed
|
247
|
-
const refs = assetVersion.dependencies.map((dep) => dep.name);
|
223
|
+
const refs = assetVersion.dependencies.map((dep: Dependency) => dep.name);
|
248
224
|
console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
|
249
225
|
await this._install(refs);
|
250
226
|
}
|
251
227
|
}
|
252
228
|
}
|
253
229
|
|
254
|
-
|
230
|
+
export const repositoryManager = new RepositoryManager();
|