Spaces:
Running
Running
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 |
|