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]>
This commit is contained in:
2026-10-01 01:19:41 +02:00
co-authored by Claude Opus 5
parent 8e18c7bcf0
commit f6225d7341
34 changed files with 517 additions and 123 deletions
+10 -3
View File
@@ -9,8 +9,15 @@ import { heuteLokal } from "./helfer-zeit.mjs";
const ordner = mkdtempSync(join(tmpdir(), "ws-callbild-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4319, "das Bildwerkzeug");
process.env.PORT = "4319";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4319, "das Bildwerkzeug");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -19,7 +26,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 1000));
const BASIS = "http://127.0.0.1:4319";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+10 -3
View File
@@ -7,8 +7,15 @@ import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-chatbild-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4315, "das Bildwerkzeug");
process.env.PORT = "4315";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4315, "das Bildwerkzeug");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -17,7 +24,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 1000));
const BASIS = "http://127.0.0.1:4315";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+10 -3
View File
@@ -18,8 +18,15 @@ import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-bild-st-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4333, "das Bildwerkzeug fuer die Stufen");
process.env.PORT = "4333";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4333, "das Bildwerkzeug fuer die Stufen");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -28,7 +35,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 1200));
const BASIS = "http://127.0.0.1:4333";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+10 -3
View File
@@ -9,8 +9,15 @@ import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-sicht-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4329, "das Bildwerkzeug");
process.env.PORT = "4329";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4329, "das Bildwerkzeug");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -19,7 +26,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 1000));
const BASIS = "http://127.0.0.1:4329";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+10 -3
View File
@@ -15,8 +15,15 @@ import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-bild-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4331, "das Bildwerkzeug");
process.env.PORT = "4331";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4331, "das Bildwerkzeug");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -25,7 +32,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 1200));
const BASIS = "http://127.0.0.1:4331";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+10 -3
View File
@@ -7,8 +7,15 @@ import { join } from "node:path";
const ordner = mkdtempSync(join(tmpdir(), "ws-bild-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const { portMussFreiSein } = await import("./helfer-port.mjs");
await portMussFreiSein(4307, "das Bildwerkzeug");
process.env.PORT = "4307";
/* DIE ANTWORT DES WAECHTERS WIRD BENUTZT (01.10.2026). Hier
stand die Zahl dreimal, und der Rueckgabewert wurde
weggeworfen. Gibt das System den Port dauerhaft nicht her,
weicht `portMussFreiSein` auf Port + 4000 aus und meldet die
neue Nummer -- dieses Werkzeug lauschte danach trotzdem auf
der alten und stuerzte mit `listen EACCES` ab. Genau der
Fall ist am 23.09. auf Port 5040 eingetreten. */
const PORT = await portMussFreiSein(4307, "das Bildwerkzeug");
process.env.PORT = String(PORT);
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
@@ -17,7 +24,7 @@ const ec = express.response.cookie;
express.response.cookie = function (n, w, o) { return ec.call(this, n, w, { ...(o || {}), secure: false }); };
await import("./index.js");
await new Promise((r) => setTimeout(r, 900));
const BASIS = "http://127.0.0.1:4307";
const BASIS = `http://127.0.0.1:${PORT}`;
const { DatabaseSync } = await import("node:sqlite");
const { scryptSync, randomBytes } = await import("node:crypto");
+56 -7
View File
@@ -180,6 +180,33 @@ import { basename, dirname } from "node:path";
* werden: "irgendwo ueber 4400" haette plausibel geklungen. */
const BASIS = 5000;
const PRO_DATEI = 2;
/** Ab hier die MESSDATEIEN (01.10.2026).
*
* Sie hatten ihre Nummern von Hand. Nachgemessen lagen ACHT davon
* IM abgeleiteten Bereich der Pruefungen: Der ist bei 204 Dateien
* dicht von 5000 bis 5409 belegt, und 5387/5397/5399/5401/5403/5405
* liegen mittendrin. Zwei Laeufe konnten also denselben Port
* bekommen, ohne dass es jemand merkt. Untereinander war fuenfmal
* dieselbe Nummer doppelt vergeben (5397, 5399, 5461, 5483, 5491).
*
* Aufgefallen ist es, weil mess-reaktion und mess-buehne beide auf
* 5483 lagen und ein haengengebliebener Lauf einen ganzen Messlauf
* gekostet hat.
*
* 5900 UND NICHT 5500: Zwischen dem Ende der Pruefungen (5409) und
* hier bleibt Platz fuer 245 weitere Pruefdateien -- bei 5500 waeren
* es nur 45, und die waeren in einem Jahr aufgebraucht. Nach oben:
* 5900 + 24 Dateien * 2 = 5948; plus AUSWEICHEN (4000) sind das
* 9948, also unter 10080, der naechsten gesperrten Nummer. Beides
* nachgerechnet, nicht geschaetzt -- dieselbe Ueberlegung wie bei
* BASIS, wo eine geschaetzte 4500 danebengelegen haette.
*
* AUSGELEITET aus demselben Grund wie AUSWEICHEN und GESPERRT:
* pruef-portnummern.mjs weist nach, dass die beiden Bereiche sich
* nicht beruehren -- und muss dafuer DIESE Zahl ansehen, nicht eine
* Abschrift, die beim naechsten Verschieben stehen bleibt. */
export const MESS_BASIS = 5900;
/** Um wie viel ausgewichen wird, wenn das System einen Port nicht
* hergibt. 4000 liegt sicher oberhalb des ganzen abgeleiteten
* Bereichs (BASIS bis BASIS+5000 in Schritten von 2, bei derzeit
@@ -244,8 +271,8 @@ export const GESPERRT = new Set([
* Ausnahmen musste dafuer niemand pflegen: Uebersprungen wird nach
* der Regel, nicht nach einer Tabelle von Sonderfaellen.
*/
export function portNummer(nte) {
let p = BASIS;
export function portNummer(nte, basis = BASIS) {
let p = basis;
let uebrig = nte;
while (true) {
if (!GESPERRT.has(p)) {
@@ -253,8 +280,8 @@ export function portNummer(nte) {
uebrig -= 1;
}
p += 1;
if (p > BASIS + 5000) {
throw new Error("[Port] Kein freier Nummernbereich mehr oberhalb von " + BASIS + ".");
if (p > basis + 5000) {
throw new Error("[Port] Kein freier Nummernbereich mehr oberhalb von " + basis + ".");
}
}
}
@@ -263,18 +290,40 @@ export async function eigenerPort(meta, wer = null, nr = 0) {
const pfad = fileURLToPath(meta.url);
const mein = basename(pfad);
const ordner = dirname(pfad);
/* ZWEI SORTEN, ZWEI BEREICHE (01.10.2026). Eine Messdatei zaehlt
unter ihresgleichen, eine Pruefdatei unter ihresgleichen -- sonst
verschoebe eine neue Pruefung die Nummern aller Messungen und
umgekehrt. Welche Sorte es ist, sagt der Dateiname. */
const istMess = mein.startsWith("mess-");
const vorsilbe = istMess ? "mess-" : "pruef-";
const alle = readdirSync(ordner)
.filter((f) => f.startsWith("pruef-") && f.endsWith(".mjs"))
.filter((f) => f.startsWith(vorsilbe) && f.endsWith(".mjs"))
.sort();
const stelle = alle.indexOf(mein);
if (stelle < 0) {
throw new Error(
`[Port] ${mein} steht nicht in der Liste der Pruefdateien in ${ordner}.\n`
`[Port] ${mein} steht nicht in der Liste der ${vorsilbe}Dateien in ${ordner}.\n`
+ " Die Nummer wird aus der Stelle im Alphabet abgeleitet -- ohne\n"
+ " Stelle gibt es keine Nummer, und geraten wird nicht.");
}
if (nr < 0 || nr >= PRO_DATEI) {
throw new Error(`[Port] Es gibt ${PRO_DATEI} Nummern je Datei (0 und 1), nicht ${nr}.`);
}
return portMussFreiSein(portNummer(stelle * PRO_DATEI + nr), wer || mein.replace(/\.mjs$/, ""));
const port = istMess
? portNummer(stelle * PRO_DATEI + nr, MESS_BASIS)
: portNummer(stelle * PRO_DATEI + nr);
/* DIE WACHE GEGEN DAS ZUSAMMENWACHSEN. Kommen so viele
Pruefdateien dazu, dass ihr Bereich den der Messungen erreicht,
bekaemen zwei Laeufe still dieselbe Nummer -- genau der Fehler,
den diese Ableitung beseitigt. Dann lieber ein lauter Abbruch
mit Anleitung. */
if (!istMess && port >= MESS_BASIS) {
throw new Error(
`[Port] Der Bereich der Pruefungen ist bei ${port} angekommen und\n`
+ ` stoesst an den der Messdateien (ab ${MESS_BASIS}).\n`
+ " MESS_BASIS in helfer-port.mjs hochsetzen -- und dabei nachsehen,\n"
+ " dass MESS_BASIS + 4000 (AUSWEICHEN) unter 10080 bleibt.");
}
return portMussFreiSein(port, wer || mein.replace(/\.mjs$/, ""));
}
+8 -4
View File
@@ -15,9 +15,11 @@
ist die Karte 380 px breit, nicht 400.
SIE PRUEFT NICHTS und meldet keinen Fehlschlag. Sie macht ein Bild,
auf dem man nachsehen kann. Deshalb `mess-` und nicht `pruef-`: Die
Portvergabe leitet sich aus den `pruef-`-Namen ab, und eine
Messdatei darf die Nummern der Pruefungen nicht verschieben.
auf dem man nachsehen kann. Sie heisst `mess-` und nicht `pruef-`: Beide Sorten leiten ihre
Portnummer aus der Stelle im Alphabet ab, aber jede aus IHRER
eigenen Liste und in ihrem eigenen Bereich (Pruefungen ab 5000,
Messungen ab 5900). So verschiebt eine neue Messdatei die Nummern
der Pruefungen nicht -- und umgekehrt.
---------------------------------------------------------------------
EIGENE WEGWERF-DATENBANK, NIE DIE ECHTE
@@ -36,7 +38,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5397, HP = 5398;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-alle-einzelsicht (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-alle-sicht-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+3 -1
View File
@@ -25,7 +25,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5481, HP = 5482;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-aushang (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-aushang-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+3 -2
View File
@@ -42,8 +42,9 @@ const HIER = dirname(fileURLToPath(import.meta.url));
const ordner = mkdtempSync(join(tmpdir(), "mess-buehne-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const PORT = 5483;
const HTTPS_PORT = PORT + 1;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HTTPS_PORT = await eigenerPort(import.meta, "mess-buehne (HTTPS)", 1);
process.env.PORT = `${PORT}`;
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
+7 -4
View File
@@ -21,9 +21,11 @@
Diese Datei legt den Bestand an, den er sieht, und macht Bilder.
Sie prueft NICHTS und meldet keinen Fehlschlag.
Sie heisst `mess-` und nicht `pruef-`: Die Portvergabe leitet sich
aus den `pruef-`-Namen ab, und eine Messdatei darf die Nummern der
Pruefungen nicht verschieben.
Sie heisst `mess-` und nicht `pruef-`: Beide Sorten leiten ihre
Portnummer aus der Stelle im Alphabet ab, aber jede aus IHRER
eigenen Liste und in ihrem eigenen Bereich (Pruefungen ab 5000,
Messungen ab 5900). So verschiebt eine neue Messdatei die Nummern
der Pruefungen nicht -- und umgekehrt.
Aufrufen mit: node server/mess-chat-liste.mjs
Bilder: server/mess-chat-liste-breit.png
@@ -34,7 +36,8 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const PORT = 5397;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-messchat-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+3 -1
View File
@@ -27,7 +27,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5491, HP = 5492;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-chat-neu-stelle (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-neustelle-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+3 -1
View File
@@ -26,7 +26,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5403, HP = 5404;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-chat-optik (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-chatoptik-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+3 -1
View File
@@ -39,7 +39,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5399, HP = 5400;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-dialog-ausgang (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-dialog-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+3 -1
View File
@@ -24,7 +24,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5401, HP = 5402;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-eingang-optik (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-eingang-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+2 -1
View File
@@ -36,7 +36,8 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const PORT = 5399;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-messkachel-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+2 -1
View File
@@ -24,7 +24,8 @@ import { join } from "node:path";
const SEITE = process.argv[2] || "treff-regeln.html";
const SUCHE = process.argv[3] || "Schön, dass du da bist";
const PORT = 5451;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-kontrast-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+9 -21
View File
@@ -24,27 +24,15 @@ import { join } from "node:path";
const SEITE = process.argv[2] || "wissen.html";
const SUCHE = process.argv[3] || ".kachel";
const PORT = 5457;
/* IST DIE NUMMER FREI? Sonst misst dieses Werkzeug an einem fremden
Server -- und liefert ein Ergebnis, das zu einem ganz anderen Stand
gehoert. Die Pruefungen holen sich ihre Nummer ueber helfer-port;
ein Messwerkzeug, das von Hand gestartet wird, braucht wenigstens
diese eine Frage. */
{
const netz = await import("node:net");
const frei = await new Promise((fertig) => {
const s = netz.createServer();
s.once("error", () => fertig(false));
s.once("listening", () => s.close(() => fertig(true)));
s.listen(PORT, "127.0.0.1");
});
if (!frei) {
console.error(`Port ${PORT} ist belegt -- hier laeuft schon etwas. `
+ "Gemessen wuerde sonst ein fremder Stand. Abgebrochen.");
process.exit(3);
}
}
/* DIE NUMMER KOMMT AUS DEM ALPHABET, WIE BEI DEN PRUEFUNGEN
(01.10.2026). Hier stand eine feste 5457 mit einer eigenen, kurzen
Fassung des Waechters daneben. Die konnte weniger als das Original:
Sie kannte den dritten Ausgang nicht (EACCES -- das System gibt den
Port dauerhaft nicht her) und sagte nicht, wie man nachsieht, wer
ihn haelt. Eine Abschrift eines Waechters ist dieselbe Falle wie
import { eigenerPort } from "./helfer-port.mjs";
eine Abschrift einer Spaltenliste. */
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-kontrast-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+3 -1
View File
@@ -33,7 +33,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5431, HP = 5432;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-gifs-handy (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-gifs-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+8 -5
View File
@@ -16,10 +16,11 @@
dieselbe Seite, und die Unterschiede werden AUFGEZAEHLT.
SIE PRUEFT NICHTS und meldet keinen Fehlschlag. Sie macht eine Liste
und zwei Bilder, auf denen man nachsehen kann. Deshalb `mess-` und
nicht `pruef-`: Die Portvergabe leitet sich aus den `pruef-`-Namen
ab, und eine Messdatei darf die Nummern der Pruefungen nicht
verschieben.
und zwei Bilder, auf denen man nachsehen kann. Sie heisst `mess-` und nicht `pruef-`: Beide Sorten leiten ihre
Portnummer aus der Stelle im Alphabet ab, aber jede aus IHRER
eigenen Liste und in ihrem eigenen Bereich (Pruefungen ab 5000,
Messungen ab 5900). So verschiebt eine neue Messdatei die Nummern
der Pruefungen nicht -- und umgekehrt.
EIGENE WEGWERF-DATENBANK, NIE DIE ECHTE. Es entstehen echte Personen
und echte Protokollzeilen; in einem laufenden System waeren das
@@ -34,7 +35,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5405, HP = 5406;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-hand-personen (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-hand-pers-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+8 -4
View File
@@ -29,9 +29,11 @@
Sie prüft NICHTS und meldet keinen Fehlschlag. Sie beantwortet eine
Frage, die man vor jeder Umsortierung stellen muss.
Sie heißt `mess-` und nicht `pruef-`: Die Portvergabe leitet sich
aus den `pruef-`-Namen ab, und eine Messdatei darf die Nummern der
Prüfungen nicht verschieben.
Sie heisst `mess-` und nicht `pruef-`: Beide Sorten leiten ihre
Portnummer aus der Stelle im Alphabet ab, aber jede aus IHRER
eigenen Liste und in ihrem eigenen Bereich (Pruefungen ab 5000,
Messungen ab 5900). So verschiebt eine neue Messdatei die Nummern
der Pruefungen nicht -- und umgekehrt.
Aufrufen mit: node server/mess-kachelreihen.mjs
Nur eine Rolle: ROLLE=modi node server/mess-kachelreihen.mjs
@@ -45,7 +47,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5387, HP = 5388;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-kachelreihen (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-kachelreihen-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+2 -1
View File
@@ -20,7 +20,8 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const PORT = 5471;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-kopf-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+15 -16
View File
@@ -56,21 +56,16 @@ process.env.WORKSPACE_DB = join(ordner, "workspace.db");
import { notbremse } from "./helfer-notbremse.mjs";
import { zertifikatBauen } from "./helfer-openssl.mjs";
/* Eine feste Nummer -- `eigenerPort` leitet seine aus der Stelle im
Alphabet der PRUEFdateien ab, und dieses Werkzeug ist keine.
Geprueft wird trotzdem, ob sie frei ist: Sonst misst man an einem
fremden Server und bekommt ein Bild von einem anderen Stand. */
const PORT = 5461;
{
const netz = await import("node:net");
const frei = await new Promise((fertig) => {
const s = netz.createServer();
s.once("error", () => fertig(false));
s.once("listening", () => s.close(() => fertig(true)));
s.listen(PORT, "127.0.0.1");
});
if (!frei) { console.error(`Port ${PORT} ist belegt. Abgebrochen.`); process.exit(3); }
}
/* DIE NUMMER KOMMT AUS DEM ALPHABET (01.10.2026). Hier stand: „eine
feste Nummer -- `eigenerPort` leitet seine aus der Stelle im
Alphabet der PRUEFdateien ab, und dieses Werkzeug ist keine." Das
stimmte, war aber die falsche Schlussfolgerung: Statt den Waechter
zu meiden, leiten die Messdateien jetzt aus IHRER eigenen Liste ab,
in einem eigenen Bereich ab 5900. Die abgeschriebene Kurzfassung,
die hier stand, kannte den dritten Ausgang nicht (EACCES) und sagte
auch nicht, wie man nachsieht, wer den Port haelt. */
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
process.env.PORT = `${PORT}`;
process.env.SITE_ACCESS_SECRET = "lokaler-test";
@@ -185,7 +180,11 @@ const { request: httpAnfrage } = await import("node:http");
const schluesselDatei = join(ordner, "m.key");
const zertDatei = join(ordner, "m.crt");
zertifikatBauen(schluesselDatei, zertDatei, CREW);
const HTTPS_PORT = PORT + 1;
/* NICHT `PORT + 1`: `portNummer` ueberspringt gesperrte Nummern,
deshalb kann die naechste Zahl die NUMMER DER NAECHSTEN DATEI sein,
sobald einmal eine Sperre dazwischenliegt. Heute liegt keine dort --
das ist Glueck, kein Entwurf. Die zweite Nummer gibt es als nr=1. */
const HTTPS_PORT = await eigenerPort(import.meta, "mess-notizblock (HTTPS)", 1);
const vorbau = httpsServer({ key: readFileSync(schluesselDatei), cert: readFileSync(zertDatei) },
(von, nach) => {
const weiter = httpAnfrage({ host: "127.0.0.1", port: PORT, path: von.url,
+3 -2
View File
@@ -29,8 +29,9 @@ const HIER = dirname(fileURLToPath(import.meta.url));
const ordner = mkdtempSync(join(tmpdir(), "mess-reakt-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const PORT = 5491;
const HTTPS_PORT = PORT + 1;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HTTPS_PORT = await eigenerPort(import.meta, "mess-quer (HTTPS)", 1);
process.env.PORT = `${PORT}`;
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
+3 -2
View File
@@ -29,8 +29,9 @@ const HIER = dirname(fileURLToPath(import.meta.url));
const ordner = mkdtempSync(join(tmpdir(), "mess-reakt-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
const PORT = 5483;
const HTTPS_PORT = PORT + 1;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HTTPS_PORT = await eigenerPort(import.meta, "mess-reaktion (HTTPS)", 1);
process.env.PORT = `${PORT}`;
process.env.SITE_ACCESS_SECRET = "lokaler-test";
process.env.SITE_PUBLIC_LAUNCH_AT = "2020-01-01T00:00:00+01:00";
+2 -1
View File
@@ -21,7 +21,8 @@ import { tmpdir } from "node:os";
import { join } from "node:path";
const SEITE = process.argv[2] || "entwicklung.html";
const PORT = 5461;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-inhalt-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+2 -2
View File
@@ -23,9 +23,9 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { request as httpAnfrage } from "node:http";
import { portMussFreiSein } from "./helfer-port.mjs";
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await portMussFreiSein(4496, "mess-sichtbarkeit");
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-mess-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+2 -2
View File
@@ -26,9 +26,9 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
import { portMussFreiSein } from "./helfer-port.mjs";
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await portMussFreiSein(4471, "mess-startseite");
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-mess-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+3 -1
View File
@@ -39,7 +39,9 @@ import { execFileSync } from "node:child_process";
import { request as httpAnfrage } from "node:http";
import { createServer as httpsServer } from "node:https";
const PORT = 5411, HP = 5412;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const HP = await eigenerPort(import.meta, "mess-support-runde (HTTPS)", 1);
const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "ws-supportrunde-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
+2 -1
View File
@@ -19,7 +19,8 @@ import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
const PORT = 5441;
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-ueber-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+2 -2
View File
@@ -40,9 +40,9 @@
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { portMussFreiSein } from "./helfer-port.mjs";
import { eigenerPort } from "./helfer-port.mjs";
const PORT = await portMussFreiSein(5493, "mess-vanvan-karte");
const PORT = await eigenerPort(import.meta);
const ordner = mkdtempSync(join(tmpdir(), "ws-vanvan-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
process.env.PORT = String(PORT);
+251 -2
View File
@@ -20,8 +20,11 @@
sie faellt nur niemandem auf, bis zwei Laeufe kollidieren.
===================================================================== */
import { readdirSync, readFileSync } from "node:fs";
import { eigenerPort, portNummer } from "./helfer-port.mjs";
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); }
@@ -30,6 +33,11 @@ const ok = (b, text) => { if (b) { ok_++; console.log(" ok " + 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 = [];
@@ -186,6 +194,247 @@ 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);
+35 -4
View File
@@ -62,9 +62,9 @@ let fehler = 0, geprueft = 0, offen = 0;
const ok = (b, t) => { geprueft++; console.log((b ? " ok " : " FEHL ") + t); if (!b) fehler++; };
const unklar = (t) => { offen++; console.log(" -- " + t); };
const { portNummer, AUSWEICHEN, GESPERRT } = await import("./helfer-port.mjs");
const { portNummer, AUSWEICHEN, GESPERRT, MESS_BASIS } = await import("./helfer-port.mjs");
console.log("=== Kann jede Pruefung ihren Port bekommen? ===");
console.log("=== Kann jede Pruefung und jede Messung ihren Port bekommen? ===");
console.log("");
/* DIE LISTE WIRD GELESEN, NICHT GEPFLEGT -- und zwar mit derselben
@@ -76,7 +76,18 @@ const dateien = readdirSync(HIER)
.filter((f) => f.startsWith("pruef-") && f.endsWith(".mjs"))
.sort();
/* DIE MESSDATEIEN GEHOEREN SEIT DEM 01.10.2026 DAZU. Sie hatten ihre
Nummern bis dahin von Hand -- einundzwanzig von 24 sogar ohne
jeden Waechter -- und lagen teils mitten im Bereich der
Pruefungen. Jetzt leiten sie ab, aus ihrer eigenen Liste, ab
MESS_BASIS. Dieser Bereich ist neu, und ob der Rechner ihn hergibt,
war eine Annahme, bis er hier durchprobiert wurde. */
const messen = readdirSync(HIER)
.filter((f) => f.startsWith("mess-") && f.endsWith(".mjs"))
.sort();
ok(dateien.length > 50, `${dateien.length} Pruefdateien gefunden`);
ok(messen.length > 10, `${messen.length} Messdateien dazu`);
ok(dateien.includes("pruef-ports.mjs"),
"diese Datei steht selbst in der Liste -- sonst waere die Regel eine andere"
+ " als die, nach der die Nummern vergeben werden");
@@ -98,8 +109,28 @@ const nummern = [];
for (let i = 0; i < dateien.length; i++) {
for (const nr of [0, 1]) nummern.push({ datei: dateien[i], nr, port: portNummer(i * 2 + nr) });
}
ok(nummern.length === dateien.length * 2,
`${nummern.length} Nummern fuer ${dateien.length} Dateien (je zwei)`);
/* IN DIESELBE LISTE, nicht in eine zweite: So erben die Messnummern
jeden Abschnitt dieser Datei -- Doppelungen, Sperrliste, die Frage
ans System, den Ausweichport. Eine eigene Liste daneben waere die,
die beim naechsten Abschnitt vergessen wird. */
for (let i = 0; i < messen.length; i++) {
for (const nr of [0, 1]) {
nummern.push({ datei: messen[i], nr, port: portNummer(i * 2 + nr, MESS_BASIS) });
}
}
const wieViele = dateien.length + messen.length;
ok(nummern.length === wieViele * 2,
`${nummern.length} Nummern fuer ${wieViele} Dateien (je zwei)`);
/* DASS SICH DIE BEIDEN BEREICHE NICHT BERUEHREN, steht eine Zeile
weiter unten schon als „keine Nummer doppelt" drin. Hier zusaetzlich
in Klartext, weil die Zahl das Interessante ist: Wie viele
Pruefdateien passen noch dazwischen, bevor es eng wird? */
const hoechstPruef = Math.max(...nummern
.filter((x) => x.datei.startsWith("pruef-")).map((x) => x.port));
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 doppelt = nummern
.map((x) => x.port)
+14 -14
View File
@@ -80,7 +80,6 @@ import { fileURLToPath } from "node:url";
import { request as httpAnfrage } from "node:http";
import { execFileSync, spawnSync } from "node:child_process";
import { createServer as httpsServer } from "node:https";
import { createServer as netServer } from "node:net";
import { zertifikatBauen } from "./helfer-openssl.mjs";
const HIER = dirname(fileURLToPath(import.meta.url));
@@ -91,19 +90,18 @@ const CREW = "crew.dogfather-universe.com";
const ordner = mkdtempSync(join(tmpdir(), "tk-video-"));
process.env.WORKSPACE_DB = join(ordner, "workspace.db");
/* Eine eigene Nummer. Frei sein muss sie trotzdem -- sonst filmt
dieses Werkzeug einen fremden Server, und man sieht es dem Bild
nicht an. */
const PORT = 5471;
{
const frei = await new Promise((fertig) => {
const s = netServer();
s.once("error", () => fertig(false));
s.once("listening", () => s.close(() => fertig(true)));
s.listen(PORT, "127.0.0.1");
});
if (!frei) { console.error(`Port ${PORT} ist belegt. Abgebrochen.`); process.exit(3); }
}
/* DER ECHTE WAECHTER, NICHT EINE ABSCHRIFT (01.10.2026). Hier stand
eine kurze eigene Fassung -- und die kannte den dritten Ausgang
nicht: Gibt das System den Port dauerhaft nicht her (EACCES),
meldete sie „belegt" und brach ab, statt auszuweichen. Auf diesem
Rechner ist genau das am 23.09. eingetreten (Port 5040, von einem
Windows-Dienst gehalten). Eine abgeschriebene Sicherung ist
dieselbe Falle wie eine abgeschriebene Liste.
Frei sein muss die Nummer ohnehin: sonst filmt dieses Werkzeug
einen fremden Server, und man sieht es dem Bild nicht an. */
const { portMussFreiSein } = await import("./helfer-port.mjs");
const PORT = await portMussFreiSein(5471, "das Videowerkzeug");
process.env.PORT = `${PORT}`;
process.env.SITE_ACCESS_SECRET = "lokaler-test";
@@ -495,6 +493,8 @@ console.log(`Chat: ${treffRaum ? `${imChat} von ${CHAT.length} Nachrichten` : "R
/* ---------- Der Vorbau mit dem Zertifikat ------------------------------- */
const key = join(ordner, "v.key"), crt = join(ordner, "v.crt");
zertifikatBauen(key, crt, CREW);
/* NICHT AUS EINER FESTEN ZAHL: Weicht der Waechter oben auf
PORT + 4000 aus, muss der Vorbau mitwandern. */
const HTTPS_PORT = PORT + 1;
const vorbau = httpsServer({ key: readFileSync(key), cert: readFileSync(crt) }, (von, nach) => {
const weiter = httpAnfrage({