@mmmbuto/nexuscrew 0.8.49 → 0.8.50
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/frontend/dist/index.html
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
<meta name="apple-mobile-web-app-title" content="NexusCrew" />
|
|
12
12
|
<link rel="manifest" href="/manifest.json" />
|
|
13
13
|
<title>NexusCrew</title>
|
|
14
|
-
<script type="module" crossorigin src="/assets/index-
|
|
14
|
+
<script type="module" crossorigin src="/assets/index-kj-l-RDc.js"></script>
|
|
15
15
|
<link rel="stylesheet" crossorigin href="/assets/index-43DFO1EH.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.8.
|
|
1
|
+
{"version":"0.8.50"}
|
|
@@ -96,4 +96,28 @@ function summarizeStops(results) {
|
|
|
96
96
|
return { stoppedAny, quarantinedAny, allClosed: stoppedAny && !quarantinedAny };
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
|
|
99
|
+
// Esito di un giro di verifica del pool. `verified` richiede TUTTI gli slot:
|
|
100
|
+
// e' una scelta deliberata, perche' rotateRotatableReverse si rifiuta di
|
|
101
|
+
// commutare dentro un pool non interamente provato. La conseguenza pero' va
|
|
102
|
+
// detta, non dedotta: finche' il pool non e' verificato la rotazione
|
|
103
|
+
// automatica resta SPENTA e il watcher non viene nemmeno armato. Un pool
|
|
104
|
+
// "unverifiable" non e' un'etichetta descrittiva, e' autoriparazione assente.
|
|
105
|
+
function summarizePoolVerification(results, slotCount) {
|
|
106
|
+
const list = Array.isArray(results) ? results : [];
|
|
107
|
+
const total = Number.isSafeInteger(slotCount) && slotCount > 0 ? slotCount : 0;
|
|
108
|
+
const verifiedSlots = [...new Set(list.filter((r) => r && r.proven === true)
|
|
109
|
+
.map((r) => r.slot).filter(Number.isSafeInteger))].sort((a, b) => a - b);
|
|
110
|
+
const failures = list.filter((r) => r && r.proven !== true)
|
|
111
|
+
.map((r) => ({ slot: r.slot, code: typeof r.code === 'string' && /^[a-z0-9-]{1,64}$/.test(r.code) ? r.code : 'reverse-slot-verify-failed' }));
|
|
112
|
+
// Zero slot dichiarati non e' "tutto verificato": senza un pool da provare
|
|
113
|
+
// non c'e' nulla da cui ruotare.
|
|
114
|
+
const verified = total > 0 && verifiedSlots.length === total;
|
|
115
|
+
return {
|
|
116
|
+
verifiedSlots,
|
|
117
|
+
failures,
|
|
118
|
+
verification: verified ? 'verified' : 'unverifiable',
|
|
119
|
+
rotationActive: verified,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
module.exports = { LEASE_MS, GRACE_MS, nextReadySlot, prepareRotation, abortPrepared, commitRotation, settleGrace, quarantineSlot, stopWasDemonstrated, summarizeStops, summarizePoolVerification };
|
package/lib/server.js
CHANGED
|
@@ -267,6 +267,10 @@ function createServer(opts = {}) {
|
|
|
267
267
|
async function verifyRotatablePool(node) {
|
|
268
268
|
const pool = node?.reversePool;
|
|
269
269
|
if (!pool || !node.shared || !node.token || !node.nodeId) return { verified: false, code: 'reverse-pool-not-ready' };
|
|
270
|
+
// Fermarsi al primo slot che non si prova nasconde quali altri fossero
|
|
271
|
+
// sani: l'esito e' identico (servono tutti per 'verified'), ma la diagnosi
|
|
272
|
+
// no. Chi guarda deve poter distinguere "un solo slot non risponde" da
|
|
273
|
+
// "non risponde nessuno", perche' sono due guasti diversi.
|
|
270
274
|
const proven = [];
|
|
271
275
|
for (let slot = 0; slot < pool.slots.length; slot += 1) {
|
|
272
276
|
const candidate = pool.slots[slot];
|
|
@@ -275,9 +279,9 @@ function createServer(opts = {}) {
|
|
|
275
279
|
await startRotatableReverse(node, { slot, generation: candidate.generation });
|
|
276
280
|
temporary = slot !== pool.activeSlot;
|
|
277
281
|
await federation.verifyHubPoolSlot({ node, slot, generation: candidate.generation, fetchImpl: healthFetch });
|
|
278
|
-
proven.push(slot);
|
|
279
|
-
} catch (
|
|
280
|
-
|
|
282
|
+
proven.push({ slot, proven: true });
|
|
283
|
+
} catch (error) {
|
|
284
|
+
proven.push({ slot, proven: false, code: error && error.code });
|
|
281
285
|
} finally {
|
|
282
286
|
if (temporary) await stopRotatableReverse(node.name, { remotePort: candidate.port, generation: candidate.generation });
|
|
283
287
|
}
|
|
@@ -285,15 +289,27 @@ function createServer(opts = {}) {
|
|
|
285
289
|
const current = nodesStore.loadStoreStrict(nodesPath);
|
|
286
290
|
const fresh = nodesStore.getNode(current, node.name);
|
|
287
291
|
if (!fresh?.reversePool) return { verified: false, code: 'reverse-pool-missing' };
|
|
288
|
-
const
|
|
289
|
-
const
|
|
292
|
+
const outcome = reverseRotation.summarizePoolVerification(proven, fresh.reversePool.slots.length);
|
|
293
|
+
const { verifiedSlots, verification, failures } = outcome;
|
|
290
294
|
const updatedPool = { ...fresh.reversePool, verifiedSlots, verification };
|
|
291
295
|
nodesStore.atomicWriteStore(nodesPath, nodesStore.setNodeReversePool(current, fresh.name, updatedPool));
|
|
292
296
|
diagnostics.record(verification === 'verified' ? 'info' : 'warn', 'reverse-pool',
|
|
293
297
|
verification === 'verified' ? 'REVERSE_POOL_VERIFIED' : 'REVERSE_POOL_UNVERIFIABLE',
|
|
294
|
-
verification === 'verified' ? 'Reverse pool verified' : 'Reverse pool could not be fully verified',
|
|
298
|
+
verification === 'verified' ? 'Reverse pool verified' : 'Reverse pool could not be fully verified',
|
|
299
|
+
{ node: fresh.name, verifiedSlots: verifiedSlots.length, slots: fresh.reversePool.slots.length,
|
|
300
|
+
...(failures.length ? { failedSlots: failures } : {}) });
|
|
301
|
+
// Un pool non verificato non e' solo un'etichetta: la rotazione automatica
|
|
302
|
+
// RIFIUTA di partire senza tutti gli slot provati (scelta deliberata, vedi
|
|
303
|
+
// rotateRotatableReverse) e il watcher non viene nemmeno armato. Detto
|
|
304
|
+
// altrimenti: l'autoriparazione del canale reverse resta SPENTA, e finora
|
|
305
|
+
// nessuno lo diceva. Va dichiarato, non dedotto da un aggettivo.
|
|
306
|
+
if (verification !== 'verified') {
|
|
307
|
+
diagnostics.record('warn', 'reverse-pool', 'REVERSE_POOL_ROTATION_INACTIVE',
|
|
308
|
+
'Automatic reverse rotation is not active: the pool is not fully verified',
|
|
309
|
+
{ node: fresh.name, verifiedSlots: verifiedSlots.length, slots: fresh.reversePool.slots.length });
|
|
310
|
+
}
|
|
295
311
|
if (verification === 'verified') ensureReverseWatcher(fresh.name);
|
|
296
|
-
return { verified: verification === 'verified', verification, verifiedSlots };
|
|
312
|
+
return { verified: verification === 'verified', verification, verifiedSlots, ...(failures.length ? { failures } : {}) };
|
|
297
313
|
}
|
|
298
314
|
async function settleRotatableGrace(name, generation) {
|
|
299
315
|
const current = nodesStore.loadStoreStrict(nodesPath);
|