@kapeta/local-cluster-service 0.0.60
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/.github/workflows/pr-check.yml +18 -0
- package/.github/workflows/publish.yml +20 -0
- package/.vscode/launch.json +17 -0
- package/LICENSE +21 -0
- package/README.md +32 -0
- package/definitions.d.ts +42 -0
- package/index.js +127 -0
- package/package.json +45 -0
- package/src/assetManager.js +249 -0
- package/src/assets/routes.js +133 -0
- package/src/clusterService.js +134 -0
- package/src/codeGeneratorManager.js +40 -0
- package/src/config/routes.js +118 -0
- package/src/configManager.js +128 -0
- package/src/containerManager.js +279 -0
- package/src/filesystem/routes.js +74 -0
- package/src/filesystemManager.js +89 -0
- package/src/identities/routes.js +19 -0
- package/src/instanceManager.js +416 -0
- package/src/instances/routes.js +117 -0
- package/src/middleware/cors.js +7 -0
- package/src/middleware/kapeta.js +20 -0
- package/src/middleware/stringBody.js +11 -0
- package/src/networkManager.js +120 -0
- package/src/operatorManager.js +180 -0
- package/src/providerManager.js +84 -0
- package/src/providers/routes.js +26 -0
- package/src/proxy/routes.js +125 -0
- package/src/proxy/types/rest.js +163 -0
- package/src/proxy/types/web.js +83 -0
- package/src/serviceManager.js +117 -0
- package/src/socketManager.js +50 -0
- package/src/storageService.js +87 -0
- package/src/traffic/routes.js +18 -0
- package/src/utils/pathTemplateParser.js +116 -0
- package/start.js +7 -0
@@ -0,0 +1,180 @@
|
|
1
|
+
const ClusterConfiguration = require('@kapeta/local-cluster-config');
|
2
|
+
const serviceManager = require('./serviceManager');
|
3
|
+
const storageService = require('./storageService');
|
4
|
+
const containerManager = require('./containerManager');
|
5
|
+
const _ = require('lodash');
|
6
|
+
const mkdirp = require('mkdirp');
|
7
|
+
const Path = require('path');
|
8
|
+
const md5 = require('md5');
|
9
|
+
|
10
|
+
const KIND_OPERATOR = 'core/resource-type-operator';
|
11
|
+
|
12
|
+
class Operator {
|
13
|
+
constructor(data) {
|
14
|
+
this._data = data;
|
15
|
+
}
|
16
|
+
|
17
|
+
getData() {
|
18
|
+
return this._data;
|
19
|
+
}
|
20
|
+
|
21
|
+
getCredentials() {
|
22
|
+
return this._data.credentials;
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
class OperatorManager {
|
27
|
+
|
28
|
+
constructor() {
|
29
|
+
this._mountDir = Path.join(storageService.getKapetaBasedir(), 'mounts');
|
30
|
+
|
31
|
+
mkdirp.sync(this._mountDir);
|
32
|
+
}
|
33
|
+
|
34
|
+
_getMountPoint(operatorType, mountName) {
|
35
|
+
return Path.join(this._mountDir, operatorType, mountName);
|
36
|
+
}
|
37
|
+
|
38
|
+
/**
|
39
|
+
* Get operator definition for resource type
|
40
|
+
*
|
41
|
+
* @param resourceType
|
42
|
+
* @return {Operator}
|
43
|
+
*/
|
44
|
+
getOperator(resourceType) {
|
45
|
+
const operators = ClusterConfiguration.getDefinitions(KIND_OPERATOR);
|
46
|
+
|
47
|
+
const operator = _.find(operators, (operator) => operator.definition &&
|
48
|
+
operator.definition.metadata &&
|
49
|
+
operator.definition.metadata.name &&
|
50
|
+
operator.definition.metadata.name.toLowerCase() === resourceType.toLowerCase());
|
51
|
+
|
52
|
+
if (!operator) {
|
53
|
+
throw new Error('Unknown resource type: ' + resourceType);
|
54
|
+
}
|
55
|
+
|
56
|
+
if (!operator.definition.spec ||
|
57
|
+
!operator.definition.spec.local) {
|
58
|
+
throw new Error('Operator missing local definition: ' + resourceType);
|
59
|
+
}
|
60
|
+
|
61
|
+
return new Operator(operator.definition.spec.local);
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* Get information about a specific resource
|
66
|
+
*
|
67
|
+
* @param {string} systemId
|
68
|
+
* @param {string} fromServiceId
|
69
|
+
* @param {string} resourceType
|
70
|
+
* @param {string} portType
|
71
|
+
* @param {string} name
|
72
|
+
* @returns {Promise<{host: string, port: (*|string), type: *, protocol: *, credentials: *}>}
|
73
|
+
*/
|
74
|
+
async getResourceInfo(systemId, fromServiceId, resourceType, portType, name) {
|
75
|
+
|
76
|
+
const operator = this.getOperator(resourceType);
|
77
|
+
|
78
|
+
const credentials = operator.getCredentials();
|
79
|
+
|
80
|
+
const container = await this.ensureResource(systemId, resourceType);
|
81
|
+
|
82
|
+
const portInfo = await container.getPort(portType);
|
83
|
+
|
84
|
+
if (!portInfo) {
|
85
|
+
throw new Error('Unknown resource port type : ' + resourceType + '#' + portType);
|
86
|
+
}
|
87
|
+
|
88
|
+
const dbName = name + '_' + fromServiceId.replace(/[^a-z0-9]/gi, '');
|
89
|
+
|
90
|
+
return {
|
91
|
+
host: 'localhost',
|
92
|
+
port: portInfo.hostPort,
|
93
|
+
type: portType,
|
94
|
+
protocol: portInfo.protocol,
|
95
|
+
options: {
|
96
|
+
dbName
|
97
|
+
},
|
98
|
+
credentials
|
99
|
+
};
|
100
|
+
}
|
101
|
+
|
102
|
+
/**
|
103
|
+
* Ensure we have a running operator of given type
|
104
|
+
*
|
105
|
+
* @param systemId
|
106
|
+
* @param resourceType
|
107
|
+
* @return {Promise<ContainerInfo>}
|
108
|
+
*/
|
109
|
+
async ensureResource(systemId, resourceType) {
|
110
|
+
const operator = this.getOperator(resourceType);
|
111
|
+
|
112
|
+
const operatorData = operator.getData();
|
113
|
+
|
114
|
+
const portTypes = Object.keys(operatorData.ports);
|
115
|
+
|
116
|
+
portTypes.sort();
|
117
|
+
|
118
|
+
const containerBaseName = 'kapeta-resource';
|
119
|
+
|
120
|
+
const nameParts = [resourceType.toLowerCase()];
|
121
|
+
|
122
|
+
const ports = {};
|
123
|
+
|
124
|
+
for(let i = 0 ; i < portTypes.length; i++) {
|
125
|
+
const portType = portTypes[i];
|
126
|
+
let containerPortInfo = operatorData.ports[portType];
|
127
|
+
const hostPort = await serviceManager.ensureServicePort(resourceType, portType);
|
128
|
+
|
129
|
+
if (typeof containerPortInfo === 'number' ||
|
130
|
+
typeof containerPortInfo === 'string') {
|
131
|
+
containerPortInfo = {port: containerPortInfo, type: 'tcp'};
|
132
|
+
}
|
133
|
+
|
134
|
+
if (!containerPortInfo.type) {
|
135
|
+
containerPortInfo.type = 'tcp';
|
136
|
+
}
|
137
|
+
|
138
|
+
const portId = containerPortInfo.port + '/' + containerPortInfo.type;
|
139
|
+
nameParts.push(portType + '-' + portId + '-' + hostPort);
|
140
|
+
|
141
|
+
ports[portId] = {
|
142
|
+
type: portType,
|
143
|
+
hostPort
|
144
|
+
};
|
145
|
+
}
|
146
|
+
|
147
|
+
const mounts = {};
|
148
|
+
|
149
|
+
_.forEach(operatorData.mounts, (containerPath, mountName) => {
|
150
|
+
const hostPath = this._getMountPoint(resourceType, mountName);
|
151
|
+
mkdirp.sync(hostPath);
|
152
|
+
mounts[containerPath] = hostPath;
|
153
|
+
});
|
154
|
+
|
155
|
+
const containerName = containerBaseName + '-' + md5(nameParts.join('_'));
|
156
|
+
let container = await containerManager.get(containerName);
|
157
|
+
|
158
|
+
const isRunning = container ? await container.isRunning() : false;
|
159
|
+
if (container && !isRunning) {
|
160
|
+
await container.start();
|
161
|
+
}
|
162
|
+
|
163
|
+
if (!container) {
|
164
|
+
|
165
|
+
container = await containerManager.run(
|
166
|
+
operatorData.image,
|
167
|
+
containerName,
|
168
|
+
{
|
169
|
+
mounts,
|
170
|
+
ports,
|
171
|
+
health: operatorData.health,
|
172
|
+
env: operatorData.env
|
173
|
+
});
|
174
|
+
}
|
175
|
+
|
176
|
+
return container;
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
module.exports = new OperatorManager();
|
@@ -0,0 +1,84 @@
|
|
1
|
+
const _ = require('lodash');
|
2
|
+
const FS = require('fs');
|
3
|
+
const Path = require('path');
|
4
|
+
const Glob = require("glob");
|
5
|
+
|
6
|
+
const ClusterConfiguration = require('@kapeta/local-cluster-config');
|
7
|
+
|
8
|
+
class ProviderManager {
|
9
|
+
|
10
|
+
constructor() {
|
11
|
+
this._assetCache = {};
|
12
|
+
}
|
13
|
+
|
14
|
+
getWebProviders() {
|
15
|
+
return ClusterConfiguration
|
16
|
+
.getProviderDefinitions()
|
17
|
+
.filter((providerDefinition) => providerDefinition.hasWeb)
|
18
|
+
}
|
19
|
+
|
20
|
+
getWebAssets() {
|
21
|
+
const webProviders = this.getWebProviders();
|
22
|
+
|
23
|
+
let providerFiles = [];
|
24
|
+
webProviders.map((webProvider) => {
|
25
|
+
return Glob.sync('web/**/*.js', {cwd: webProvider.path}).map((file) => {
|
26
|
+
return {webProvider, file};
|
27
|
+
});
|
28
|
+
}).forEach((webFiles) => {
|
29
|
+
providerFiles.push(...webFiles);
|
30
|
+
});
|
31
|
+
|
32
|
+
return providerFiles;
|
33
|
+
}
|
34
|
+
|
35
|
+
loadAssets() {
|
36
|
+
this.getWebAssets().forEach((asset) => {
|
37
|
+
const providerId = asset.webProvider.definition.metadata.name;
|
38
|
+
const file = asset.file;
|
39
|
+
const assetId = `${providerId}/${asset.webProvider.version}/${file}`;
|
40
|
+
this._assetCache[assetId] = Path.join(asset.webProvider.path, file);
|
41
|
+
})
|
42
|
+
}
|
43
|
+
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Returns all public (web) javascript for available providers.
|
47
|
+
*
|
48
|
+
* Provides frontend / applications with the implementation of the frontends for the
|
49
|
+
* providers.
|
50
|
+
*
|
51
|
+
*/
|
52
|
+
getPublicJS() {
|
53
|
+
this.loadAssets();
|
54
|
+
const includes = Object.keys(this._assetCache).map((assetId) => {
|
55
|
+
return `${ClusterConfiguration.getClusterServiceAddress()}/providers/asset/${assetId}`
|
56
|
+
});
|
57
|
+
|
58
|
+
return `Kapeta.setPluginPaths(${JSON.stringify(includes)});`
|
59
|
+
}
|
60
|
+
|
61
|
+
getAsset(id) {
|
62
|
+
if (_.isEmpty(this._assetCache)) {
|
63
|
+
this.loadAssets();
|
64
|
+
}
|
65
|
+
if (this._assetCache[id]) {
|
66
|
+
return FS.readFileSync(this._assetCache[id]).toString();
|
67
|
+
}
|
68
|
+
return null;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
const providerDefinitions = ClusterConfiguration.getProviderDefinitions();
|
73
|
+
|
74
|
+
if (providerDefinitions.length > 0) {
|
75
|
+
console.log('## Loaded the following providers ##');
|
76
|
+
providerDefinitions.forEach(providerDefinition => {
|
77
|
+
console.log(' - %s[%s:%s]', providerDefinition.definition.kind, providerDefinition.definition.metadata.name, providerDefinition.version);
|
78
|
+
console.log(' from %s', providerDefinition.path);
|
79
|
+
})
|
80
|
+
} else {
|
81
|
+
console.log('## No providers found ##');
|
82
|
+
}
|
83
|
+
|
84
|
+
module.exports = new ProviderManager();
|
@@ -0,0 +1,26 @@
|
|
1
|
+
const Router = require('express-promise-router').default;
|
2
|
+
const providerManager = require('../providerManager');
|
3
|
+
|
4
|
+
const router = new Router();
|
5
|
+
|
6
|
+
router.use('/', require('../middleware/cors'));
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Get all local assets available
|
10
|
+
*/
|
11
|
+
router.get('/all.js', (req, res) => {
|
12
|
+
res.send(providerManager.getPublicJS());
|
13
|
+
});
|
14
|
+
|
15
|
+
router.get('/asset/*', (req, res) => {
|
16
|
+
const assetId = req.params[0];
|
17
|
+
const result = providerManager.getAsset(assetId)
|
18
|
+
if (!result) {
|
19
|
+
res.status(404).send('');
|
20
|
+
} else {
|
21
|
+
res.send(result);
|
22
|
+
}
|
23
|
+
});
|
24
|
+
|
25
|
+
|
26
|
+
module.exports = router;
|
@@ -0,0 +1,125 @@
|
|
1
|
+
const Router = require('express-promise-router').default;
|
2
|
+
const _ = require('lodash');
|
3
|
+
|
4
|
+
const router = new Router();
|
5
|
+
const serviceManager = require('../serviceManager');
|
6
|
+
const clusterService = require('../clusterService');
|
7
|
+
const assetManager = require('../assetManager');
|
8
|
+
|
9
|
+
/**
|
10
|
+
* @var {{[key:string]:ProxyRequestHandler}}
|
11
|
+
*/
|
12
|
+
const TYPE_HANDLERS = {
|
13
|
+
rest: require('./types/rest'),
|
14
|
+
web: require('./types/web')
|
15
|
+
};
|
16
|
+
|
17
|
+
function getResource(resources, resourceName) {
|
18
|
+
return _.find(resources, (resource) => {
|
19
|
+
return (resource.metadata.name.toLowerCase() === resourceName.toLowerCase());
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
router.use('/:systemId/:consumerInstanceId/:consumerResourceName', require('../middleware/stringBody'));
|
24
|
+
|
25
|
+
router.all('/:systemId/:consumerInstanceId/:consumerResourceName/:type/*', async (req, res) => {
|
26
|
+
|
27
|
+
try {
|
28
|
+
|
29
|
+
const typeHandler = TYPE_HANDLERS[req.params.type.toLowerCase()];
|
30
|
+
if (!typeHandler) {
|
31
|
+
res.status(401).send({error: 'Unknown connection type: ' + req.params.type});
|
32
|
+
return;
|
33
|
+
}
|
34
|
+
|
35
|
+
const plan = await assetManager.getPlan(req.params.systemId);
|
36
|
+
|
37
|
+
// We can find the connection by the consumer information alone since
|
38
|
+
// only 1 provider can be connected to a consumer resource at a time
|
39
|
+
const connection = _.find(plan.spec.connections, (connection) => {
|
40
|
+
return connection.to.blockId.toLowerCase() === req.params.consumerInstanceId.toLowerCase() &&
|
41
|
+
connection.to.resourceName.toLowerCase() === req.params.consumerResourceName.toLowerCase();
|
42
|
+
});
|
43
|
+
|
44
|
+
if (!connection) {
|
45
|
+
res.status(401).send({error:`No connection found for consumer "${req.params.consumerInstanceId}::${req.params.consumerResourceName}"`});
|
46
|
+
return;
|
47
|
+
}
|
48
|
+
|
49
|
+
const toBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
50
|
+
return blockInstance.id.toLowerCase() === connection.to.blockId.toLowerCase();
|
51
|
+
});
|
52
|
+
|
53
|
+
if (!toBlockInstance) {
|
54
|
+
res.status(401).send({error:`Block instance not found "${req.params.consumerInstanceId}`});
|
55
|
+
return;
|
56
|
+
}
|
57
|
+
|
58
|
+
const toBlockAsset = await assetManager.getAsset(toBlockInstance.block.ref);
|
59
|
+
|
60
|
+
const toResource = getResource(toBlockAsset.data.spec.consumers, req.params.consumerResourceName);
|
61
|
+
|
62
|
+
if (!toResource) {
|
63
|
+
res.status(401).send({error:`Block resource not found "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`});
|
64
|
+
return;
|
65
|
+
}
|
66
|
+
|
67
|
+
const basePath = clusterService.getProxyPath(
|
68
|
+
req.params.systemId,
|
69
|
+
req.params.consumerInstanceId,
|
70
|
+
req.params.consumerResourceName,
|
71
|
+
req.params.type
|
72
|
+
);
|
73
|
+
|
74
|
+
/*
|
75
|
+
Get the path the consumer requested.
|
76
|
+
Note that this might not match the path the destination is expecting so we need to identify the method
|
77
|
+
that is being called and identify the destination path from the connection.
|
78
|
+
*/
|
79
|
+
const consumerPath = req.originalUrl.substr(basePath.length - 1);
|
80
|
+
|
81
|
+
const fromBlockInstance = _.find(plan.spec.blocks, (blockInstance) => {
|
82
|
+
return blockInstance.id.toLowerCase() === connection.from.blockId.toLowerCase();
|
83
|
+
});
|
84
|
+
|
85
|
+
if (!fromBlockInstance) {
|
86
|
+
res.status(401).send({error:`Block instance not found "${connection.from.blockId}`});
|
87
|
+
return;
|
88
|
+
}
|
89
|
+
|
90
|
+
const fromBlockAsset = await assetManager.getAsset(fromBlockInstance.block.ref);
|
91
|
+
|
92
|
+
const fromResource = getResource(fromBlockAsset.data.spec.providers, connection.from.resourceName);
|
93
|
+
|
94
|
+
if (!fromResource) {
|
95
|
+
res.status(401).send({error:`Block resource not found "${connection.from.blockId}::${connection.from.resourceName}`});
|
96
|
+
return;
|
97
|
+
}
|
98
|
+
|
99
|
+
|
100
|
+
//Get target address
|
101
|
+
let address = await serviceManager.getProviderAddress(
|
102
|
+
req.params.systemId,
|
103
|
+
connection.from.blockId,
|
104
|
+
req.params.type
|
105
|
+
);
|
106
|
+
|
107
|
+
while(address.endsWith('/')) {
|
108
|
+
address = address.substr(0, address.length - 1);
|
109
|
+
}
|
110
|
+
|
111
|
+
typeHandler(req, res, {
|
112
|
+
consumerPath,
|
113
|
+
address,
|
114
|
+
toResource,
|
115
|
+
fromResource,
|
116
|
+
connection
|
117
|
+
});
|
118
|
+
|
119
|
+
} catch(err) {
|
120
|
+
res.status(400).send({error: err.message});
|
121
|
+
}
|
122
|
+
|
123
|
+
});
|
124
|
+
|
125
|
+
module.exports = router;
|
@@ -0,0 +1,163 @@
|
|
1
|
+
const request = require('request');
|
2
|
+
const Path = require('path');
|
3
|
+
const _ = require('lodash');
|
4
|
+
|
5
|
+
const pathTemplateParser = require('../../utils/pathTemplateParser');
|
6
|
+
const networkManager = require('../../networkManager');
|
7
|
+
const socketManager = require('../../socketManager');
|
8
|
+
|
9
|
+
|
10
|
+
function getRestMethodId(restResource, httpMethod, httpPath) {
|
11
|
+
return _.findKey(restResource.spec.methods, (method) => {
|
12
|
+
let methodType = method.method ? method.method.toUpperCase() : 'GET';
|
13
|
+
|
14
|
+
if (methodType !== httpMethod.toUpperCase()) {
|
15
|
+
return false;
|
16
|
+
}
|
17
|
+
|
18
|
+
let path = method.path;
|
19
|
+
|
20
|
+
if (restResource.spec.basePath) {
|
21
|
+
path = Path.join(restResource.spec.basePath, path);
|
22
|
+
}
|
23
|
+
|
24
|
+
const pathTemplate = pathTemplateParser(path);
|
25
|
+
|
26
|
+
return pathTemplate.matches(httpPath);
|
27
|
+
|
28
|
+
});
|
29
|
+
}
|
30
|
+
|
31
|
+
/**
|
32
|
+
*
|
33
|
+
* @param req {Request}
|
34
|
+
* @param opts {ProxyRequestInfo}
|
35
|
+
* @return {{consumerMethod: *, providerMethod: *}}
|
36
|
+
*/
|
37
|
+
function resolveMethods(req, opts) {
|
38
|
+
const consumerMethodId = getRestMethodId(opts.toResource, req.method, opts.consumerPath);
|
39
|
+
|
40
|
+
if (!consumerMethodId) {
|
41
|
+
throw new Error(
|
42
|
+
`Consumer method not found for path "${req.method} ${opts.consumerPath}" in resource "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`
|
43
|
+
);
|
44
|
+
}
|
45
|
+
|
46
|
+
const consumerMethod = _.cloneDeep(opts.toResource.spec.methods[consumerMethodId]);
|
47
|
+
|
48
|
+
if (!consumerMethod) {
|
49
|
+
throw new Error(
|
50
|
+
`Consumer method not found for path "${req.method} ${opts.consumerPath}" in resource "${req.params.consumerInstanceId}::${req.params.consumerResourceName}`
|
51
|
+
);
|
52
|
+
}
|
53
|
+
|
54
|
+
consumerMethod.id = consumerMethodId;
|
55
|
+
|
56
|
+
const providerMethodId = _.findKey(opts.connection.mapping, (mapping) => {
|
57
|
+
return mapping.targetId === consumerMethodId;
|
58
|
+
});
|
59
|
+
|
60
|
+
if (!providerMethodId) {
|
61
|
+
throw new Error(`Connection contained no mapping for consumer method "${consumerMethodId}`);
|
62
|
+
}
|
63
|
+
|
64
|
+
const providerMethod = _.cloneDeep(opts.fromResource.spec.methods[providerMethodId]);
|
65
|
+
|
66
|
+
if (!providerMethod) {
|
67
|
+
throw new Error(
|
68
|
+
`Provider method not found "${providerMethodId}" in resource "${opts.connection.from.blockId}::${opts.connection.from.resourceName}`
|
69
|
+
);
|
70
|
+
}
|
71
|
+
|
72
|
+
providerMethod.id = providerMethodId;
|
73
|
+
|
74
|
+
return {
|
75
|
+
consumerMethod,
|
76
|
+
providerMethod
|
77
|
+
};
|
78
|
+
}
|
79
|
+
|
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);
|
89
|
+
|
90
|
+
const consumerPathTemplate = pathTemplateParser(consumerMethod.path);
|
91
|
+
const providerPathTemplate = pathTemplateParser(providerMethod.path);
|
92
|
+
|
93
|
+
const pathVariables = consumerPathTemplate.parse(opts.consumerPath);
|
94
|
+
|
95
|
+
let providerPath = providerPathTemplate.create(pathVariables);
|
96
|
+
|
97
|
+
if (!providerPath.startsWith('/')) {
|
98
|
+
providerPath = '/' + providerPath;
|
99
|
+
}
|
100
|
+
|
101
|
+
const requestHeaders = _.clone(req.headers);
|
102
|
+
|
103
|
+
delete requestHeaders['content-length'];
|
104
|
+
delete requestHeaders['content-encoding'];
|
105
|
+
delete requestHeaders['connection'];
|
106
|
+
delete requestHeaders['host'];
|
107
|
+
delete requestHeaders['origin'];
|
108
|
+
|
109
|
+
|
110
|
+
console.log('Route to provider: %s => %s', opts.consumerPath, opts.address + providerPath);
|
111
|
+
|
112
|
+
const reqOpts = {
|
113
|
+
method: providerMethod.method || 'GET',
|
114
|
+
url: opts.address + providerPath,
|
115
|
+
body: req.stringBody,
|
116
|
+
headers: requestHeaders
|
117
|
+
};
|
118
|
+
|
119
|
+
const traffic = networkManager.addRequest(
|
120
|
+
req.params.systemId,
|
121
|
+
opts.connection,
|
122
|
+
reqOpts,
|
123
|
+
consumerMethod.id,
|
124
|
+
providerMethod.id
|
125
|
+
);
|
126
|
+
|
127
|
+
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
128
|
+
|
129
|
+
request(reqOpts, function(err, response, responseBody) {
|
130
|
+
if (err) {
|
131
|
+
traffic.asError(err);
|
132
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
133
|
+
|
134
|
+
res.status(500).send({error: '' + err});
|
135
|
+
return;
|
136
|
+
}
|
137
|
+
|
138
|
+
const responseHeaders = _.clone(response.headers);
|
139
|
+
|
140
|
+
delete responseHeaders['content-length'];
|
141
|
+
delete responseHeaders['content-encoding'];
|
142
|
+
delete responseHeaders['connection'];
|
143
|
+
|
144
|
+
res.set(responseHeaders);
|
145
|
+
|
146
|
+
res.status(response.statusCode);
|
147
|
+
|
148
|
+
traffic.withResponse({
|
149
|
+
code: response.statusCode,
|
150
|
+
headers: response.headers,
|
151
|
+
body: responseBody
|
152
|
+
});
|
153
|
+
|
154
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
155
|
+
|
156
|
+
if (responseBody) {
|
157
|
+
res.send(responseBody);
|
158
|
+
} else {
|
159
|
+
res.end();
|
160
|
+
}
|
161
|
+
});
|
162
|
+
|
163
|
+
};
|
@@ -0,0 +1,83 @@
|
|
1
|
+
const request = require('request');
|
2
|
+
const _ = require('lodash');
|
3
|
+
|
4
|
+
const networkManager = require('../../networkManager');
|
5
|
+
const socketManager = require('../../socketManager');
|
6
|
+
|
7
|
+
/**
|
8
|
+
*
|
9
|
+
* @param req {Request}
|
10
|
+
* @param res {Response}
|
11
|
+
* @param opts {ProxyRequestInfo}
|
12
|
+
*/
|
13
|
+
module.exports = function proxyRestRequest(req, res, opts) {
|
14
|
+
|
15
|
+
console.log('Route to provider: %s => %s', opts.consumerPath, opts.address);
|
16
|
+
|
17
|
+
const requestHeaders = _.clone(req.headers);
|
18
|
+
|
19
|
+
delete requestHeaders['content-length'];
|
20
|
+
delete requestHeaders['content-encoding'];
|
21
|
+
delete requestHeaders['connection'];
|
22
|
+
delete requestHeaders['host'];
|
23
|
+
delete requestHeaders['origin'];
|
24
|
+
|
25
|
+
const sourceBasePath = opts.fromResource.spec.path;
|
26
|
+
const targetBasePath = opts.toResource.spec.path;
|
27
|
+
let path = opts.consumerPath;
|
28
|
+
if (opts.consumerPath.startsWith(sourceBasePath)) {
|
29
|
+
path = path.replace(sourceBasePath, targetBasePath);
|
30
|
+
}
|
31
|
+
|
32
|
+
|
33
|
+
const reqOpts = {
|
34
|
+
method: req.method,
|
35
|
+
url: opts.address + path,
|
36
|
+
headers: requestHeaders,
|
37
|
+
body: req.stringBody
|
38
|
+
};
|
39
|
+
|
40
|
+
console.log('reqOpts', reqOpts);
|
41
|
+
|
42
|
+
const traffic = networkManager.addRequest(
|
43
|
+
req.params.systemId,
|
44
|
+
opts.connection,
|
45
|
+
reqOpts
|
46
|
+
);
|
47
|
+
|
48
|
+
socketManager.emit(traffic.connectionId, 'traffic_start', traffic);
|
49
|
+
|
50
|
+
request(reqOpts, function(err, response, responseBody) {
|
51
|
+
if (err) {
|
52
|
+
traffic.asError(err);
|
53
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
54
|
+
|
55
|
+
res.status(500).send({error: '' + err});
|
56
|
+
return;
|
57
|
+
}
|
58
|
+
|
59
|
+
const responseHeaders = _.clone(response.headers);
|
60
|
+
|
61
|
+
delete responseHeaders['content-length'];
|
62
|
+
delete responseHeaders['content-encoding'];
|
63
|
+
delete responseHeaders['connection'];
|
64
|
+
|
65
|
+
res.set(responseHeaders);
|
66
|
+
res.status(response.statusCode);
|
67
|
+
|
68
|
+
traffic.withResponse({
|
69
|
+
code: response.statusCode,
|
70
|
+
headers: response.headers,
|
71
|
+
body: responseBody
|
72
|
+
});
|
73
|
+
|
74
|
+
socketManager.emit(traffic.connectionId, 'traffic_end', traffic);
|
75
|
+
|
76
|
+
if (responseBody) {
|
77
|
+
res.send(responseBody);
|
78
|
+
} else {
|
79
|
+
res.end();
|
80
|
+
}
|
81
|
+
});
|
82
|
+
|
83
|
+
};
|