Skip to content

Commit 1db7a8f

Browse files
committed
test CLOSE message to client after disconnect
1 parent f9f2c80 commit 1db7a8f

File tree

1 file changed

+39
-6
lines changed

1 file changed

+39
-6
lines changed

src/diart/handler.py

+39-6
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from typing import Union, Text, Optional, AnyStr, Dict, Any, Callable
44
import logging
55
from websocket_server import WebsocketServer
6+
import socket
67

78
from . import blocks
89
from . import sources as src
@@ -223,8 +224,13 @@ def _on_message_received(
223224
if client_id in self._clients:
224225
try:
225226
self._clients[client_id].audio_source.process_message(message)
227+
except (socket.error, ConnectionError) as e:
228+
logger.warning(f"Client {client_id} disconnected: {e}")
229+
self.close(client_id)
226230
except Exception as e:
227231
logger.error(f"Error processing message from client {client_id}: {e}")
232+
# Don't close the connection for non-connection related errors
233+
# This allows the client to retry sending the message
228234

229235
def send(self, client_id: Text, message: AnyStr) -> None:
230236
"""Send a message to a specific client.
@@ -247,18 +253,34 @@ def send(self, client_id: Text, message: AnyStr) -> None:
247253
if client is not None:
248254
try:
249255
self.server.send_message(client, message)
256+
except (socket.error, ConnectionError) as e:
257+
logger.warning(f"Client {client_id} disconnected while sending message: {e}")
258+
self.close(client_id)
250259
except Exception as e:
251260
logger.error(f"Failed to send message to client {client_id}: {e}")
252261

253262
def run(self) -> None:
254263
"""Start the WebSocket server."""
255264
logger.info(f"Starting WebSocket server on {self.uri}")
256-
try:
257-
self.server.run_forever()
258-
except Exception as e:
259-
logger.error(f"Server error: {e}")
260-
finally:
261-
self.close_all()
265+
max_retries = 3
266+
retry_count = 0
267+
268+
while retry_count < max_retries:
269+
try:
270+
self.server.run_forever()
271+
break # If server exits normally, break the retry loop
272+
except (socket.error, ConnectionError) as e:
273+
logger.warning(f"WebSocket connection error: {e}")
274+
retry_count += 1
275+
if retry_count < max_retries:
276+
logger.info(f"Attempting to restart server (attempt {retry_count + 1}/{max_retries})")
277+
else:
278+
logger.error("Max retry attempts reached. Server shutting down.")
279+
except Exception as e:
280+
logger.error(f"Fatal server error: {e}")
281+
break
282+
finally:
283+
self.close_all()
262284

263285
def close(self, client_id: Text) -> None:
264286
"""Close a specific client's connection and cleanup resources.
@@ -277,9 +299,20 @@ def close(self, client_id: Text) -> None:
277299
# Close audio source and remove client
278300
client_state.audio_source.close()
279301
del self._clients[client_id]
302+
303+
# Try to send a close frame to the client
304+
try:
305+
client = next((c for c in self.server.clients if c["id"] == client_id), None)
306+
if client:
307+
self.server.send_message(client, "CLOSE")
308+
except Exception:
309+
pass # Ignore errors when trying to send close message
310+
280311
logger.info(f"Closed connection and cleaned up state for client: {client_id}")
281312
except Exception as e:
282313
logger.error(f"Error closing client {client_id}: {e}")
314+
# Ensure client is removed from dictionary even if cleanup fails
315+
self._clients.pop(client_id, None)
283316

284317
def close_all(self) -> None:
285318
"""Shutdown the server and cleanup all client connections."""

0 commit comments

Comments
 (0)