Spaces:
Sleeping
Sleeping
Debug - Notifications
Browse files- app/main.py +55 -40
app/main.py
CHANGED
|
@@ -114,66 +114,69 @@ async def make_api_request(method: str, endpoint: str, **kwargs):
|
|
| 114 |
|
| 115 |
async def listen_to_websockets(token: str, notification_state: list):
|
| 116 |
"""Connects to WS and updates state list when a message arrives."""
|
|
|
|
|
|
|
|
|
|
|
|
|
| 117 |
if not token:
|
| 118 |
-
logger.warning("
|
| 119 |
-
return notification_state
|
| 120 |
|
| 121 |
ws_url_base = API_BASE_URL.replace("http", "ws")
|
| 122 |
ws_url = f"{ws_url_base}/ws/{token}"
|
| 123 |
-
logger.info(f"Attempting to connect to WebSocket: {ws_url}")
|
| 124 |
|
| 125 |
try:
|
| 126 |
-
|
| 127 |
-
|
| 128 |
-
logger.info(f"WebSocket connected successfully to {ws_url}")
|
| 129 |
while True:
|
| 130 |
try:
|
| 131 |
message_str = await websocket.recv()
|
| 132 |
-
|
| 133 |
-
|
| 134 |
-
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
|
| 149 |
-
|
| 150 |
-
|
| 151 |
-
|
| 152 |
-
|
|
|
|
|
|
|
|
|
|
| 153 |
|
| 154 |
except websockets.ConnectionClosedOK:
|
| 155 |
-
logger.info("WebSocket connection closed normally.")
|
| 156 |
break
|
| 157 |
except websockets.ConnectionClosedError as e:
|
| 158 |
-
logger.error(f"WebSocket connection closed with error: {e}")
|
| 159 |
break
|
| 160 |
-
except json.JSONDecodeError:
|
| 161 |
-
logger.error(f"Failed to decode JSON from WebSocket message: {message_str}")
|
| 162 |
except Exception as e:
|
| 163 |
-
logger.error(f"Error in WebSocket listener loop: {e}")
|
| 164 |
-
# Avoid
|
| 165 |
-
|
| 166 |
except asyncio.TimeoutError:
|
| 167 |
-
logger.error(f"WebSocket connection timed out: {ws_url}")
|
| 168 |
except websockets.exceptions.InvalidURI:
|
| 169 |
-
logger.error(f"Invalid WebSocket URI: {ws_url}")
|
| 170 |
except websockets.exceptions.WebSocketException as e:
|
| 171 |
-
logger.error(f"WebSocket connection failed: {e}")
|
| 172 |
except Exception as e:
|
| 173 |
-
logger.error(f"Unexpected error
|
| 174 |
|
| 175 |
-
|
| 176 |
-
# The calling Gradio function will handle this return value.
|
| 177 |
return notification_state
|
| 178 |
|
| 179 |
|
|
@@ -225,6 +228,18 @@ with gr.Blocks(theme=gr.themes.Soft()) as demo:
|
|
| 225 |
# This function will read the `notification_list` state
|
| 226 |
every=1
|
| 227 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 228 |
|
| 229 |
# --- Event Handlers ---
|
| 230 |
|
|
|
|
| 114 |
|
| 115 |
async def listen_to_websockets(token: str, notification_state: list):
|
| 116 |
"""Connects to WS and updates state list when a message arrives."""
|
| 117 |
+
# <<< Add Logging >>>
|
| 118 |
+
ws_listener_id = f"WSListener-{os.getpid()}-{asyncio.current_task().get_name()}"
|
| 119 |
+
logger.info(f"[{ws_listener_id}] Starting WebSocket listener task.")
|
| 120 |
+
|
| 121 |
if not token:
|
| 122 |
+
logger.warning(f"[{ws_listener_id}] No token provided. Listener task exiting.")
|
| 123 |
+
return notification_state
|
| 124 |
|
| 125 |
ws_url_base = API_BASE_URL.replace("http", "ws")
|
| 126 |
ws_url = f"{ws_url_base}/ws/{token}"
|
| 127 |
+
logger.info(f"[{ws_listener_id}] Attempting to connect to WebSocket: {ws_url}")
|
| 128 |
|
| 129 |
try:
|
| 130 |
+
async with asyncio.wait_for(websockets.connect(ws_url), timeout=15.0) as websocket: # Increased timeout slightly
|
| 131 |
+
logger.info(f"[{ws_listener_id}] WebSocket connected successfully to {ws_url}")
|
|
|
|
| 132 |
while True:
|
| 133 |
try:
|
| 134 |
message_str = await websocket.recv()
|
| 135 |
+
# <<< Add Logging >>>
|
| 136 |
+
logger.info(f"[{ws_listener_id}] Received raw message: {message_str}")
|
| 137 |
+
try:
|
| 138 |
+
message_data = json.loads(message_str)
|
| 139 |
+
logger.info(f"[{ws_listener_id}] Parsed message data: {message_data}")
|
| 140 |
+
|
| 141 |
+
if message_data.get("type") == "new_user":
|
| 142 |
+
notification = schemas.Notification(**message_data)
|
| 143 |
+
# <<< Add Logging >>>
|
| 144 |
+
logger.info(f"[{ws_listener_id}] Processing 'new_user' notification: {notification.message}")
|
| 145 |
+
# Modify the list in place
|
| 146 |
+
notification_state.insert(0, notification.message)
|
| 147 |
+
logger.info(f"[{ws_listener_id}] State list updated. New length: {len(notification_state)}. Content: {notification_state[:5]}") # Log first few items
|
| 148 |
+
# Limit state history
|
| 149 |
+
if len(notification_state) > 10:
|
| 150 |
+
notification_state.pop()
|
| 151 |
+
else:
|
| 152 |
+
logger.warning(f"[{ws_listener_id}] Received message of unknown type: {message_data.get('type')}")
|
| 153 |
+
|
| 154 |
+
except json.JSONDecodeError:
|
| 155 |
+
logger.error(f"[{ws_listener_id}] Failed to decode JSON from WebSocket message: {message_str}")
|
| 156 |
+
except Exception as parse_err:
|
| 157 |
+
logger.error(f"[{ws_listener_id}] Error processing received message: {parse_err}")
|
| 158 |
+
|
| 159 |
|
| 160 |
except websockets.ConnectionClosedOK:
|
| 161 |
+
logger.info(f"[{ws_listener_id}] WebSocket connection closed normally.")
|
| 162 |
break
|
| 163 |
except websockets.ConnectionClosedError as e:
|
| 164 |
+
logger.error(f"[{ws_listener_id}] WebSocket connection closed with error: {e}")
|
| 165 |
break
|
|
|
|
|
|
|
| 166 |
except Exception as e:
|
| 167 |
+
logger.error(f"[{ws_listener_id}] Error in WebSocket listener receive loop: {e}")
|
| 168 |
+
await asyncio.sleep(1) # Avoid tight loop on errors
|
| 169 |
+
|
| 170 |
except asyncio.TimeoutError:
|
| 171 |
+
logger.error(f"[{ws_listener_id}] WebSocket connection timed out: {ws_url}")
|
| 172 |
except websockets.exceptions.InvalidURI:
|
| 173 |
+
logger.error(f"[{ws_listener_id}] Invalid WebSocket URI: {ws_url}")
|
| 174 |
except websockets.exceptions.WebSocketException as e:
|
| 175 |
+
logger.error(f"[{ws_listener_id}] WebSocket connection failed: {e}")
|
| 176 |
except Exception as e:
|
| 177 |
+
logger.error(f"[{ws_listener_id}] Unexpected error in WebSocket listener task: {e}")
|
| 178 |
|
| 179 |
+
logger.info(f"[{ws_listener_id}] Listener task finished.")
|
|
|
|
| 180 |
return notification_state
|
| 181 |
|
| 182 |
|
|
|
|
| 228 |
# This function will read the `notification_list` state
|
| 229 |
every=1
|
| 230 |
)
|
| 231 |
+
def update_notification_ui(notif_list_state):
|
| 232 |
+
# <<< Add Logging >>>
|
| 233 |
+
# notif_list_state here *is* the Python list from the gr.State object
|
| 234 |
+
logger.debug(f"UI Update Triggered. State List Length: {len(notif_list_state)}. Content: {notif_list_state[:5]}")
|
| 235 |
+
# Join the list items into a string for display
|
| 236 |
+
return "\n".join(notif_list_state)
|
| 237 |
+
|
| 238 |
+
notification_display.change( # Use .change with every= setup on the component
|
| 239 |
+
fn=update_notification_ui,
|
| 240 |
+
inputs=[notification_list], # Read the state
|
| 241 |
+
outputs=[notification_display] # Update the component
|
| 242 |
+
)
|
| 243 |
|
| 244 |
# --- Event Handlers ---
|
| 245 |
|