From ae2024ef55313075f967b0667f9b810ec35aee10 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 25 Oct 2026 13:26:23 +0100 Subject: [PATCH] feat(app): "Auf Updates pruefen" sagt immer, was los ist Keine neue Version: Meldung mit installierter Version, neuester Version auf dem Server und ob Update-Server und Download-Weg erreichbar sind (HEAD auf /update/latest.apk). Keine Verbindung: Meldung mit Server-Adresse, Zustand und letztem Verbindungsfehler. Keine Antwort in 10 s: Hinweis auf alten RVS. Neue Version: wie bisher der Update-Dialog (nur einmal, nicht doppelt ueber den ChatScreen-Listener). RVS antwortet auf update_check jetzt auch ohne neue Version (update_none mit latest/current). Co-Authored-By: Claude Opus 5.5 --- android/src/screens/SettingsScreen.tsx | 3 +- android/src/services/updater.ts | 70 ++++++++++++++++++++++++++ rvs/server.js | 10 +++- 3 files changed, 80 insertions(+), 3 deletions(-) diff --git a/android/src/screens/SettingsScreen.tsx b/android/src/screens/SettingsScreen.tsx index 5eee6b5..d76c665 100644 --- a/android/src/screens/SettingsScreen.tsx +++ b/android/src/screens/SettingsScreen.tsx @@ -2539,8 +2539,7 @@ const SettingsScreen: React.FC = () => { style={[styles.connectButton, {marginTop: 12}]} onPress={() => { const updateService = require('../services/updater').default; - updateService.checkForUpdate(); - Alert.alert('Update-Check', 'Pruefe auf neue Version...'); + updateService.checkForUpdateManual(); }} > Auf Updates pr{'\u00FC'}fen diff --git a/android/src/services/updater.ts b/android/src/services/updater.ts index 2ed1a9c..044bd66 100644 --- a/android/src/services/updater.ts +++ b/android/src/services/updater.ts @@ -50,6 +50,9 @@ class UpdateService { private progressListeners: ProgressCallback[] = []; private progress: UpdateProgress = { active: false, version: '', fraction: -1, receivedMB: 0, totalMB: 0, status: '' }; private jobId: number | null = null; + /** Laeuft gerade eine Pruefung per Knopf? Dann geht die Antwort NUR dorthin + * (sonst zeigt der ChatScreen-Listener denselben Dialog ein zweites Mal). */ + private manualWaiter: ((r: { type: 'available'; info: UpdateInfo } | { type: 'none'; latest: string }) => void) | null = null; private cancelled = false; constructor() { @@ -66,10 +69,19 @@ class UpdateService { downloadUrl: (msg.payload.downloadUrl as string) || '', size: (msg.payload.size as number) || 0, }; + if (this.manualWaiter) { + const w = this.manualWaiter; this.manualWaiter = null; + if (info.version && this.isNewer(info.version)) w({ type: 'available', info }); + else w({ type: 'none', latest: info.version }); + return; + } if (info.version && this.isNewer(info.version)) { console.log(`[Update] Neue Version verfuegbar: ${info.version} (aktuell: ${APP_VERSION})`); this.listeners.forEach(cb => cb(info)); } + } else if ((msg.type as string) === 'update_none' && this.manualWaiter) { + const w = this.manualWaiter; this.manualWaiter = null; + w({ type: 'none', latest: String(msg.payload.latest || '') }); } }); } @@ -150,6 +162,64 @@ class UpdateService { setTimeout(() => { this.checking = false; }, 10000); } + /** + * Pruefung per Knopf (Einstellungen → Ueber): sagt IMMER etwas — + * neue Version (Update-Dialog), "keine neue Version" mit der Version auf dem + * Server, oder warum der Update-Server nicht erreichbar ist (mit Details). + */ + async checkForUpdateManual(): Promise { + const cfg = rvs.getConfig(); + const where = cfg ? `${cfg.useTLS ? 'wss' : 'ws'}://${cfg.host}:${cfg.port}` : '(nicht eingerichtet)'; + if (!cfg) { + Alert.alert('Update-Server nicht erreichbar', 'Es ist noch kein Server eingerichtet (Einstellungen → Verbindung).'); + return; + } + if (!rvs.isSocketOpen()) { + const lastErr = [...rvs.getConnectionLog()].reverse().find(e => e.level === 'error'); + Alert.alert('Update-Server nicht erreichbar', + `Keine Verbindung zu ${where}.\n\nZustand: ${rvs.getState()}` + + (lastErr ? `\nLetzter Fehler (${new Date(lastErr.timestamp).toLocaleTimeString()}):\n${lastErr.message}` : '')); + return; + } + + const result = await new Promise<{ type: 'available'; info: UpdateInfo } | { type: 'none'; latest: string } | { type: 'timeout' }>(resolve => { + const t = setTimeout(() => { this.manualWaiter = null; resolve({ type: 'timeout' }); }, 10_000); + this.manualWaiter = (r) => { clearTimeout(t); resolve(r); }; + rvs.send('update_check' as any, { version: APP_VERSION }); + }); + + if (result.type === 'available') { + this.promptUpdate(result.info); + return; + } + if (result.type === 'timeout') { + Alert.alert('Update-Server antwortet nicht', + `Verbunden mit ${where}, aber nach 10 s keine Antwort auf die Update-Anfrage.\n\n` + + 'Moeglicherweise laeuft auf dem Server eine alte RVS-Version.'); + return; + } + + // Keine neue Version — zusaetzlich pruefen, ob der Download-Weg funktioniert + let dl = ''; + try { + const ctrl = new AbortController(); + const t = setTimeout(() => ctrl.abort(), 10_000); + const r = await fetch(`${cfg.useTLS ? 'https' : 'http'}://${cfg.host}:${cfg.port}/update/latest.apk`, + { method: 'HEAD', headers: { 'X-RVS-Token': cfg.token }, signal: ctrl.signal }); + clearTimeout(t); + dl = r.ok ? 'Download-Weg: erreichbar ✓' + : r.status === 404 && result.latest ? 'Download-Weg: vom Server noch nicht unterstuetzt (alter RVS)' + : r.status === 404 ? 'Download-Weg: erreichbar, aber auf dem Server liegt keine APK' + : `Download-Weg: Fehler HTTP ${r.status}`; + } catch (e: any) { + dl = `Download-Weg: nicht erreichbar (${e?.name === 'AbortError' ? 'Zeitueberschreitung' : (e?.message || e)})`; + } + Alert.alert('Keine neue Version', + `Installiert: ${APP_VERSION}\n` + + `Neueste auf dem Server: ${result.latest || '(keine APK hinterlegt)'}\n\n` + + `Update-Server: ${where} ✓\n${dl}`); + } + /** Callback registrieren */ onUpdateAvailable(callback: UpdateCallback): () => void { this.listeners.push(callback); diff --git a/rvs/server.js b/rvs/server.js index 63452d0..c1ef06f 100644 --- a/rvs/server.js +++ b/rvs/server.js @@ -27,7 +27,7 @@ const ALLOWED_TYPES = new Set([ "chat", "audio", "file", "location", "mode", "log", "event", "heartbeat", "file_request", "file_response", "file_saved", "stt_result", "config", "tts_request", "xtts_request", "xtts_response", "xtts_list_voices", "xtts_voices_list", "voice_upload", "xtts_voice_saved", - "update_check", "update_available", "update_download", "update_data", + "update_check", "update_available", "update_none", "update_download", "update_data", "agent_activity", "cancel_request", "interject", "audio_pcm", "file_from_aria", @@ -614,6 +614,14 @@ function registerClient(ws, token) { }, timestamp: Date.now(), })); + } else { + // Auch "nichts Neues" beantworten — die App zeigt dann, dass der + // Update-Server erreichbar ist und welche Version er hat + ws.send(JSON.stringify({ + type: "update_none", + payload: { latest: apkInfo ? apkInfo.version : "", current: clientVersion }, + timestamp: Date.now(), + })); } return; }