@kapeta/local-cluster-service 0.0.0-96f91ef
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 +25 -0
- package/.github/workflows/check-license.yml +17 -0
- package/.github/workflows/main.yml +26 -0
- package/.prettierignore +4 -0
- package/.vscode/launch.json +19 -0
- package/CHANGELOG.md +920 -0
- package/LICENSE +38 -0
- package/README.md +36 -0
- package/definitions.d.ts +35 -0
- package/dist/cjs/index.d.ts +34 -0
- package/dist/cjs/index.js +263 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/src/RepositoryWatcher.d.ts +30 -0
- package/dist/cjs/src/RepositoryWatcher.js +332 -0
- package/dist/cjs/src/ai/aiClient.d.ts +20 -0
- package/dist/cjs/src/ai/aiClient.js +74 -0
- package/dist/cjs/src/ai/routes.d.ts +7 -0
- package/dist/cjs/src/ai/routes.js +37 -0
- package/dist/cjs/src/ai/transform.d.ts +11 -0
- package/dist/cjs/src/ai/transform.js +239 -0
- package/dist/cjs/src/ai/types.d.ts +40 -0
- package/dist/cjs/src/ai/types.js +2 -0
- package/dist/cjs/src/api.d.ts +7 -0
- package/dist/cjs/src/api.js +29 -0
- package/dist/cjs/src/assetManager.d.ts +41 -0
- package/dist/cjs/src/assetManager.js +274 -0
- package/dist/cjs/src/assets/routes.d.ts +7 -0
- package/dist/cjs/src/assets/routes.js +165 -0
- package/dist/cjs/src/attachments/routes.d.ts +7 -0
- package/dist/cjs/src/attachments/routes.js +72 -0
- package/dist/cjs/src/authManager.d.ts +16 -0
- package/dist/cjs/src/authManager.js +64 -0
- package/dist/cjs/src/cacheManager.d.ts +20 -0
- package/dist/cjs/src/cacheManager.js +51 -0
- package/dist/cjs/src/clusterService.d.ts +44 -0
- package/dist/cjs/src/clusterService.js +120 -0
- package/dist/cjs/src/codeGeneratorManager.d.ts +14 -0
- package/dist/cjs/src/codeGeneratorManager.js +93 -0
- package/dist/cjs/src/config/routes.d.ts +7 -0
- package/dist/cjs/src/config/routes.js +160 -0
- package/dist/cjs/src/configManager.d.ts +42 -0
- package/dist/cjs/src/configManager.js +136 -0
- package/dist/cjs/src/containerManager.d.ts +148 -0
- package/dist/cjs/src/containerManager.js +958 -0
- package/dist/cjs/src/definitionsManager.d.ts +20 -0
- package/dist/cjs/src/definitionsManager.js +171 -0
- package/dist/cjs/src/filesystem/routes.d.ts +7 -0
- package/dist/cjs/src/filesystem/routes.js +105 -0
- package/dist/cjs/src/filesystemManager.d.ts +27 -0
- package/dist/cjs/src/filesystemManager.js +118 -0
- package/dist/cjs/src/identities/routes.d.ts +7 -0
- package/dist/cjs/src/identities/routes.js +37 -0
- package/dist/cjs/src/instanceManager.d.ts +69 -0
- package/dist/cjs/src/instanceManager.js +910 -0
- package/dist/cjs/src/instances/routes.d.ts +7 -0
- package/dist/cjs/src/instances/routes.js +179 -0
- package/dist/cjs/src/middleware/cors.d.ts +6 -0
- package/dist/cjs/src/middleware/cors.js +14 -0
- package/dist/cjs/src/middleware/kapeta.d.ts +15 -0
- package/dist/cjs/src/middleware/kapeta.js +28 -0
- package/dist/cjs/src/middleware/stringBody.d.ts +9 -0
- package/dist/cjs/src/middleware/stringBody.js +18 -0
- package/dist/cjs/src/networkManager.d.ts +37 -0
- package/dist/cjs/src/networkManager.js +119 -0
- package/dist/cjs/src/operatorManager.d.ts +41 -0
- package/dist/cjs/src/operatorManager.js +211 -0
- package/dist/cjs/src/progressListener.d.ts +31 -0
- package/dist/cjs/src/progressListener.js +133 -0
- package/dist/cjs/src/providerManager.d.ts +11 -0
- package/dist/cjs/src/providerManager.js +84 -0
- package/dist/cjs/src/providers/routes.d.ts +7 -0
- package/dist/cjs/src/providers/routes.js +46 -0
- package/dist/cjs/src/proxy/routes.d.ts +7 -0
- package/dist/cjs/src/proxy/routes.js +115 -0
- package/dist/cjs/src/proxy/types/rest.d.ts +10 -0
- package/dist/cjs/src/proxy/types/rest.js +123 -0
- package/dist/cjs/src/proxy/types/web.d.ts +8 -0
- package/dist/cjs/src/proxy/types/web.js +61 -0
- package/dist/cjs/src/repositoryManager.d.ts +35 -0
- package/dist/cjs/src/repositoryManager.js +247 -0
- package/dist/cjs/src/serviceManager.d.ts +36 -0
- package/dist/cjs/src/serviceManager.js +106 -0
- package/dist/cjs/src/socketManager.d.ts +32 -0
- package/dist/cjs/src/socketManager.js +125 -0
- package/dist/cjs/src/storageService.d.ts +21 -0
- package/dist/cjs/src/storageService.js +81 -0
- package/dist/cjs/src/taskManager.d.ts +70 -0
- package/dist/cjs/src/taskManager.js +181 -0
- package/dist/cjs/src/tasks/routes.d.ts +7 -0
- package/dist/cjs/src/tasks/routes.js +39 -0
- package/dist/cjs/src/traffic/routes.d.ts +7 -0
- package/dist/cjs/src/traffic/routes.js +22 -0
- package/dist/cjs/src/types.d.ts +99 -0
- package/dist/cjs/src/types.js +39 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.d.ts +28 -0
- package/dist/cjs/src/utils/BlockInstanceRunner.js +432 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.d.ts +15 -0
- package/dist/cjs/src/utils/DefaultProviderInstaller.js +136 -0
- package/dist/cjs/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/cjs/src/utils/InternalConfigProvider.js +146 -0
- package/dist/cjs/src/utils/LogData.d.ts +23 -0
- package/dist/cjs/src/utils/LogData.js +46 -0
- package/dist/cjs/src/utils/commandLineUtils.d.ts +8 -0
- package/dist/cjs/src/utils/commandLineUtils.js +39 -0
- package/dist/cjs/src/utils/pathTemplateParser.d.ts +30 -0
- package/dist/cjs/src/utils/pathTemplateParser.js +135 -0
- package/dist/cjs/src/utils/utils.d.ts +40 -0
- package/dist/cjs/src/utils/utils.js +148 -0
- package/dist/cjs/start.d.ts +5 -0
- package/dist/cjs/start.js +17 -0
- package/dist/cjs/test/proxy/types/rest.test.d.ts +5 -0
- package/dist/cjs/test/proxy/types/rest.test.js +48 -0
- package/dist/cjs/test/utils/pathTemplateParser.test.d.ts +5 -0
- package/dist/cjs/test/utils/pathTemplateParser.test.js +27 -0
- package/dist/esm/index.d.ts +34 -0
- package/dist/esm/index.js +263 -0
- package/dist/esm/package.json +1 -0
- package/dist/esm/src/RepositoryWatcher.d.ts +30 -0
- package/dist/esm/src/RepositoryWatcher.js +332 -0
- package/dist/esm/src/ai/aiClient.d.ts +20 -0
- package/dist/esm/src/ai/aiClient.js +74 -0
- package/dist/esm/src/ai/routes.d.ts +7 -0
- package/dist/esm/src/ai/routes.js +37 -0
- package/dist/esm/src/ai/transform.d.ts +11 -0
- package/dist/esm/src/ai/transform.js +239 -0
- package/dist/esm/src/ai/types.d.ts +40 -0
- package/dist/esm/src/ai/types.js +2 -0
- package/dist/esm/src/api.d.ts +7 -0
- package/dist/esm/src/api.js +29 -0
- package/dist/esm/src/assetManager.d.ts +41 -0
- package/dist/esm/src/assetManager.js +274 -0
- package/dist/esm/src/assets/routes.d.ts +7 -0
- package/dist/esm/src/assets/routes.js +165 -0
- package/dist/esm/src/attachments/routes.d.ts +7 -0
- package/dist/esm/src/attachments/routes.js +72 -0
- package/dist/esm/src/authManager.d.ts +16 -0
- package/dist/esm/src/authManager.js +64 -0
- package/dist/esm/src/cacheManager.d.ts +20 -0
- package/dist/esm/src/cacheManager.js +51 -0
- package/dist/esm/src/clusterService.d.ts +44 -0
- package/dist/esm/src/clusterService.js +120 -0
- package/dist/esm/src/codeGeneratorManager.d.ts +14 -0
- package/dist/esm/src/codeGeneratorManager.js +93 -0
- package/dist/esm/src/config/routes.d.ts +7 -0
- package/dist/esm/src/config/routes.js +160 -0
- package/dist/esm/src/configManager.d.ts +42 -0
- package/dist/esm/src/configManager.js +136 -0
- package/dist/esm/src/containerManager.d.ts +148 -0
- package/dist/esm/src/containerManager.js +958 -0
- package/dist/esm/src/definitionsManager.d.ts +20 -0
- package/dist/esm/src/definitionsManager.js +171 -0
- package/dist/esm/src/filesystem/routes.d.ts +7 -0
- package/dist/esm/src/filesystem/routes.js +105 -0
- package/dist/esm/src/filesystemManager.d.ts +27 -0
- package/dist/esm/src/filesystemManager.js +118 -0
- package/dist/esm/src/identities/routes.d.ts +7 -0
- package/dist/esm/src/identities/routes.js +37 -0
- package/dist/esm/src/instanceManager.d.ts +69 -0
- package/dist/esm/src/instanceManager.js +910 -0
- package/dist/esm/src/instances/routes.d.ts +7 -0
- package/dist/esm/src/instances/routes.js +179 -0
- package/dist/esm/src/middleware/cors.d.ts +6 -0
- package/dist/esm/src/middleware/cors.js +14 -0
- package/dist/esm/src/middleware/kapeta.d.ts +15 -0
- package/dist/esm/src/middleware/kapeta.js +28 -0
- package/dist/esm/src/middleware/stringBody.d.ts +9 -0
- package/dist/esm/src/middleware/stringBody.js +18 -0
- package/dist/esm/src/networkManager.d.ts +37 -0
- package/dist/esm/src/networkManager.js +119 -0
- package/dist/esm/src/operatorManager.d.ts +41 -0
- package/dist/esm/src/operatorManager.js +211 -0
- package/dist/esm/src/progressListener.d.ts +31 -0
- package/dist/esm/src/progressListener.js +133 -0
- package/dist/esm/src/providerManager.d.ts +11 -0
- package/dist/esm/src/providerManager.js +84 -0
- package/dist/esm/src/providers/routes.d.ts +7 -0
- package/dist/esm/src/providers/routes.js +46 -0
- package/dist/esm/src/proxy/routes.d.ts +7 -0
- package/dist/esm/src/proxy/routes.js +115 -0
- package/dist/esm/src/proxy/types/rest.d.ts +10 -0
- package/dist/esm/src/proxy/types/rest.js +123 -0
- package/dist/esm/src/proxy/types/web.d.ts +8 -0
- package/dist/esm/src/proxy/types/web.js +61 -0
- package/dist/esm/src/repositoryManager.d.ts +35 -0
- package/dist/esm/src/repositoryManager.js +247 -0
- package/dist/esm/src/serviceManager.d.ts +36 -0
- package/dist/esm/src/serviceManager.js +106 -0
- package/dist/esm/src/socketManager.d.ts +32 -0
- package/dist/esm/src/socketManager.js +125 -0
- package/dist/esm/src/storageService.d.ts +21 -0
- package/dist/esm/src/storageService.js +81 -0
- package/dist/esm/src/taskManager.d.ts +70 -0
- package/dist/esm/src/taskManager.js +181 -0
- package/dist/esm/src/tasks/routes.d.ts +7 -0
- package/dist/esm/src/tasks/routes.js +39 -0
- package/dist/esm/src/traffic/routes.d.ts +7 -0
- package/dist/esm/src/traffic/routes.js +22 -0
- package/dist/esm/src/types.d.ts +99 -0
- package/dist/esm/src/types.js +39 -0
- package/dist/esm/src/utils/BlockInstanceRunner.d.ts +28 -0
- package/dist/esm/src/utils/BlockInstanceRunner.js +432 -0
- package/dist/esm/src/utils/DefaultProviderInstaller.d.ts +15 -0
- package/dist/esm/src/utils/DefaultProviderInstaller.js +136 -0
- package/dist/esm/src/utils/InternalConfigProvider.d.ts +38 -0
- package/dist/esm/src/utils/InternalConfigProvider.js +146 -0
- package/dist/esm/src/utils/LogData.d.ts +23 -0
- package/dist/esm/src/utils/LogData.js +46 -0
- package/dist/esm/src/utils/commandLineUtils.d.ts +8 -0
- package/dist/esm/src/utils/commandLineUtils.js +39 -0
- package/dist/esm/src/utils/pathTemplateParser.d.ts +30 -0
- package/dist/esm/src/utils/pathTemplateParser.js +135 -0
- package/dist/esm/src/utils/utils.d.ts +40 -0
- package/dist/esm/src/utils/utils.js +148 -0
- package/dist/esm/start.d.ts +5 -0
- package/dist/esm/start.js +17 -0
- package/dist/esm/test/proxy/types/rest.test.d.ts +5 -0
- package/dist/esm/test/proxy/types/rest.test.js +48 -0
- package/dist/esm/test/utils/pathTemplateParser.test.d.ts +5 -0
- package/dist/esm/test/utils/pathTemplateParser.test.js +27 -0
- package/index.ts +280 -0
- package/jest.config.js +8 -0
- package/package.json +134 -0
- package/src/RepositoryWatcher.ts +363 -0
- package/src/ai/aiClient.ts +93 -0
- package/src/ai/routes.ts +39 -0
- package/src/ai/transform.ts +275 -0
- package/src/ai/types.ts +45 -0
- package/src/api.ts +32 -0
- package/src/assetManager.ts +355 -0
- package/src/assets/routes.ts +183 -0
- package/src/attachments/routes.ts +79 -0
- package/src/authManager.ts +67 -0
- package/src/cacheManager.ts +59 -0
- package/src/clusterService.ts +142 -0
- package/src/codeGeneratorManager.ts +109 -0
- package/src/config/routes.ts +201 -0
- package/src/configManager.ts +180 -0
- package/src/containerManager.ts +1178 -0
- package/src/definitionsManager.ts +212 -0
- package/src/filesystem/routes.ts +123 -0
- package/src/filesystemManager.ts +133 -0
- package/src/identities/routes.ts +38 -0
- package/src/instanceManager.ts +1160 -0
- package/src/instances/routes.ts +203 -0
- package/src/middleware/cors.ts +14 -0
- package/src/middleware/kapeta.ts +41 -0
- package/src/middleware/stringBody.ts +21 -0
- package/src/networkManager.ts +148 -0
- package/src/operatorManager.ts +294 -0
- package/src/progressListener.ts +151 -0
- package/src/providerManager.ts +97 -0
- package/src/providers/routes.ts +51 -0
- package/src/proxy/routes.ts +153 -0
- package/src/proxy/types/rest.ts +172 -0
- package/src/proxy/types/web.ts +70 -0
- package/src/repositoryManager.ts +291 -0
- package/src/serviceManager.ts +133 -0
- package/src/socketManager.ts +138 -0
- package/src/storageService.ts +97 -0
- package/src/taskManager.ts +247 -0
- package/src/tasks/routes.ts +43 -0
- package/src/traffic/routes.ts +23 -0
- package/src/types.ts +112 -0
- package/src/utils/BlockInstanceRunner.ts +577 -0
- package/src/utils/DefaultProviderInstaller.ts +150 -0
- package/src/utils/InternalConfigProvider.ts +214 -0
- package/src/utils/LogData.ts +50 -0
- package/src/utils/commandLineUtils.ts +45 -0
- package/src/utils/pathTemplateParser.ts +157 -0
- package/src/utils/utils.ts +155 -0
- package/start.ts +14 -0
- package/test/proxy/types/rest.test.ts +54 -0
- package/test/utils/pathTemplateParser.test.ts +29 -0
- package/tsconfig.json +15 -0
@@ -0,0 +1,133 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import _ from 'lodash';
|
7
|
+
import { clusterService } from './clusterService';
|
8
|
+
import { storageService } from './storageService';
|
9
|
+
import { DOCKER_HOST_INTERNAL, EnvironmentType } from './types';
|
10
|
+
import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
11
|
+
import { resolvePortType } from './utils/BlockInstanceRunner';
|
12
|
+
import { getRemoteHostForEnvironment } from './utils/utils';
|
13
|
+
|
14
|
+
export const HTTP_PORT_TYPE = 'http';
|
15
|
+
|
16
|
+
export const DEFAULT_PORT_TYPE = HTTP_PORT_TYPE;
|
17
|
+
|
18
|
+
export const HTTP_PORTS = [HTTP_PORT_TYPE, 'web', 'rest'];
|
19
|
+
|
20
|
+
class ServiceManager {
|
21
|
+
private _systems: any;
|
22
|
+
|
23
|
+
constructor() {
|
24
|
+
this._systems = storageService.get('services');
|
25
|
+
if (!this._systems) {
|
26
|
+
this._systems = {};
|
27
|
+
}
|
28
|
+
|
29
|
+
_.forEach(this._systems, (system) => {
|
30
|
+
_.forEach(system, (services) => {
|
31
|
+
_.forEach(services, (portInfo) => {
|
32
|
+
clusterService.reservePort(portInfo.port);
|
33
|
+
});
|
34
|
+
});
|
35
|
+
});
|
36
|
+
}
|
37
|
+
|
38
|
+
_forLocal(port: string | number, path?: string, environmentType?: EnvironmentType) {
|
39
|
+
if (!path) {
|
40
|
+
path = '';
|
41
|
+
}
|
42
|
+
const hostname = getRemoteHostForEnvironment(environmentType);
|
43
|
+
|
44
|
+
if (path.startsWith('/')) {
|
45
|
+
path = path.substring(1);
|
46
|
+
}
|
47
|
+
return `http://${hostname}:${port}/${path}`;
|
48
|
+
}
|
49
|
+
|
50
|
+
_ensureSystem(systemId: string) {
|
51
|
+
systemId = normalizeKapetaUri(systemId);
|
52
|
+
|
53
|
+
if (!this._systems[systemId]) {
|
54
|
+
this._systems[systemId] = {};
|
55
|
+
}
|
56
|
+
|
57
|
+
return this._systems[systemId];
|
58
|
+
}
|
59
|
+
|
60
|
+
_ensureService(systemId: string, serviceId: string) {
|
61
|
+
const system = this._ensureSystem(systemId);
|
62
|
+
|
63
|
+
if (!system[serviceId]) {
|
64
|
+
system[serviceId] = {};
|
65
|
+
}
|
66
|
+
|
67
|
+
return system[serviceId];
|
68
|
+
}
|
69
|
+
|
70
|
+
async ensureServicePort(systemId: string, blockInstanceId: string, portType: string = DEFAULT_PORT_TYPE) {
|
71
|
+
systemId = normalizeKapetaUri(systemId);
|
72
|
+
if (!portType) {
|
73
|
+
portType = DEFAULT_PORT_TYPE;
|
74
|
+
}
|
75
|
+
|
76
|
+
portType = resolvePortType(portType);
|
77
|
+
|
78
|
+
const service = this._ensureService(systemId, blockInstanceId);
|
79
|
+
|
80
|
+
if (!service[portType]) {
|
81
|
+
const port = await clusterService.getNextAvailablePort();
|
82
|
+
service[portType] = { port };
|
83
|
+
this._save();
|
84
|
+
}
|
85
|
+
|
86
|
+
const portTypeSection = service[portType];
|
87
|
+
|
88
|
+
return portTypeSection.port;
|
89
|
+
}
|
90
|
+
|
91
|
+
_save() {
|
92
|
+
storageService.put('services', this._systems);
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* Gets the consumable address of a service block resource
|
97
|
+
*
|
98
|
+
* This returns a local proxy path to allow traffic inspection and control.
|
99
|
+
*
|
100
|
+
*/
|
101
|
+
getConsumerAddress(
|
102
|
+
systemId: string,
|
103
|
+
consumerInstanceId: string,
|
104
|
+
consumerResourceName: string,
|
105
|
+
portType: string,
|
106
|
+
environmentType?: EnvironmentType
|
107
|
+
): string {
|
108
|
+
systemId = normalizeKapetaUri(systemId);
|
109
|
+
const port = clusterService.getClusterServicePort();
|
110
|
+
const path = clusterService.getProxyPath(systemId, consumerInstanceId, consumerResourceName, portType);
|
111
|
+
return this._forLocal(port, path, environmentType);
|
112
|
+
}
|
113
|
+
|
114
|
+
/**
|
115
|
+
* Gets the direct address of a service block
|
116
|
+
*
|
117
|
+
* This returns the actual endpoint address of a service that we're talking to.
|
118
|
+
* For local services this address will be on localhost - for remote services it will
|
119
|
+
* be their remotely available address.
|
120
|
+
*
|
121
|
+
*/
|
122
|
+
async getProviderAddress(systemId: string, providerInstanceId: string, portType: string): Promise<string> {
|
123
|
+
systemId = normalizeKapetaUri(systemId);
|
124
|
+
const port = await this.ensureServicePort(systemId, providerInstanceId, portType);
|
125
|
+
return this._forLocal(port);
|
126
|
+
}
|
127
|
+
|
128
|
+
getServices() {
|
129
|
+
return this._systems;
|
130
|
+
}
|
131
|
+
}
|
132
|
+
|
133
|
+
export const serviceManager = new ServiceManager();
|
@@ -0,0 +1,138 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import _ from 'lodash';
|
7
|
+
import { Socket, Server } from 'socket.io';
|
8
|
+
import { normalizeKapetaUri } from '@kapeta/nodejs-utils';
|
9
|
+
import { LogEntry } from './types';
|
10
|
+
import { containerManager } from './containerManager';
|
11
|
+
export const EVENT_STATUS_CHANGED = 'status-changed';
|
12
|
+
export const EVENT_INSTANCE_CREATED = 'instance-created';
|
13
|
+
export const EVENT_INSTANCE_EXITED = 'instance-exited';
|
14
|
+
export const EVENT_INSTANCE_LOG = 'instance-log';
|
15
|
+
|
16
|
+
export const EVENT_SYSTEM_LOG = 'system-log';
|
17
|
+
export const EVENT_LOG = 'log';
|
18
|
+
|
19
|
+
export class SocketManager {
|
20
|
+
private _io: Server | null;
|
21
|
+
private readonly _sockets: Socket[];
|
22
|
+
|
23
|
+
constructor() {
|
24
|
+
this._io = null;
|
25
|
+
this._sockets = [];
|
26
|
+
return this;
|
27
|
+
}
|
28
|
+
|
29
|
+
setIo(io: Server) {
|
30
|
+
this._io = io;
|
31
|
+
this._bindIO();
|
32
|
+
}
|
33
|
+
|
34
|
+
isAlive() {
|
35
|
+
return !!this._io;
|
36
|
+
}
|
37
|
+
|
38
|
+
private get io() {
|
39
|
+
if (!this._io) {
|
40
|
+
throw new Error('Socket server not ready');
|
41
|
+
}
|
42
|
+
return this._io;
|
43
|
+
}
|
44
|
+
|
45
|
+
emit(context: string, type: string, payload: any) {
|
46
|
+
if (!this._io) {
|
47
|
+
return;
|
48
|
+
}
|
49
|
+
this.io.to(context).emit(type, { context, payload });
|
50
|
+
}
|
51
|
+
|
52
|
+
emitGlobal(type: string, payload: any) {
|
53
|
+
if (!this._io) {
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
this.io.emit(type, payload);
|
57
|
+
}
|
58
|
+
|
59
|
+
emitSystemEvent(systemId: string, type: string, payload: any) {
|
60
|
+
systemId = normalizeKapetaUri(systemId);
|
61
|
+
try {
|
62
|
+
const contextId = `system-events/${encodeURIComponent(systemId)}`;
|
63
|
+
this.emit(contextId, type, payload);
|
64
|
+
} catch (e: any) {
|
65
|
+
console.warn('Failed to emit instance event: %s', e.message);
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
emitInstanceLog(systemId: string, instanceId: string, payload: LogEntry) {
|
70
|
+
systemId = normalizeKapetaUri(systemId);
|
71
|
+
try {
|
72
|
+
this.emit(
|
73
|
+
`instance-logs/${encodeURIComponent(systemId)}/${encodeURIComponent(instanceId)}`,
|
74
|
+
EVENT_INSTANCE_LOG,
|
75
|
+
payload
|
76
|
+
);
|
77
|
+
} catch (e: any) {
|
78
|
+
console.warn('Failed to emit instance event: %s', e.message);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
|
82
|
+
emitSystemLog(systemId: string, payload: LogEntry) {
|
83
|
+
this.emitSystemEvent(systemId, EVENT_SYSTEM_LOG, payload);
|
84
|
+
}
|
85
|
+
|
86
|
+
emitGlobalLog(payload: LogEntry) {
|
87
|
+
this.emitGlobal(EVENT_LOG, payload);
|
88
|
+
}
|
89
|
+
|
90
|
+
private _bindIO() {
|
91
|
+
this.io.on('connection', (socket) => this._handleSocketCreated(socket));
|
92
|
+
}
|
93
|
+
|
94
|
+
private _handleSocketCreated(socket: Socket) {
|
95
|
+
this._bindSocket(socket);
|
96
|
+
this._sockets.push(socket);
|
97
|
+
}
|
98
|
+
|
99
|
+
private _bindSocket(socket: Socket) {
|
100
|
+
socket.on('disconnect', () => {
|
101
|
+
_.pull(this._sockets, socket);
|
102
|
+
socket.rooms.forEach((roomId) => {
|
103
|
+
this.handleLeaveRoom(roomId);
|
104
|
+
});
|
105
|
+
});
|
106
|
+
socket.on('join', (id) => {
|
107
|
+
socket.join(id);
|
108
|
+
this.handleJoinRoom(id);
|
109
|
+
});
|
110
|
+
socket.on('leave', (id) => {
|
111
|
+
socket.leave(id);
|
112
|
+
this.handleLeaveRoom(id);
|
113
|
+
});
|
114
|
+
}
|
115
|
+
private handleJoinRoom(id: string) {
|
116
|
+
if (id.startsWith('instance-logs/')) {
|
117
|
+
let [, systemId, instanceId] = id.split(/\//g);
|
118
|
+
systemId = decodeURIComponent(systemId);
|
119
|
+
instanceId = decodeURIComponent(instanceId);
|
120
|
+
console.log('Start listening for logs', systemId, instanceId);
|
121
|
+
containerManager
|
122
|
+
.ensureLogListening(systemId, instanceId, (log) => {
|
123
|
+
this.emitInstanceLog(systemId, instanceId, log);
|
124
|
+
})
|
125
|
+
.catch((e) => {});
|
126
|
+
}
|
127
|
+
}
|
128
|
+
private handleLeaveRoom(id: string) {
|
129
|
+
if (id.startsWith('instance-logs/')) {
|
130
|
+
let [, systemId, instanceId] = id.split(/\//g);
|
131
|
+
systemId = decodeURIComponent(systemId);
|
132
|
+
instanceId = decodeURIComponent(instanceId);
|
133
|
+
console.log('Stop listening for logs', systemId, instanceId);
|
134
|
+
containerManager.stopLogListening(systemId, instanceId).catch((e) => {});
|
135
|
+
}
|
136
|
+
}
|
137
|
+
}
|
138
|
+
export const socketManager = new SocketManager();
|
@@ -0,0 +1,97 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import _ from 'lodash';
|
7
|
+
import FS from 'fs';
|
8
|
+
import FSExtra from 'fs-extra';
|
9
|
+
import YAML from 'yaml';
|
10
|
+
import ClusterConfiguration from '@kapeta/local-cluster-config';
|
11
|
+
|
12
|
+
/**
|
13
|
+
* Class that handles reading and writing from local configuration file.
|
14
|
+
*/
|
15
|
+
class StorageService {
|
16
|
+
private _data: { [key: string]: any };
|
17
|
+
|
18
|
+
constructor() {
|
19
|
+
this._data = this._readConfig();
|
20
|
+
}
|
21
|
+
|
22
|
+
getKapetaBasedir() {
|
23
|
+
return ClusterConfiguration.getKapetaBasedir();
|
24
|
+
}
|
25
|
+
|
26
|
+
_readConfig() {
|
27
|
+
return ClusterConfiguration.getClusterConfig();
|
28
|
+
}
|
29
|
+
|
30
|
+
_writeConfig() {
|
31
|
+
const configFile = ClusterConfiguration.getClusterConfigFile();
|
32
|
+
|
33
|
+
FSExtra.mkdirsSync(this.getKapetaBasedir());
|
34
|
+
|
35
|
+
FS.writeFileSync(configFile, YAML.stringify(this._data));
|
36
|
+
}
|
37
|
+
|
38
|
+
section<T = any>(section: string, defaultValue?: any): T {
|
39
|
+
if (!defaultValue) {
|
40
|
+
defaultValue = {};
|
41
|
+
}
|
42
|
+
if (!this._data[section]) {
|
43
|
+
this._data[section] = defaultValue;
|
44
|
+
this._writeConfig();
|
45
|
+
}
|
46
|
+
|
47
|
+
return this._data[section];
|
48
|
+
}
|
49
|
+
|
50
|
+
put(section: string, property: string | any, value?: any) {
|
51
|
+
if (!_.isString(property)) {
|
52
|
+
this._data[section] = property;
|
53
|
+
this._writeConfig();
|
54
|
+
return;
|
55
|
+
}
|
56
|
+
|
57
|
+
this.section(section)[property] = value;
|
58
|
+
this._writeConfig();
|
59
|
+
}
|
60
|
+
|
61
|
+
get<T = any>(section: string, property?: string, defaultValue?: T): T | undefined {
|
62
|
+
if (!property) {
|
63
|
+
return this.section(section);
|
64
|
+
}
|
65
|
+
|
66
|
+
if (!this.contains(section, property)) {
|
67
|
+
return defaultValue;
|
68
|
+
}
|
69
|
+
|
70
|
+
return this.section(section)[property];
|
71
|
+
}
|
72
|
+
|
73
|
+
contains(section: string, property: string) {
|
74
|
+
if (!this._data[section]) {
|
75
|
+
return false;
|
76
|
+
}
|
77
|
+
|
78
|
+
return this._data[section].hasOwnProperty(property);
|
79
|
+
}
|
80
|
+
|
81
|
+
ensure(section: string, property: string, value: any) {
|
82
|
+
if (this.contains(section, property)) {
|
83
|
+
return this.get(section, property);
|
84
|
+
}
|
85
|
+
|
86
|
+
let out = value;
|
87
|
+
if (typeof value === 'function') {
|
88
|
+
out = value();
|
89
|
+
}
|
90
|
+
|
91
|
+
this.put(section, property, out);
|
92
|
+
|
93
|
+
return out;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
|
97
|
+
export const storageService = new StorageService();
|
@@ -0,0 +1,247 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Class that handles processing background tasks.
|
8
|
+
*/
|
9
|
+
import { socketManager } from './socketManager';
|
10
|
+
import { LogLevel } from './types';
|
11
|
+
|
12
|
+
const EVENT_TASK_UPDATED = 'task-updated';
|
13
|
+
const EVENT_TASK_ADDED = 'task-added';
|
14
|
+
const EVENT_TASK_REMOVED = 'task-removed';
|
15
|
+
const EVENT_TASK_LOG = 'task-log';
|
16
|
+
|
17
|
+
export type TaskRunner<T> = (task: Task<T>) => Promise<T>;
|
18
|
+
|
19
|
+
export enum TaskStatus {
|
20
|
+
PENDING = 'PENDING',
|
21
|
+
RUNNING = 'RUNNING',
|
22
|
+
COMPLETED = 'COMPLETED',
|
23
|
+
FAILED = 'FAILED',
|
24
|
+
}
|
25
|
+
|
26
|
+
interface Future<T = void> {
|
27
|
+
promise: Promise<T>;
|
28
|
+
resolve: (result: T) => void;
|
29
|
+
reject: (e: any) => void;
|
30
|
+
}
|
31
|
+
|
32
|
+
interface TaskMetadata {
|
33
|
+
name: string;
|
34
|
+
/**
|
35
|
+
* A unique prefix for the task. If defined only 1 task with this ID prefix will be executed at a time
|
36
|
+
*/
|
37
|
+
group?: string;
|
38
|
+
progress?: number;
|
39
|
+
|
40
|
+
[key: string]: any;
|
41
|
+
}
|
42
|
+
|
43
|
+
interface TaskData<T = void> {
|
44
|
+
id: string;
|
45
|
+
status: TaskStatus;
|
46
|
+
errorMessage?: string;
|
47
|
+
metadata: TaskMetadata;
|
48
|
+
future: Future<T>;
|
49
|
+
run: TaskRunner<T>;
|
50
|
+
}
|
51
|
+
|
52
|
+
export class Task<T = void> implements TaskData<T> {
|
53
|
+
private data: TaskData<T>;
|
54
|
+
|
55
|
+
constructor(task: TaskData<T>) {
|
56
|
+
this.data = task;
|
57
|
+
}
|
58
|
+
|
59
|
+
get id() {
|
60
|
+
return this.data.id;
|
61
|
+
}
|
62
|
+
|
63
|
+
get status() {
|
64
|
+
return this.data.status;
|
65
|
+
}
|
66
|
+
|
67
|
+
get errorMessage() {
|
68
|
+
return this.data.errorMessage;
|
69
|
+
}
|
70
|
+
|
71
|
+
get metadata() {
|
72
|
+
return this.data.metadata;
|
73
|
+
}
|
74
|
+
|
75
|
+
get future() {
|
76
|
+
return this.data.future;
|
77
|
+
}
|
78
|
+
|
79
|
+
get run() {
|
80
|
+
return this.data.run;
|
81
|
+
}
|
82
|
+
|
83
|
+
set status(status: TaskStatus) {
|
84
|
+
this.data.status = status;
|
85
|
+
}
|
86
|
+
|
87
|
+
set errorMessage(errorMessage: string | undefined) {
|
88
|
+
this.data.errorMessage = errorMessage;
|
89
|
+
}
|
90
|
+
|
91
|
+
set metadata(metadata: TaskMetadata) {
|
92
|
+
this.data.metadata = metadata;
|
93
|
+
}
|
94
|
+
|
95
|
+
public emitUpdate() {
|
96
|
+
socketManager.emitGlobal(EVENT_TASK_UPDATED, this.toData());
|
97
|
+
}
|
98
|
+
|
99
|
+
public addLog(log: string, level: LogLevel = 'INFO') {
|
100
|
+
socketManager.emitGlobal(EVENT_TASK_LOG, {
|
101
|
+
id: this.id,
|
102
|
+
message: log,
|
103
|
+
level,
|
104
|
+
time: Date.now(),
|
105
|
+
});
|
106
|
+
}
|
107
|
+
|
108
|
+
async wait(): Promise<T> {
|
109
|
+
return this.future.promise;
|
110
|
+
}
|
111
|
+
|
112
|
+
toData() {
|
113
|
+
return { ...this.data };
|
114
|
+
}
|
115
|
+
}
|
116
|
+
|
117
|
+
function createFuture<T>(): Future<T> {
|
118
|
+
let resolve: (arg: T) => void = () => {};
|
119
|
+
let reject: () => void = () => {};
|
120
|
+
const promise = new Promise<T>((res, rej) => {
|
121
|
+
resolve = res;
|
122
|
+
reject = rej;
|
123
|
+
});
|
124
|
+
|
125
|
+
// Ignore unhandled promise rejections
|
126
|
+
promise.catch(() => {});
|
127
|
+
|
128
|
+
return {
|
129
|
+
promise,
|
130
|
+
resolve,
|
131
|
+
reject,
|
132
|
+
};
|
133
|
+
}
|
134
|
+
|
135
|
+
class TaskManager {
|
136
|
+
private _tasks: Task<any>[] = [];
|
137
|
+
|
138
|
+
public add<T>(id: string, runner: TaskRunner<T>, metadata: TaskMetadata): Task<T> {
|
139
|
+
const existingTask = this.get(id);
|
140
|
+
if (existingTask) {
|
141
|
+
return existingTask;
|
142
|
+
}
|
143
|
+
|
144
|
+
const future = createFuture<T>();
|
145
|
+
|
146
|
+
const task = new Task<T>({
|
147
|
+
id,
|
148
|
+
status: TaskStatus.PENDING,
|
149
|
+
metadata,
|
150
|
+
future,
|
151
|
+
run: runner,
|
152
|
+
});
|
153
|
+
|
154
|
+
this._tasks.push(task);
|
155
|
+
|
156
|
+
socketManager.emitGlobal(EVENT_TASK_ADDED, task.toData());
|
157
|
+
|
158
|
+
this.invokeTask(task).catch((err) => {
|
159
|
+
console.warn(`Task ${task.id} failed`, err);
|
160
|
+
});
|
161
|
+
|
162
|
+
return task;
|
163
|
+
}
|
164
|
+
|
165
|
+
async waitFor(filter: (task: Task<any>) => boolean) {
|
166
|
+
const tasks = this._tasks.filter(filter);
|
167
|
+
while (tasks.length > 0) {
|
168
|
+
const task = tasks.shift();
|
169
|
+
if (!task) {
|
170
|
+
continue;
|
171
|
+
}
|
172
|
+
try {
|
173
|
+
await task.wait();
|
174
|
+
} catch (e) {
|
175
|
+
//Ignore
|
176
|
+
}
|
177
|
+
}
|
178
|
+
}
|
179
|
+
|
180
|
+
public get(taskId: string) {
|
181
|
+
return this._tasks.find((t) => t.id === taskId);
|
182
|
+
}
|
183
|
+
|
184
|
+
public exists(taskId: string) {
|
185
|
+
return !!this.get(taskId);
|
186
|
+
}
|
187
|
+
|
188
|
+
public remove(taskId: string) {
|
189
|
+
const task = this.get(taskId);
|
190
|
+
if (!task) {
|
191
|
+
return;
|
192
|
+
}
|
193
|
+
|
194
|
+
if (task.status === TaskStatus.RUNNING) {
|
195
|
+
throw new Error('Cannot remove a running task');
|
196
|
+
}
|
197
|
+
|
198
|
+
this._tasks = this._tasks.filter((t) => t.id !== taskId);
|
199
|
+
socketManager.emitGlobal(EVENT_TASK_REMOVED, task.toData());
|
200
|
+
}
|
201
|
+
|
202
|
+
public list(): TaskData[] {
|
203
|
+
return this._tasks.map((t) => t.toData());
|
204
|
+
}
|
205
|
+
|
206
|
+
private async invokeTask(task: Task<any>): Promise<void> {
|
207
|
+
if (task.metadata.group) {
|
208
|
+
const existingTaskInGroup = this._tasks.find(
|
209
|
+
(t) => t.id !== task.id && t.metadata.group === task.metadata.group && t.status === TaskStatus.RUNNING
|
210
|
+
);
|
211
|
+
|
212
|
+
if (existingTaskInGroup) {
|
213
|
+
return;
|
214
|
+
}
|
215
|
+
}
|
216
|
+
|
217
|
+
const startTime = Date.now();
|
218
|
+
try {
|
219
|
+
task.status = TaskStatus.RUNNING;
|
220
|
+
task.emitUpdate();
|
221
|
+
const result = await task.run(task);
|
222
|
+
task.status = TaskStatus.COMPLETED;
|
223
|
+
task.future.resolve(result);
|
224
|
+
task.emitUpdate();
|
225
|
+
} catch (e: any) {
|
226
|
+
console.warn(`Task ${task.id} failed while waiting for it to resolve`, e);
|
227
|
+
task.errorMessage = e.message;
|
228
|
+
task.status = TaskStatus.FAILED;
|
229
|
+
task.future.reject(e);
|
230
|
+
task.emitUpdate();
|
231
|
+
} finally {
|
232
|
+
this.remove(task.id);
|
233
|
+
console.log(`Task ${task.id} completed in ${Date.now() - startTime}ms`);
|
234
|
+
}
|
235
|
+
|
236
|
+
if (task.metadata.group) {
|
237
|
+
const nextTaskInGroup = this._tasks.find(
|
238
|
+
(t) => t.id !== task.id && t.metadata.group === task.metadata.group && t.status === TaskStatus.PENDING
|
239
|
+
);
|
240
|
+
if (nextTaskInGroup) {
|
241
|
+
return this.invokeTask(nextTaskInGroup);
|
242
|
+
}
|
243
|
+
}
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
export const taskManager = new TaskManager();
|
@@ -0,0 +1,43 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import Router from 'express-promise-router';
|
7
|
+
import { Request, Response } from 'express';
|
8
|
+
|
9
|
+
import { corsHandler } from '../middleware/cors';
|
10
|
+
import { taskManager } from '../taskManager';
|
11
|
+
|
12
|
+
const router = Router();
|
13
|
+
|
14
|
+
router.use('/', corsHandler);
|
15
|
+
|
16
|
+
/**
|
17
|
+
* Get all current tasks
|
18
|
+
*/
|
19
|
+
router.get('/', (req: Request, res: Response) => {
|
20
|
+
res.send(taskManager.list());
|
21
|
+
});
|
22
|
+
|
23
|
+
router.get('/:taskId', (req: Request, res: Response) => {
|
24
|
+
const task = taskManager.get(req.params.taskId);
|
25
|
+
if (!task) {
|
26
|
+
res.status(404).send({ error: 'Task not found' });
|
27
|
+
return;
|
28
|
+
}
|
29
|
+
|
30
|
+
res.send(task.toData());
|
31
|
+
});
|
32
|
+
|
33
|
+
router.delete('/:taskId', (req: Request, res: Response) => {
|
34
|
+
try {
|
35
|
+
taskManager.remove(req.params.taskId);
|
36
|
+
res.send({ ok: true });
|
37
|
+
} catch (e: any) {
|
38
|
+
res.status(400).send({ error: e.message });
|
39
|
+
return;
|
40
|
+
}
|
41
|
+
});
|
42
|
+
|
43
|
+
export default router;
|
@@ -0,0 +1,23 @@
|
|
1
|
+
/**
|
2
|
+
* Copyright 2023 Kapeta Inc.
|
3
|
+
* SPDX-License-Identifier: BUSL-1.1
|
4
|
+
*/
|
5
|
+
|
6
|
+
import Router from 'express-promise-router';
|
7
|
+
import { Request, Response } from 'express';
|
8
|
+
import { networkManager } from '../networkManager';
|
9
|
+
|
10
|
+
const router = Router();
|
11
|
+
router.get('/:systemId/target/:connectionId/', (req: Request, res: Response) => {
|
12
|
+
res.send(networkManager.getTrafficForConnection(req.params.systemId, req.params.connectionId));
|
13
|
+
});
|
14
|
+
|
15
|
+
router.get('/:systemId/source/:blockInstanceId/', (req: Request, res: Response) => {
|
16
|
+
res.send(networkManager.getTrafficForSource(req.params.systemId, req.params.blockInstanceId));
|
17
|
+
});
|
18
|
+
|
19
|
+
router.get('/:systemId/target/:blockInstanceId/', (req: Request, res: Response) => {
|
20
|
+
res.send(networkManager.getTrafficForTarget(req.params.systemId, req.params.blockInstanceId));
|
21
|
+
});
|
22
|
+
|
23
|
+
export default router;
|