GEMESSEN, BEVOR ICH ETWAS ANGEFASST HABE:
204 pruef-Dateien, abgeleitete Ports 5000-5409 (dicht belegt)
24 mess-Dateien, Nummern von Hand: 4471 bis 5493
davon IM Pruefbereich: 5387, 5397, 5397, 5399, 5399, 5401, 5403, 5405
untereinander doppelt: 5397, 5399, 5461, 5483, 5491
Aufgefallen ist es, weil mess-buehne und mess-reaktion beide auf 5483
lagen und ein haengengebliebener Lauf gestern einen ganzen Messlauf
gekostet hat.
Beim Umbau kam das Groessere heraus: EINUNDZWANZIG der 24 Messdateien
hatten nicht nur eine Nummer von Hand, sondern ueberhaupt keinen
Waechter -- schlicht `const PORT = 5397;`. Liegt dort schon ein
Server, startet der eigene still nicht, und gemessen wird ab da ein
fremder Stand. Genau der Fehler, gegen den helfer-port.mjs gebaut
wurde; die Messdateien standen die ganze Zeit ausserhalb.
WAS JETZT GILT
Zwei Sorten, zwei Bereiche, beide abgeleitet aus der Stelle im
Alphabet -- jede Sorte unter ihresgleichen, sonst verschoebe eine
neue Pruefung die Nummern aller Messungen. Pruefungen ab 5000,
Messungen ab MESS_BASIS = 5900.
5900 und nicht 5500: dazwischen bleibt Platz fuer 245 weitere
Pruefdateien (bei 5500 waeren es 45). Nach oben 5948 + AUSWEICHEN
4000 = 9948, also unter 10080, der naechsten gesperrten Nummer.
Nachgerechnet, nicht geschaetzt -- eine geschaetzte 4500 hatte bei
BASIS schon einmal danebengelegen.
Eine Wache dazu: Waechst der Pruefbereich bis an MESS_BASIS heran,
bricht die Ableitung ab und sagt, was zu tun ist. Eine stille
Ueberschneidung waere genau der Fehler, den das hier beseitigt.
Die zweite Nummer kommt ueber nr=1, nie ueber `PORT + 1`:
portNummer ueberspringt gesperrte Nummern, deshalb kann die naechste
Zahl die Nummer der naechsten DATEI sein, sobald einmal eine Sperre
dazwischenliegt. Heute liegt dort keine -- das ist Glueck, kein
Entwurf.
NEBENBEI GEFUNDEN UND MIT REPARIERT
Sechs bild-*.mjs riefen den Waechter und warfen seine Antwort weg:
await portMussFreiSein(4315, "das Bildwerkzeug");
process.env.PORT = "4315";
const BASIS = "http://127.0.0.1:4315";
Er lief, meldete nichts und wirkte nicht. Gibt das System den Port
dauerhaft nicht her, weicht er auf Port + 4000 aus und GIBT DIE NEUE
NUMMER ZURUECK -- diese Werkzeuge hoerten danach trotzdem auf der
alten und stuerzten mit `listen EACCES` ab, also mit genau dem
Fehler, gegen den er gebaut wurde. Dazu stand die Zahl dreimal je
Datei. Jetzt einmal, und die Antwort wird benutzt.
tiktok-videos.mjs hatte den Waechter ABGESCHRIEBEN -- eine kurze
eigene Fassung ohne den dritten Ausgang: Bei EACCES meldete sie
"belegt" und brach ab, statt auszuweichen. Auf diesem Rechner ist
genau das am 23.09. eingetreten (Port 5040, Windows-Dienst).
mess-fokus und mess-notizblock hatten dieselbe Abschrift. Eine
abgeschriebene Sicherung ist dieselbe Falle wie eine abgeschriebene
Liste.
GEPRUEFT
pruef-portnummern 15 -> 41 Pruefungen, 0 Fehler
pruef-ports 8 -> 10 Pruefungen, 456 statt 408 Ports geprobt
node --check auf allen 33 geaenderten Dateien
Gegenproben, die wirklich rot werden:
- eine Messdatei auf eine feste Nummer zurueckgesetzt -> 2 FEHL,
danach wieder 41/0
- die Wache: in einem Wegwerf-Ordner mit 452 pruef-Dateien bricht
eigenerPort ab statt still zu ueberlappen; eine Datei knapp
darunter bekommt weiter ihre Nummer (5846)
- die Erkennungen fuer feste Nummern, PORT + 1 und weggeworfene
Waechterantworten je gegen einen gebauten Rueckschritt
Am echten Verhalten gemessen:
- mess-chat-liste und mess-alle-einzelsicht (beide vorher 5397)
GLEICHZEITIG gestartet: 5906 und 5900, beide exit=0. Vorher war
das unmoeglich.
- die 48 neuen Nummern 5900-5947 auf diesem Rechner durchprobiert:
keine belegt, keine vom System gesperrt
- bild-chat.mjs durchgelaufen, drei Bilder, exit=0
Kein Eingriff am laufenden Dienst: helfer-port.mjs wird von index.js
und workspace.js nicht geladen (nachgesehen), nur von Pruef- und
Messwerkzeugen. Beide Haeuser unberuehrt -- es wird keine Zeile
angefasst, die eine Seite ausliefert.
Co-Authored-By: Claude Opus 5 <[email protected]>
441 lines
22 KiB
JavaScript
441 lines
22 KiB
JavaScript
/* =====================================================================
|
|
pruef-portnummern.mjs — Zwei Pruefungen, eine Nummer
|
|
|
|
WAS HIER SCHIEFGING (20.09.2026 gemessen):
|
|
164 Pruefdateien, 129 verschiedene Nummern -- NEUNZEHN waren doppelt
|
|
vergeben, 4186 und 4188 und 4196 und 4198 sogar dreifach. Niemand
|
|
hatte das gewollt; jede neue Pruefung wurde von einer vorhandenen
|
|
abgeschrieben, und die Nummer kam mit.
|
|
|
|
WAS DAS ANRICHTET: Der Waechter bricht ab, statt gegen einen fremden
|
|
Server zu messen -- so weit, so richtig. Aber zwei Pruefungen mit
|
|
derselben Nummer koennen nie gleichzeitig laufen, und ein
|
|
liegengebliebener Prozess der einen laesst die andere mit einer
|
|
Meldung abbrechen, die wie ein Befund aussieht. Genau das ist am
|
|
20.09. zweimal passiert, beide Male mit Fehlersuche an der falschen
|
|
Stelle.
|
|
|
|
WAS DIESE PRUEFUNG SICHERT: Dass die Nummer ABGELEITET bleibt. Eine
|
|
von Hand eingetragene Zahl ist der Anfang der naechsten Doppelung --
|
|
sie faellt nur niemandem auf, bis zwei Laeufe kollidieren.
|
|
===================================================================== */
|
|
|
|
import { mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { pathToFileURL } from "node:url";
|
|
import { eigenerPort, portNummer, MESS_BASIS, GESPERRT } from "./helfer-port.mjs";
|
|
|
|
let ok_ = 0, fehl = 0;
|
|
const ok = (b, text) => { if (b) { ok_++; console.log(" ok " + text); }
|
|
else { fehl++; console.log(" FEHL " + text); } };
|
|
|
|
const ORDNER = new URL(".", import.meta.url).pathname.replace(/^\/([A-Za-z]:)/, "$1");
|
|
const dateien = readdirSync(ORDNER)
|
|
.filter((f) => f.startsWith("pruef-") && f.endsWith(".mjs")).sort();
|
|
/* DIE MESSDATEIEN GEHOEREN DAZU (01.10.2026). Sie standen bis heute
|
|
ganz ausserhalb dieser Pruefung -- und genau dort ist der Fehler
|
|
auch gewachsen, den sie verhindern soll. */
|
|
const messen = readdirSync(ORDNER)
|
|
.filter((f) => f.startsWith("mess-") && f.endsWith(".mjs")).sort();
|
|
|
|
console.log("\n=== 1. Niemand traegt eine Nummer von Hand ein ===");
|
|
const vonHand = [];
|
|
const ohneWaechter = [];
|
|
for (const f of dateien) {
|
|
const s = readFileSync(ORDNER + "/" + f, "utf8");
|
|
/* Kommentare zaehlen nicht: In helfer-port.mjs und hier stehen alte
|
|
Nummern als Beleg, und ein Beleg ist kein Eintrag. */
|
|
const code = s.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
if (/portMussFreiSein\(\s*\d/.test(code)) vonHand.push(f);
|
|
/* ==== WER STARTET WIRKLICH EINEN SERVER? (25.09.2026) ==========
|
|
|
|
Hier stand `listen(` -- und das trifft auch den, der nur
|
|
NACHSIEHT, ob eine Nummer frei ist: `pruef-ports.mjs` macht einen
|
|
Port auf, schliesst ihn sofort wieder und startet dabei gar
|
|
nichts. Sie wurde deshalb angemahnt, den Waechter nicht zu
|
|
benutzen, den sie selbst prueft.
|
|
|
|
DAS ECHTE MERKMAL IST DAS HAUS: Wer `index.js` importiert oder
|
|
`process.env.PORT` setzt, laesst den Workspace laufen und braucht
|
|
eine eigene, eindeutige Nummer. Wer nur `createServer().listen()`
|
|
aufruft, um das Betriebssystem zu fragen, braucht sie nicht --
|
|
und darf es auch gar nicht, sonst verschoebe sich die ganze
|
|
Nummernfolge.
|
|
|
|
DIE GEGENPROBE UNTEN BLEIBT GUELTIG und wird sogar schaerfer: Sie
|
|
baut eine Datei, die `index.js` importiert und keinen Waechter
|
|
hat -- also genau den Fall, um den es geht. */
|
|
const startetServer = /import\(\s*["'`]\.\/index\.js["'`]\s*\)/.test(code)
|
|
|| /process\.env\.PORT\s*=/.test(code);
|
|
if (startetServer && !/eigenerPort\(\s*import\.meta/.test(code)) ohneWaechter.push(f);
|
|
}
|
|
ok(dateien.length > 100, `${dateien.length} Pruefdateien angesehen`);
|
|
ok(vonHand.length === 0,
|
|
`keine traegt eine feste Nummer im Waechter (${vonHand.slice(0, 4).join(", ") || "—"})`);
|
|
ok(ohneWaechter.length === 0,
|
|
`jede, die einen Server startet, leitet ihre Nummer ab (${ohneWaechter.slice(0, 4).join(", ") || "—"})`);
|
|
|
|
/* ==== KANN DIESE ERKENNUNG AUCH NEIN SAGEN? (25.09.2026) ============
|
|
|
|
Die Zeile darueber meldet „alles in Ordnung", solange sie NICHTS
|
|
findet -- und genau so sieht auch eine Erkennung aus, die nichts
|
|
mehr findet, weil man sie zu eng gefasst hat. Am 25.09. wurde sie
|
|
enger gefasst (vorher schlug jedes `listen(` an, auch das blosse
|
|
Nachsehen, ob ein Port frei ist). Ohne diese Probe waere aus der
|
|
Verbesserung ein blinder Fleck geworden.
|
|
|
|
Gebaut wird der Fall im Speicher, nicht als Datei: Eine echte Datei
|
|
im Ordner wuerde die Nummernfolge aller anderen verschieben -- und
|
|
das ist genau das, wovor diese Pruefung schuetzt. */
|
|
{
|
|
const wieErkannt = (code) =>
|
|
(/import\(\s*["'`]\.\/index\.js["'`]\s*\)/.test(code)
|
|
|| /process\.env\.PORT\s*=/.test(code))
|
|
&& !/eigenerPort\(\s*import\.meta/.test(code);
|
|
|
|
ok(wieErkannt('await import("./index.js");'),
|
|
"Gegenprobe: ein Serverstart ohne Waechter faellt auf");
|
|
ok(wieErkannt('process.env.PORT = "5000";'),
|
|
" und eine von Hand gesetzte Nummer ebenfalls");
|
|
ok(!wieErkannt('const PORT = await eigenerPort(import.meta, "x");\n'
|
|
+ 'process.env.PORT = `${PORT}`;\nawait import("./index.js");'),
|
|
" wer den Waechter benutzt, faellt NICHT auf");
|
|
ok(!wieErkannt('const s = createServer(); s.listen(port, "127.0.0.1");'),
|
|
" und wer nur nachsieht, ob ein Port frei ist, auch nicht");
|
|
}
|
|
|
|
console.log("\n=== 2. Die abgeleiteten Nummern sind eindeutig ===");
|
|
const belegt = new Map();
|
|
let doppelt = 0;
|
|
dateien.forEach((f, i) => {
|
|
for (let n = 0; n < 2; n++) {
|
|
const p = portNummer(i * 2 + n);
|
|
if (belegt.has(p)) { doppelt++; console.log(` ${p}: ${belegt.get(p)} und ${f}`); }
|
|
belegt.set(p, f);
|
|
}
|
|
});
|
|
ok(belegt.size === dateien.length * 2 && doppelt === 0,
|
|
`${belegt.size} Nummern fuer ${dateien.length} Dateien, ${doppelt} doppelt`);
|
|
|
|
console.log("\n=== 2b. Keine davon ist eine, die `fetch` verweigert ===");
|
|
/* DIE TEUERSTE HALBE STUNDE DIESES ABENDS. Nach der Umstellung bekam
|
|
pruef-chat-kanaele die 5060 und stuerzte ab -- obwohl der Server
|
|
nachweislich lief und die Anmeldung ueber `http.request` geklappt
|
|
hatte. 5060 ist SIP und steht auf der "bad ports"-Liste der
|
|
Fetch-Spezifikation, die Node uebernommen hat: `fetch` baut dorthin
|
|
keine Verbindung auf.
|
|
|
|
Die Meldung lautet "fetch failed" -- genau wie bei einem Server, der
|
|
nicht laeuft. Wer sie liest, sucht am Server. Deshalb steht sie
|
|
jetzt hier als eigene Pruefung: Die naechste Datei, die in so eine
|
|
Nummer rutscht, soll es HIER erfahren und nicht in einer
|
|
Fehlersuche. */
|
|
const BOESE = [1, 7, 9, 11, 13, 15, 17, 19, 20, 21, 22, 23, 25, 37, 42, 43, 53,
|
|
69, 77, 79, 87, 95, 101, 102, 103, 104, 109, 110, 111, 113, 115, 117, 119,
|
|
123, 135, 137, 138, 139, 143, 161, 179, 389, 427, 465, 512, 513, 514, 515,
|
|
526, 530, 531, 532, 540, 548, 554, 556, 563, 587, 601, 636, 989, 990, 993,
|
|
995, 1719, 1720, 1723, 2049, 3659, 4045, 4190, 5060, 5061, 6000, 6566, 6665,
|
|
6666, 6667, 6668, 6669, 6679, 6697, 10080];
|
|
const getroffen = [...belegt.keys()].filter((x) => BOESE.includes(x));
|
|
ok(getroffen.length === 0,
|
|
`keine der ${belegt.size} Nummern steht auf der Sperrliste (${getroffen.join(", ") || "—"})`);
|
|
|
|
/* GEGENPROBE AM ECHTEN VERHALTEN, nicht an der Liste: Ein Zuhoerer auf
|
|
einer gesperrten Nummer muss fuer `fetch` unerreichbar sein, einer
|
|
daneben erreichbar. Ohne das waere die Liste oben nur eine
|
|
Behauptung ueber Node -- und Behauptungen altern. */
|
|
{
|
|
const { createServer } = await import("node:http");
|
|
const probe = async (nummer) => {
|
|
const dienst = createServer((q, a) => { a.writeHead(200); a.end("da"); });
|
|
await new Promise((r) => dienst.listen(nummer, "127.0.0.1", r));
|
|
let grund = "erreichbar";
|
|
try { await fetch(`http://127.0.0.1:${nummer}/`); }
|
|
catch (f) { grund = f?.cause?.message || f?.message || "?"; }
|
|
await new Promise((r) => dienst.close(r));
|
|
return grund;
|
|
};
|
|
const gesperrt = await probe(5060);
|
|
const erlaubt = await probe(portNummer(0));
|
|
ok(/bad port/i.test(gesperrt),
|
|
`eine gesperrte Nummer ist fuer fetch tot, obwohl jemand lauscht (5060: ${gesperrt})`);
|
|
ok(erlaubt === "erreichbar",
|
|
`eine abgeleitete dagegen nicht (${portNummer(0)}: ${erlaubt})`);
|
|
}
|
|
|
|
console.log("\n=== 3. Die Ableitung stimmt wirklich (gemessen, nicht gerechnet) ===");
|
|
/* NICHT die Formel gegen sich selbst pruefen -- das waere eine
|
|
Bestaetigung ohne Aussage. Gefragt wird die Funktion, die die
|
|
Pruefungen auch benutzen, und verglichen wird mit der Stelle im
|
|
Alphabet. */
|
|
const ersteDatei = dateien[0];
|
|
const meine = dateien.indexOf("pruef-portnummern.mjs");
|
|
const p0 = await eigenerPort(import.meta, "pruef-portnummern (Selbsttest)", 0);
|
|
ok(p0 === portNummer(meine * 2),
|
|
`meine eigene Nummer ist ${p0} — Stelle ${meine} im Alphabet, erste Datei ${ersteDatei}`);
|
|
const p1 = await eigenerPort(import.meta, "pruef-portnummern (Selbsttest)", 1);
|
|
ok(p1 === p0 + 1, `und die zweite ist ${p1}, also genau eine daneben`);
|
|
|
|
console.log("\n=== 4. Gegenprobe: kann sie auch NICHT IN ORDNUNG sagen? ===");
|
|
/* Eine Pruefung, die immer bestaetigt, bestaetigt nichts. */
|
|
let drittesAusgangGriff = false;
|
|
try {
|
|
/* Eine Datei, die es nicht gibt -- die Ableitung darf dann NICHT
|
|
raten, sondern muss abbrechen. */
|
|
await eigenerPort({ url: new URL("./gibt-es-nicht.mjs", import.meta.url).href }, "Gegenprobe");
|
|
} catch (f) {
|
|
drittesAusgangGriff = /steht nicht in der Liste/.test(f?.message || "");
|
|
}
|
|
ok(drittesAusgangGriff, "eine unbekannte Datei bekommt keine geratene Nummer, sondern einen Abbruch");
|
|
|
|
let zuHoheNummer = false;
|
|
try { await eigenerPort(import.meta, "Gegenprobe", 7); }
|
|
catch (f) { zuHoheNummer = /Nummern je Datei/.test(f?.message || ""); }
|
|
ok(zuHoheNummer, "und eine dritte Nummer je Datei gibt es nicht");
|
|
|
|
console.log("\n=== 5. Die Messdateien leiten ihre Nummer auch ab (01.10.2026) ===");
|
|
/* WAS HIER AM 01.10. GEMESSEN WURDE, BEVOR ES DIESE PRUEFUNG GAB:
|
|
24 Messdateien, und EINUNDZWANZIG davon hatten ihre Nummer nicht
|
|
nur von Hand, sondern ganz ohne Waechter -- schlicht
|
|
`const PORT = 5397;`. Fuenf Nummern waren untereinander doppelt
|
|
vergeben (5397, 5399, 5461, 5483, 5491), und acht lagen mitten im
|
|
dicht belegten Bereich der Pruefungen (5000-5409).
|
|
|
|
Gekostet hat das einen ganzen Messlauf: mess-buehne und
|
|
mess-reaktion teilten sich die 5483, ein liegengebliebener Prozess
|
|
hielt sie, und die zweite Messung lief gegen einen fremden Stand.
|
|
|
|
Die Messdateien standen bei alldem AUSSERHALB dieser Pruefung --
|
|
sie hat 204 Pruefdateien angesehen und die 24 daneben nie. Eine
|
|
Sicherung, die nur die halbe Menge kennt, faellt genau in der
|
|
anderen Haelfte aus. */
|
|
{
|
|
const festeNummer = [];
|
|
const ohneWaechter = [];
|
|
const platteSumme = [];
|
|
for (const f of messen) {
|
|
const code = readFileSync(ORDNER + "/" + f, "utf8")
|
|
.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
if (/const\s+\w*PORT\w*\s*=\s*\d/.test(code)
|
|
|| /portMussFreiSein\(\s*\d/.test(code)) festeNummer.push(f);
|
|
/* `PORT + 1` IST KEINE ABLEITUNG. `portNummer` ueberspringt
|
|
gesperrte Nummern -- liegt einmal eine dazwischen, ist die
|
|
naechste Zahl die Nummer der naechsten DATEI. Heute liegt dort
|
|
keine; das ist Glueck, kein Entwurf. */
|
|
if (/PORT\s*\+\s*1\b/.test(code)) platteSumme.push(f);
|
|
const startetServer = /import\(\s*["'`]\.\/index\.js["'`]\s*\)/.test(code)
|
|
|| /process\.env\.PORT\s*=/.test(code);
|
|
if (startetServer && !/eigenerPort\(\s*import\.meta/.test(code)) ohneWaechter.push(f);
|
|
}
|
|
ok(messen.length > 10, `${messen.length} Messdateien angesehen`);
|
|
ok(festeNummer.length === 0,
|
|
`keine traegt eine Nummer von Hand (${festeNummer.slice(0, 4).join(", ") || "—"})`);
|
|
ok(ohneWaechter.length === 0,
|
|
`jede, die einen Server startet, leitet ihre Nummer ab (${ohneWaechter.slice(0, 4).join(", ") || "—"})`);
|
|
ok(platteSumme.length === 0,
|
|
`keine rechnet ihre zweite Nummer als PORT + 1 (${platteSumme.slice(0, 4).join(", ") || "—"})`);
|
|
|
|
/* ---- KANN DIESE ERKENNUNG AUCH NEIN SAGEN? -----------------------
|
|
Die drei Zeilen darueber melden „in Ordnung", solange sie NICHTS
|
|
finden -- und genau so sieht auch eine Erkennung aus, die man zu
|
|
eng gefasst hat. Am 01.10. waren es 21 Treffer; ab morgen sollen
|
|
es null sein, und dann sagt die Zahl allein nichts mehr darueber,
|
|
ob noch hingesehen wird. */
|
|
const alsFest = (c) => /const\s+\w*PORT\w*\s*=\s*\d/.test(c)
|
|
|| /portMussFreiSein\(\s*\d/.test(c);
|
|
ok(alsFest("const PORT = 5397;"), "Gegenprobe: eine feste Nummer faellt auf");
|
|
/* ZUSAMMENGESETZT, NICHT AUSGESCHRIEBEN: Abschnitt 1 dieser Datei
|
|
sucht in JEDER Pruefdatei nach genau diesem Wortlaut und
|
|
entfernt vorher nur Kommentare, keine Zeichenketten. Stuende
|
|
das Beispiel hier am Stueck, zeigte diese Pruefung sich
|
|
selbst an -- gemessen, sie tat es beim ersten Lauf. */
|
|
ok(alsFest("const HTTPS_PORT = await portMuss" + "FreiSein(5484);"),
|
|
" und eine feste Nummer im Waechter ebenfalls");
|
|
ok(!alsFest("const PORT = await eigenerPort(import.meta);"),
|
|
" wer ableitet, faellt NICHT auf");
|
|
ok(/PORT\s*\+\s*1/.test("const HTTPS_PORT = PORT + 1;"),
|
|
" und PORT + 1 wird als solches erkannt");
|
|
|
|
/* ---- Die beiden Bereiche beruehren sich nicht -------------------- */
|
|
const pruefPorts = [];
|
|
dateien.forEach((f, i) => pruefPorts.push(portNummer(i * 2), portNummer(i * 2 + 1)));
|
|
const messPorts = [];
|
|
messen.forEach((f, i) => messPorts.push(
|
|
portNummer(i * 2, MESS_BASIS), portNummer(i * 2 + 1, MESS_BASIS)));
|
|
const hoechstPruef = Math.max(...pruefPorts);
|
|
ok(hoechstPruef < MESS_BASIS,
|
|
`die Pruefungen enden bei ${hoechstPruef}, die Messungen fangen bei ${MESS_BASIS} an`
|
|
+ ` — Luft fuer ${((MESS_BASIS - hoechstPruef) / 2) | 0} weitere Pruefdateien`);
|
|
|
|
const zusammen = [...pruefPorts, ...messPorts];
|
|
ok(new Set(zusammen).size === zusammen.length,
|
|
`alle ${zusammen.length} Nummern beider Sorten sind verschieden`);
|
|
const boeseMess = messPorts.filter((p) => GESPERRT.has(p));
|
|
ok(boeseMess.length === 0,
|
|
`keine Messnummer steht auf der Sperrliste (${boeseMess.join(", ") || "—"})`);
|
|
|
|
/* ---- GEMESSEN, nicht gerechnet: die echte Funktion befragen ------ */
|
|
const erste = messen[0];
|
|
const echt = await eigenerPort(
|
|
{ url: pathToFileURL(ORDNER + "/" + erste).href }, "pruef-portnummern (Selbsttest)");
|
|
ok(echt === portNummer(0, MESS_BASIS) && echt >= MESS_BASIS,
|
|
`${erste} bekommt von eigenerPort wirklich ${echt}`);
|
|
const letzte = messen.at(-1);
|
|
const echt2 = await eigenerPort(
|
|
{ url: pathToFileURL(ORDNER + "/" + letzte).href }, "pruef-portnummern (Selbsttest)", 1);
|
|
ok(echt2 === portNummer((messen.length - 1) * 2 + 1, MESS_BASIS),
|
|
`und ${letzte} als zweite Nummer ${echt2} — beide aus dem Messbereich`);
|
|
}
|
|
|
|
console.log("\n=== 6. Gegenprobe: die Wache gegen das Zusammenwachsen ===");
|
|
/* Eine Grenze, die nie anschlaegt, ist keine Grenze. Waechst die Zahl
|
|
der Pruefdateien so weit, dass ihr Bereich den der Messungen
|
|
erreicht, bekaemen zwei Laeufe still dieselbe Nummer -- genau der
|
|
Fehler, den diese ganze Ableitung beseitigt.
|
|
|
|
GEPRUEFT WIRD DIE ECHTE FUNKTION, nicht eine Nachbildung ihrer
|
|
Bedingung: In einem Wegwerf-Ordner liegen so viele leere
|
|
`pruef-*.mjs`, dass die letzte ueber MESS_BASIS hinauskaeme. Ein
|
|
eigener Ordner deshalb, weil echte Dateien hier die Nummern aller
|
|
anderen verschieben wuerden. */
|
|
{
|
|
const wegwerf = mkdtempSync(join(tmpdir(), "portwache-"));
|
|
const noetig = Math.ceil((MESS_BASIS - portNummer(0)) / 2) + 2;
|
|
for (let i = 0; i < noetig; i++) {
|
|
writeFileSync(join(wegwerf, `pruef-${String(i).padStart(5, "0")}.mjs`), "");
|
|
}
|
|
const letzte = join(wegwerf, `pruef-${String(noetig - 1).padStart(5, "0")}.mjs`);
|
|
let sagte = "";
|
|
try { await eigenerPort({ url: pathToFileURL(letzte).href }, "Gegenprobe"); }
|
|
catch (f) { sagte = f?.message || ""; }
|
|
ok(/stoesst an den der Messdateien/.test(sagte),
|
|
`bei ${noetig} Pruefdateien bricht die Ableitung ab statt still zu ueberlappen`);
|
|
ok(/MESS_BASIS/.test(sagte) && /hochsetzen/.test(sagte),
|
|
"und sagt dabei, was zu tun ist");
|
|
|
|
/* UND DIE ANDERE RICHTUNG: Eine Datei knapp DARUNTER muss noch
|
|
durchgehen. Ohne das hiesse „bricht ab" womoeglich nur, dass in
|
|
diesem Ordner alles abbricht. */
|
|
const knapp = join(wegwerf, `pruef-${String(noetig - 30).padStart(5, "0")}.mjs`);
|
|
let ging = 0;
|
|
try { ging = await eigenerPort({ url: pathToFileURL(knapp).href }, "Gegenprobe"); }
|
|
catch { ging = 0; }
|
|
ok(ging > 0 && ging < MESS_BASIS,
|
|
`eine Datei knapp darunter bekommt weiter ihre Nummer (${ging})`);
|
|
rmSync(wegwerf, { recursive: true, force: true });
|
|
}
|
|
|
|
console.log("\n=== 7. Die uebrigen Werkzeuge, die einen Server starten ===");
|
|
/* BEIM UMBAU AM 01.10. AUFGEFALLEN: Es gibt eine dritte Sorte. Zehn
|
|
Werkzeuge starten den Workspace ebenfalls -- `bild-*`, `tmp-lokal`,
|
|
`tiktok-videos`, `zz-*` -- und alle zehn auf einer Nummer von Hand;
|
|
sieben davon ohne jeden Waechter.
|
|
|
|
SIE LEITEN NICHT AB, UND DAS IST ABSICHT: Es waeren vier weitere
|
|
Vorsilben mit ein bis sechs Dateien, also vier Bereiche fuer zehn
|
|
Werkzeuge, die nie gleichzeitig laufen. Der saubere Weg waere, sie
|
|
`mess-` zu nennen -- ein eigener Schritt.
|
|
|
|
WAS HIER GEPRUEFT WIRD, IST DESHALB WENIGER UND TROTZDEM DAS
|
|
ENTSCHEIDENDE: dass keine dieser Nummern in einen abgeleiteten
|
|
Bereich faellt und keine zweimal vergeben ist. Genau daraus ist die
|
|
Doppelung bei den Messdateien entstanden -- aus einer Lage, die
|
|
einmal in Ordnung war und die danach niemand mehr nachgesehen hat. */
|
|
{
|
|
const uebrige = readdirSync(ORDNER)
|
|
.filter((f) => f.endsWith(".mjs")
|
|
&& !f.startsWith("pruef-") && !f.startsWith("mess-") && !f.startsWith("helfer-"))
|
|
.filter((f) => /process\.env\.PORT\s*=/.test(readFileSync(ORDNER + "/" + f, "utf8")))
|
|
.sort();
|
|
ok(uebrige.length > 0, `${uebrige.length} weitere Werkzeuge starten einen Server`);
|
|
|
|
/* DIE NUMMER MUSS ABLESBAR SEIN. Findet sich keine, wird nicht
|
|
uebersprungen -- ein uebersprungener Fall beweist nichts, und
|
|
genau hier soll er auffallen. */
|
|
const nummern = new Map();
|
|
const unlesbar = [];
|
|
for (const f of uebrige) {
|
|
const code = readFileSync(ORDNER + "/" + f, "utf8")
|
|
.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
const t = code.match(/process\.env\.PORT\s*=\s*[`"']?(\d{3,5})/)
|
|
|| code.match(/const PORT\s*=\s*(\d{3,5})/)
|
|
|| code.match(/portMussFreiSein\(\s*(\d{3,5})/);
|
|
if (!t) { unlesbar.push(f); continue; }
|
|
nummern.set(f, Number(t[1]));
|
|
}
|
|
ok(unlesbar.length === 0,
|
|
`bei jedem steht die Nummer im Quelltext (${unlesbar.join(", ") || "—"})`);
|
|
|
|
const werte = [...nummern.values()];
|
|
const doppelte = werte.filter((p, i) => werte.indexOf(p) !== i);
|
|
ok(werte.length > 0 && doppelte.length === 0,
|
|
`keine ihrer ${werte.length} Nummern ist doppelt (${[...new Set(doppelte)].join(", ") || "—"})`);
|
|
|
|
const pruefPorts2 = [];
|
|
dateien.forEach((f, i) => pruefPorts2.push(portNummer(i * 2), portNummer(i * 2 + 1)));
|
|
const messPorts2 = [];
|
|
messen.forEach((f, i) => messPorts2.push(
|
|
portNummer(i * 2, MESS_BASIS), portNummer(i * 2 + 1, MESS_BASIS)));
|
|
const abgeleitet = new Set([...pruefPorts2, ...messPorts2]);
|
|
const drin = [...nummern].filter(([, p]) => abgeleitet.has(p));
|
|
ok(werte.length > 0 && drin.length === 0,
|
|
"keine liegt in einem abgeleiteten Bereich"
|
|
+ ` (${drin.map(([f, p]) => `${f}:${p}`).join(", ") || "—"})`);
|
|
|
|
/* GEGENPROBE: Diese drei Zeilen melden „in Ordnung", solange sie
|
|
nichts finden. Also einmal zeigen, dass sie etwas finden KOENNEN. */
|
|
const probe = [...abgeleitet][0];
|
|
ok(abgeleitet.has(probe) && probe >= 5000,
|
|
`Gegenprobe: ${probe} waere ein Treffer — die Liste der abgeleiteten`
|
|
+ ` Nummern hat ${abgeleitet.size} Eintraege und ist nicht leer`);
|
|
|
|
/* ---- EIN WAECHTER, DESSEN ANTWORT NIEMAND LIEST, IST KEINER -----
|
|
Am 01.10. in allen sechs `bild-*.mjs` gefunden:
|
|
|
|
await portMussFreiSein(4315, "das Bildwerkzeug");
|
|
process.env.PORT = "4315";
|
|
const BASIS = "http://127.0.0.1:4315";
|
|
|
|
Der Waechter lief, meldete nichts und wirkte nicht. Gibt das
|
|
System den Port dauerhaft nicht her, weicht er auf Port + 4000
|
|
aus und GIBT DIE NEUE NUMMER ZURUECK -- diese Werkzeuge hoerten
|
|
danach trotzdem auf der alten und stuerzten mit `listen EACCES`
|
|
ab, also mit genau dem Fehler, gegen den er gebaut wurde.
|
|
|
|
Dazu stand die Zahl dreimal je Datei. Wer eine davon aendert,
|
|
hat einen Server auf dem einen Port und ein Werkzeug, das den
|
|
anderen abfragt. */
|
|
const weggeworfen = [];
|
|
const mehrfach = [];
|
|
for (const f of uebrige) {
|
|
const code = readFileSync(ORDNER + "/" + f, "utf8")
|
|
.replace(/\/\*[\s\S]*?\*\//g, "").replace(/^\s*\/\/.*$/gm, "");
|
|
if (/^\s*await\s+(portMussFreiSein|eigenerPort)\(/m.test(code)) weggeworfen.push(f);
|
|
const n = nummern.get(f);
|
|
if (n !== undefined) {
|
|
const wieOft = (code.match(new RegExp(String(n), "g")) || []).length;
|
|
if (wieOft > 1) mehrfach.push(`${f}:${wieOft}x`);
|
|
}
|
|
}
|
|
ok(weggeworfen.length === 0,
|
|
`jedes benutzt die Antwort des Waechters (${weggeworfen.join(", ") || "—"})`);
|
|
ok(mehrfach.length === 0,
|
|
`und schreibt seine Nummer nur einmal hin (${mehrfach.join(", ") || "—"})`);
|
|
|
|
/* GEGENPROBE zu beiden: Erkennen sie den Rueckschritt auch? */
|
|
const wirftWeg = (c) => /^\s*await\s+(portMussFreiSein|eigenerPort)\(/m.test(c);
|
|
ok(wirftWeg('await portMuss' + 'FreiSein(4315, "x");'),
|
|
"Gegenprobe: eine weggeworfene Antwort faellt auf");
|
|
ok(!wirftWeg('const PORT = await portMuss' + 'FreiSein(4315, "x");'),
|
|
" wer sie in eine Zeile schreibt, faellt NICHT auf");
|
|
ok((('p = 4315; q = 4315;').match(/4315/g) || []).length === 2,
|
|
" und eine zweimal genannte Nummer wird gezaehlt");
|
|
|
|
console.log(` ${[...nummern].map(([f, p]) => `${f.replace(/\.mjs$/, "")} ${p}`).join(", ")}`);
|
|
}
|
|
|
|
console.log(`\n${ok_} Pruefungen, ${fehl} Fehler`);
|
|
console.log(fehl ? "NICHT IN ORDNUNG\n" : "ALLES IN ORDNUNG\n");
|
|
process.exit(fehl ? 1 : 0);
|