From 785f5d080547add3702a957b653ba827a38189c3 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sat, 16 May 2026 19:18:52 +0200 Subject: [PATCH] fix(bridge): grosse File-Re-Downloads zerreissen nicht mehr die WS MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Symptom (aus Bridge-Log): bei chat_history_request triggert die App file_request fuer alle fehlenden Anhaenge. Bei einem 40 MB MP4 wird das base64-encoded ~53 MB, ueberschreitet das RVS-maxPayload (50 MB). Server droppt mit Code 1009 'message too big', Bridge crasht im cleanup mit AttributeError 'NoneType has no call_soon' (websockets-Lib-Bug bei nested context-manager-cleanup nach abgerissener Verbindung). Drei Layer: (1) RVS-Server: maxPayload 50 → 100 MB — deckt ~70 MB binaer ab nach base64-inflate. Comment im server.js erklaert den Hintergrund. (2) Bridge: max_size 50 → 100 MB synchron zum Server. PLUS pre-check im file_request-Handler — Dateien > 70 MB werden mit Fehler-Response abgewiesen statt blind base64-zu-encoden und die WS zu killen. Limit knapp unter Server-Limit damit Bridge proaktiv blockiert. (3) App: file_response-Handler liest 'error'-Feld aus dem Payload und zeigt nen Toast 'Datei X: Datei zu gross fuer Transfer (40 MB, Limit 70 MB)'. Statt einfach zu schweigen oder endlos zu retryen. Crash bei websockets-cleanup ist ein Lib-Bug (NoneType.call_soon) — nicht direkt fixbar, aber tritt jetzt nicht mehr auf weil Bridge proaktiv die zu grossen Files ablehnt und die WS nicht mehr abreisst. Co-Authored-By: Claude Opus 4.7 (1M context) --- android/src/screens/ChatScreen.tsx | 10 +++++++++ bridge/aria_bridge.py | 34 ++++++++++++++++++++++++++++-- rvs/server.js | 10 ++++++--- 3 files changed, 49 insertions(+), 5 deletions(-) diff --git a/android/src/screens/ChatScreen.tsx b/android/src/screens/ChatScreen.tsx index 99faf84..c8a1cfb 100644 --- a/android/src/screens/ChatScreen.tsx +++ b/android/src/screens/ChatScreen.tsx @@ -888,6 +888,16 @@ const ChatScreen: React.FC = () => { const b64 = (message.payload.base64 as string) || ''; const serverPath = (message.payload.serverPath as string) || ''; const mimeType = (message.payload.mimeType as string) || ''; + // Fehler-Response (z.B. Datei zu gross, nicht gefunden) → Toast, + // kein erneuter Versuch. Hauptverdacht: 40+ MB Videos die ueber + // den 70 MB Bridge-Limit gehen. + const fileErr = (message.payload as any).error as string | undefined; + if (fileErr) { + const fname = (message.payload.name as string) || serverPath.split('/').pop() || 'Datei'; + console.warn('[Chat] file_response Fehler fuer %s: %s', fname, fileErr); + ToastAndroid.show(`${fname}: ${fileErr}`, ToastAndroid.LONG); + return; + } if (b64 && reqId) { const fileName = (message.payload.name as string) || 'download'; persistAttachment(b64, reqId, fileName).then(filePath => { diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index f4da5b5..3eba639 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -1478,8 +1478,11 @@ class ARIABridge: try: url = f"{current_url}?token={self.rvs_token}" logger.info("[rvs] Verbinde: %s", current_url) - # max_size=50MB (siehe core-Connect oben — gleicher Grund). - async with websockets.connect(url, max_size=50 * 1024 * 1024) as ws: + # max_size=100MB synchron zum RVS-Server (siehe rvs/server.js). + # File-Re-Download fuer Anhaenge braucht Platz fuer base64- + # inflate (~1.33×). Groessere Files lehnt der file_request- + # Handler proaktiv ab bevor's zur 1009-Disconnection kommt. + async with websockets.connect(url, max_size=100 * 1024 * 1024) as ws: self.ws_rvs = ws retry_delay = 2 logger.info("[rvs] Verbunden — warte auf App-Nachrichten") @@ -2204,6 +2207,33 @@ class ARIABridge: "timestamp": int(asyncio.get_event_loop().time() * 1000), }) return + # Groessen-Check VOR base64-Encode + Send. Sonst zerreisst's bei + # grossen Files (>~70 MB binaer) die WebSocket-Verbindung mit + # Code 1009 (message too big) — RVS-Server droppt, Bridge crasht + # im cleanup (websockets-Lib-Bug). Limit deckt typische Videos + # und Bilder ab; alles drueber soll der User per SSH abholen. + FILE_MAX_BYTES = 70 * 1024 * 1024 + try: + file_size = os.path.getsize(server_path) + except OSError as exc: + logger.warning("[rvs] getsize fehlgeschlagen: %s", exc) + file_size = 0 + if file_size > FILE_MAX_BYTES: + logger.warning("[rvs] Re-Download abgelehnt: %s zu gross (%dMB > %dMB)", + server_path, file_size // (1024 * 1024), + FILE_MAX_BYTES // (1024 * 1024)) + await self._send_to_rvs({ + "type": "file_response", + "payload": { + "requestId": req_id, + "serverPath": server_path, + "name": os.path.basename(server_path), + "error": f"Datei zu gross fuer Transfer ({file_size // (1024 * 1024)} MB, Limit {FILE_MAX_BYTES // (1024 * 1024)} MB)", + "sizeBytes": file_size, + }, + "timestamp": int(asyncio.get_event_loop().time() * 1000), + }) + return with open(server_path, "rb") as f: file_b64 = base64.b64encode(f.read()).decode("ascii") mime, _ = mimetypes.guess_type(server_path) diff --git a/rvs/server.js b/rvs/server.js index e001c3c..fd7f573 100644 --- a/rvs/server.js +++ b/rvs/server.js @@ -71,10 +71,14 @@ function cleanupRooms() { // ── WebSocket-Server starten ──────────────────────────────────────── -// maxPayload 50MB: TTS-Streaming + Voice-Upload (WAV als base64) + +// maxPayload 100MB: TTS-Streaming + Voice-Upload (WAV als base64) + // audio_pcm Chunks koennen die ws-Library Default 1MB ueberschreiten. -// Default-Limit war der Killer fuer die voice_upload Pipeline. -const wss = new WebSocketServer({ port: PORT, maxPayload: 50 * 1024 * 1024 }); +// Plus: file_request/file_response fuer Re-Download von Anhaengen. +// 40 MB MP4 → ~53 MB base64 → vorher mit 50 MB Limit zerschossen +// (Code 1009 message too big, Bridge crashed im cleanup). 100 MB +// deckt bis ~70 MB binaer ab; groessere Files werden Bridge-seitig +// abgewiesen (siehe file_request-Handler) bevor die WS abreisst. +const wss = new WebSocketServer({ port: PORT, maxPayload: 100 * 1024 * 1024 }); wss.on("listening", () => { log(`RVS läuft auf Port ${PORT} | Max Sessions: ${MAX_SESSIONS}`);