soajs.controller 4.2.20 → 4.2.30

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/lib/http.js CHANGED
@@ -19,7 +19,7 @@ const http = require('http');
19
19
  *
20
20
  * @returns {*}
21
21
  */
22
- http.IncomingMessage.prototype.getClientIP = function() {
22
+ http.IncomingMessage.prototype.getClientIP = function () {
23
23
  let x_forwarded_for = this.get('x-forwarded-for') ? this.get('x-forwarded-for').split(',')[0] : '';
24
24
  let ip_address = this.get('x-real-ip') || x_forwarded_for || this.connection.remoteAddress;
25
25
 
package/lib/request.js ADDED
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * @license
5
+ * Copyright SOAJS All Rights Reserved.
6
+ *
7
+ * Use of this source code is governed by an Apache license that can be
8
+ * found in the LICENSE file at the root of this repository
9
+ */
10
+
11
+ const http = require('http');
12
+
13
+ function checkStatus(uri) {
14
+ return new Promise((resolve, reject) => {
15
+ let onResponse = false;
16
+
17
+ const req = http.get(uri, (res) => {
18
+ if (res.statusCode === 200) {
19
+ onResponse = true;
20
+ resolve(res.statusCode === 200); // Resolve with true if 200, false otherwise
21
+ }
22
+ // res.on('data', () => { }); // Consume data to avoid issues (important!)
23
+
24
+ res.on('error', (err) => {
25
+ if (!onResponse) {
26
+ onResponse = true;
27
+ return reject(err);
28
+ }
29
+ });
30
+ res.on('close', () => {
31
+ if (!onResponse) {
32
+ onResponse = true;
33
+ return reject(new Error("Closed"));
34
+ }
35
+ });
36
+ });
37
+
38
+ req.on('error', (err) => {
39
+ if (!onResponse) {
40
+ onResponse = true;
41
+ return reject(err);
42
+ }
43
+ });
44
+ req.on('close', () => {
45
+ if (!onResponse) {
46
+ onResponse = true;
47
+ return reject(new Error("Closed"));
48
+ }
49
+ });
50
+
51
+
52
+ req.end();
53
+ });
54
+ }
55
+
56
+ function httpRequestLight({ uri, data = null, method = 'GET', headers = null, json = true }) {
57
+ return new Promise((resolve, reject) => {
58
+ let onResponse = false;
59
+ let options = {};
60
+ const requestDataString = data ? (json ? JSON.stringify(data) : data.toString()) : '';
61
+
62
+ try {
63
+ const urlObj = new URL(uri);
64
+ options = {
65
+ hostname: urlObj.hostname,
66
+ port: urlObj.port,
67
+ path: urlObj.pathname + urlObj.search,
68
+ method: method.toUpperCase(), // Ensure method is uppercase
69
+ headers: {
70
+ 'Content-Type': json ? 'application/json' : 'application/x-www-form-urlencoded',
71
+ 'Content-Length': data ? Buffer.byteLength(requestDataString) : 0,
72
+ },
73
+ };
74
+ if (headers) {
75
+ for (const key in headers) {
76
+ if (headers.hasOwnProperty(key)) {
77
+ options.headers[key] = headers[key];
78
+ }
79
+ }
80
+ }
81
+ } catch (error) {
82
+ if (!onResponse) {
83
+ onResponse = true;
84
+ return reject(error); // Reject with error and null data for request errors
85
+ }
86
+ }
87
+ const req = http.request(options);
88
+
89
+ req.on('response', (res) => { // Listen for the 'response' event
90
+ if (res.statusCode < 200 || res.statusCode >= 300) {
91
+ return reject(new Error(`Status Code: ${res.statusCode}`));
92
+ }
93
+
94
+ let responseData = '';
95
+
96
+ res.on('data', (chunk) => {
97
+ responseData += chunk;
98
+ });
99
+
100
+ res.on('end', () => {
101
+
102
+ if (!onResponse) {
103
+ onResponse = true;
104
+ try {
105
+ const parsedData = json ? JSON.parse(responseData) : responseData;
106
+ return resolve(parsedData);
107
+ } catch (error) {
108
+ return resolve(responseData);
109
+ }
110
+ }
111
+ });
112
+
113
+ res.on('error', (err) => {
114
+ if (!onResponse) {
115
+ onResponse = true;
116
+ return reject(err);
117
+ }
118
+ });
119
+ res.on('close', () => {
120
+ if (!onResponse) {
121
+ onResponse = true;
122
+ return reject(new Error("Closed"));
123
+ }
124
+ });
125
+ });
126
+
127
+ req.on('error', (err) => {
128
+ if (!onResponse) {
129
+ onResponse = true;
130
+ return reject(err);
131
+ }
132
+ });
133
+ req.on('close', () => {
134
+ if (!onResponse) {
135
+ onResponse = true;
136
+ return reject(new Error("Closed"));
137
+ }
138
+ });
139
+
140
+ if (data) {
141
+ req.write(requestDataString);
142
+ }
143
+
144
+ req.end();
145
+ });
146
+ }
147
+
148
+ function httpRequest({ uri, data = null, method = 'GET', headers = null, json = true }) {
149
+ return new Promise((resolve, reject) => {
150
+ let onResponse = false;
151
+ let options = {};
152
+
153
+ const requestDataString = data ? (json ? JSON.stringify(data) : data.toString()) : '';
154
+ try {
155
+ const urlObj = new URL(uri);
156
+
157
+ options = {
158
+ "hostname": urlObj.hostname,
159
+ "port": urlObj.port,
160
+ "path": urlObj.pathname + urlObj.search,
161
+ "method": method.toUpperCase(),
162
+ "headers": {
163
+ 'Content-Type': json ? 'application/json' : 'application/x-www-form-urlencoded',
164
+ 'Content-Length': data ? Buffer.byteLength(requestDataString) : 0,
165
+ },
166
+ };
167
+ if (headers) {
168
+ for (const key in headers) {
169
+ if (headers.hasOwnProperty(key)) {
170
+ options.headers[key] = headers[key];
171
+ }
172
+ }
173
+ }
174
+ } catch (error) {
175
+ if (!onResponse) {
176
+ onResponse = true;
177
+ return reject({ error: error, body: null }); // Reject with error and null data for request errors
178
+ }
179
+ }
180
+ const req = http.request(options);
181
+
182
+ req.on('response', (res) => { // Listen for the 'response' event
183
+ let responseData = '';
184
+
185
+ res.on('data', (chunk) => {
186
+ responseData += chunk;
187
+ });
188
+
189
+ res.on('end', () => {
190
+ if (!onResponse) {
191
+ onResponse = true;
192
+ if (res.statusCode < 200 || res.statusCode >= 300) {
193
+ const error = new Error(`Status Code: ${res.statusCode}`);
194
+ try {
195
+ const parsedData = json ? JSON.parse(responseData) : responseData;
196
+ return reject({ error: error, body: parsedData }); // Reject with error and data
197
+ } catch (parseError) {
198
+ return reject({ error: error, body: responseData }); // Reject with error and raw data if parse fails
199
+ }
200
+ }
201
+
202
+ try {
203
+ const parsedData = json ? JSON.parse(responseData) : responseData;
204
+ return resolve(parsedData);
205
+ } catch (parseError) {
206
+ return resolve(responseData);
207
+ }
208
+ }
209
+ });
210
+
211
+ res.on('close', () => {
212
+ if (!onResponse) {
213
+ onResponse = true;
214
+ return reject({ error: new Error("Closed"), body: null }); // Reject with error and null data for request errors
215
+ }
216
+ });
217
+ res.on('error', (error) => {
218
+ if (!onResponse) {
219
+ onResponse = true;
220
+ return reject({ error: error, body: null }); // Reject with error and null data for request errors
221
+ }
222
+ });
223
+ });
224
+
225
+ req.on('close', () => {
226
+ if (!onResponse) {
227
+ onResponse = true;
228
+ return reject({ error: new Error("Closed"), body: null }); // Reject with error and null data for request errors
229
+ }
230
+ });
231
+ req.on('error', (error) => {
232
+ if (!onResponse) {
233
+ onResponse = true;
234
+ return reject({ error: error, body: null }); // Reject with error and null data for request errors
235
+ }
236
+ });
237
+
238
+ if (data) {
239
+ req.write(requestDataString);
240
+ }
241
+ req.end();
242
+ });
243
+ }
244
+
245
+ function proxyRequest(req, res, options, extraOptions = {}) {
246
+ return new Promise((resolve, reject) => {
247
+ let onResponse = false;
248
+
249
+ const proxyReq = http.request(options);
250
+ if (extraOptions && extraOptions.fetchProxReq) {
251
+ extraOptions.fetchProxReq(proxyReq);
252
+ }
253
+ proxyReq.on('response', (proxyRes) => {
254
+ if (extraOptions && extraOptions.resHeaders) {
255
+ extraOptions.resHeaders.forEach(x => {
256
+ proxyRes.headers[x] = extraOptions.resHeaders[x];
257
+ });
258
+ }
259
+ res.writeHead(proxyRes.statusCode, proxyRes.headers); // Forward status code and headers
260
+ if (options.method !== 'HEAD') {
261
+
262
+ proxyRes.on('end', () => {
263
+ if (!onResponse) {
264
+ onResponse = true;
265
+ return resolve(); // Resolve when the proxy response ends
266
+ }
267
+ });
268
+
269
+ proxyRes.on('close', () => {
270
+ if (!onResponse) {
271
+ onResponse = true;
272
+ return reject(new Error("Closed")); // Reject if the proxy response encounters an error
273
+ }
274
+ });
275
+ proxyRes.on('error', (err) => {
276
+ if (!onResponse) {
277
+ onResponse = true;
278
+ return reject(err); // Reject if the proxy response encounters an error
279
+ }
280
+ });
281
+
282
+ proxyRes.pipe(res); // Pipe the proxy response to the original response
283
+ } else {
284
+ onResponse = true;
285
+ res.end(); // End response immediately for HEAD requests
286
+ return resolve();
287
+ }
288
+ });
289
+
290
+ req.pipe(proxyReq); // Pipe the original request to the proxy request
291
+
292
+ proxyReq.on('close', () => {
293
+ if (!onResponse) {
294
+ onResponse = true;
295
+ return reject(new Error("Closed")); // Reject if the proxy request encounters an error
296
+ }
297
+ });
298
+ proxyReq.on('error', (err) => {
299
+ if (!onResponse) {
300
+ onResponse = true;
301
+ return reject(err); // Reject if the proxy request encounters an error
302
+ }
303
+ });
304
+ });
305
+ }
306
+
307
+ function proxyRequestMonitor(req, res, options, extraOptions = {}) {
308
+ return new Promise((resolve, reject) => {
309
+ let onResponse = false;
310
+
311
+ const proxyReq = http.request(options);
312
+ if (extraOptions && extraOptions.fetchProxReq) {
313
+ extraOptions.fetchProxReq(proxyReq);
314
+ }
315
+ proxyReq.on('response', (proxyRes) => {
316
+ if (extraOptions && extraOptions.resHeaders) {
317
+ extraOptions.resHeaders.forEach(x => {
318
+ proxyRes.headers[x] = extraOptions.resHeaders[x];
319
+ });
320
+ }
321
+ if (!res.headersSent) {
322
+ res.writeHead(proxyRes.statusCode, proxyRes.headers); // Forward status code and headers
323
+ }
324
+ let resContentType = proxyRes.headers['content-type'];
325
+
326
+ if (extraOptions && extraOptions.events && extraOptions.events.response) {
327
+ extraOptions.events.response(resContentType);
328
+ }
329
+
330
+ if (options.method !== 'HEAD') {
331
+ if (extraOptions && extraOptions.events && extraOptions.events.data) {
332
+ proxyRes.on('data', (chunk) => {
333
+ extraOptions.events.data(chunk);
334
+ });
335
+ }
336
+ proxyRes.on('end', () => {
337
+ if (!onResponse) {
338
+ onResponse = true;
339
+ return resolve(); // Resolve when the proxy response ends
340
+ }
341
+ });
342
+
343
+ proxyRes.on('close', () => {
344
+ if (!onResponse) {
345
+ onResponse = true;
346
+ return reject(new Error("Closed")); // Reject if the proxy response encounters an error
347
+ }
348
+ });
349
+ proxyRes.on('error', (err) => {
350
+ if (!onResponse) {
351
+ onResponse = true;
352
+ return reject(err); // Reject if the proxy response encounters an error
353
+ }
354
+ });
355
+
356
+ proxyRes.pipe(res); // Pipe the proxy response to the original response
357
+ } else {
358
+ onResponse = true;
359
+ res.end(); // End response immediately for HEAD requests
360
+ return resolve();
361
+ }
362
+ });
363
+
364
+ req.pipe(proxyReq); // Pipe the original request to the proxy request
365
+
366
+ proxyReq.on('close', () => {
367
+ if (!onResponse) {
368
+ onResponse = true;
369
+ return reject(new Error("Closed")); // Reject if the proxy request encounters an error
370
+ }
371
+ });
372
+ proxyReq.on('error', (err) => {
373
+ if (!onResponse) {
374
+ onResponse = true;
375
+ return reject(err); // Reject if the proxy request encounters an error
376
+ }
377
+ });
378
+ });
379
+ }
380
+
381
+ module.exports = { checkStatus, httpRequestLight, httpRequest, proxyRequest, proxyRequestMonitor };
@@ -9,8 +9,8 @@
9
9
  */
10
10
 
11
11
  const registryModule = require("./../../modules/registry");
12
+ const { checkStatus } = require("../../lib/request.js");
12
13
 
13
- const request = require('request');
14
14
  const async = require('async');
15
15
 
16
16
  let registry = null;
@@ -32,7 +32,7 @@ let awareness_healthCheck = function (core, log) {
32
32
  for (let s in registry.services) {
33
33
  if (Object.hasOwnProperty.call(registry.services, s)) {
34
34
  if (!serviceAwarenessObj[s]) {
35
- serviceAwarenessObj[s] = {"healthy": {}, "indexes": {}};
35
+ serviceAwarenessObj[s] = { "healthy": {}, "indexes": {} };
36
36
  }
37
37
  if (!serviceAwarenessObj[s].healthy) {
38
38
  serviceAwarenessObj[s].healthy = {};
@@ -64,11 +64,11 @@ let awareness_healthCheck = function (core, log) {
64
64
  }
65
65
  }
66
66
  }
67
-
67
+
68
68
  for (let s in registry.daemons) {
69
69
  if (Object.hasOwnProperty.call(registry.daemons, s)) {
70
70
  if (!serviceAwarenessObj[s]) {
71
- serviceAwarenessObj[s] = {"healthy": {}, "indexes": {}};
71
+ serviceAwarenessObj[s] = { "healthy": {}, "indexes": {} };
72
72
  }
73
73
  if (!serviceAwarenessObj[s].healthy) {
74
74
  serviceAwarenessObj[s].healthy = {};
@@ -103,24 +103,32 @@ let awareness_healthCheck = function (core, log) {
103
103
  }
104
104
  async.each(awarenessHosts.servicesArr,
105
105
  function (sObj, callback) {
106
-
106
+
107
107
  let checkForHeartBeat = function (host, port, path, callback) {
108
- request({
109
- 'uri': 'http://' + host + ':' + port + path
110
- }, function (error, response) {
111
- if (!error && response.statusCode === 200) {
112
- callback(true);
113
- } else {
114
- callback(false);
115
- }
108
+ checkStatus ('http://' + host + ':' + port + path)
109
+ .then (()=>{
110
+ callback(true);
111
+ })
112
+ .catch (()=>{
113
+ callback(false);
116
114
  });
115
+
116
+ // request({
117
+ // 'uri': 'http://' + host + ':' + port + path
118
+ // }, function (error, response) {
119
+ // if (!error && response.statusCode === 200) {
120
+ // callback(true);
121
+ // } else {
122
+ // callback(false);
123
+ // }
124
+ // });
117
125
  };
118
-
126
+
119
127
  let nextStep = function (found) {
120
128
  if (registry[sObj.what][sObj.name] && !registry[sObj.what][sObj.name].awarenessStats) {
121
129
  registry[sObj.what][sObj.name].awarenessStats = {};
122
130
  }
123
- let statusObj = {"lastCheck": new Date().getTime(), "healthy": false, "version": sObj.version};
131
+ let statusObj = { "lastCheck": new Date().getTime(), "healthy": false, "version": sObj.version };
124
132
  if (found) {
125
133
  statusObj.healthy = true;
126
134
  if (serviceAwarenessObj[sObj.name].healthy[sObj.version].indexOf(sObj.host) === -1) {
@@ -134,7 +142,7 @@ let awareness_healthCheck = function (core, log) {
134
142
  statusObj.downSince = statusObj.lastCheck;
135
143
  statusObj.downCount = 0;
136
144
  }
137
-
145
+
138
146
  let stopLoggingAfter = registry.serviceConfig.awareness.maxLogCount;
139
147
  if (statusObj.downCount <= stopLoggingAfter) {
140
148
  log.warn("Self Awareness health check for service [" + sObj.name + "] for host [" + sObj.host + "] is NOT healthy");
@@ -148,13 +156,13 @@ let awareness_healthCheck = function (core, log) {
148
156
  }
149
157
  }
150
158
  }
151
-
159
+
152
160
  if (registry[sObj.what][sObj.name] && registry[sObj.what][sObj.name].awarenessStats) {
153
161
  registry[sObj.what][sObj.name].awarenessStats[sObj.host] = statusObj;
154
162
  }
155
163
  callback();
156
164
  };
157
-
165
+
158
166
  if (registry.services[sObj.name] && registry.services[sObj.name].maintenance && registry.services[sObj.name].maintenance.readiness && registry.services[sObj.name].maintenance.port) {
159
167
  let port = sObj.port;
160
168
  let path = registry.services[sObj.name].maintenance.readiness;
@@ -8,10 +8,10 @@
8
8
  * found in the LICENSE file at the root of this repository
9
9
  */
10
10
 
11
- const request = require('request');
12
11
  const async = require('async');
13
12
 
14
13
  const registryModule = require("./../../modules/registry");
14
+ const { checkStatus } = require("../../lib/request.js");
15
15
 
16
16
  let gatewayServiceName = null;
17
17
  let regEnvironment = (process.env.SOAJS_ENV || "dev");
@@ -34,7 +34,7 @@ let fetchControllerHosts = function (core, log, next) {
34
34
  setTimeout(() => {
35
35
  fetchControllerHosts(core, log);
36
36
  }, registry.serviceConfig.awareness.autoRelaodRegistry);
37
-
37
+
38
38
  if (next && typeof next === "function") {
39
39
  next();
40
40
  }
@@ -43,7 +43,7 @@ let fetchControllerHosts = function (core, log, next) {
43
43
 
44
44
  let awareness_healthCheck = function (core, log) {
45
45
  registry = registryModule.get();
46
-
46
+
47
47
  let resume = () => {
48
48
  if (controllerHosts && Array.isArray(controllerHosts) && controllerHosts.length > 0) {
49
49
  let controllerPort = registry.services.controller.port;
@@ -53,7 +53,7 @@ let awareness_healthCheck = function (core, log) {
53
53
  serviceAwarenessObj[sObj.env] = {};
54
54
  }
55
55
  if (!serviceAwarenessObj[sObj.env][sObj.name]) {
56
- serviceAwarenessObj[sObj.env][sObj.name] = {"healthy": {}, "indexes": {}, "latest": 1};
56
+ serviceAwarenessObj[sObj.env][sObj.name] = { "healthy": {}, "indexes": {}, "latest": 1 };
57
57
  }
58
58
  if (!serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version]) {
59
59
  serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version] = [];
@@ -61,17 +61,18 @@ let awareness_healthCheck = function (core, log) {
61
61
  if (!serviceAwarenessObj[sObj.env][sObj.name].indexes[sObj.version]) {
62
62
  serviceAwarenessObj[sObj.env][sObj.name].indexes[sObj.version] = 0;
63
63
  }
64
- request({
65
- 'uri': 'http://' + sObj.ip + ':' + (controllerPort + registry.serviceConfig.ports.maintenanceInc) + '/heartbeat'
66
- }, function (error, response) {
67
- if (serviceAwarenessObj[sObj.env][sObj.name].latest < sObj.version) {
68
- serviceAwarenessObj[sObj.env][sObj.name].latest = sObj.version;
69
- }
70
- if (!error && response.statusCode === 200) {
64
+
65
+ if (serviceAwarenessObj[sObj.env][sObj.name].latest < sObj.version) {
66
+ serviceAwarenessObj[sObj.env][sObj.name].latest = sObj.version;
67
+ }
68
+ checkStatus('http://' + sObj.ip + ':' + (controllerPort + registry.serviceConfig.ports.maintenanceInc) + '/heartbeat')
69
+ .then(() => {
71
70
  if (serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].indexOf(sObj.ip) === -1) {
72
71
  serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].push(sObj.ip);
73
72
  }
74
- } else {
73
+ callback();
74
+ })
75
+ .catch(() => {
75
76
  if (serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].indexOf(sObj.ip) !== -1) {
76
77
  //TODO: if we guarantee uniqueness we will not need the for loop
77
78
  for (let ii = 0; ii < serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].length; ii++) {
@@ -80,9 +81,30 @@ let awareness_healthCheck = function (core, log) {
80
81
  }
81
82
  }
82
83
  }
83
- }
84
- callback();
85
- });
84
+ callback();
85
+ });
86
+ // request({
87
+ // 'uri': 'http://' + sObj.ip + ':' + (controllerPort + registry.serviceConfig.ports.maintenanceInc) + '/heartbeat'
88
+ // }, function (error, response) {
89
+ // if (serviceAwarenessObj[sObj.env][sObj.name].latest < sObj.version) {
90
+ // serviceAwarenessObj[sObj.env][sObj.name].latest = sObj.version;
91
+ // }
92
+ // if (!error && response.statusCode === 200) {
93
+ // if (serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].indexOf(sObj.ip) === -1) {
94
+ // serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].push(sObj.ip);
95
+ // }
96
+ // } else {
97
+ // if (serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].indexOf(sObj.ip) !== -1) {
98
+ // //TODO: if we guarantee uniqueness we will not need the for loop
99
+ // for (let ii = 0; ii < serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].length; ii++) {
100
+ // if (serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version][ii] === sObj.ip) {
101
+ // serviceAwarenessObj[sObj.env][sObj.name].healthy[sObj.version].splice(ii, 1);
102
+ // }
103
+ // }
104
+ // }
105
+ // }
106
+ // callback();
107
+ // });
86
108
  }, function (err) {
87
109
  if (err) {
88
110
  log.warn('Unable to build awareness ENV structure for controllers: ' + err);
@@ -93,13 +115,13 @@ let awareness_healthCheck = function (core, log) {
93
115
  awareness_healthCheck(core, log);
94
116
  }, registry.serviceConfig.awareness.healthCheckInterval);
95
117
  };
96
-
118
+
97
119
  if (timeLoaded !== registry.timeLoaded) {
98
120
  fetchControllerHosts(core, log, resume);
99
121
  } else {
100
122
  resume();
101
123
  }
102
-
124
+
103
125
  timeLoaded = registry.timeLoaded;
104
126
  };
105
127
 
@@ -123,7 +145,7 @@ function roundRobin() {
123
145
  env = arguments[2];
124
146
  break;
125
147
  }
126
-
148
+
127
149
  env = env || regEnvironment;
128
150
  s = gatewayServiceName;
129
151
  if (env && s && serviceAwarenessObj[env] && serviceAwarenessObj[env][s] && serviceAwarenessObj[env][s].healthy) {