@activeledger/activenetwork 2.15.6 → 4.3.3

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.
Files changed (79) hide show
  1. package/es/network/cpus.d.ts +1 -0
  2. package/es/network/cpus.d.ts.map +1 -1
  3. package/es/network/cpus.js +26 -15
  4. package/es/network/cpus.js.map +1 -1
  5. package/es/network/endpoints.d.ts +7 -3
  6. package/es/network/endpoints.d.ts.map +1 -1
  7. package/es/network/endpoints.js +685 -172
  8. package/es/network/endpoints.js.map +1 -1
  9. package/es/network/home.d.ts.map +1 -1
  10. package/es/network/home.js +41 -19
  11. package/es/network/home.js.map +1 -1
  12. package/es/network/host.d.ts +15 -7
  13. package/es/network/host.d.ts.map +1 -1
  14. package/es/network/host.js +631 -240
  15. package/es/network/host.js.map +1 -1
  16. package/es/network/locker.d.ts +10 -5
  17. package/es/network/locker.d.ts.map +1 -1
  18. package/es/network/locker.js +50 -17
  19. package/es/network/locker.js.map +1 -1
  20. package/es/network/maintain.d.ts.map +1 -1
  21. package/es/network/maintain.js +42 -42
  22. package/es/network/maintain.js.map +1 -1
  23. package/es/network/neighbour.d.ts +8 -4
  24. package/es/network/neighbour.d.ts.map +1 -1
  25. package/es/network/neighbour.js +82 -18
  26. package/es/network/neighbour.js.map +1 -1
  27. package/es/network/neighbourhood.d.ts +1 -1
  28. package/es/network/neighbourhood.d.ts.map +1 -1
  29. package/es/network/neighbourhood.js +39 -42
  30. package/es/network/neighbourhood.js.map +1 -1
  31. package/es/network/p2pClient.d.ts +20 -0
  32. package/es/network/p2pClient.d.ts.map +1 -0
  33. package/es/network/p2pClient.js +84 -0
  34. package/es/network/p2pClient.js.map +1 -0
  35. package/es/network/process.js +99 -65
  36. package/es/network/process.js.map +1 -1
  37. package/es/network/utils.d.ts.map +1 -1
  38. package/es/network/utils.js +17 -21
  39. package/es/network/utils.js.map +1 -1
  40. package/lib/network/cpus.d.ts +1 -0
  41. package/lib/network/cpus.d.ts.map +1 -1
  42. package/lib/network/cpus.js +26 -15
  43. package/lib/network/cpus.js.map +1 -1
  44. package/lib/network/endpoints.d.ts +7 -3
  45. package/lib/network/endpoints.d.ts.map +1 -1
  46. package/lib/network/endpoints.js +684 -171
  47. package/lib/network/endpoints.js.map +1 -1
  48. package/lib/network/home.d.ts.map +1 -1
  49. package/lib/network/home.js +41 -19
  50. package/lib/network/home.js.map +1 -1
  51. package/lib/network/host.d.ts +15 -7
  52. package/lib/network/host.d.ts.map +1 -1
  53. package/lib/network/host.js +630 -239
  54. package/lib/network/host.js.map +1 -1
  55. package/lib/network/locker.d.ts +10 -5
  56. package/lib/network/locker.d.ts.map +1 -1
  57. package/lib/network/locker.js +50 -17
  58. package/lib/network/locker.js.map +1 -1
  59. package/lib/network/maintain.d.ts.map +1 -1
  60. package/lib/network/maintain.js +42 -42
  61. package/lib/network/maintain.js.map +1 -1
  62. package/lib/network/neighbour.d.ts +8 -4
  63. package/lib/network/neighbour.d.ts.map +1 -1
  64. package/lib/network/neighbour.js +82 -18
  65. package/lib/network/neighbour.js.map +1 -1
  66. package/lib/network/neighbourhood.d.ts +1 -1
  67. package/lib/network/neighbourhood.d.ts.map +1 -1
  68. package/lib/network/neighbourhood.js +39 -42
  69. package/lib/network/neighbourhood.js.map +1 -1
  70. package/lib/network/p2pClient.d.ts +20 -0
  71. package/lib/network/p2pClient.d.ts.map +1 -0
  72. package/lib/network/p2pClient.js +88 -0
  73. package/lib/network/p2pClient.js.map +1 -0
  74. package/lib/network/process.js +98 -64
  75. package/lib/network/process.js.map +1 -1
  76. package/lib/network/utils.d.ts.map +1 -1
  77. package/lib/network/utils.js +17 -21
  78. package/lib/network/utils.js.map +1 -1
  79. package/package.json +10 -8
@@ -1,8 +1,8 @@
1
- import { createServer } from "http";
2
1
  import { fork } from "child_process";
3
2
  import { readlinkSync } from "fs";
4
3
  import { basename } from "path";
5
- import { ActiveDSConnect, ActiveOptions, ActiveGZip, ActiveRequest, } from "@activeledger/activeoptions";
4
+ import * as net from "net";
5
+ import { ActiveDSConnect, ActiveOptions, ActiveGZip, ActiveRequest, ActiveClone, } from "@activeledger/activeoptions";
6
6
  import { ActiveCrypto } from "@activeledger/activecrypto";
7
7
  import { ActiveLogger } from "@activeledger/activelogger";
8
8
  import { Home } from "./home";
@@ -12,80 +12,72 @@ import { Endpoints, Maintain } from "./index";
12
12
  import { Locker } from "./locker";
13
13
  import { PhysicalCores } from "./cpus";
14
14
  import * as process from "process";
15
- const RELEASE_SHUTDOWN_TIMEOUT = 5 * 60 * 1000;
16
- const RELEASE_DELETE_TIMEOUT = 1 * 60 * 1000;
17
- const TIMER_QUEUE_INTERVAL = 10 * 1000;
15
+ import { App, us_listen_socket_close, } from "uWebSockets.js";
16
+ const RELEASE_SHUTDOWN_TIMEOUT = 1 * 60 * 1000;
17
+ const RELEASE_DELETE_TIMEOUT = 2 * 60 * 1000;
18
+ const TIMER_QUEUE_INTERVAL = 2 * 1000;
18
19
  const GRACEFUL_PROC_SHUTDOWN = 7 * 60 * 1000;
19
20
  const KILL_PROC_SHUTDOWN = 2.5 * 1000;
