Files
DogFatherGitandClaude Opus 5 f6225d7341 Ports: auch die Messwerkzeuge leiten ihre Nummer ab
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]>
2026-10-01 01:19:41 +02:00

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);