Add network status/latency info

This commit is contained in:
Peter Stockings
2026-03-05 14:09:58 +11:00
parent a301d1521b
commit 887648bf85
3 changed files with 49 additions and 0 deletions

View File

@@ -52,7 +52,9 @@ class VlcSyncApp(QMainWindow):
# Network Service
self.sync_client = SyncClientThread("wss://video-sync.peterstockings.com/ws")
self.sync_client.connected.connect(self.on_ws_connected)
self.sync_client.connected.connect(lambda: self.room_widget.update_connection_status(True))
self.sync_client.disconnected.connect(self.on_ws_disconnected)
self.sync_client.disconnected.connect(lambda: self.room_widget.update_connection_status(False))
self.sync_client.room_joined.connect(self.on_room_joined)
self.sync_client.room_rejoined.connect(self.on_room_rejoined)
self.sync_client.room_error.connect(self.on_room_error)
@@ -61,6 +63,7 @@ class VlcSyncApp(QMainWindow):
self.sync_client.chat_message.connect(self.room_widget.add_chat_message)
self.sync_client.system_message.connect(self.room_widget.add_system_message)
self.sync_client.sync_event.connect(self.room_widget.handle_sync_event)
self.sync_client.latency_updated.connect(self.room_widget.update_latency)
self.apply_stylesheet()

View File

@@ -120,6 +120,12 @@ class RoomWidget(QWidget):
self.copy_code_btn.setToolTip("Copy Room Code")
self.copy_code_btn.clicked.connect(self.copy_room_code)
self.status_dot = QLabel("")
self.status_dot.setFixedWidth(20)
self.status_dot.setStyleSheet("color: #888; font-size: 14px; background: transparent;")
self.status_dot.setToolTip("Connecting...")
self._latency_ms = None
self.room_file_badge = QLabel("📄 No file")
self.room_file_badge.setObjectName("fileBadge")
@@ -129,6 +135,7 @@ class RoomWidget(QWidget):
topbar_layout.addWidget(self.room_code_display)
topbar_layout.addWidget(self.copy_code_btn)
topbar_layout.addWidget(self.status_dot)
topbar_layout.addStretch()
topbar_layout.addWidget(self.room_file_badge)
topbar_layout.addWidget(self.leave_btn)
@@ -345,6 +352,26 @@ class RoomWidget(QWidget):
def set_room_code_display(self, text: str):
self.room_code_display.setText(f"Room: {text}")
def update_connection_status(self, connected: bool):
if connected:
self.status_dot.setStyleSheet("color: #4BB543; font-size: 14px; background: transparent;")
self.status_dot.setToolTip("Connected")
else:
self.status_dot.setStyleSheet("color: #ff4e45; font-size: 14px; background: transparent;")
self.status_dot.setToolTip("Disconnected")
self._latency_ms = None
def update_latency(self, latency_ms: int):
self._latency_ms = latency_ms
if latency_ms < 100:
color = "#4BB543" # green
elif latency_ms < 250:
color = "#f0ad4e" # yellow
else:
color = "#ff4e45" # red
self.status_dot.setStyleSheet(f"color: {color}; font-size: 14px; background: transparent;")
self.status_dot.setToolTip(f"Latency: {latency_ms}ms")
def toggle_tags_panel(self):
if self.tags_list.isHidden():
self.tags_list.show()

View File

@@ -1,5 +1,6 @@
import asyncio
import json
import time
import websockets
from PyQt6.QtCore import QThread, pyqtSignal
@@ -15,6 +16,7 @@ class SyncClientThread(QThread):
chat_message = pyqtSignal(str, str, int) # author, text, timestamp
system_message = pyqtSignal(str)
sync_event = pyqtSignal(dict)
latency_updated = pyqtSignal(int) # latency in ms
def __init__(self, url="ws://localhost:3000/ws"):
super().__init__()
@@ -22,6 +24,7 @@ class SyncClientThread(QThread):
self.ws = None
self.loop = None
self.running = False
self._ping_sent_at = 0
def run(self):
"""Runs strictly within the newly created QThread"""
@@ -44,6 +47,19 @@ class SyncClientThread(QThread):
json_str = json.dumps(message)
asyncio.run_coroutine_threadsafe(self.ws.send(json_str), self.loop)
async def _ping_loop(self, ws):
"""Sends WebSocket protocol-level pings every 5s to measure latency."""
while self.running:
try:
pong = await ws.ping()
sent_at = time.time()
await asyncio.wait_for(pong, timeout=5)
latency_ms = int((time.time() - sent_at) * 1000)
self.latency_updated.emit(latency_ms)
except Exception:
break
await asyncio.sleep(5)
async def _connect_and_listen(self):
while self.running:
try:
@@ -51,6 +67,7 @@ class SyncClientThread(QThread):
self.ws = ws
self.connected.emit()
ping_task = asyncio.create_task(self._ping_loop(ws))
try:
async for message in ws:
if not self.running:
@@ -58,6 +75,8 @@ class SyncClientThread(QThread):
self._handle_message(json.loads(message))
except websockets.ConnectionClosed:
pass
finally:
ping_task.cancel()
except Exception as e:
print(f"WebSocket Error: {e}")