3.8 KiB
Architektur-Übersicht
Kern-Designprinzipien
Event-Driven Pipeline
Der gesamte Ripping-Workflow ist als State Machine implementiert. Der pipelineService verwaltet den aktuellen Zustand und emittiert Ereignisse bei jedem Zustandswechsel. Der WebSocket-Service überträgt diese Ereignisse sofort an alle verbundenen Clients.
Zustandswechsel → Event → WebSocket → Frontend-Update
Service-Layer-Muster
HTTP-Route → Service → Datenbank
Routes delegieren die gesamte Business-Logik an Services. Services sind voneinander unabhängig und können einzeln getestet werden.
Schema-getriebene Einstellungen
Die Settings-Konfiguration definiert sowohl die Validierungsregeln als auch die UI-Struktur in einer einzigen Quelle (settings_schema-Tabelle). Die DynamicSettingsForm-Komponente rendert das Formular dynamisch aus dem Schema.
Echtzeit-Kommunikation
WebSocket-Protokoll
Der WebSocket-Server läuft unter dem Pfad /ws. Nachrichten werden als JSON übertragen:
{
"type": "PIPELINE_STATE_CHANGED",
"payload": {
"state": "ENCODING",
"activeJobId": 42,
"progress": 73.5,
"eta": "00:12:34"
}
}
Nachrichtentypen:
| Typ | Beschreibung |
|---|---|
PIPELINE_STATE_CHANGED |
Pipeline-Zustand hat gewechselt |
PIPELINE_PROGRESS |
Fortschritt (% und ETA) |
PIPELINE_QUEUE_CHANGED |
Queue-Status geändert |
DISC_DETECTED |
Disc wurde erkannt |
DISC_REMOVED |
Disc wurde entfernt |
PIPELINE_ERROR |
Pipeline-Fehler aufgetreten |
DISK_DETECTION_ERROR |
Laufwerkserkennung-Fehler |
Reconnect-Logik
Der Frontend-Hook useWebSocket.js implementiert automatisches Reconnect mit festem Intervall von 1500ms bei Verbindungsabbrüchen.
Prozess-Management
processRunner.js
Externe Tools (MakeMKV, HandBrake, MediaInfo) werden als Child Processes gestartet:
spawn(command, args, { stdio: ['ignore', 'pipe', 'pipe'] })
- stdout/stderr werden zeilenweise gelesen und in Echtzeit verarbeitet
- Progress-Parsing erfolgt über reguläre Ausdrücke in
progressParsers.js - Graceful Shutdown: SIGINT → Timeout → SIGKILL
- Prozess-Tracking: Aktive Prozesse werden registriert für sauberes Beenden
Datenpersistenz
SQLite-Datenbank
Ripster verwendet eine einzige SQLite-Datei für alle persistenten Daten:
backend/data/ripster.db
Tabellen:
| Tabelle | Inhalt |
|---|---|
jobs |
Alle Rip-Jobs mit Status, Logs, Metadaten |
pipeline_state |
Aktueller Pipeline-Zustand (Singleton) |
settings_schema |
Schema aller verfügbaren Einstellungen |
settings_values |
Benutzer-konfigurierte Werte |
Migrations-Strategie
Beim Start prüft database.js automatisch, ob das Schema aktuell ist, und führt fehlende Migrationen aus. Korrupte Datenbankdateien werden in ein Quarantäne-Verzeichnis verschoben und eine neue Datenbank erstellt.
Fehlerbehandlung
Strukturierte Fehler
Alle Fehler werden mit Kontext-Metadaten protokolliert:
logger.error('Encoding fehlgeschlagen', {
jobId: job.id,
command: cmd,
exitCode: code,
stderr: lastLines
});
Job-Fehler-Recovery
- Fehlgeschlagene Jobs bleiben in der Datenbank (Status
ERROR) - Vollständige Fehler-Logs werden im Job-Datensatz gespeichert
- Retry-Funktion ermöglicht Neustart von einem Fehler-Zustand
- Re-Encode erlaubt erneutes Encodieren ohne neu zu rippen
Sicherheit
Eingabe-Validierung
- Alle Benutzer-Eingaben werden in
validators.jsvalidiert - CLI-Argumente werden sicher über
commandLine.jskonstruiert (kein Shell-Injection-Risiko) - Pfade werden sanitisiert bevor sie an externe Prozesse übergeben werden
CORS-Konfiguration
CORS_ORIGIN=http://localhost:5173
In Produktion sollte dieser Wert auf die tatsächliche Frontend-URL gesetzt werden.