@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.
- package/es/network/cpus.d.ts +1 -0
- package/es/network/cpus.d.ts.map +1 -1
- package/es/network/cpus.js +26 -15
- package/es/network/cpus.js.map +1 -1
- package/es/network/endpoints.d.ts +7 -3
- package/es/network/endpoints.d.ts.map +1 -1
- package/es/network/endpoints.js +685 -172
- package/es/network/endpoints.js.map +1 -1
- package/es/network/home.d.ts.map +1 -1
- package/es/network/home.js +41 -19
- package/es/network/home.js.map +1 -1
- package/es/network/host.d.ts +15 -7
- package/es/network/host.d.ts.map +1 -1
- package/es/network/host.js +631 -240
- package/es/network/host.js.map +1 -1
- package/es/network/locker.d.ts +10 -5
- package/es/network/locker.d.ts.map +1 -1
- package/es/network/locker.js +50 -17
- package/es/network/locker.js.map +1 -1
- package/es/network/maintain.d.ts.map +1 -1
- package/es/network/maintain.js +42 -42
- package/es/network/maintain.js.map +1 -1
- package/es/network/neighbour.d.ts +8 -4
- package/es/network/neighbour.d.ts.map +1 -1
- package/es/network/neighbour.js +82 -18
- package/es/network/neighbour.js.map +1 -1
- package/es/network/neighbourhood.d.ts +1 -1
- package/es/network/neighbourhood.d.ts.map +1 -1
- package/es/network/neighbourhood.js +39 -42
- package/es/network/neighbourhood.js.map +1 -1
- package/es/network/p2pClient.d.ts +20 -0
- package/es/network/p2pClient.d.ts.map +1 -0
- package/es/network/p2pClient.js +84 -0
- package/es/network/p2pClient.js.map +1 -0
- package/es/network/process.js +99 -65
- package/es/network/process.js.map +1 -1
- package/es/network/utils.d.ts.map +1 -1
- package/es/network/utils.js +17 -21
- package/es/network/utils.js.map +1 -1
- package/lib/network/cpus.d.ts +1 -0
- package/lib/network/cpus.d.ts.map +1 -1
- package/lib/network/cpus.js +26 -15
- package/lib/network/cpus.js.map +1 -1
- package/lib/network/endpoints.d.ts +7 -3
- package/lib/network/endpoints.d.ts.map +1 -1
- package/lib/network/endpoints.js +684 -171
- package/lib/network/endpoints.js.map +1 -1
- package/lib/network/home.d.ts.map +1 -1
- package/lib/network/home.js +41 -19
- package/lib/network/home.js.map +1 -1
- package/lib/network/host.d.ts +15 -7
- package/lib/network/host.d.ts.map +1 -1
- package/lib/network/host.js +630 -239
- package/lib/network/host.js.map +1 -1
- package/lib/network/locker.d.ts +10 -5
- package/lib/network/locker.d.ts.map +1 -1
- package/lib/network/locker.js +50 -17
- package/lib/network/locker.js.map +1 -1
- package/lib/network/maintain.d.ts.map +1 -1
- package/lib/network/maintain.js +42 -42
- package/lib/network/maintain.js.map +1 -1
- package/lib/network/neighbour.d.ts +8 -4
- package/lib/network/neighbour.d.ts.map +1 -1
- package/lib/network/neighbour.js +82 -18
- package/lib/network/neighbour.js.map +1 -1
- package/lib/network/neighbourhood.d.ts +1 -1
- package/lib/network/neighbourhood.d.ts.map +1 -1
- package/lib/network/neighbourhood.js +39 -42
- package/lib/network/neighbourhood.js.map +1 -1
- package/lib/network/p2pClient.d.ts +20 -0
- package/lib/network/p2pClient.d.ts.map +1 -0
- package/lib/network/p2pClient.js +88 -0
- package/lib/network/p2pClient.js.map +1 -0
- package/lib/network/process.js +98 -64
- package/lib/network/process.js.map +1 -1
- package/lib/network/utils.d.ts.map +1 -1
- package/lib/network/utils.js +17 -21
- package/lib/network/utils.js.map +1 -1
- package/package.json +10 -8
package/es/network/host.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
16
|
-
const
|
|
17
|
-
const
|
|
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
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
this.
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
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
|
-
|
|
68
|
-
this.
|
|
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
|
-
|
|
88
|
-
|
|
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
|
|
113
|
+
entry,
|
|
111
114
|
resolve: (response) => {
|
|
112
|
-
this.
|
|
113
|
-
|
|
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.
|
|
117
|
-
|
|
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
|
-
|
|
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 (
|
|
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:
|
|
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,
|
|
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.
|
|
245
|
-
this.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
318
|
-
|
|
319
|
-
|
|
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
|
-
|
|
324
|
-
|
|
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
|
-
|
|
328
|
-
|
|
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
|
|
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]:
|
|
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
|
-
|
|
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 &&
|
|
346
|
-
|
|
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
|
-
|
|
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
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
...this.labelOrKey(v.$tx.$
|
|
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 (
|
|
418
|
-
|
|
419
|
-
entry
|
|
420
|
-
|
|
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
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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:
|
|
786
|
+
data: v,
|
|
453
787
|
});
|
|
454
|
-
}
|
|
788
|
+
}
|
|
455
789
|
}
|
|
456
790
|
else {
|
|
457
|
-
this.processPending[v.$umid].
|
|
458
|
-
status:
|
|
459
|
-
|
|
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(
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
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
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
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
|
-
|
|
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
|
-
|
|
516
|
-
|
|
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
|
-
...(
|
|
551
|
-
...(
|
|
909
|
+
...(activityStreams?.new || []),
|
|
910
|
+
...(activityStreams?.updated || []),
|
|
552
911
|
].map((stream) => stream.id);
|
|
553
|
-
const input = tx.$tx.$i
|
|
554
|
-
|
|
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 (
|
|
571
|
-
tmp.push(
|
|
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["
|
|
982
|
+
processEndpoints(req, res, body, from, isP2P = false) {
|
|
983
|
+
let requester = req.headers["X-Activeledger"] || "NA";
|
|
625
984
|
let response;
|
|
626
|
-
|
|
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
|
-
|
|
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
|
-
|
|
730
|
-
|
|
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
|
-
|
|
740
|
-
|
|
741
|
-
|
|
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,
|
|
744
|
-
return (requester
|
|
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
|