21
+ const MAX_RETRIES = 35;
22
+ function peekBytes(chunks, n) {
23
+ if (chunks.length > 0 && chunks[0].length >= n) {
24
+ return chunks[0];
25
+ }
26
+ let total = 0;
27
+ let end = 0;
28
+ while (end < chunks.length && total < n) {
29
+ total += chunks[end].length;
30
+ end++;
31
+ }
32
+ return Buffer.concat(chunks.slice(0, end));
33
+ }
20
34
  export class Host extends Home {
21
- constructor() {
22
- super();
23
- this.processPending = {};
24
- this.cpuReady = 0;
25
- this.busyLocksQueue = [];
26
- let db = ActiveOptions.get("db", {});
27
- this.dbConnection = new ActiveDSConnect(db.url + "/" + db.database);
28
- this.dbConnection.info();
29
- this.dbErrorConnection = new ActiveDSConnect(db.url + "/" + db.error);
30
- this.dbErrorConnection.info();
31
- this.dbEventConnection = new ActiveDSConnect(db.url + "/" + db.event);
32
- this.dbEventConnection.info();
33
- this.hybridHosts = ActiveOptions.get("hybrid", []);
34
- if (this.hybridHosts.length) {
35
- for (let i = this.hybridHosts.length; i--;) {
36
- const hybrid = this.hybridHosts[i];
37
- hybrid.docName = ActiveCrypto.Hash.getHash(hybrid.url + hybrid.auth);
38
- }
35
+ p2pServer;
36
+ listenSocket;
37
+ api;
38
+ dbConnection;
39
+ dbErrorConnection;
40
+ dbEventConnection;
41
+ processPending = {};
42
+ cpuReady = 0;
43
+ hybridHosts;
44
+ busyLocksQueue = { internal: [], external: [] };
45
+ shutdown() {
46
+ if (this.listenSocket) {
47
+ us_listen_socket_close(this.listenSocket);
48
+ this.listenSocket = null;
49
+ setTimeout(() => {
50
+ ActiveLogger.info("Stopping HTTP Server");
51
+ this.api.close();
52
+ ActiveLogger.info("Shutting down...");
53
+ process.exit(0);
54
+ }, 1300);
39
55
  }
40
- this.api = createServer((req, res) => {
41
- ActiveLogger.debug(`Request - ${req.connection.remoteAddress} @ ${req.method}:${req.url}`);
42
- if (req.method == "POST") {
43
- const body = [];
44
- req.on("data", (chunk) => {
45
- body.push(chunk);
46
- });
47
- req.on("end", async () => {
48
- let data = Buffer.concat(body);
49
- if (req.headers["content-encoding"] == "gzip" ||
50
- (data[0] == 0x1f && data[1] == 0x8b)) {
51
- try {
52
- data = await ActiveGZip.ungzip(data);
53
- }
54
- catch (_a) {
56
+ }
57
+ pending(entry, remoteAddr, internal = false, forceRestart = false, isP2P = false) {
58
+ return new Promise(async (resolve, reject) => {
59
+ if (entry.$broadcast && entry.$nodes) {
60
+ const nodeSpoofCheck = Object.keys(entry.$nodes);
61
+ if (nodeSpoofCheck.length) {
62
+ for (let i = nodeSpoofCheck.length; i--;) {
63
+ const nodeCheck = nodeSpoofCheck[i];
64
+ if (!this.neighbourhood.checkFirewall(remoteAddr, nodeCheck)) {
65
+ return reject("Bad Neighbour Payload");
55
66
  }
56
67
  }
57
- Endpoints.postConvertor(this, data.toString(), req.headers["x-activeledger-encrypt"] ||
58
- false)
59
- .then((body) => {
60
- this.processEndpoints(req, res, body.body, body.from);
61
- })
62
- .catch((error) => {
63
- this.writeResponse(res, error.statusCode || 500, JSON.stringify(error.content || {}), req.headers["accept-encoding"]);
64
- });
65
- });
68
+ }
66
69
  }
67
- else {
68
- this.processEndpoints(req, res);
70
+ if (forceRestart && this.processPending[entry.$umid]) {
71
+ this.destroy(entry.$umid, true);
72
+ delete this.processPending[entry.$umid];
69
73
  }
70
- });
71
- const cpuTotal = PhysicalCores.count();
72
- const latestSetupMsg = this.getLatestSetup();
73
- for (let i = 0; i < cpuTotal; i++) {
74
- const processor = this.createProcessor(cpuTotal);
75
- this.processors.push(processor);
76
- processor.send(latestSetupMsg);
77
- }
78
- this.standbyProcess = this.createProcessor(cpuTotal);
79
- this.standbyProcess.send(latestSetupMsg);
80
- this.processorIterator = this.processors[Symbol.iterator]();
81
- this.timerQueue();
82
- }
83
- pending(entry, internal = false) {
84
- return new Promise((resolve, reject) => {
85
74
  if (entry.$broadcast) {
86
75
  if (this.processPending[entry.$umid]) {
87
- ActiveLogger.debug("Broadcast Recieved : " + entry.$umid);
88
- if (this.processPending[entry.$umid].pid) {
76
+ if (!this.processPending[entry.$umid]?.finished &&
77
+ this.processPending[entry.$umid]?.pid &&
78
+ !this.processPending[entry.$umid]?.entry?.$nodes?.[this.reference]
79
+ ?.leader) {
80
+ ActiveLogger.debug(`Broadcast Recieved [${isP2P ? "P2P" : "HTTP"}] : ` + entry.$umid);
89
81
  const processor = this.findProcessor(this.processPending[entry.$umid].pid);
90
82
  if (processor) {
91
83
  processor.send({
@@ -99,35 +91,327 @@ export class Host extends Home {
99
91
  else {
100
92
  }
101
93
  }
94
+ else {
95
+ const pendingEntry = this.processPending[entry.$umid]?.entry;
96
+ if (pendingEntry) {
97
+ delete entry.$nodes[this.reference];
98
+ pendingEntry.$nodes = { ...pendingEntry.$nodes, ...entry.$nodes };
99
+ }
100
+ }
101
+ if (!entry.$$noreply) {
102
+ this.broadcast(entry.$umid, false, true);
103
+ }
102
104
  return resolve({
103
105
  status: 200,
104
106
  data: this.processPending[entry.$umid].entry,
107
+ dontRelease: true,
105
108
  });
106
109
  }
107
110
  }
108
111
  if (!this.processPending[entry.$umid]) {
109
112
  this.processPending[entry.$umid] = {
110
- entry: entry,
113
+ entry,
111
114
  resolve: (response) => {
112
- this.release({ entry, resolve: null, reject: null, pid: 0 });
113
- resolve(response);
115
+ if (internal && this.processPending[entry.$umid]?.responded) {
116
+ this.release(entry.$umid);
117
+ }
118
+ if (this.processPending[entry.$umid]) {
119
+ this.processPending[entry.$umid].finished = true;
120
+ }
121
+ if (!this.processPending[entry.$umid]?.responded) {
122
+ resolve(response);
123
+ try {
124
+ this.processPending[entry.$umid].responded = true;
125
+ ActiveLogger.debug("Client Response TX : " + entry.$umid);
126
+ }
127
+ catch { }
128
+ }
114
129
  },
115
130
  reject: (response) => {
116
- this.release({ entry, resolve: null, reject: null, pid: 0 });
117
- reject(response);
131
+ if (this.processPending[entry.$umid]) {
132
+ this.processPending[entry.$umid].finished = true;
133
+ }
134
+ if (!this.processPending[entry.$umid]?.responded) {
135
+ reject(response);
136
+ try {
137
+ this.processPending[entry.$umid].responded = true;
138
+ }
139
+ catch { }
140
+ }
118
141
  },
119
142
  pid: 0,
143
+ finished: false,
144
+ responded: false,
120
145
  };
146
+ if (entry.$tx.$expire && remoteAddr !== this.host) {
147
+ if (await this.dbConnection.exists(`${entry.$umid}:umid`)) {
148
+ if (entry.$nodes) {
149
+ entry.$nodes[this.reference] = {
150
+ vote: false,
151
+ commit: false,
152
+ error: `Transaction Exists : ${entry.$umid}`,
153
+ };
154
+ }
155
+ else {
156
+ entry.$nodes = {
157
+ [this.reference]: {
158
+ vote: false,
159
+ commit: false,
160
+ error: `Transaction Exists : ${entry.$umid}`,
161
+ },
162
+ };
163
+ }
164
+ return this.processPending[entry.$umid].resolve({
165
+ status: 200,
166
+ data: entry,
167
+ });
168
+ }
169
+ }
121
170
  this.processQueue(entry, internal);
171
+ if (internal && entry.$broadcast) {
172
+ this.processPending[entry.$umid].responded = true;
173
+ return resolve({
174
+ status: 200,
175
+ data: { ok: true },
176
+ dontRelease: true,
177
+ });
178
+ }
122
179
  }
123
180
  else {
124
181
  return resolve({
125
182
  status: 200,
126
183
  data: this.processPending[entry.$umid].entry,
184
+ dontRelease: true,
127
185
  });
128
186
  }
129
187
  });
130
188
  }
189
+ constructor() {
190
+ super();
191
+ if (ActiveOptions.get("p2pStreamServer", false)) {
192
+ this.p2pServer = net.createServer((socket) => {
193
+ ActiveLogger.info(`P2P TCP connection accepted from ${socket.remoteAddress}`);
194
+ let chunks = [];
195
+ let bufferLength = 0;
196
+ socket.on("data", async (data) => {
197
+ chunks.push(data);
198
+ bufferLength += data.length;
199
+ while (bufferLength >= 44) {
200
+ const header = peekBytes(chunks, 44);
201
+ const length = header.readUInt32BE(40);
202
+ if (bufferLength >= 44 + length) {
203
+ const fullBuffer = Buffer.concat(chunks);
204
+ const senderRef = fullBuffer.slice(0, 40).toString().trim();
205
+ const item = fullBuffer.slice(44, 44 + length);
206
+ const remaining = fullBuffer.slice(44 + length);
207
+ chunks = remaining.length > 0 ? [remaining] : [];
208
+ bufferLength = remaining.length;
209
+ const tx = await ActiveClone.deserialize(item);
210
+ this.processEndpoints({
211
+ headers: { "X-Activeledger": senderRef },
212
+ method: "POST",
213
+ url: "/a/init",
214
+ connection: { remoteAddress: socket.remoteAddress || "127.0.0.1" },
215
+ }, null, tx, senderRef, true);
216
+ }
217
+ else {
218
+ break;
219
+ }
220
+ }
221
+ });
222
+ socket.on("error", (err) => {
223
+ ActiveLogger.error(err, "P2P socket error");
224
+ });
225
+ });
226
+ const p2pPort = parseInt(ActiveInterfaces.getBindingDetails("port")) + 1;
227
+ this.p2pServer.listen(p2pPort, () => {
228
+ ActiveLogger.info(`P2P TCP server listening on port ${p2pPort}`);
229
+ });
230
+ }
231
+ let db = ActiveOptions.get("db", {});
232
+ this.dbConnection = new ActiveDSConnect(db.url + "/" + db.database);
233
+ this.dbConnection.info();
234
+ this.dbErrorConnection = new ActiveDSConnect(db.url + "/" + db.error);
235
+ this.dbErrorConnection.info();
236
+ this.dbEventConnection = new ActiveDSConnect(db.url + "/" + db.event);
237
+ this.dbEventConnection.info();
238
+ this.hybridHosts = ActiveOptions.get("hybrid", []);
239
+ if (this.hybridHosts.length) {
240
+ for (let i = this.hybridHosts.length; i--;) {
241
+ const hybrid = this.hybridHosts[i];
242
+ hybrid.docName = ActiveCrypto.Hash.getHash(hybrid.url + hybrid.auth);
243
+ }
244
+ }
245
+ this.api = App();
246
+ this.api.any("/*", async (res, req) => {
247
+ res.onAborted(() => {
248
+ res.writable = false;
249
+ });
250
+ res.writable = true;
251
+ const headers = {
252
+ "Accept-Encoding": req.getHeader("accept-encoding"),
253
+ "X-Activeledger": req.getHeader("x-activeledger"),
254
+ "x-activeledger-encrypt": req.getHeader("x-activeledger-encrypt"),
255
+ "content-encoding": req.getHeader("content-encoding"),
256
+ "X-Bundle": req.getHeader("x-bundle"),
257
+ };
258
+ const method = req.getMethod().toUpperCase();
259
+ const url = req.getUrl();
260
+ let ipFrom = Buffer.from(res.getProxiedRemoteAddressAsText().byteLength
261
+ ? res.getProxiedRemoteAddressAsText()
262
+ : res.getRemoteAddressAsText()).toString();
263
+ if (ipFrom.indexOf(":") !== -1) {
264
+ const ip6 = this.parseIp6(ipFrom);
265
+ ipFrom =
266
+ (ip6[6] >> 8) +
267
+ "." +
268
+ (ip6[6] & 0xff) +
269
+ "." +
270
+ (ip6[7] >> 8) +
271
+ "." +
272
+ (ip6[7] & 0xff);
273
+ }
274
+ if (method === "POST") {
275
+ let body = await this.readBuffer(res);
276
+ if (headers["content-encoding"] == "gzip" ||
277
+ (body[0] == 0x1f && body[1] == 0x8b)) {
278
+ try {
279
+ body = await ActiveGZip.ungzip(body);
280
+ }
281
+ catch (e) {
282
+ }
283
+ }
284
+ const bodyString = (await this.makeSureNotBuffer(body));
285
+ let bundles;
286
+ if (headers["X-Bundle"]) {
287
+ bundles = bodyString.split(":$ALB:");
288
+ res.cork(() => {
289
+ res.writeStatus("200");
290
+ res.writeHeader("Content-Type", "application/json");
291
+ res.end("{}");
292
+ });
293
+ res.writable = false;
294
+ }
295
+ else {
296
+ bundles = [bodyString];
297
+ }
298
+ for (let i = bundles.length; i--;) {
299
+ if (bundles[i]) {
300
+ Endpoints.postConvertor(this, bundles[i], headers["x-activeledger-encrypt"] || false)
301
+ .then((body) => {
302
+ this.processEndpoints({
303
+ headers,
304
+ method,
305
+ url,
306
+ connection: {
307
+ remoteAddress: ipFrom,
308
+ },
309
+ }, res, body.body, body.from);
310
+ })
311
+ .catch((error) => {
312
+ ActiveLogger.error(error, "Server POST Parser 500");
313
+ this.writeResponse(res, error.statusCode || 500, JSON.stringify(error.content || { error: 1 }), headers["Accept-Encoding"]);
314
+ })
315
+ .finally(() => {
316
+ });
317
+ }
318
+ }
319
+ }
320
+ else {
321
+ if (method === "OPTIONS") {
322
+ await this.writeResponse(res, 200, "{}", "", true);
323
+ }
324
+ else {
325
+ await this.processEndpoints({
326
+ headers,
327
+ method,
328
+ url,
329
+ connection: {
330
+ remoteAddress: ipFrom,
331
+ },
332
+ }, res);
333
+ }
334
+ }
335
+ });
336
+ const cpuTotal = parseInt(ActiveOptions.get("cpus", "0")) || PhysicalCores.count();
337
+ const latestSetupMsg = this.getLatestSetup();
338
+ for (let i = 0; i < cpuTotal; i++) {
339
+ const processor = this.createProcessor(cpuTotal);
340
+ this.processors.push(processor);
341
+ processor.send(latestSetupMsg);
342
+ }
343
+ this.standbyProcess = this.createProcessor(cpuTotal);
344
+ this.standbyProcess.send(latestSetupMsg);
345
+ this.processorIterator = this.processors[Symbol.iterator]();
346
+ this.timerQueue();
347
+ }
348
+ readBuffer(res) {
349
+ return new Promise((resolve, reject) => {
350
+ const chunks = [];
351
+ res.onData((ab, isLast) => {
352
+ if (res.aborted) {
353
+ reject(new Error("Request aborted"));
354
+ return;
355
+ }
356
+ if (ab.byteLength > 0) {
357
+ const buffer = Buffer.allocUnsafe(ab.byteLength);
358
+ buffer.set(new Uint8Array(ab));
359
+ chunks.push(buffer);
360
+ }
361
+ if (isLast) {
362
+ resolve(chunks.length === 0
363
+ ? Buffer.alloc(0)
364
+ : chunks.length === 1
365
+ ? chunks[0]
366
+ : Buffer.concat(chunks));
367
+ }
368
+ });
369
+ });
370
+ }
371
+ parseIp6(str) {
372
+ var ar = new Array();
373
+ for (var i = 0; i < 8; i++)
374
+ ar[i] = 0;
375
+ if (str == "::")
376
+ return ar;
377
+ var sar = str.split(":");
378
+ var slen = sar.length;
379
+ if (slen > 8)
380
+ slen = 8;
381
+ var j = 0;
382
+ for (var i = 0; i < slen; i++) {
383
+ if (i && sar[i] == "") {
384
+ j = 9 - slen + i;
385
+ continue;
386
+ }
387
+ ar[j] = parseInt("0x0" + sar[i]);
388
+ j++;
389
+ }
390
+ return ar;
391
+ }
392
+ async makeSureNotBuffer(obj) {
393
+ if (obj.type === "Buffer" && obj.data?.length) {
394
+ if (obj.data[0] == 0x1f && obj.data[1] == 0x8b) {
395
+ return (await ActiveGZip.ungzip(Buffer.from(obj.data))).toString();
396
+ }
397
+ return Buffer.from(obj.data).toString();
398
+ }
399
+ if (Buffer.isBuffer(obj)) {
400
+ if (obj[0] == 0x1f && obj[1] == 0x8b) {
401
+ return (await ActiveGZip.ungzip(obj)).toString();
402
+ }
403
+ const tmp = obj.toString();
404
+ if (tmp.startsWith('{"type":"Buffer"')) {
405
+ const asBufferObj = JSON.parse(tmp);
406
+ if (asBufferObj.data[0] == 0x1f && asBufferObj.data[1] == 0x8b) {
407
+ return (await ActiveGZip.ungzip(Buffer.from(asBufferObj.data))).toString();
408
+ }
409
+ return Buffer.from(asBufferObj.data).toString();
410
+ }
411
+ return obj.toString();
412
+ }
413
+ return obj;
414
+ }
131
415
  getLatestSetup() {
132
416
  return {
133
417
  type: "setup",
@@ -151,29 +435,33 @@ export class Host extends Home {
151
435
  pFork.stop = false;
152
436
  let unloadHandled = false;
153
437
  const unloadProcessorSafely = (...error) => {
154
- if (unloadHandled) {
155
- ActiveLogger.fatal(error, "Processor Crashed - Already Shutting Down");
438
+ if (unloadHandled || !this.listenSocket) {
156
439
  }
157
440
  else {
158
441
  pFork.stop = unloadHandled = true;
159
442
  ActiveLogger.fatal(error, "Processor Crashed");
160
443
  this.processors.push(this.standbyProcess);
161
444
  this.standbyProcess = this.createProcessor();
162
- this.standbyProcess.send(this.getLatestSetup());
445
+ setTimeout(() => {
446
+ this.standbyProcess.send(this.getLatestSetup(), (e) => {
447
+ if (e) {
448
+ ActiveLogger.fatal(e, "Issue with new Standby Process");
449
+ }
450
+ });
451
+ }, 1000);
163
452
  ActiveLogger.fatal(pFork, "Will Gracefully Shutdown in " + GRACEFUL_PROC_SHUTDOWN);
164
453
  setTimeout(() => {
165
454
  ActiveLogger.fatal(pFork, "Starting Graceful Shutdown");
166
455
  const pendings = Object.keys(this.processPending);
167
456
  pendings.forEach((key) => {
168
457
  let pending = this.processPending[key];
169
- if ((pending === null || pending === void 0 ? void 0 : pending.pid) === pFork.pid) {
458
+ if (pending?.pid === pFork.pid) {
170
459
  pending.entry.$nodes[this.reference].error =
171
460
  "(Contract Thread Error) Unknown - Try Again";
172
461
  pending.resolve({
173
462
  status: 200,
174
463
  data: pending.entry,
175
464
  });
176
- this.release(pending);
177
465
  }
178
466
  });
179
467
  ActiveLogger.fatal(pFork, "Will Kill in " + KILL_PROC_SHUTDOWN);
@@ -191,10 +479,9 @@ export class Host extends Home {
191
479
  }
192
480
  };
193
481
  pFork.on("message", (m) => {
194
- var _a;
195
482
  const pending = this.processPending[m.data.umid];
196
483
  if (pending) {
197
- if (m.data.nodes) {
484
+ if (m.data.nodes && !m.data.early) {
198
485
  pending.entry.$nodes = {
199
486
  ...pending.entry.$nodes,
200
487
  ...m.data.nodes,
@@ -213,12 +500,10 @@ export class Host extends Home {
213
500
  return;
214
501
  pending.resolve({
215
502
  status: 200,
216
- data: pending.entry,
503
+ data: m.data.entry
504
+ ? { ...pending.entry, ...m.data.entry }
505
+ : pending.entry,
217
506
  });
218
- this.release(pending);
219
- if (m.data && this.hybridHosts.length) {
220
- this.processHybridNodes(pending.entry);
221
- }
222
507
  break;
223
508
  case "commited":
224
509
  if (!pending)
@@ -227,9 +512,8 @@ export class Host extends Home {
227
512
  status: 200,
228
513
  data: { ...pending.entry, ...m.data.entry },
229
514
  });
230
- this.release(pending);
231
515
  if (this.hybridHosts.length) {
232
- this.processHybridNodes(pending.entry, (_a = m.data.entry) === null || _a === void 0 ? void 0 : _a.$streams);
516
+ this.processHybridNodes(pending.entry, m.data.entry?.$streams);
233
517
  }
234
518
  break;
235
519
  case "broadcast":
@@ -241,8 +525,10 @@ export class Host extends Home {
241
525
  case "ready":
242
526
  if (cpuTotal) {
243
527
  this.cpuReady++;
244
- if (!this.api.listening && this.cpuReady >= cpuTotal) {
245
- this.api.listen(ActiveInterfaces.getBindingDetails("port"), () => {
528
+ if (!this.listeing && this.cpuReady >= cpuTotal) {
529
+ this.listeing = true;
530
+ this.api.listen(ActiveInterfaces.getBindingDetails("port"), (token) => {
531
+ this.listenSocket = token;
246
532
  ActiveLogger.info("Activeledger listening on port " +
247
533
  ActiveInterfaces.getBindingDetails("port"));
248
534
  });
@@ -256,10 +542,12 @@ export class Host extends Home {
256
542
  status: 200,
257
543
  data: { ...pending.entry, ...m.data.entry },
258
544
  });
259
- this.release(pending);
260
545
  }
261
- unloadProcessorSafely("unhandledrejection - Already Handled, Tidying up processes");
546
+ if (!m.data.recoverable) {
547
+ unloadProcessorSafely("unhandledrejection - Already Handled, Tidying up processes");
548
+ }
262
549
  break;
550
+ case "contractData":
263
551
  case "contractLatestVersion":
264
552
  this.processors.forEach((processor) => {
265
553
  processor.send(m);
@@ -276,6 +564,7 @@ export class Host extends Home {
276
564
  pFork.on("error", unloadProcessorSafely);
277
565
  return pFork;
278
566
  }
567
+ listeing = false;
279
568
  reload() {
280
569
  ActiveOptions.extendConfig()
281
570
  .then((config) => {
@@ -304,57 +593,73 @@ export class Host extends Home {
304
593
  ActiveLogger.info(e, "Failed to reload Neighbourhood");
305
594
  });
306
595
  }
307
- destroy(umid) {
308
- var _a;
596
+ destroy(umid, skipTimeout = false) {
309
597
  if (this.processPending[umid]) {
310
598
  this.processPending[umid].shutdown = true;
311
- (_a = this.findProcessor(this.processPending[umid].pid)) === null || _a === void 0 ? void 0 : _a.send({
599
+ this.findProcessor(this.processPending[umid].pid)?.send({
312
600
  type: "destory",
313
601
  data: {
314
602
  umid,
603
+ skipTimeout,
315
604
  },
316
605
  });
317
- setTimeout(() => {
318
- delete this.processPending[umid];
319
- }, RELEASE_DELETE_TIMEOUT);
606
+ if (!skipTimeout) {
607
+ setTimeout(() => {
608
+ delete this.processPending[umid];
609
+ }, RELEASE_DELETE_TIMEOUT);
610
+ }
320
611
  }
321
612
  }
322
- broadcast(umid, early = false) {
323
- var _a;
324
- if (((_a = this.processPending[umid]) === null || _a === void 0 ? void 0 : _a.entry) &&
613
+ broadcast(umid, early = false, noreply = false) {
614
+ if (this.processPending[umid] && this.processPending[umid].broadcasting) {
615
+ return;
616
+ }
617
+ if (this.processPending[umid]?.entry &&
325
618
  this.processPending[umid].entry.$broadcast &&
326
619
  this.processPending[umid].entry.$nodes &&
327
- this.processPending[umid].entry.$nodes[this.reference]) {
328
- ActiveLogger.debug("Broadcasting TX : " + umid);
620
+ (early ||
621
+ (this.processPending[umid].entry.$nodes[this.reference] &&
622
+ "vote" in this.processPending[umid].entry.$nodes[this.reference]))) {
623
+ this.processPending[umid].broadcasting = true;
624
+ ActiveLogger.debug(`Broadcasting TX ($$NR ${noreply}) : ` + umid);
329
625
  let neighbourhood = this.neighbourhood.get();
330
626
  let nodes = this.neighbourhood.keys();
331
- let i = nodes.length;
332
627
  let promises = [];
333
- const data = !early
628
+ const selfEntry = this.processPending[umid].entry.$nodes[this.reference];
629
+ const data = selfEntry && !selfEntry.early
334
630
  ? Object.assign(this.processPending[umid].entry, {
335
631
  $nodes: {
336
- [this.reference]: this.processPending[umid].entry.$nodes[this.reference],
632
+ [this.reference]: selfEntry,
337
633
  },
338
634
  })
339
635
  : Object.assign(this.processPending[umid].entry, {
340
636
  $nodes: {},
341
637
  });
342
638
  if (data) {
343
- while (i--) {
639
+ data.$$noreply = noreply;
640
+ if (early) {
641
+ data.$$noreply = true;
642
+ }
643
+ for (let i = nodes.length; i--;) {
344
644
  let node = neighbourhood[nodes[i]];
345
- if (node.isHome && node.reference !== this.reference) {
346
- promises.push(node.knock("init", data));
645
+ if (node.isHome &&
646
+ node.reference !==
647
+ this
648
+ .reference) {
649
+ promises.push(node.knock("init", data, false, 0, true));
347
650
  }
348
651
  }
652
+ Promise.all(promises)
653
+ .then(() => {
654
+ this.processPending[umid].broadcasting = false;
655
+ })
656
+ .catch(() => {
657
+ this.processPending[umid].broadcasting = false;
658
+ setTimeout(() => {
659
+ this.broadcastResolver(umid);
660
+ }, 250);
661
+ });
349
662
  }
350
- Promise.all(promises)
351
- .then(() => {
352
- })
353
- .catch(() => {
354
- setTimeout(() => {
355
- this.broadcastResolver(umid);
356
- }, 500);
357
- });
358
663
  }
359
664
  }
360
665
  broadcastResolver(umid) {
@@ -374,14 +679,18 @@ export class Host extends Home {
374
679
  },
375
680
  reason: "Failed to rebroadcast while in memory",
376
681
  };
377
- this.dbErrorConnection.post(doc);
682
+ this.dbErrorConnection.post(doc).catch((error) => {
683
+ ActiveLogger.error(error, "Failed to write rebroadcast-failure error document");
684
+ });
378
685
  }
379
686
  }
380
687
  labelOrKey(txIO) {
381
688
  const keys = Object.keys(txIO || {});
382
689
  const out = [];
383
690
  for (let i = keys.length; i--;) {
384
- out.push(this.filterPrefix(txIO[keys[i]].$stream || keys[i]));
691
+ if (!txIO[keys[i]].$sigOnly) {
692
+ out.push(this.filterPrefix(txIO[keys[i]].$stream || keys[i]));
693
+ }
385
694
  }
386
695
  return out;
387
696
  }
@@ -392,19 +701,27 @@ export class Host extends Home {
392
701
  return streamId;
393
702
  }
394
703
  hold(v, retries = 0) {
395
- if (v.$selfsign ||
396
- Locker.hold([
397
- ...new Set([
398
- ...this.labelOrKey(v.$tx.$i),
399
- ...this.labelOrKey(v.$tx.$o),
400
- ]),
401
- ])) {
704
+ if (!v.$$labelOrKey) {
705
+ const outputs = this.labelOrKey(v.$tx.$o);
706
+ if (!v.$selfsign) {
707
+ v.$$labelOrKey = [
708
+ ...new Set([...this.labelOrKey(v.$tx.$i), ...outputs]),
709
+ ];
710
+ }
711
+ else {
712
+ v.$$labelOrKey = outputs;
713
+ }
714
+ }
715
+ if (Locker.hold(v.$$labelOrKey, v.$umid)) {
402
716
  const robin = this.getRobin();
403
717
  if (!this.processPending[v.$umid].entry.$nodes)
404
- this.processPending[v.$umid].entry.$nodes = {};
718
+ if (!this.processPending[v.$umid].entry.$nodes) {
719
+ this.processPending[v.$umid].entry.$nodes = {};
720
+ }
405
721
  this.processPending[v.$umid].entry.$nodes[Home.reference] = {
406
722
  vote: false,
407
723
  commit: false,
724
+ early: true
408
725
  };
409
726
  this.processPending[v.$umid].pid = robin.pid || 0;
410
727
  robin.send({
@@ -414,60 +731,70 @@ export class Host extends Home {
414
731
  return true;
415
732
  }
416
733
  else {
417
- if (retries === 0) {
418
- this.busyLocksQueue.push({
419
- entry: v,
420
- retry: 1,
421
- });
422
- }
423
- else {
424
- const internal = v.$revs ? true : false;
425
- const maxRetries = internal
426
- ? 2
427
- : ActiveOptions.get("queue_retry", 5);
428
- if (retries > maxRetries) {
429
- if (internal) {
430
- if (!v.$nodes) {
431
- v.$nodes = {};
432
- }
433
- v.$nodes[this.reference] = {
734
+ if (v.$nolock) {
735
+ if (v.$broadcast) {
736
+ this.processPending[v.$umid].entry.$nodes = {
737
+ [this.reference]: {
434
738
  vote: false,
435
739
  commit: false,
436
740
  error: "Busy Locks",
437
- };
438
- const doc = {
439
- code: 1100,
440
- processed: false,
441
- umid: v.$umid,
442
- transaction: v,
443
- locker: Locker.getLocks(),
444
- reason: "Internal Busy Locks",
445
- };
446
- this.dbErrorConnection.post(doc);
447
- if (!v.$broadcast && Home.right.reference != v.$origin) {
448
- (async () => {
449
- const next = await Home.right.knock("init", v);
741
+ },
742
+ };
743
+ this.broadcast(v.$umid, false, true);
744
+ ActiveLogger.warn(this.processPending[v.$umid], `${v.$umid} busy lock broadcasting that fact`);
745
+ }
746
+ this.processPending[v.$umid].reject({
747
+ status: 100,
748
+ error: "Busy Locks",
749
+ });
750
+ }
751
+ else {
752
+ if (retries === 0) {
753
+ (v.$revs
754
+ ? this.busyLocksQueue.internal
755
+ : this.busyLocksQueue.external).push({
756
+ running: false,
757
+ entry: v,
758
+ retry: 1,
759
+ });
760
+ }
761
+ else {
762
+ const internal = v.$revs ? true : false;
763
+ if (retries > ActiveOptions.get("queue_retry", MAX_RETRIES)) {
764
+ if (internal) {
765
+ if (!v.$nodes) {
766
+ v.$nodes = {};
767
+ }
768
+ v.$nodes[this.reference] = {
769
+ vote: false,
770
+ commit: false,
771
+ error: "IBL01",
772
+ };
773
+ if (!v.$broadcast && Home.right.reference != v.$origin) {
774
+ (async () => {
775
+ const next = await Home.right.knock("init", v);
776
+ this.processPending[v.$umid].resolve({
777
+ status: 200,
778
+ data: { ...v, ...next.data },
779
+ });
780
+ })();
781
+ }
782
+ else {
783
+ this.broadcast(v.$umid, false, true);
450
784
  this.processPending[v.$umid].resolve({
451
785
  status: 200,
452
- data: { ...v, ...next.data },
786
+ data: v,
453
787
  });
454
- })();
788
+ }
455
789
  }
456
790
  else {
457
- this.processPending[v.$umid].resolve({
458
- status: 200,
459
- data: v,
791
+ this.processPending[v.$umid].reject({
792
+ status: 100,
793
+ error: "Busy Locks",
460
794
  });
461
795
  }
796
+ return true;
462
797
  }
463
- else {
464
- this.processPending[v.$umid].reject({
465
- status: 100,
466
- error: "Busy Locks",
467
- });
468
- }
469
- this.release(this.processPending[v.$umid]);
470
- return true;
471
798
  }
472
799
  }
473
800
  return false;
@@ -484,36 +811,68 @@ export class Host extends Home {
484
811
  }
485
812
  return robin;
486
813
  }
487
- release(pending) {
488
- Locker.release([
489
- ...this.labelOrKey(pending.entry.$tx.$i),
490
- ...this.labelOrKey(pending.entry.$tx.$o),
491
- ]);
492
- setTimeout(() => {
493
- if (pending.entry) {
494
- this.destroy(pending.entry.$umid);
495
- }
496
- }, RELEASE_SHUTDOWN_TIMEOUT);
497
- setTimeout(() => {
498
- this.processQueue();
499
- }, 100);
814
+ release(umid) {
815
+ if (this.processPending[umid]) {
816
+ const entry = this.processPending[umid].entry;
817
+ Locker.release(entry.$$labelOrKey || [
818
+ ...this.labelOrKey(entry.$tx.$i),
819
+ ...this.labelOrKey(entry.$tx.$o),
820
+ ], entry.$umid);
821
+ setTimeout(() => {
822
+ if (entry) {
823
+ this.destroy(entry.$umid);
824
+ }
825
+ }, RELEASE_SHUTDOWN_TIMEOUT);
826
+ setTimeout(() => {
827
+ this.processQueue();
828
+ }, 200);
829
+ }
830
+ else {
831
+ ActiveLogger.warn(umid, "Trying to release unknown umid");
832
+ }
500
833
  }
834
+ processingBLQ = false;
501
835
  processQueue(next, internal = false) {
502
- let skipped = false;
503
- if (next && internal && !next.$broadcast) {
504
- this.hold(next);
505
- skipped = true;
506
- }
507
- if (this.busyLocksQueue.length) {
508
- for (let i = 0; i < this.busyLocksQueue.length; i++) {
509
- if (this.hold(this.busyLocksQueue[i].entry, this.busyLocksQueue[i].retry++)) {
510
- delete this.busyLocksQueue[i];
836
+ if (!this.processingBLQ) {
837
+ this.processingBLQ = true;
838
+ const checked = new Set();
839
+ if (this.busyLocksQueue.internal.length) {
840
+ const stillPending = [];
841
+ busyQueueInternal: for (let i = 0; i < this.busyLocksQueue.internal.length; i++) {
842
+ const labelOrKey = this.busyLocksQueue.internal[i].entry.$$labelOrKey;
843
+ if (labelOrKey?.length) {
844
+ if (labelOrKey.some((io) => checked.has(io))) {
845
+ continue busyQueueInternal;
846
+ }
847
+ labelOrKey.forEach((io) => checked.add(io));
848
+ }
849
+ if (!this.hold(this.busyLocksQueue.internal[i].entry, this.busyLocksQueue.internal[i].retry++)) {
850
+ stillPending.push(this.busyLocksQueue.internal[i]);
851
+ }
511
852
  }
853
+ this.busyLocksQueue.internal = stillPending;
854
+ }
855
+ if (next && internal) {
856
+ this.hold(next);
512
857
  }
513
- this.busyLocksQueue = this.busyLocksQueue.filter((n) => n);
858
+ if (this.busyLocksQueue.external.length) {
859
+ const stillPending = [];
860
+ for (let i = 0; i < this.busyLocksQueue.external.length; i++) {
861
+ if (!this.hold(this.busyLocksQueue.external[i].entry, this.busyLocksQueue.external[i].retry++)) {
862
+ stillPending.push(this.busyLocksQueue.external[i]);
863
+ }
864
+ }
865
+ this.busyLocksQueue.external = stillPending;
866
+ }
867
+ if (next && !internal) {
868
+ this.hold(next);
869
+ }
870
+ this.processingBLQ = false;
514
871
  }
515
- if (next && !skipped) {
516
- this.hold(next);
872
+ else {
873
+ if (next) {
874
+ this.hold(next);
875
+ }
517
876
  }
518
877
  }
519
878
  timerQueue() {
@@ -547,12 +906,12 @@ export class Host extends Home {
547
906
  const data = response.data;
548
907
  if (data.status !== "ok") {
549
908
  const updated = [
550
- ...((activityStreams === null || activityStreams === void 0 ? void 0 : activityStreams.new) || []),
551
- ...((activityStreams === null || activityStreams === void 0 ? void 0 : activityStreams.updated) || []),
909
+ ...(activityStreams?.new || []),
910
+ ...(activityStreams?.updated || []),
552
911
  ].map((stream) => stream.id);
553
- const input = tx.$tx.$i
554
- ? this.hybridLabelKeyId(tx.$tx.$i)
555
- : [];
912
+ const input = tx.$tx.$i ?
913
+ this.hybridLabelKeyId(tx.$tx.$i) :
914
+ [];
556
915
  const output = tx.$tx.$o
557
916
  ? this.hybridLabelKeyId(tx.$tx.$o)
558
917
  : [];
@@ -567,8 +926,8 @@ export class Host extends Home {
567
926
  }
568
927
  }
569
928
  const tmp = [];
570
- for (let i = keys.length; i--;) {
571
- tmp.push(keys[i] + ":stream");
929
+ for (const key of keys) {
930
+ tmp.push(key + ":stream");
572
931
  }
573
932
  keys.push(...tmp);
574
933
  return this.dbConnection
@@ -620,15 +979,16 @@ export class Host extends Home {
620
979
  return streams;
621
980
  }
622
981
  }
623
- processEndpoints(req, res, body, from) {
624
- let requester = req.headers["x-activeledger"] || "NA";
982
+ processEndpoints(req, res, body, from, isP2P = false) {
983
+ let requester = req.headers["X-Activeledger"] || "NA";
625
984
  let response;
626
- let gzipAccepted = req.headers["accept-encoding"];
985
+ const started = Date.now();
986
+ let gzipAccepted = req.headers["Accept-Encoding"];
627
987
  switch (req.method) {
628
988
  case "GET":
629
989
  switch (req.url) {
630
990
  case "/a/locks":
631
- return this.writeResponse(res, 200, JSON.stringify(Locker.getLocks()), gzipAccepted);
991
+ return this.writeResponse(res, 200, JSON.stringify({ L: Locker.getLocks(), Q: this.busyLocksQueue }), gzipAccepted);
632
992
  case "/a/locks/check":
633
993
  Locker.checkLocks();
634
994
  return this.writeResponse(res, 200, JSON.stringify({ checked: true }), gzipAccepted);
@@ -636,15 +996,39 @@ export class Host extends Home {
636
996
  response = Endpoints.status(this, requester);
637
997
  break;
638
998
  case "/a/all":
639
- if (this.firewallCheck(requester, req)) {
999
+ if (this.firewallCheck(requester, req.connection.remoteAddress)) {
640
1000
  response = Endpoints.all(this.dbConnection);
641
1001
  }
642
1002
  else {
643
1003
  return this.writeResponse(res, 403, "Forbidden", gzipAccepted);
644
1004
  }
645
1005
  break;
1006
+ case "/a/admin-reload":
1007
+ if (!ActiveOptions.get("remote", false)) {
1008
+ return this.writeResponse(res, 200, JSON.stringify({
1009
+ status: "failed",
1010
+ message: "remote disabled"
1011
+ }), gzipAccepted);
1012
+ }
1013
+ try {
1014
+ ActiveOptions.parseConfig();
1015
+ ActiveLogger.enableDebug = ActiveOptions.get("debug", false);
1016
+ this.reload();
1017
+ ActiveLogger.info("Host and child processes config.json reloaded successfully via admin API");
1018
+ return this.writeResponse(res, 200, JSON.stringify({
1019
+ status: "success",
1020
+ build: ActiveOptions.get("build", 0),
1021
+ }), gzipAccepted);
1022
+ }
1023
+ catch (error) {
1024
+ ActiveLogger.error(error, "Admin reload error");
1025
+ return this.writeResponse(res, 200, JSON.stringify({
1026
+ status: "failed",
1027
+ message: error.message || "Internal Error"
1028
+ }), gzipAccepted);
1029
+ }
646
1030
  default:
647
- if (this.firewallCheck(requester, req)) {
1031
+ if (this.firewallCheck(requester, req.connection.remoteAddress)) {
648
1032
  if (req.url) {
649
1033
  let match = req.url.substr(0, 7);
650
1034
  switch (match) {
@@ -670,41 +1054,27 @@ export class Host extends Home {
670
1054
  case "POST":
671
1055
  switch (req.url) {
672
1056
  case "/":
673
- response = Endpoints.ExternalInitalise(this, body, req.connection.remoteAddress || "unknown");
1057
+ response = Endpoints.ExternalInitalise(this, body, req.connection.remoteAddress || "unknown", this.dbConnection);
674
1058
  break;
675
1059
  case "/a/encrypt":
676
1060
  response = Endpoints.ExternalEncrypt(this, body, req.headers["x-activeledger-encrypt"] ||
677
1061
  false, this.dbConnection);
678
1062
  break;
679
1063
  case "/a/init":
680
- if (this.firewallCheck(requester, req)) {
681
- response = Endpoints.InternalInitalise(this, body);
1064
+ if (this.firewallCheck(requester, req.connection.remoteAddress)) {
1065
+ response = Endpoints.InternalInitalise(this, body, req.connection.remoteAddress, false, isP2P);
682
1066
  }
683
1067
  else {
684
1068
  return this.writeResponse(res, 403, "Forbidden", gzipAccepted);
685
1069
  }
686
1070
  break;
687
1071
  case "/a/stream":
688
- if (this.firewallCheck(requester, req)) {
689
- response = Endpoints.streams(this.dbConnection, body);
690
- }
691
- else {
692
- return this.writeResponse(res, 403, "Forbidden", gzipAccepted);
693
- }
1072
+ response = Endpoints.streams(this.dbConnection, body);
694
1073
  break;
695
1074
  default:
696
1075
  return this.writeResponse(res, 404, "Not Found", gzipAccepted);
697
1076
  }
698
1077
  break;
699
- case "OPTIONS":
700
- res.writeHead(200, {
701
- "Access-Control-Allow-Origin": "*",
702
- "Access-Control-Allow-Methods": "GET, POST",
703
- "Access-Control-Allow-Headers": req.headers["access-control-request-headers"] || "*",
704
- "X-Powered-By": "Activeledger",
705
- });
706
- res.end();
707
- return;
708
1078
  default:
709
1079
  return this.writeResponse(res, 404, "Not Found", gzipAccepted);
710
1080
  }
@@ -719,31 +1089,52 @@ export class Host extends Home {
719
1089
  $enc: true,
720
1090
  };
721
1091
  }
1092
+ if (data.$umid) {
1093
+ const TT = Date.now() - started;
1094
+ if (TT > 5) {
1095
+ ActiveLogger.info(`[RR] ${data.$umid ? data.$umid : "No Umid"} : S=${started}, TT=${TT}ms ${TT > 30000 ? "TTLR" : " OK"}`);
1096
+ }
1097
+ }
722
1098
  this.writeResponse(res, response.statusCode, JSON.stringify(data), gzipAccepted);
723
1099
  })
724
1100
  .catch((error) => {
1101
+ ActiveLogger.error(error, "Failed to send response back");
1102
+ ActiveLogger.info(`[RR] ERROR : S=${started}, TT=${Date.now() - started}ms`);
725
1103
  this.writeResponse(res, error.statusCode || 500, JSON.stringify(error.content || "Something has gone wrong"), gzipAccepted);
726
1104
  });
727
1105
  }
728
- async writeResponse(res, statusCode, content, encoding) {
729
- let headers = {
730
- "Content-Type": "application/json",
731
- "Content-Encoding": "none",
732
- "Access-Control-Allow-Origin": "*",
733
- "X-Powered-By": "Activeledger",
734
- };
735
- if (encoding == "gzip") {
736
- headers["Content-Encoding"] = "gzip";
737
- content = await ActiveGZip.gzip(content);
1106
+ async writeResponse(res, statusCode, content, encoding, cors = false) {
1107
+ if (!res || !res.writable) {
1108
+ return;
738
1109
  }
739
- res.writeHead(statusCode, headers);
740
- res.write(content);
741
- res.end();
1110
+ if (content) {
1111
+ if (encoding == "gzip") {
1112
+ content = await ActiveGZip.gzip(content);
1113
+ }
1114
+ }
1115
+ res.cork(() => {
1116
+ res.writeStatus(`${statusCode}`);
1117
+ res.writeHeader("Access-Control-Allow-Origin", "*");
1118
+ res.writeHeader("X-Content-Type-Options", "nosniff");
1119
+ res.writeHeader("X-Frame-Options", "DENY");
1120
+ res.writeHeader("Strict-Transport-Security", "max-age=63072000; includeSubDomains; preload");
1121
+ res.writeHeader("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none';");
1122
+ if (cors) {
1123
+ res.writeHeader("Access-Control-Allow-Methods", "GET, POST");
1124
+ res.writeHeader("Access-Control-Allow-Headers", "*");
1125
+ }
1126
+ if (content) {
1127
+ res.writeHeader("Content-Type", "application/json");
1128
+ if (encoding == "gzip") {
1129
+ res.writeHeader("Content-Encoding", "gzip");
1130
+ }
1131
+ res.end(content);
1132
+ res.writable = false;
1133
+ }
1134
+ });
742
1135
  }
743
- firewallCheck(requester, req) {
744
- return (requester !== "NA" &&
745
- this.neighbourhood.checkFirewall(req.headers["x-forwarded-for"] ||
746
- req.connection.remoteAddress));
1136
+ firewallCheck(requester, remoteAddr) {
1137
+ return this.neighbourhood.checkFirewall(remoteAddr, requester);
747
1138
  }
748
1139
  }
749
1140
  //# sourceMappingURL=host.js.map