+
+
+ RVS-Räume 🚪
+ +
+
+ + Alle Räume auf dem RVS. Jeder Token bildet einen eigenen Raum — nur Clients + im GLEICHEN Raum sehen sich. Der RVS-Log kürzt Tokens auf 8 Zeichen, dadurch + können zwei verschiedene Tokens gleich aussehen (Prefix-Kollision). Der + Fingerprint + die Länge hier machen das + eindeutig: mehrere Räume = Token-Mismatch irgendwo. ★ = dein Raum + (Diagnostic). +
+
+
(Aktualisieren klicken)
+ Satelliten 🛰️
@@ -1484,7 +1501,19 @@
-
Compute-Flotte 🖥️
+Compute-Flotte + +
@@ -2155,6 +2184,7 @@
return;
}
if (msg.type === 'host_update') { hosts = msg.hosts || []; renderHosts(); return; }
+ if (msg.type === 'rooms_info') { rooms = (msg.payload && msg.payload.rooms) || []; renderRooms(); return; }
if (msg.type === 'sat_creds_list_result') {
const p = msg.payload || msg;
const sat = p.satellite || '';
@@ -4442,6 +4472,7 @@
} else if (tab === 'triggers') {
loadTriggers();
} else if (tab === 'satellites') {
+ requestRooms();
requestSatellites();
requestHosts();
requestWorkers();
@@ -4575,6 +4606,27 @@
function requestSatCreds(id) {
send({ action: 'sat_creds_list', satellite: id });
}
+ let rooms = []; // [{token8, fp, len, clients, you}]
+ function requestRooms() { send({ action: 'rooms_query' }); }
+ function renderRooms() {
+ const box = document.getElementById('rooms-list');
+ if (!box) return;
+ if (!rooms.length) { box.innerHTML = '(keine Räume — RVS leer?)'; return; }
+ const warn = rooms.length > 1
+ ? '' +
+ '
';
+ }
let hosts = []; // [{hostId, name, os, caps, control, online}]
function requestHosts() { send({ action: 'host_list' }); }
function renderHosts() {
diff --git a/diagnostic/server.js b/diagnostic/server.js
index e353878..fe95de6 100644
--- a/diagnostic/server.js
+++ b/diagnostic/server.js
@@ -1095,6 +1095,9 @@ function connectRVS(forcePlain) {
} else if (msg.type === "host_ping") {
const p = msg.payload || {};
if (p.hostId && hosts.has(p.hostId)) hosts.get(p.hostId).last_seen = Date.now();
+ } else if (msg.type === "rooms_info") {
+ // Antwort des RVS auf rooms_query → an den Browser (Raum-Diagnose).
+ broadcast({ type: "rooms_info", payload: msg.payload || {} });
} else if (msg.type === "sat_devices") {
// Antwort eines Satelliten auf sat_discover → Geraeteliste an Browser.
const p = msg.payload || {};
@@ -2789,6 +2792,10 @@ wss.on("connection", (ws) => {
} else if (msg.action === "host_list") {
// Browser will die aktuelle Host-Agenten-Liste.
ws.send(JSON.stringify({ type: "host_update", hosts: hostList() }));
+ } else if (msg.action === "rooms_query") {
+ // Browser will die RVS-Raum-Diagnose — via persistente rvsWs anfragen,
+ // die Antwort (rooms_info) kommt auf derselben Verbindung zurueck.
+ sendToRVS_raw({ type: "rooms_query", payload: {}, timestamp: Date.now() });
} else if (msg.action === "worker_list") {
// Browser will die aktuelle Compute-Flotte.
ws.send(JSON.stringify({ type: "worker_update", workers: workerList() }));
diff --git a/rvs/server.js b/rvs/server.js
index 5d51904..c97a8c9 100644
--- a/rvs/server.js
+++ b/rvs/server.js
@@ -88,6 +88,10 @@ const ALLOWED_TYPES = new Set([
// host_hello/host_ping und fuehrt host_command aus (exec/read/write/info/
// screenshot) -> host_result. ARIA steuert so Rechner auch hinter NAT.
"host_hello", "host_ping", "host_command", "host_result",
+ // Raum-Diagnose: Diagnostic fragt die aktuellen RVS-Raeume ab (rooms_query),
+ // RVS antwortet direkt mit rooms_info (Fingerprint + Laenge + Client-Zahl je
+ // Raum). Deckt Token-Prefix-Kollisionen auf (2 Raeume, gleicher 8-Zeichen-Log).
+ "rooms_query", "rooms_info",
// Compute-Flotte (AI-Boxen): Worker (f5tts/whisper/voxtral/llm-adapter) melden
// sich per worker_hello an und pingen per worker_ping; der Diagnostic-Server
// aggregiert das und broadcastet worker_update/worker_list an die Browser-UI.
@@ -349,6 +353,29 @@ function registerClient(ws, token) {
return;
}
+ // Raum-Diagnose: direkt an den anfragenden Client antworten (nicht relay'en).
+ // Zeigt ALLE Raeume mit token8 (wie im Log), einem laengeren Fingerprint und
+ // der Token-Laenge — so werden Prefix-Kollisionen (2 Raeume, gleicher 8-Zeichen-
+ // Log, aber verschiedene volle Tokens) sofort sichtbar. KEINE vollen Tokens.
+ if (msg.type === "rooms_query") {
+ const crypto = require("crypto");
+ const out = [];
+ for (const [tok, room] of rooms) {
+ let live = 0;
+ for (const c of room.clients) if (c.readyState === 1) live++;
+ out.push({
+ token8: tok.slice(0, 8),
+ fp: crypto.createHash("sha256").update(tok).digest("hex").slice(0, 12),
+ len: tok.length,
+ clients: live,
+ you: tok === ws._token,
+ });
+ }
+ out.sort((a, b) => b.clients - a.clients);
+ ws.send(JSON.stringify({ type: "rooms_info", payload: { rooms: out }, timestamp: Date.now() }));
+ return;
+ }
+
// Update-Download: APK als Base64 ueber WebSocket senden
if (msg.type === "update_download") {
const apkInfo = getLatestAPK();
⚠ ' + rooms.length + ' Räume — Clients in verschiedenen Räumen sehen sich NICHT. Meist ein abweichender/abgeschnittener RVS_TOKEN.
'
+ : '✓ Genau 1 Raum — alle Clients zusammen.
';
+ box.innerHTML = warn + '| Raum (token8) | Fingerprint | Länge | Clients |
|---|---|---|---|
| ' + escapeHtml(r.token8) + '…' + you + ' | ' + + '' + escapeHtml(r.fp) + ' | ' + + '' + r.len + ' | ' + + '' + r.clients + ' |