From a766d0cde3fb3c591861733874ca19fe7655b901 Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Tue, 28 Jul 2026 20:44:51 +0200 Subject: [PATCH] fix(pi-family): per-tab client_id for the QEMU-Linux WebSocket With the bare boardId as client_id, two tabs (or two users) on the same example shared one QEMU instance: serial output went to whichever socket connected last, keystrokes interleaved and one tab's stop killed the other's guest. Suffix the tab session id so each tab gets its own instance (stopped on its own disconnect, like the ESP32 workers). --- frontend/src/simulation/RaspberryPi3Bridge.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/src/simulation/RaspberryPi3Bridge.ts b/frontend/src/simulation/RaspberryPi3Bridge.ts index f04f8520..99429144 100644 --- a/frontend/src/simulation/RaspberryPi3Bridge.ts +++ b/frontend/src/simulation/RaspberryPi3Bridge.ts @@ -27,6 +27,8 @@ * { type: 'error', data: { message: string } } */ +import { getTabSessionId } from './Esp32Bridge'; + const API_BASE = (): string => { // The desktop shell injects the sidecar URL at runtime (random port) via // window.__VELXIO_API_BASE__; honor it first so the QEMU-board WebSocket @@ -92,8 +94,13 @@ export class RaspberryPi3Bridge { const base = API_BASE(); const wsProtocol = base.startsWith('https') ? 'wss:' : 'ws:'; + // Scope the backend client_id to THIS tab. With the bare boardId, two + // tabs (or two users) opening the same example shared one QEMU + // instance: serial output went to whichever WebSocket connected last, + // keystrokes interleaved, and one tab's stop killed the other's guest. + const clientId = `${this.boardId}--${getTabSessionId()}`; const wsUrl = - base.replace(/^https?:/, wsProtocol) + `/simulation/ws/${encodeURIComponent(this.boardId)}`; + base.replace(/^https?:/, wsProtocol) + `/simulation/ws/${encodeURIComponent(clientId)}`; const socket = new WebSocket(wsUrl); this.socket = socket;