@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.
@@ -0,0 +1,117 @@
1
+ const clusterService = require('./clusterService');
2
+ const storageService = require('./storageService');
3
+ const _ = require('lodash');
4
+
5
+ const DEFAULT_PORT_TYPE = 'rest';
6
+
7
+ class ServiceManager {
8
+
9
+ constructor() {
10
+ this._systems = storageService.get("services");
11
+ if (!this._systems) {
12
+ this._systems = {};
13
+ }
14
+
15
+ _.forEach(this._systems, (system) => {
16
+ _.forEach(system, (services) => {
17
+ _.forEach(services, (portInfo) => {
18
+ clusterService.reservePort(portInfo.port);
19
+ });
20
+ });
21
+ });
22
+ }
23
+
24
+ _forLocal(port, path) {
25
+ if (!path) {
26
+ path = '';
27
+ }
28
+ const host = clusterService.getClusterServiceHost();
29
+
30
+ if (path.startsWith('/')) {
31
+ path = path.substr(1);
32
+ }
33
+ return `http://${host}:${port}/${path}`;
34
+ }
35
+
36
+ _ensureSystem(systemId) {
37
+ if (!this._systems[systemId]) {
38
+ this._systems[systemId] = {};
39
+ }
40
+
41
+ return this._systems[systemId];
42
+ }
43
+
44
+ _ensureService(systemId, serviceId) {
45
+
46
+ const system = this._ensureSystem(systemId);
47
+
48
+ if (!system[serviceId]) {
49
+ system[serviceId] = {};
50
+ }
51
+
52
+ return system[serviceId];
53
+ }
54
+
55
+ async ensureServicePort(systemId, blockInstanceId, portType) {
56
+ if (!portType) {
57
+ portType = DEFAULT_PORT_TYPE;
58
+ }
59
+
60
+ const service = this._ensureService(systemId, blockInstanceId);
61
+
62
+ if (!service[portType]) {
63
+ const port = await clusterService.getNextAvailablePort();
64
+ service[portType] = {port};
65
+ this._save();
66
+ }
67
+
68
+ const portTypeSection = service[portType];
69
+
70
+
71
+ return portTypeSection.port;
72
+ }
73
+
74
+ _save() {
75
+ storageService.put("services", this._systems);
76
+ }
77
+
78
+ /**
79
+ * Gets the consumable address of a service block resource
80
+ *
81
+ * This returns a local proxy path to allow traffic inspection and control.
82
+ *
83
+ * @param {string} systemId
84
+ * @param {string} consumerInstanceId
85
+ * @param {string} consumerResourceName
86
+ * @param {string} portType
87
+ * @return {string}
88
+ */
89
+ getConsumerAddress(systemId, consumerInstanceId, consumerResourceName, portType) {
90
+ const port = clusterService.getClusterServicePort();
91
+ const path = clusterService.getProxyPath(systemId, consumerInstanceId, consumerResourceName, portType);
92
+ return this._forLocal(port, path);
93
+ }
94
+
95
+ /**
96
+ * Gets the direct address of a service block
97
+ *
98
+ * This returns the actual endpoint address of a service that we're talking to.
99
+ * For local services this address will be on localhost - for remote services it will
100
+ * be their remotely available address.
101
+ *
102
+ * @param {string} systemId
103
+ * @param {string} providerInstanceId
104
+ * @param {string} portType
105
+ * @return {Promise<string>}
106
+ */
107
+ async getProviderAddress(systemId, providerInstanceId, portType) {
108
+ const port = await this.ensureServicePort(systemId, providerInstanceId, portType);
109
+ return this._forLocal(port)
110
+ }
111
+
112
+ getServices() {
113
+ return this._systems;
114
+ }
115
+ }
116
+
117
+ module.exports = new ServiceManager();
@@ -0,0 +1,50 @@
1
+ const _ = require('lodash');
2
+
3
+ class SocketManager {
4
+
5
+ constructor() {
6
+ this._io = null;
7
+ this._sockets = [];
8
+ return this;
9
+ }
10
+
11
+ setIo(io) {
12
+ console.log("socket ready");
13
+ this._io = io;
14
+
15
+ this._bindIO();
16
+ }
17
+
18
+ emit(context, type, payload) {
19
+ this._io.to(context).emit(type, {context, payload});
20
+ }
21
+
22
+ _bindIO() {
23
+ this._io.on('connection', (socket) => this._handleSocketCreated(socket))
24
+ }
25
+
26
+ _handleSocketCreated(socket) {
27
+ this._bindSocket(socket);
28
+ this._sockets.push(socket);
29
+ }
30
+
31
+ _bindSocket(socket) {
32
+ socket.on('disconnect', () => this._handleSocketDestroyed(socket))
33
+ socket.on('join', (id) => {
34
+ console.log("socket joined ", id);
35
+ socket.join(id);
36
+ })
37
+ socket.on('leave', (id) => {
38
+ console.log("socket left ", id);
39
+ socket.leave(id);
40
+ })
41
+ }
42
+
43
+ _handleSocketDestroyed(socket) {
44
+ _.pull(this._sockets, socket);
45
+ }
46
+
47
+ }
48
+
49
+
50
+ module.exports = new SocketManager();
@@ -0,0 +1,87 @@
1
+ const _ = require('lodash');
2
+ const FS = require('fs');
3
+ const mkdirp = require('mkdirp');
4
+ const YAML = require('yaml');
5
+ const ClusterConfiguration = require('@kapeta/local-cluster-config');
6
+
7
+ /**
8
+ * Class that handles reading and writing from local configuration file.
9
+ */
10
+ class StorageService {
11
+
12
+ constructor() {
13
+ this._data = this._readConfig();
14
+ }
15
+
16
+ getKapetaBasedir() {
17
+ return ClusterConfiguration.getKapetaBasedir();
18
+ }
19
+
20
+ _readConfig() {
21
+ return ClusterConfiguration.getClusterConfig();
22
+ }
23
+
24
+ _writeConfig() {
25
+ const configFile = ClusterConfiguration.getClusterConfigFile();
26
+
27
+ mkdirp.sync(this.getKapetaBasedir());
28
+
29
+ FS.writeFileSync(configFile, YAML.stringify(this._data));
30
+ }
31
+
32
+ section(section, defaultValue) {
33
+ if (!defaultValue) {
34
+ defaultValue = {};
35
+ }
36
+ if (!this._data[section]) {
37
+ this._data[section] = defaultValue;
38
+ this._writeConfig();
39
+ }
40
+
41
+ return this._data[section];
42
+ }
43
+
44
+ put(section, property, value) {
45
+ if (!_.isString(property)) {
46
+ this._data[section] = property;
47
+ this._writeConfig();
48
+ return;
49
+ }
50
+
51
+ this.section(section)[property] = value;
52
+ this._writeConfig();
53
+ }
54
+
55
+ get(section, property) {
56
+ if (!property) {
57
+ return this.section(section);
58
+ }
59
+
60
+ return this.section(section)[property];
61
+ }
62
+
63
+ contains(section, property) {
64
+ if (!this._data[section]) {
65
+ return false;
66
+ }
67
+
68
+ return this._data[section].hasOwnProperty(property);
69
+ }
70
+
71
+ ensure(section, property, value) {
72
+ if (this.contains(section, property)) {
73
+ return this.get(section, property);
74
+ }
75
+
76
+ let out = value;
77
+ if (typeof value === 'function') {
78
+ out = value();
79
+ }
80
+
81
+ this.put(section, property, out);
82
+
83
+ return out;
84
+ }
85
+ }
86
+
87
+ module.exports = new StorageService();
@@ -0,0 +1,18 @@
1
+ const Router = require('express-promise-router').default;
2
+ const router = new Router();
3
+ const networkManager = require('../networkManager');
4
+
5
+ router.get('/:systemId/target/:connectionId/', (req, res) => {
6
+ res.send(networkManager.getTrafficForConnection(req.params.systemId, req.params.connectionId));
7
+ });
8
+
9
+ router.get('/:systemId/source/:blockInstanceId/', (req, res) => {
10
+ res.send(networkManager.getTrafficForSource(req.params.systemId, req.params.blockInstanceId));
11
+ });
12
+
13
+ router.get('/:systemId/target/:blockInstanceId/', (req, res) => {
14
+ res.send(networkManager.getTrafficForTarget(req.params.systemId, req.params.blockInstanceId));
15
+ });
16
+
17
+
18
+ module.exports = router;
@@ -0,0 +1,116 @@
1
+
2
+ const TYPE_VARIABLE = 'variable';
3
+ const TYPE_PATH = 'path';
4
+
5
+ class PathTemplate {
6
+ constructor(pathTemplate) {
7
+ if (!pathTemplate.startsWith('/')) {
8
+ pathTemplate = '/' + pathTemplate;
9
+ }
10
+ this._path = pathTemplate;
11
+
12
+ this._parts = pathTemplate.split(/{/g).map((part) => {
13
+ if (part.endsWith('}')) {
14
+ let regex,
15
+ value = part.substr(0, part.length - 1);
16
+
17
+ [value, regex] = value.split(/:/, 2);
18
+
19
+ if (regex) {
20
+ regex = new RegExp('^' + regex);
21
+ } else {
22
+ regex = /^[^\/]+/
23
+ }
24
+
25
+ return {
26
+ type: TYPE_VARIABLE,
27
+ value,
28
+ regex
29
+ };
30
+ }
31
+
32
+ return {
33
+ type: TYPE_PATH,
34
+ value: part
35
+ };
36
+ });
37
+
38
+
39
+ }
40
+
41
+ get path() {
42
+ return this._path;
43
+ }
44
+
45
+ matches(path) {
46
+ return this.parse(path) !== null;
47
+ }
48
+
49
+ parse(path) {
50
+ if (!path.startsWith('/')) {
51
+ path = '/' + path;
52
+ }
53
+
54
+ const values = {};
55
+
56
+ for(let i = 0 ; i < this._parts.length; i++) {
57
+ const part = this._parts[i];
58
+ switch (part.type) {
59
+ case TYPE_PATH:
60
+ if (!path.startsWith(part.value)) {
61
+ return null;
62
+ }
63
+
64
+ path = path.substr(part.value.length);
65
+ break;
66
+ case TYPE_VARIABLE:
67
+ if (!part.regex.test(path)) {
68
+ return null;
69
+ }
70
+
71
+ const newPath = path.replace(part.regex,'');
72
+ const value = path.substr(0, path.length - newPath.length);
73
+ values[part.value] = value;
74
+ path = newPath;
75
+ break;
76
+ }
77
+ }
78
+
79
+ if (path && path !== '/') {
80
+ //We did not match all of it
81
+ return null;
82
+ }
83
+
84
+ return values;
85
+ }
86
+
87
+ create(variables) {
88
+ return this._parts.map((part) => {
89
+ switch (part.type) {
90
+ case TYPE_PATH:
91
+ return part.value;
92
+ case TYPE_VARIABLE:
93
+ if (variables[part.value] === undefined ||
94
+ variables[part.value] === null ) {
95
+ return ''
96
+ }
97
+
98
+ return variables[part.value];
99
+ }
100
+ }).join('');
101
+ }
102
+
103
+ toString() {
104
+ return 'tmpl: ' + this.path
105
+ }
106
+ }
107
+
108
+ /**
109
+ * Parses a path into a RESTPath
110
+ * @param {string} path
111
+ */
112
+ function pathTemplateParser(path) {
113
+ return new PathTemplate(path);
114
+ }
115
+
116
+ module.exports = pathTemplateParser;
package/start.js ADDED
@@ -0,0 +1,7 @@
1
+ const localClusterService = require('./index.js');
2
+
3
+ localClusterService.start()
4
+ .then(({host,port}) => console.log('Listening on port %s:%s', host, port))
5
+ .catch(e => {
6
+ console.error('Failed to start local cluster due to an error:\n\t - %s', e.toString())
7
+ });