Die heutige Windows-Fassung ist der Docker-Code in einer EXE: PyInstaller
buendelt docker/api und docker/worker, uvicorn laeuft auf 127.0.0.1:7788,
pywebview stellt ein Fenster davor. Elf Release-Kandidaten in drei Tagen,
und die Funde sind fast alle derselbe Typ — Linux-Annahmen, die unter
Windows etwas anderes bedeuten (timeout ls -d, shutil.which, /app,
/dev/{name}, F: ohne Trenner).
Das Konzept beschreibt den Neubau als Windows-Programm: Electron 44,
TypeScript durchgehend, Einzelplatz, kein Python, kein HTTP-Server.
Vier Entscheide des Commanders (30.08.2026) sind eingearbeitet:
alles TypeScript/Node · Docker bleibt unangetastet · reiner Einzelplatz ·
eigener Branch.
Vor der ersten Zeile Konzept gemessen (Regel D), Belege in beweise/:
* Win32 aus Node an G: (HL-DT-ST BD-RE BU40N) — Laufwerkssuche,
CreateFileW, QUERY_PROPERTY (Modell + Serial), CHECK_VERIFY2,
GET_LENGTH_INFO (33,76 GB -> Blu-ray). IOCTL_CDROM_DISK_TYPE
antwortet mit Fehler 50 — derselbe Befund wie im Python-Treiber.
* Prozess-Leine (Job Object): Kind stirbt mit dem per taskkill /F
ohne /T abgeschossenen Elternprozess. Die Messung aus rc10, in
Node nachgestellt.
* node:sqlite ist in Node 24 eingebaut — in Electron noch ungeprueft,
ausdruecklich als offener Punkt markiert.
Akutestes Risiko im Dokument: MakeMKVs freier Beta-Key laeuft Ende
September 2026 ab, die Kaufseite fuer die Dauerlizenz ist seit Mai defekt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
114 lines
4.0 KiB
Markdown
114 lines
4.0 KiB
Markdown
# Beweise — die Messungen zu KONZEPT-WINDOWS.md § 3
|
|
|
|
Diese zwei Skripte sind die Grundlage für die Entscheidung, Rippy v5 in
|
|
TypeScript/Node zu bauen. Sie beantworten die einzige Frage, an der das ganze
|
|
Konzept hängt:
|
|
|
|
> **Kann Node überhaupt alles, was Rippy am Laufwerk braucht?**
|
|
|
|
Wäre die Antwort nein gewesen, wäre das Konzept wertlos gewesen. Deshalb sind
|
|
sie zuerst gelaufen — vor der ersten Zeile Konzept.
|
|
|
|
`AGENTS.md` Regel D: *„Externe Schnittstellen NIE aus dem Kopf."*
|
|
|
|
---
|
|
|
|
## Nachstellen
|
|
|
|
```
|
|
npm install koffi
|
|
node laufwerk.js
|
|
```
|
|
|
|
Gemessen am 30.08.2026 mit Node v24.19.0, koffi 3.1.6, an einem
|
|
HL-DT-ST BD-RE BU40N (USB) mit eingelegter Blu-ray.
|
|
|
|
---
|
|
|
|
## `laufwerk.js` — Win32-Laufwerkszugriff
|
|
|
|
Ruft dieselben Steuercodes auf wie `src/rippy/drives/win_ioctl.py` im
|
|
Docker-Zweig. **Nur lesend** — kein Auswerfen, kein Verriegeln.
|
|
|
|
```
|
|
1. GetLogicalDrives + GetDriveTypeW -> optische Laufwerke: [ 'G' ]
|
|
2. CreateFileW \\.\G: (Zugriff 0) -> offen
|
|
CreateFileW \\.\G: (GENERIC_READ) -> offen
|
|
3. IOCTL_STORAGE_QUERY_PROPERTY -> Hersteller: HL-DT-ST | Modell: BD-RE BU40N
|
|
| Rev: 1.03 | Serial: 0025114C0149
|
|
4. IOCTL_STORAGE_CHECK_VERIFY2 -> Medium eingelegt
|
|
5. IOCTL_CDROM_DISK_TYPE -> Win32-Fehler 50
|
|
6. IOCTL_DISK_GET_LENGTH_INFO -> 33.759.690.752 Bytes (33,76 GB) => Blu-ray
|
|
```
|
|
|
|
**Punkt 5 ist kein Fehlschlag.** Fehler 50 ist `ERROR_NOT_SUPPORTED` — genau
|
|
das, was der Python-Treiber an diesem Laufwerk auch sieht (`SAVEPOINT.md`,
|
|
v4.0-rc11, Abschnitt „Das Laufwerk"). Node verhält sich identisch. Die Lehre
|
|
steht im alten Code und gilt weiter: **Die Disc-Einordnung darf sich nicht auf
|
|
`IOCTL_CDROM_DISK_TYPE` verlassen — die Größe ist der verlässliche Weg.**
|
|
|
|
Punkt 2 zeigt die Unterscheidung, die in rc11 teuer war: `Zugriff 0` fragt das
|
|
**Gerät**, `GENERIC_READ` fragt das **Medium**. Bei einer gestörten Disc
|
|
scheitert das zweite und das erste geht weiter — wer nur eins probiert, hält
|
|
ein antwortendes Laufwerk für tot.
|
|
|
|
---
|
|
|
|
## `leine.js` — die Prozess-Leine (Job Object)
|
|
|
|
Stellt den Befund aus `SAVEPOINT.md` v4.0-rc10 nach: Windows räumt
|
|
Kindprozesse **nicht** auf. Ein hart beendeter Rippy hinterlässt ein
|
|
`makemkvcon`, das das Laufwerk festhält, und jeder spätere Rip scheitert.
|
|
|
|
Das Skript setzt eine Arbeitsgruppe mit `JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE`,
|
|
startet ein langlebiges Kind und lässt sich dann hart abschießen —
|
|
`taskkill /F` **ohne** `/T`, also genau das, was bei einem Absturz und beim
|
|
Drüber-Installieren passiert.
|
|
|
|
```
|
|
1. CreateJobObjectW -> Arbeitsgruppe angelegt
|
|
2. SetInformationJobObject -> KILL_ON_JOB_CLOSE gesetzt
|
|
3. AssignProcessToJobObject -> dieser Prozess hängt in der Gruppe
|
|
4. Kindprozess gestartet, PID 16040
|
|
|
|
vor dem Abschuss: Eltern lebt: True Kind lebt: True
|
|
taskkill /F /PID 29488 -> ERFOLGREICH
|
|
danach: Eltern lebt: False Kind lebt: False
|
|
```
|
|
|
|
Nachstellen (PowerShell):
|
|
|
|
```powershell
|
|
$p = Start-Process node -ArgumentList "leine.js" -PassThru -RedirectStandardOutput out.txt
|
|
Start-Sleep 3
|
|
$kind = (Select-String -Path out.txt -Pattern 'KIND-PID=(\d+)').Matches[0].Groups[1].Value
|
|
taskkill /F /PID $p.Id
|
|
Start-Sleep 2
|
|
Get-Process -Id $kind -ErrorAction SilentlyContinue # muss LEER sein
|
|
```
|
|
|
|
---
|
|
|
|
## Zwei weitere Messungen aus § 3, ohne eigenes Skript
|
|
|
|
**`node:sqlite` ist in Node 24 eingebaut:**
|
|
|
|
```
|
|
node -e "const s=require('node:sqlite'); const db=new s.DatabaseSync(':memory:'); db.exec('CREATE TABLE t (a TEXT)'); db.prepare('INSERT INTO t VALUES (?)').run('geht'); console.log(db.prepare('SELECT a FROM t').get().a)"
|
|
geht
|
|
```
|
|
|
|
⚠️ Das ist in **Node 24.19.0** gemessen, nicht in Electron. Electron baut sein
|
|
Node mit eigenen Flags — ob `node:sqlite` dort vorhanden ist, ist der erste
|
|
Handgriff in Etappe W-0.
|
|
|
|
**npm 11 blockiert Install-Skripte:**
|
|
|
|
```
|
|
npm warn allow-scripts koffi@3.1.6 (install: node ./cnoke.cjs -P . --prebuild --release)
|
|
```
|
|
|
|
koffi lädt trotzdem — es bringt vorgebaute Binärdateien mit. Die Warnung
|
|
gehört in die Bau-Anleitung, sonst sucht eines Tages jemand an der falschen
|
|
Stelle.
|