Fix OBS display and Start button not working
All checks were successful
Release / Bump version and tag (push) Successful in 12s
Sidecar Release / Bump sidecar version and tag (push) Successful in 6s

Three issues fixed:

1. Port mismatch: The sidecar reported the OBS port (8080) in the
   ready event but the frontend needs the API port (8081). Now reports
   the API port so WebSocket/REST connects to the right place.

2. Broadcast from wrong thread: Engine init fires state_changed from
   a background thread, but _broadcast_control used get_event_loop()
   which returns the wrong loop. Now captures the uvicorn event loop
   at startup via on_event("startup").

3. Missed ready state: If the engine finishes before the WebSocket
   client connects, the "ready" state_changed was never received.
   Added status polling (GET /api/status) on WebSocket connect that
   retries every 2s while appState is "initializing".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Developer
2026-04-07 07:35:40 -07:00
parent bc82584dff
commit a8de39de84
3 changed files with 59 additions and 6 deletions

View File

@@ -99,11 +99,19 @@ class APIServer:
self.controller.on_credits_low = on_credits_low
def set_event_loop(self, loop: asyncio.AbstractEventLoop):
"""Set the event loop used for broadcasting (call from uvicorn startup)."""
self._event_loop = loop
def _broadcast_control(self, data: dict):
"""Send a message to all connected /ws/control clients."""
if not self.control_connections:
return
loop = getattr(self, '_event_loop', None)
if loop is None:
return
message = json.dumps(data)
disconnected = []
@@ -111,7 +119,7 @@ class APIServer:
try:
asyncio.run_coroutine_threadsafe(
ws.send_text(message),
asyncio.get_event_loop(),
loop,
)
except Exception:
disconnected.append(ws)
@@ -124,6 +132,10 @@ class APIServer:
app = self.app
ctrl = self.controller
@app.on_event("startup")
async def on_startup():
self.set_event_loop(asyncio.get_event_loop())
# ── Status ─────────────────────────────────────────────
@app.get("/api/status")

View File

@@ -88,11 +88,16 @@ def main():
# Create API server wrapping the controller
api_server = APIServer(controller)
# Determine actual port (web server may have shifted if port was in use)
actual_port = controller.actual_web_port or args.port
# OBS display runs on the configured port, API server on port+1
obs_port = controller.actual_web_port or args.port
api_port = obs_port + 1
# Print ready event so Tauri can discover the port
print(json.dumps({"event": "ready", "port": actual_port}), flush=True)
# Print ready event so Tauri can discover the API port
print(json.dumps({
"event": "ready",
"port": api_port,
"obs_port": obs_port,
}), flush=True)
# Run the API server (blocks)
import uvicorn
@@ -104,7 +109,7 @@ def main():
uvicorn.run(
api_server.app,
host=args.host,
port=actual_port + 1, # API on port+1, OBS display on the main port
port=api_port,
log_level="error",
access_log=False,
)