@kapeta/local-cluster-service 0.6.0 → 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 +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 +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/dist/esm/src/config/routes.js +121 -0
- 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 +94 -175
- 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/config/routes.js +0 -160
- 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,17 @@ 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
|
-
const [handle, name, version] = filename.split(/\//g);
|
51
|
+
const [handle, name, version] = filename.toString().split(/\//g);
|
54
52
|
if (!name || !version) {
|
55
53
|
return;
|
56
54
|
}
|
@@ -59,21 +57,11 @@ class RepositoryManager {
|
|
59
57
|
return;
|
60
58
|
}
|
61
59
|
|
62
|
-
const ymlPath = Path.join(
|
63
|
-
baseDir,
|
64
|
-
handle,
|
65
|
-
name,
|
66
|
-
version,
|
67
|
-
'kapeta.yml'
|
68
|
-
);
|
60
|
+
const ymlPath = Path.join(baseDir, handle, name, version, 'kapeta.yml');
|
69
61
|
const newDefinitions = ClusterConfiguration.getDefinitions();
|
70
62
|
|
71
|
-
const newDefinition = newDefinitions.find(
|
72
|
-
|
73
|
-
);
|
74
|
-
let currentDefinition = allDefinitions.find(
|
75
|
-
(d) => d.ymlPath === ymlPath
|
76
|
-
);
|
63
|
+
const newDefinition = newDefinitions.find((d) => d.ymlPath === ymlPath);
|
64
|
+
let currentDefinition = allDefinitions.find((d) => d.ymlPath === ymlPath);
|
77
65
|
const ymlExists = FS.existsSync(ymlPath);
|
78
66
|
let type;
|
79
67
|
if (ymlExists) {
|
@@ -112,32 +100,23 @@ class RepositoryManager {
|
|
112
100
|
}
|
113
101
|
|
114
102
|
stopListening() {
|
103
|
+
if (!this.watcher) {
|
104
|
+
return;
|
105
|
+
}
|
115
106
|
this.watcher.close();
|
116
|
-
this.watcher =
|
107
|
+
this.watcher = undefined;
|
117
108
|
}
|
118
109
|
|
119
|
-
|
120
|
-
*
|
121
|
-
* @param {string[]} refs
|
122
|
-
* @return {Promise<void>}
|
123
|
-
* @private
|
124
|
-
*/
|
125
|
-
async _install(refs) {
|
110
|
+
private async _install(refs: string[]): Promise<void> {
|
126
111
|
//We make sure to only install one asset at a time - otherwise unexpected things might happen
|
127
|
-
const out = new Promise((resolve, reject) => {
|
112
|
+
const out = new Promise<void>((resolve, reject) => {
|
128
113
|
this._installQueue.push(async () => {
|
129
114
|
try {
|
130
|
-
const normalizedRefs = refs.map(
|
131
|
-
|
132
|
-
);
|
133
|
-
const filteredRefs = normalizedRefs.filter(
|
134
|
-
(ref) => !INSTALL_ATTEMPTED[ref]
|
135
|
-
);
|
115
|
+
const normalizedRefs = refs.map((ref) => parseKapetaUri(ref).id);
|
116
|
+
const filteredRefs = normalizedRefs.filter((ref) => !INSTALL_ATTEMPTED[ref]);
|
136
117
|
console.log(filteredRefs);
|
137
118
|
if (filteredRefs.length > 0) {
|
138
|
-
filteredRefs.forEach(
|
139
|
-
(ref) => (INSTALL_ATTEMPTED[ref] = true)
|
140
|
-
);
|
119
|
+
filteredRefs.forEach((ref) => (INSTALL_ATTEMPTED[ref] = true));
|
141
120
|
//Auto-install missing asset
|
142
121
|
try {
|
143
122
|
//We change to a temp dir to avoid issues with the current working directory
|
@@ -148,16 +127,12 @@ class RepositoryManager {
|
|
148
127
|
type: 'start',
|
149
128
|
refs,
|
150
129
|
});
|
151
|
-
await Actions.install(
|
152
|
-
progressListener,
|
153
|
-
normalizedRefs,
|
154
|
-
{}
|
155
|
-
);
|
130
|
+
await Actions.install(progressListener, normalizedRefs, {});
|
156
131
|
socketManager.emit(`install`, 'install:action', {
|
157
132
|
type: 'done',
|
158
133
|
refs,
|
159
134
|
});
|
160
|
-
} catch (e) {
|
135
|
+
} catch (e: any) {
|
161
136
|
socketManager.emit(`install`, 'install:action', {
|
162
137
|
type: 'failed',
|
163
138
|
refs,
|
@@ -189,27 +164,27 @@ class RepositoryManager {
|
|
189
164
|
try {
|
190
165
|
while (this._installQueue.length > 0) {
|
191
166
|
const item = this._installQueue.shift();
|
192
|
-
|
193
|
-
|
167
|
+
if (item) {
|
168
|
+
await item();
|
169
|
+
}
|
194
170
|
}
|
195
171
|
} finally {
|
196
172
|
this._processing = false;
|
197
173
|
}
|
198
174
|
}
|
199
175
|
|
200
|
-
async ensureAsset(handle, name, version) {
|
176
|
+
async ensureAsset(handle: string, name: string, version: string) {
|
201
177
|
const fullName = `${handle}/${name}`;
|
202
178
|
const ref = `${fullName}:${version}`;
|
203
179
|
|
204
180
|
if (version === 'local') {
|
205
181
|
//TODO: Get dependencies for local asset
|
206
|
-
return
|
182
|
+
return;
|
207
183
|
}
|
208
184
|
|
209
185
|
const definitions = ClusterConfiguration.getDefinitions();
|
210
186
|
const installedAsset = definitions.find(
|
211
|
-
(d) =>
|
212
|
-
d.definition.metadata.name === fullName && d.version === version
|
187
|
+
(d) => d.definition.metadata.name === fullName && d.version === version
|
213
188
|
);
|
214
189
|
|
215
190
|
if (installedAsset && this._cache[ref] === true) {
|
@@ -222,10 +197,7 @@ class RepositoryManager {
|
|
222
197
|
|
223
198
|
let assetVersion;
|
224
199
|
try {
|
225
|
-
assetVersion = await this._registryService.getVersion(
|
226
|
-
fullName,
|
227
|
-
version
|
228
|
-
);
|
200
|
+
assetVersion = await this._registryService.getVersion(fullName, version);
|
229
201
|
if (!assetVersion) {
|
230
202
|
this._cache[ref] = false;
|
231
203
|
return;
|
@@ -244,11 +216,11 @@ class RepositoryManager {
|
|
244
216
|
await this._install([ref]);
|
245
217
|
} else {
|
246
218
|
//Ensure dependencies are installed
|
247
|
-
const refs = assetVersion.dependencies.map((dep) => dep.name);
|
219
|
+
const refs = assetVersion.dependencies.map((dep: Dependency) => dep.name);
|
248
220
|
console.log(`Auto-installing dependencies: ${refs.join(', ')}`);
|
249
221
|
await this._install(refs);
|
250
222
|
}
|
251
223
|
}
|
252
224
|
}
|
253
225
|
|
254
|
-
|
226
|
+
export const repositoryManager = new RepositoryManager();
|