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