fixes
This commit is contained in:
@@ -301,41 +301,42 @@ async def event_generator(request: Request) -> AsyncGenerator[str, None]:
|
||||
|
||||
try:
|
||||
await pubsub.subscribe(redis_channel)
|
||||
logger.info(f"SSE client connected, subscribed to {redis_channel}")
|
||||
|
||||
# Create heartbeat task
|
||||
# Create heartbeat tracking
|
||||
last_heartbeat = asyncio.get_event_loop().time()
|
||||
heartbeat_interval = 25
|
||||
|
||||
while True:
|
||||
# Check if client disconnected
|
||||
if await request.is_disconnected():
|
||||
logger.info("SSE client disconnected")
|
||||
break
|
||||
|
||||
# Get message with timeout for heartbeat
|
||||
try:
|
||||
message = await asyncio.wait_for(
|
||||
pubsub.get_message(ignore_subscribe_messages=True),
|
||||
timeout=1.0
|
||||
)
|
||||
|
||||
if message and message["type"] == "message":
|
||||
# Send data event
|
||||
data = message["data"]
|
||||
yield f"event: message\ndata: {data}\n\n"
|
||||
last_heartbeat = asyncio.get_event_loop().time()
|
||||
|
||||
except asyncio.TimeoutError:
|
||||
pass
|
||||
# Try to get message (non-blocking)
|
||||
message = await pubsub.get_message(ignore_subscribe_messages=True, timeout=0.1)
|
||||
|
||||
# Handle actual data messages
|
||||
if message and message["type"] == "message":
|
||||
data = message["data"]
|
||||
logger.debug(f"Sending SSE message: {data[:100]}...")
|
||||
yield f"event: message\ndata: {data}\n\n"
|
||||
last_heartbeat = asyncio.get_event_loop().time()
|
||||
else:
|
||||
# No message, sleep a bit to avoid busy loop
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
# Send heartbeat every 25 seconds
|
||||
current_time = asyncio.get_event_loop().time()
|
||||
if current_time - last_heartbeat >= 25:
|
||||
if current_time - last_heartbeat >= heartbeat_interval:
|
||||
yield "event: ping\ndata: heartbeat\n\n"
|
||||
last_heartbeat = current_time
|
||||
|
||||
finally:
|
||||
await pubsub.unsubscribe(redis_channel)
|
||||
await pubsub.close()
|
||||
await redis_client.close()
|
||||
await pubsub.aclose()
|
||||
await redis_client.aclose()
|
||||
logger.info("SSE connection closed")
|
||||
|
||||
|
||||
@app.get("/realtime")
|
||||
|
||||
@@ -855,6 +855,12 @@
|
||||
|
||||
// Update device state
|
||||
if (data.type === 'state' && data.device_id && data.payload) {
|
||||
const card = document.querySelector(`[data-device-id="${data.device_id}"]`);
|
||||
if (!card) {
|
||||
console.warn(`No card found for device ${data.device_id}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if it's a light
|
||||
if (data.payload.power !== undefined) {
|
||||
currentState[data.device_id] = data.payload.power;
|
||||
@@ -930,11 +936,13 @@
|
||||
document.addEventListener('visibilitychange', () => {
|
||||
if (document.visibilityState === 'visible') {
|
||||
console.log('Page visible, checking SSE connection...');
|
||||
// Force reconnect if connection is dead
|
||||
if (!eventSource || eventSource.readyState === EventSource.CLOSED || eventSource.readyState === EventSource.CONNECTING) {
|
||||
console.log('SSE connection dead or connecting, forcing reconnect...');
|
||||
// Only reconnect if connection is actually dead (CLOSED = 2)
|
||||
if (!eventSource || eventSource.readyState === EventSource.CLOSED) {
|
||||
console.log('SSE connection dead, forcing reconnect...');
|
||||
reconnectAttempts = 0; // Reset for immediate reconnect
|
||||
connectSSE();
|
||||
} else {
|
||||
console.log('SSE connection OK, readyState:', eventSource.readyState);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -942,26 +950,16 @@
|
||||
// Safari/iOS specific: Reconnect on page focus
|
||||
window.addEventListener('focus', () => {
|
||||
console.log('Window focused, checking SSE connection...');
|
||||
// Only reconnect if connection is actually dead (CLOSED = 2)
|
||||
if (!eventSource || eventSource.readyState === EventSource.CLOSED) {
|
||||
console.log('SSE connection dead, forcing reconnect...');
|
||||
reconnectAttempts = 0; // Reset for immediate reconnect
|
||||
connectSSE();
|
||||
} else {
|
||||
console.log('SSE connection OK, readyState:', eventSource.readyState);
|
||||
}
|
||||
});
|
||||
|
||||
// Safari/iOS specific: Keep connection alive with periodic check
|
||||
setInterval(() => {
|
||||
if (!eventSource || eventSource.readyState === EventSource.CLOSED) {
|
||||
console.log('Periodic check: SSE connection dead, reconnecting...');
|
||||
reconnectAttempts = 0;
|
||||
connectSSE();
|
||||
} else if (eventSource.readyState === EventSource.CONNECTING) {
|
||||
console.log('Periodic check: SSE still connecting, readyState:', eventSource.readyState);
|
||||
} else {
|
||||
console.log('Periodic check: SSE connection alive, readyState:', eventSource.readyState);
|
||||
}
|
||||
}, 10000); // Check every 10 seconds
|
||||
|
||||
// Initialize
|
||||
connectSSE();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user