Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -1726,12 +1726,12 @@ Suggested Resolution Approach:
|
|
1726 |
|
1727 |
# Schedule an immediate status broadcast if anything was removed
|
1728 |
if (removed_from_list or removed_from_collab):
|
1729 |
-
|
1730 |
# Use call_soon_threadsafe to schedule the async coroutine in the main loop
|
1731 |
-
|
1732 |
-
|
1733 |
-
|
1734 |
-
|
1735 |
|
1736 |
|
1737 |
async def broadcast_collaboration_status_once(self):
|
@@ -1742,30 +1742,30 @@ Suggested Resolution Approach:
|
|
1742 |
tasks = []
|
1743 |
# No need for disconnected_clients list here, remove_ws_client handles it
|
1744 |
|
1745 |
-
|
1746 |
-
|
1747 |
-
|
1748 |
-
|
1749 |
-
|
1750 |
-
|
1751 |
-
|
1752 |
-
|
1753 |
-
|
1754 |
-
|
1755 |
-
|
1756 |
-
|
1757 |
-
|
1758 |
-
|
1759 |
-
|
1760 |
-
|
1761 |
-
|
1762 |
-
|
1763 |
-
|
1764 |
-
|
1765 |
|
1766 |
-
|
1767 |
-
|
1768 |
-
|
1769 |
|
1770 |
|
1771 |
def _identify_stale_issues(self):
|
@@ -3422,13 +3422,12 @@ def create_ui(manager: IssueManager) -> gr.Blocks:
|
|
3422 |
|
3423 |
}})(); // End IIFE
|
3424 |
</script>
|
3425 |
-
"""
|
3426 |
# The _js parameter injects the JavaScript code into the Gradio page
|
3427 |
demo_app.load(_js=web_socket_js(WS_PORT, GRADIO_PORT), fn=None, inputs=None, outputs=None)
|
3428 |
|
3429 |
return demo_app
|
3430 |
|
3431 |
-
|
3432 |
# ========== WebSocket Server Logic ==========
|
3433 |
async def handle_ws_connection(websocket: WebSocketServerProtocol, path: str, manager: IssueManager):
|
3434 |
"""Handles incoming WebSocket connections and messages for collaboration."""
|
@@ -3437,7 +3436,7 @@ async def handle_ws_connection(websocket: WebSocketServerProtocol, path: str, ma
|
|
3437 |
setattr(websocket, 'client_id', client_id)
|
3438 |
remote_addr = websocket.remote_address
|
3439 |
logger.info(f"WebSocket client connected: {remote_addr} assigned ID {client_id}")
|
3440 |
-
|
3441 |
# Add the new client to the list of active clients
|
3442 |
manager.ws_clients.append(websocket)
|
3443 |
logger.info(f"Client list size: {len(manager.ws_clients)}")
|
|
|
1726 |
|
1727 |
# Schedule an immediate status broadcast if anything was removed
|
1728 |
if (removed_from_list or removed_from_collab):
|
1729 |
+
if self.main_loop.is_running():
|
1730 |
# Use call_soon_threadsafe to schedule the async coroutine in the main loop
|
1731 |
+
self.main_loop.call_soon_threadsafe(asyncio.create_task, self.broadcast_collaboration_status_once())
|
1732 |
+
logger.debug(f"Scheduled immediate status broadcast after removing client {client_desc}.")
|
1733 |
+
else:
|
1734 |
+
logger.warning("Main loop not running, cannot schedule immediate status broadcast after client removal.")
|
1735 |
|
1736 |
|
1737 |
async def broadcast_collaboration_status_once(self):
|
|
|
1742 |
tasks = []
|
1743 |
# No need for disconnected_clients list here, remove_ws_client handles it
|
1744 |
|
1745 |
+
for client in active_clients_snapshot:
|
1746 |
+
# Check if client is closed using the standard websockets property
|
1747 |
+
if client.closed:
|
1748 |
+
continue
|
1749 |
+
try:
|
1750 |
+
tasks.append(client.send(status_payload))
|
1751 |
+
except (ConnectionClosed, ConnectionAbortedError, ConnectionResetError, WebSocketException) as e:
|
1752 |
+
logger.warning(f"Client {getattr(client, 'client_id', client.remote_address)} seems disconnected during single broadcast: {type(e).__name__}. Attempting removal.")
|
1753 |
+
if self.main_loop.is_running():
|
1754 |
+
self.main_loop.call_soon_threadsafe(self.remove_ws_client, client)
|
1755 |
+
else:
|
1756 |
+
logger.warning("Main loop not running, cannot schedule client removal.")
|
1757 |
+
continue
|
1758 |
+
except Exception as e:
|
1759 |
+
logger.error(f"Unexpected error preparing single broadcast to client {getattr(client, 'client_id', client.remote_address)}: {e}. Attempting removal.")
|
1760 |
+
if self.main_loop.is_running():
|
1761 |
+
self.main_loop.call_soon_threadsafe(self.remove_ws_client, client)
|
1762 |
+
else:
|
1763 |
+
logger.warning("Main loop not running, cannot schedule client removal.")
|
1764 |
+
continue
|
1765 |
|
1766 |
+
if tasks:
|
1767 |
+
logger.debug(f"Broadcasting single status update to {len(tasks)} clients.")
|
1768 |
+
# No need to await tasks here if remove_ws_client is scheduled via call_soon_threadsafe
|
1769 |
|
1770 |
|
1771 |
def _identify_stale_issues(self):
|
|
|
3422 |
|
3423 |
}})(); // End IIFE
|
3424 |
</script>
|
3425 |
+
}"""
|
3426 |
# The _js parameter injects the JavaScript code into the Gradio page
|
3427 |
demo_app.load(_js=web_socket_js(WS_PORT, GRADIO_PORT), fn=None, inputs=None, outputs=None)
|
3428 |
|
3429 |
return demo_app
|
3430 |
|
|
|
3431 |
# ========== WebSocket Server Logic ==========
|
3432 |
async def handle_ws_connection(websocket: WebSocketServerProtocol, path: str, manager: IssueManager):
|
3433 |
"""Handles incoming WebSocket connections and messages for collaboration."""
|
|
|
3436 |
setattr(websocket, 'client_id', client_id)
|
3437 |
remote_addr = websocket.remote_address
|
3438 |
logger.info(f"WebSocket client connected: {remote_addr} assigned ID {client_id}")
|
3439 |
+
|
3440 |
# Add the new client to the list of active clients
|
3441 |
manager.ws_clients.append(websocket)
|
3442 |
logger.info(f"Client list size: {len(manager.ws_clients)}")
|