@aj-shadow/z-abs-corelayer-server 0.0.0-aj-beta.221
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/.gitattributes +26 -0
- package/LICENSE.txt +96 -0
- package/README.md +5 -0
- package/npm-shrinkwrap.json +13 -0
- package/package.json +10 -0
- package/project/server/_build/Server-CoreLayer-server.bld +12 -0
- package/project/server/_build/z-abs-corelayer-server.prj +12 -0
- package/project/server/communication/core-protocol/decoder.js +404 -0
- package/project/server/communication/core-protocol/encoder.js +503 -0
- package/project/server/communication/messages/messages-s-to-c/message-persistent-init-response.js +14 -0
- package/project/server/communication/messages/messages-s-to-c/message-persistent-publish.js +16 -0
- package/project/server/communication/messages/messages-s-to-c/message-ws-init.js +14 -0
- package/project/server/communication/messages/messages-s-to-s/service-init-request.js +17 -0
- package/project/server/communication/messages/messages-s-to-s/service-init-response.js +18 -0
- package/project/server/communication/messages/messages-s-to-s/service-offer-off.js +15 -0
- package/project/server/communication/messages/messages-s-to-s/service-offer-on.js +15 -0
- package/project/server/communication/messages/messages-s-to-s/worker-init-request.js +15 -0
- package/project/server/data-response.js +588 -0
- package/project/server/high-resolution-timestamp.js +36 -0
- package/project/server/log/log-config.js +107 -0
- package/project/server/log/log-types.js +14 -0
- package/project/server/log/logger-console.js +36 -0
- package/project/server/log/logger.js +114 -0
- package/project/server/node/channel-input.js +65 -0
- package/project/server/node/channel-output.js +39 -0
- package/project/server/node/clients.js +80 -0
- package/project/server/node/connection-address.js +24 -0
- package/project/server/node/connection-data-ip.js +82 -0
- package/project/server/node/connection-data.js +25 -0
- package/project/server/node/const.js +44 -0
- package/project/server/node/external-services.js +209 -0
- package/project/server/node/http-cache.js +109 -0
- package/project/server/node/http-proxy.js +97 -0
- package/project/server/node/http-request-handler.js +219 -0
- package/project/server/node/http-server.js +36 -0
- package/project/server/node/http2-server.js +67 -0
- package/project/server/node/https-server.js +63 -0
- package/project/server/node/ip-client.js +98 -0
- package/project/server/node/ip-server.js +63 -0
- package/project/server/node/ip-subscription.js +46 -0
- package/project/server/node/message-channel.js +98 -0
- package/project/server/node/node-admin.js +513 -0
- package/project/server/node/node-data.js +25 -0
- package/project/server/node/node-settings.js +352 -0
- package/project/server/node/node-worker.js +76 -0
- package/project/server/node/node.js +156 -0
- package/project/server/node/servers.js +168 -0
- package/project/server/node/ws-client.js +12 -0
- package/project/server/node/ws-server.js +20 -0
- package/project/server/node/ws-web-server.js +52 -0
- package/project/server/node/wss-server.js +20 -0
- package/project/server/node/wss-web-server.js +82 -0
- package/project/server/path/actor-path-build.js +29 -0
- package/project/server/path/actor-path-content.js +51 -0
- package/project/server/path/actor-path-creator.js +90 -0
- package/project/server/path/actor-path-data.js +487 -0
- package/project/server/path/actor-path-dist.js +132 -0
- package/project/server/path/actor-path-generated.js +202 -0
- package/project/server/path/actor-path-project.js +181 -0
- package/project/server/path/actor-path.js +57 -0
- package/project/server/path/paths/actor-content-paths.js +34 -0
- package/project/server/path/paths/actor-data-paths.js +302 -0
- package/project/server/path/paths/actor-generated-paths.js +99 -0
- package/project/server/path/paths/actor-paths.js +22 -0
- package/project/server/plugin-base-multi.js +484 -0
- package/project/server/plugin-base.js +233 -0
- package/project/server/plugin-component.js +92 -0
- package/project/server/plugin-data/client/plugin_data_ClientGet.js +18 -0
- package/project/server/plugin-data/dialog-file/plugin_data_DialogFileGet.js +197 -0
- package/project/server/plugin-data/platform/plugin_data_PlatformPing.js +19 -0
- package/project/server/plugin-factor-protocol.js +35 -0
- package/project/server/plugin-factory.js +127 -0
- package/project/server/plugin-lock.js +164 -0
- package/project/server/response-queue.js +46 -0
- package/project/server/responses.js +20 -0
- package/project/server/service/plugin-service.js +264 -0
- package/project/server/service/service-export.js +47 -0
- package/project/server/service/service-manager.js +270 -0
- package/project/server/service/service-requests.js +49 -0
- package/project/server/session-cache.js +39 -0
- package/project/server/session.js +23 -0
- package/project/server/worker/worker-channel.js +175 -0
- package/project/server/worker/worker-core.js +58 -0
- package/project/server/worker/worker-main.js +165 -0
- package/project/server/worker/worker-pool.js +94 -0
- package/project/server/worker/worker-thread.js +128 -0
- package/project/z-abs-corelayer-server.tree +99 -0
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const Const = require('./const');
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class ExternalServices {
|
|
8
|
+
static emptyMap = new Map();
|
|
9
|
+
static NODE = ddb.cyan('Node: ');
|
|
10
|
+
|
|
11
|
+
constructor() {
|
|
12
|
+
this.nodes = new Map();
|
|
13
|
+
this.services = new Map();
|
|
14
|
+
this.dependencyNodeNames = new Set();
|
|
15
|
+
this.eventListeners = new Map();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
addDependencyNodeNames(dependencyNodeNames) {
|
|
19
|
+
this.dependencyNodeNames = new Set([...dependencyNodeNames]);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
_hasNode(nodeName) {
|
|
23
|
+
for(let [symbol, node] of this.nodes) {
|
|
24
|
+
if(nodeName === node.nodeName) {
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
getOfferData(nodeName, nodeSymbol) {
|
|
32
|
+
let offer = true;
|
|
33
|
+
let isDependent = this.dependencyNodeNames.has(nodeName);
|
|
34
|
+
const dependencies = this.dependencyNodeNames.size;
|
|
35
|
+
let connectedDependencies = 0;
|
|
36
|
+
if(isDependent) {
|
|
37
|
+
this.dependencyNodeNames.forEach((dependencyNodeName) => {
|
|
38
|
+
if(this._hasNode(dependencyNodeName)) {
|
|
39
|
+
++connectedDependencies;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
offer = false;
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
return {
|
|
47
|
+
offer: offer || !isDependent,
|
|
48
|
+
isDependent,
|
|
49
|
+
dependencies,
|
|
50
|
+
connectedDependencies
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
addNode(connectionData) {
|
|
55
|
+
const externalNode = {
|
|
56
|
+
nodeSymbol: connectionData.nodeSymbol,
|
|
57
|
+
nodeName: connectionData.nodeName,
|
|
58
|
+
nodeType: connectionData.nodeType,
|
|
59
|
+
connectionData: connectionData,
|
|
60
|
+
isDependent: this.dependencyNodeNames.has(connectionData.nodeName),
|
|
61
|
+
offered: false,
|
|
62
|
+
serviceExport: null
|
|
63
|
+
};
|
|
64
|
+
this.nodes.set(connectionData.nodeSymbol, externalNode);
|
|
65
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.green(' connected'));
|
|
66
|
+
return externalNode;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
deleteNode(connectionData) {
|
|
70
|
+
if(this.nodes.delete(connectionData.nodeSymbol)) {
|
|
71
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.red(' disconnected'));
|
|
72
|
+
}
|
|
73
|
+
this.offerOff(connectionData);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
getNodeData(connectionData) {
|
|
77
|
+
return this.nodes.get(connectionData.nodeSymbol);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
setNodeOffer(connectionData, serviceExport) {
|
|
81
|
+
const nodeData = this.nodes.get(connectionData.nodeSymbol);
|
|
82
|
+
nodeData.serviceExport = serviceExport;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
offerOn(connectionData, serviceExport) {
|
|
86
|
+
serviceExport.frontendServices.forEach((serviceName) => {
|
|
87
|
+
this._offerOn(serviceName, Const.OFFER_FRONTEND, connectionData);
|
|
88
|
+
});
|
|
89
|
+
serviceExport.backendServices.forEach((serviceName) => {
|
|
90
|
+
this._offerOn(serviceName, Const.OFFER_BACKEND, connectionData);
|
|
91
|
+
});
|
|
92
|
+
serviceExport.surveillanceServices.forEach((serviceName) => {
|
|
93
|
+
this._offerOn(serviceName, Const.OFFER_SURVEILLANCE, connectionData);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
offerOff(connectionData) {
|
|
98
|
+
connectionData.frontendServices.forEach((serviceName) => {
|
|
99
|
+
this._offerOff(serviceName, connectionData);
|
|
100
|
+
});
|
|
101
|
+
connectionData.backendServices.forEach((serviceName) => {
|
|
102
|
+
this._offerOff(serviceName, connectionData);
|
|
103
|
+
});
|
|
104
|
+
connectionData.surveillanceServices.forEach((serviceName) => {
|
|
105
|
+
this._offerOff(serviceName, connectionData);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
_offerOn(serviceName, offerType, connectionData) {
|
|
110
|
+
const externalService = this.services.get(serviceName);
|
|
111
|
+
if(!externalService) {
|
|
112
|
+
connectionData.addService(serviceName, offerType);
|
|
113
|
+
this.services.set(serviceName, new Map([[connectionData.id, {connectionData , instances: 1}]]));
|
|
114
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.yellow(' offer '), ddb.cyan(serviceName), ddb.green(' on'), ddb.yellow(' id: '), connectionData.id, ', instances: ', ddb.yellow(1));
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
let externalConnectionData = null;
|
|
118
|
+
if(externalService.has(connectionData.id)) {
|
|
119
|
+
externalConnectionData = externalService.get(connectionData.id);
|
|
120
|
+
++externalConnectionData.instances;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
connectionData.addService(serviceName, offerType);
|
|
124
|
+
externalConnectionData = {connectionData , instances: 1};
|
|
125
|
+
externalService.set(connectionData.id, externalConnectionData);
|
|
126
|
+
}
|
|
127
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.yellow(' offer '), ddb.cyan(serviceName), ddb.green(' on'), ddb.yellow(' id: '), connectionData.id, ', instances: ', ddb.yellow(externalConnectionData.instances));
|
|
128
|
+
}
|
|
129
|
+
const serviceListeners = this.eventListeners.get(serviceName);
|
|
130
|
+
if(serviceListeners) {
|
|
131
|
+
serviceListeners.forEach((cb) => {
|
|
132
|
+
process.nextTick(cb, connectionData, true);
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
_offerOff(serviceName, connectionData) {
|
|
138
|
+
const externalService = this.services.get(serviceName);
|
|
139
|
+
if(externalService) {
|
|
140
|
+
const externalConnectionData = externalService.get(connectionData.id);
|
|
141
|
+
if(externalConnectionData) {
|
|
142
|
+
if(0 === --externalConnectionData.instances) {
|
|
143
|
+
connectionData.deleteService(serviceName);
|
|
144
|
+
externalService.delete(connectionData.id);
|
|
145
|
+
if(0 === externalService.size) {
|
|
146
|
+
this.services.delete(serviceName, connectionData.nodeType);
|
|
147
|
+
}
|
|
148
|
+
const serviceListeners = this.eventListeners.get(serviceName);
|
|
149
|
+
if(serviceListeners) {
|
|
150
|
+
serviceListeners.forEach((cb) => {
|
|
151
|
+
process.nextTick(cb, connectionData, false);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.yellow(' offer '), ddb.cyan(serviceName), ddb.red(' off'), ddb.yellow(' id: '), connectionData.id, ', instances: ', ddb.yellow(externalConnectionData.instances));
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.red(' Service: '), ddb.cyan(serviceName), ddb.yellow(' id: '), connectionData.id, ddb.red(' not removed, it does not exist!'));
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
else {
|
|
162
|
+
ddb.writelnTime(ExternalServices.NODE, connectionData.nodeName, ddb.yellow('::'), connectionData.nodeId, ddb.red(' Service: '), ddb.cyan(serviceName), ddb.yellow(' not removed, it does not exist!'));
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
getServices() {
|
|
167
|
+
if(0 !== this.services.size) {
|
|
168
|
+
return [...this.services.keys()];
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/*has(serviceName) {
|
|
176
|
+
return this.services.has(serviceName);
|
|
177
|
+
}*/
|
|
178
|
+
|
|
179
|
+
getConnectionData(serviceName) {
|
|
180
|
+
const externalService = this.services.get(serviceName);
|
|
181
|
+
if(externalService) {
|
|
182
|
+
// ROUND - ROBIN
|
|
183
|
+
const externalConnectionData = externalService.entries().next().value[1];
|
|
184
|
+
if(1 <= externalService.size) {
|
|
185
|
+
externalService.delete(externalConnectionData.connectionData.id);
|
|
186
|
+
externalService.set(externalConnectionData.connectionData.id, externalConnectionData);
|
|
187
|
+
}
|
|
188
|
+
return externalConnectionData.connectionData;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
on(serviceName, pluginService, cb) {
|
|
196
|
+
let serviceListeners = this.eventListeners.get(serviceName);
|
|
197
|
+
if(!serviceListeners) {
|
|
198
|
+
serviceListeners = new Map();
|
|
199
|
+
this.eventListeners.set(serviceName, serviceListeners);
|
|
200
|
+
}
|
|
201
|
+
serviceListeners.set(pluginService, cb);
|
|
202
|
+
if(this.services.has(serviceName)) {
|
|
203
|
+
cb();
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
module.exports = ExternalServices;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const GuidGenerator = require('z-abs-corelayer-cs/clientServer/guid-generator');
|
|
5
|
+
const MimeTypes = require('mime-types');
|
|
6
|
+
const Fs = require('fs');
|
|
7
|
+
const Path = require('path');
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class HttpCache {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.pathsArray = [];
|
|
13
|
+
this.cacheContent = new Map();
|
|
14
|
+
this.watchPaths = new Set();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
setPaths(watchPaths) {
|
|
18
|
+
this.pathsArray.push(watchPaths);
|
|
19
|
+
watchPaths.forEach((watchPath) => {
|
|
20
|
+
if(!this.watchPaths.has(watchPath)) {
|
|
21
|
+
Fs.watch(watchPath, {persistent: false, recursive: true}, (eventType, filename) => {
|
|
22
|
+
if(filename && 'change' === eventType) {
|
|
23
|
+
const file = `${watchPath}/${filename.replace(/\\/g, '/')}`;
|
|
24
|
+
this.cacheContent.delete(file);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
this.watchPaths.add(watchPath);
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
return this.pathsArray.length - 1;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
get(pathIndex, req, file, compressed, cb) {
|
|
34
|
+
const paths = this.pathsArray[pathIndex];
|
|
35
|
+
if(0 == paths.length) {
|
|
36
|
+
cb(false, null);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const pragma = req.headers['pragma'];
|
|
40
|
+
if('no-cache' === pragma) {
|
|
41
|
+
this.cacheContent.delete(file);
|
|
42
|
+
}
|
|
43
|
+
this._getContent(req, file, paths, compressed, (data) => {
|
|
44
|
+
if(!data) {
|
|
45
|
+
cb(true, null);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const ifNoneMatch = req.headers['if-none-match'];
|
|
49
|
+
if(ifNoneMatch === data.eTag) {
|
|
50
|
+
cb(false, data);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
const ifModifiedSince = req.headers['if-modified-since'];
|
|
54
|
+
if(ifModifiedSince === data.lastModified) {
|
|
55
|
+
cb(false, data);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
cb(true, data);
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
_readFile(file, paths, compressed, cb) {
|
|
64
|
+
let found = false;
|
|
65
|
+
let index = 0;
|
|
66
|
+
let pendings = paths.length;
|
|
67
|
+
while(!found && index < paths.length) {
|
|
68
|
+
const fileAndPath = `${paths[index++]}${file}${compressed ? '.gzip' : ''}`;
|
|
69
|
+
Fs.readFile(fileAndPath, (err, data) => {
|
|
70
|
+
if(!err) {
|
|
71
|
+
if(!found) {
|
|
72
|
+
found = true;
|
|
73
|
+
const foundContent = {
|
|
74
|
+
content: data,
|
|
75
|
+
contentLength: Buffer.byteLength(data),
|
|
76
|
+
mimeType: MimeTypes.lookup(file),
|
|
77
|
+
lastModified: new Date().toUTCString(),
|
|
78
|
+
eTag: `W/"${GuidGenerator.create()}"`
|
|
79
|
+
};
|
|
80
|
+
this.cacheContent.set(file, foundContent);
|
|
81
|
+
cb(foundContent);
|
|
82
|
+
}
|
|
83
|
+
--pendings;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
if(0 === --pendings) {
|
|
87
|
+
if(!found) {
|
|
88
|
+
cb(null);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
_getContent(req, file, paths, compressed, cb) {
|
|
97
|
+
const range = req.headers['range'];
|
|
98
|
+
const content = this.cacheContent.get(file);
|
|
99
|
+
if(content) {
|
|
100
|
+
cb(content);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
this._readFile(file, paths, compressed, cb);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
module.exports = HttpCache;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const http = require('http');
|
|
5
|
+
|
|
6
|
+
class HttpProxy {
|
|
7
|
+
constructor() {
|
|
8
|
+
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
init(httpData, tls) {}
|
|
12
|
+
|
|
13
|
+
handle(req, res) {
|
|
14
|
+
let reqUrl = '';
|
|
15
|
+
if(req.url.startsWith('/http')) {
|
|
16
|
+
reqUrl = req.url.substring(1).replaceAll('%3A', ':');
|
|
17
|
+
reqUrl = reqUrl.replaceAll('%2E', '.');
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
reqUrl = req.url;
|
|
21
|
+
}
|
|
22
|
+
console.log('reqUrl:', reqUrl);
|
|
23
|
+
const url = new URL(reqUrl);
|
|
24
|
+
const httpAgent = new http.Agent({keepAlive:true});
|
|
25
|
+
const options = {
|
|
26
|
+
hostname: url.hostname,
|
|
27
|
+
port: url.port,
|
|
28
|
+
path: req.path,
|
|
29
|
+
method: req.method,
|
|
30
|
+
headers: {...req.headers, connection:'keep-alive'}//,
|
|
31
|
+
// agent: httpAgent
|
|
32
|
+
};
|
|
33
|
+
Reflect.set(options.headers, 'host', url.hostname);
|
|
34
|
+
// Reflect.set(options.headers, 'referer', `http://${url.hostname}`);
|
|
35
|
+
|
|
36
|
+
this.sendRequest(req, res, options);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
sendRequest(req, res, options) {
|
|
40
|
+
console.log('****', options.hostname);
|
|
41
|
+
console.log('****', options.port);
|
|
42
|
+
console.log('****', options.path);
|
|
43
|
+
console.log('****', options.method);
|
|
44
|
+
console.log('****', options.headers);
|
|
45
|
+
const proxy = http.request(options, (proxyRes) => {
|
|
46
|
+
//console.log(proxyRes);
|
|
47
|
+
/*const headers = { ...proxyRes.headers, connection: 'keep-alive' };
|
|
48
|
+
res.writeHead(proxyRes.statusCode, headers);
|
|
49
|
+
//proxyRes.pipe(res, { end: true });*/
|
|
50
|
+
let body = '';
|
|
51
|
+
|
|
52
|
+
// Collect the response data
|
|
53
|
+
proxyRes.on('data', (chunk) => {
|
|
54
|
+
console.log('************************************************** data');
|
|
55
|
+
body += chunk;
|
|
56
|
+
console.log(chunk.toString());
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// Modify the response data and send it back to the client
|
|
60
|
+
proxyRes.on('end', () => {
|
|
61
|
+
console.log('************************************************** end');
|
|
62
|
+
// Modify the body here
|
|
63
|
+
// body = body.replace('original text', 'modified text');
|
|
64
|
+
console.log(body.toString());
|
|
65
|
+
// Modify response headers if necessary
|
|
66
|
+
const headers = { ...proxyRes.headers, connection: 'keep-alive' }; // Set keep-alive header
|
|
67
|
+
console.log('#####', proxyRes.statusCode)
|
|
68
|
+
if(200 === proxyRes.statusCode) {
|
|
69
|
+
res.writeHead(proxyRes.statusCode, headers);
|
|
70
|
+
res.end(body);
|
|
71
|
+
}
|
|
72
|
+
else if(302 === proxyRes.statusCode) {
|
|
73
|
+
// console.log(proxyRes.headers);
|
|
74
|
+
// console.log(proxyRes.rawHeaders);
|
|
75
|
+
options.path = headers.location;
|
|
76
|
+
this.sendRequest(req, res, options);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
res.writeHead(proxyRes.statusCode, headers);
|
|
80
|
+
res.end(body);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
proxy.on('error', (err) => {
|
|
86
|
+
console.log('************************************************** error');
|
|
87
|
+
console.error('Error with proxy:', err);
|
|
88
|
+
res.writeHead(502, { 'Content-Type': 'text/plain' });
|
|
89
|
+
res.end('Bad Gateway');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
req.pipe(proxy, { end: true });
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
module.exports = HttpProxy;
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
class HttpRequestHandler {
|
|
6
|
+
constructor(httpCache, dataResponse, defaultSite) {
|
|
7
|
+
this.httpCache = httpCache;
|
|
8
|
+
this.dataResponse = dataResponse;
|
|
9
|
+
this.defaultSite = defaultSite.startsWith('/') ? defaultSite : `/${defaultSite}`;
|
|
10
|
+
this.baseUrl = '';
|
|
11
|
+
this.pathId = -1;
|
|
12
|
+
this.authenticationToken = `token-${this.dataResponse.appName}=`
|
|
13
|
+
this.production = 'production' === process.env.NODE_ENV;
|
|
14
|
+
this.content = [
|
|
15
|
+
{
|
|
16
|
+
search: '/assets/',
|
|
17
|
+
route: '',
|
|
18
|
+
remove: ''
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
search: '/fonts/',
|
|
22
|
+
route: '',
|
|
23
|
+
remove: '/fonts'
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
_getToken(cookie) {
|
|
29
|
+
let token = '';
|
|
30
|
+
if(cookie) {
|
|
31
|
+
let startIndex = cookie.indexOf(this.authenticationToken);
|
|
32
|
+
if(-1 !== startIndex) {
|
|
33
|
+
startIndex += this.authenticationToken.length;
|
|
34
|
+
const stopIndex = cookie.indexOf(';', startIndex);
|
|
35
|
+
token = cookie.substring(startIndex, -1 !== stopIndex ? stopIndex : undefined);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
handle(req, res) {
|
|
41
|
+
//console.log('############################################');
|
|
42
|
+
//console.log(req.url, {...req.headers});
|
|
43
|
+
//console.log('############################################');
|
|
44
|
+
const myURL = new URL(req.url, this.baseUrl);
|
|
45
|
+
//console.log(req.url);
|
|
46
|
+
// console.log(req.headers);
|
|
47
|
+
if(myURL.pathname.startsWith('/abs-data/')) {
|
|
48
|
+
try {
|
|
49
|
+
if(req.method == 'POST') {
|
|
50
|
+
const rawBody = [];
|
|
51
|
+
req.on('data', (chunk) => {
|
|
52
|
+
rawBody.push(chunk);
|
|
53
|
+
});
|
|
54
|
+
req.on('end', () => {
|
|
55
|
+
const token = this._getToken(req.headers.cookie);
|
|
56
|
+
const requestObject = this._safeJsonParse(Buffer.concat(rawBody).toString());
|
|
57
|
+
if(null !== requestObject) {
|
|
58
|
+
this.dataResponse.handleRequests(requestObject, token, null, (response, dataBuffers, debug, token) => {
|
|
59
|
+
if(!token) {
|
|
60
|
+
this.jsonResponseHttp(res, JSON.stringify(response));
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
this.jsonLoginResponseHttp(res, token, JSON.stringify(response));
|
|
64
|
+
}
|
|
65
|
+
}, (message) => {
|
|
66
|
+
ddb.warning('DROPPED MSG:');
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
ddb.error('BAD REQ:');
|
|
71
|
+
res.writeHead(400, 'Bad Request', {'Content-Length': '0'});
|
|
72
|
+
res.end();
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
catch(err) {
|
|
79
|
+
ddb.error(err);
|
|
80
|
+
this.notFound(res);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
this.notImplementedServerError(res);
|
|
84
|
+
}
|
|
85
|
+
else if(myURL.pathname.startsWith('/abs-scripts/')) {
|
|
86
|
+
this.contentResponse(req, res, `/${myURL.pathname.substring('/abs-scripts/'.length)}`, true);
|
|
87
|
+
}
|
|
88
|
+
else if(myURL.pathname.startsWith('/abs-css/')) {
|
|
89
|
+
this.contentResponse(req, res, `/${myURL.pathname.substring('/abs-css/'.length)}`, true);
|
|
90
|
+
}
|
|
91
|
+
else if(myURL.pathname.startsWith('/abs-images/')) {
|
|
92
|
+
this.contentResponse(req, res, `/${myURL.pathname.substring('/abs-images/'.length)}`);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
const foundIndex = this.content.findIndex((content) => (-1 != myURL.pathname.indexOf(content.search)));
|
|
96
|
+
if(-1 !== foundIndex) {
|
|
97
|
+
const content = this.content[foundIndex];
|
|
98
|
+
const url = `${content.route}${myURL.pathname.substring(myURL.pathname.indexOf(content.search) + content.remove.length)}`;
|
|
99
|
+
this.contentResponse(req, res, url);
|
|
100
|
+
}
|
|
101
|
+
else if(myURL.pathname === '/favicon.ico') {
|
|
102
|
+
this.contentResponse(req, res, '/svg/ActorJsA.svg');
|
|
103
|
+
}
|
|
104
|
+
else if(myURL.pathname === '/') {
|
|
105
|
+
this.redirect(res, this.defaultSite);
|
|
106
|
+
}
|
|
107
|
+
else if(myURL.pathname.startsWith('/abs-api/')) {
|
|
108
|
+
const rawBody = [];
|
|
109
|
+
req.on('data', (chunk) => {
|
|
110
|
+
rawBody.push(chunk);
|
|
111
|
+
});
|
|
112
|
+
req.on('end', () => {
|
|
113
|
+
const token = this._getToken(req.headers.cookie);
|
|
114
|
+
this.dataResponse._handleRest(req.method, myURL.pathname, req.headers['content-type'], rawBody, token, (statusCode, reasonPhrase, contentType, content) => {
|
|
115
|
+
this.restResponse(res, statusCode, reasonPhrase, contentType, content)
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
this.contentResponse(req, res, '/index.html', false, true);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
init(data, tls) {
|
|
126
|
+
this.baseUrl = `http${tls ? 's' : ''}://${data.host}:${data.port}`;
|
|
127
|
+
this.domain = data.host;
|
|
128
|
+
this.pathId = this.httpCache.setPaths(data.directories);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
contentResponse(req, res, file, compressed, forced) {
|
|
132
|
+
const useCompressed = !!compressed && this.production;
|
|
133
|
+
this.httpCache.get(this.pathId, req, file, useCompressed, (modified, data) => {
|
|
134
|
+
if(data) {
|
|
135
|
+
if(modified || forced) {
|
|
136
|
+
res.setHeader('Accept-Ranges', 'bytes');
|
|
137
|
+
res.setHeader('Cache-Control', 'public, max-age=604800');
|
|
138
|
+
res.setHeader('ETag', data.eTag);
|
|
139
|
+
res.setHeader('Content-Type', data.mimeType + '; charset=utf-8');
|
|
140
|
+
res.setHeader('Date', new Date().toUTCString());
|
|
141
|
+
if(useCompressed) {
|
|
142
|
+
res.setHeader('Content-Encoding', 'gzip');
|
|
143
|
+
}
|
|
144
|
+
res.write(data.content);
|
|
145
|
+
res.end();
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
res.writeHead(304, 'Not Modified', {
|
|
149
|
+
'Cache-Control': 'public, max-age=604800',
|
|
150
|
+
'ETag': data.eTag,
|
|
151
|
+
'Date': new Date().toUTCString()
|
|
152
|
+
});
|
|
153
|
+
res.end();
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
ddb.error('not found:', file);
|
|
158
|
+
this.notFound(res);
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
jsonResponseHttp(res, data) {
|
|
164
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
165
|
+
res.write(data);
|
|
166
|
+
res.end();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
jsonLoginResponseHttp(res, token, data) {
|
|
170
|
+
res.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
171
|
+
res.setHeader('Set-Cookie', `${this.authenticationToken}${'-1' === token ? '' : token}; Domain=${this.domain}; Max-Age=${'-1' === token ? '0' : '604800'}; HttpOnly`);
|
|
172
|
+
res.write(data);
|
|
173
|
+
res.end();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
restResponse(res, statusCode, reasonPhrase, contentType, content) {
|
|
177
|
+
res.writeHead(statusCode, reasonPhrase);
|
|
178
|
+
if(content) {
|
|
179
|
+
res.setHeader('Content-Type', contentType + '; charset=utf-8');
|
|
180
|
+
if('application/json' === contentType) {
|
|
181
|
+
res.write(JSON.stringify(content, null, 2));
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
res.write(content);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
res.end();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
redirect(res, to) {
|
|
191
|
+
res.writeHead(302, {'Location': to});
|
|
192
|
+
res.end();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
notImplementedServerError(res) {
|
|
196
|
+
res.writeHead(501, "Not implemented", {'Content-Type': 'text/html; charset=utf-8'});
|
|
197
|
+
res.end(this.errorHtml('501 - Not implemented', '<h1>Not implemented!</h1>'));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
notFound(res) {
|
|
201
|
+
res.writeHead(404, 'Not Found', {"Content-Type": "text/html; charset=utf-8"});
|
|
202
|
+
res.end(this.errorHtml('404 - Not Found', '<h1>Not Found!</h1>'));
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
errorHtml(title, bodyText) {
|
|
206
|
+
return '<!DOCTYPE html><html lang="en-US"><head><title>' + title + '</title><meta charset="UTF-8"></head><body>' + bodyText + '</body></html>';
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
_safeJsonParse(string) {
|
|
210
|
+
try {
|
|
211
|
+
return JSON.parse(string);
|
|
212
|
+
}
|
|
213
|
+
catch(err) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
module.exports = HttpRequestHandler;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const HttpProxy = require('./http-proxy');
|
|
5
|
+
const HttpRequestHandler = require('./http-request-handler');
|
|
6
|
+
const Http = require('http');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class HttpServer {
|
|
10
|
+
constructor(serverData, nodeName, nodeId, httpCache, dataResponse, defaultSite) {
|
|
11
|
+
this.serverData = serverData;
|
|
12
|
+
this.nodeName = nodeName;
|
|
13
|
+
this.nodeId = nodeId;
|
|
14
|
+
this.httpRequestHandler = 'web & rest' === serverData.type ? new HttpRequestHandler(httpCache, dataResponse, defaultSite) : new HttpProxy();
|
|
15
|
+
this.pathsId = -1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
start(httpData, cb) {
|
|
19
|
+
this.httpRequestHandler.init(httpData, false);
|
|
20
|
+
const server = Http.createServer((req, res) => {
|
|
21
|
+
this.httpRequestHandler.handle(req, res);
|
|
22
|
+
});
|
|
23
|
+
server.on('listening', () => {
|
|
24
|
+
ddb.writelnTime(ddb.cyan('Server: '), `${this.nodeName}-${httpData.name} `, ddb.green('started at '), `http://${httpData.host}:${httpData.port}`);
|
|
25
|
+
cb();
|
|
26
|
+
});
|
|
27
|
+
server.on('error', (err) => {
|
|
28
|
+
ddb.writelnTimeError(err, ddb.red('Server: '), `'${this.nodeName}-${httpData.name}' `, ddb.red('did not start at '), `http://${httpData.host}:${httpData.port }`, ddb.red(',error: '), err.message);
|
|
29
|
+
cb(err);
|
|
30
|
+
});
|
|
31
|
+
server.listen(httpData.port, httpData.host);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
module.exports = HttpServer;
|