jbilcke-hf HF Staff commited on
Commit
998c45a
·
1 Parent(s): a337ed2
Files changed (1) hide show
  1. server.py +88 -33
server.py CHANGED
@@ -487,16 +487,25 @@ async def root_handler(request: web.Request) -> web.Response:
487
  return web.Response(text=html_content, content_type='text/html')
488
 
489
  async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
 
490
  logger.info(f"WebSocket connection attempt - PATH: {request.path}, QUERY: {request.query_string}")
491
- logger.info(f"WebSocket request headers: {dict(request.headers)}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
492
 
493
  try:
494
- ws = web.WebSocketResponse(
495
- max_msg_size=1024*1024*10, # 10MB max message size
496
- timeout=60.0,
497
- heartbeat=30.0 # Add heartbeat to keep connection alive
498
- )
499
-
500
  logger.info("Preparing WebSocket connection...")
501
  await ws.prepare(request)
502
 
@@ -510,26 +519,49 @@ async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
510
  else:
511
  client_ip = request.headers.get('X-Forwarded-For', 'unknown').split(',')[0].strip()
512
 
513
- logger.info(f"Client {user_id} connecting from IP: {client_ip} - WebSocket ready state: {ws.ready_state}")
 
514
 
515
- # Store the user ID in the websocket for easy access
516
- ws.user_id = user_id
517
 
518
- # Create a new session for this user
519
- logger.info(f"Creating game session for user {user_id}")
520
- user_session = await game_manager.create_session(user_id, ws)
521
- logger.info(f"Game session created for user {user_id}")
 
 
 
 
 
 
 
 
 
 
 
 
522
  except Exception as e:
523
  logger.error(f"Error establishing WebSocket connection: {str(e)}", exc_info=True)
524
- raise
 
 
525
 
526
  # Send initial welcome message
527
- await ws.send_json({
528
- 'action': 'welcome',
529
- 'userId': user_id,
530
- 'message': 'Welcome to the MatrixGame WebSocket server!',
531
- 'scenes': game_manager.valid_scenes
532
- })
 
 
 
 
 
 
 
 
533
 
534
  try:
535
  async for msg in ws:
@@ -538,6 +570,8 @@ async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
538
  data = json.loads(msg.data)
539
  action = data.get('action')
540
 
 
 
541
  if action == 'ping':
542
  # Respond to ping immediately
543
  await ws.send_json({
@@ -551,25 +585,46 @@ async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
551
 
552
  except json.JSONDecodeError:
553
  logger.error(f"Invalid JSON from user {user_id}: {msg.data}")
554
- await ws.send_json({
555
- 'error': 'Invalid JSON message',
556
- 'success': False
557
- })
 
558
  except Exception as e:
559
  logger.error(f"Error processing WebSocket message for user {user_id}: {str(e)}")
560
- await ws.send_json({
561
- 'action': data.get('action') if 'data' in locals() else 'unknown',
562
- 'success': False,
563
- 'error': f'Error processing message: {str(e)}'
564
- })
 
565
 
566
- elif msg.type in (WSMsgType.ERROR, WSMsgType.CLOSE):
 
 
 
 
 
567
  break
568
 
 
 
 
 
 
 
 
 
 
 
569
  finally:
570
  # Cleanup session
571
- await game_manager.delete_session(user_id)
572
- logger.info(f"Connection closed for user {user_id}")
 
 
 
 
573
 
574
  return ws
575
 
 
487
  return web.Response(text=html_content, content_type='text/html')
488
 
489
  async def websocket_handler(request: web.Request) -> web.WebSocketResponse:
490
+ """Handle WebSocket connections with robust error handling"""
491
  logger.info(f"WebSocket connection attempt - PATH: {request.path}, QUERY: {request.query_string}")
492
+
493
+ # Log request headers at debug level only (could contain sensitive information)
494
+ logger.debug(f"WebSocket request headers: {dict(request.headers)}")
495
+
496
+ # Prepare a WebSocket response with appropriate settings
497
+ ws = web.WebSocketResponse(
498
+ max_msg_size=1024*1024*10, # 10MB max message size
499
+ timeout=60.0,
500
+ heartbeat=30.0 # Add heartbeat to keep connection alive
501
+ )
502
+
503
+ # Check if WebSocket protocol is supported
504
+ if not ws.can_prepare(request):
505
+ logger.error("Cannot prepare WebSocket: WebSocket protocol not supported")
506
+ return web.Response(status=400, text="WebSocket protocol not supported")
507
 
508
  try:
 
 
 
 
 
 
509
  logger.info("Preparing WebSocket connection...")
510
  await ws.prepare(request)
511
 
 
519
  else:
520
  client_ip = request.headers.get('X-Forwarded-For', 'unknown').split(',')[0].strip()
521
 
522
+ # Log connection success
523
+ logger.info(f"Client {user_id} connecting from IP: {client_ip} - WebSocket connection established")
524
 
525
+ # Mark that the session is established
526
+ is_session_created = False
527
 
528
+ try:
529
+ # Store the user ID in the websocket for easy access
530
+ ws.user_id = user_id
531
+
532
+ # Create a new session for this user
533
+ logger.info(f"Creating game session for user {user_id}")
534
+ user_session = await game_manager.create_session(user_id, ws)
535
+ is_session_created = True
536
+ logger.info(f"Game session created for user {user_id}")
537
+ except Exception as session_error:
538
+ logger.error(f"Error creating game session: {str(session_error)}", exc_info=True)
539
+ if not ws.closed:
540
+ await ws.close(code=1011, message=f"Server error: {str(session_error)}".encode())
541
+ if is_session_created:
542
+ await game_manager.delete_session(user_id)
543
+ return ws
544
  except Exception as e:
545
  logger.error(f"Error establishing WebSocket connection: {str(e)}", exc_info=True)
546
+ if not ws.closed and ws.prepared:
547
+ await ws.close(code=1011, message=f"Server error: {str(e)}".encode())
548
+ return ws
549
 
550
  # Send initial welcome message
551
+ try:
552
+ await ws.send_json({
553
+ 'action': 'welcome',
554
+ 'userId': user_id,
555
+ 'message': 'Welcome to the MatrixGame WebSocket server!',
556
+ 'scenes': game_manager.valid_scenes
557
+ })
558
+ logger.info(f"Sent welcome message to user {user_id}")
559
+ except Exception as welcome_error:
560
+ logger.error(f"Error sending welcome message: {str(welcome_error)}")
561
+ if not ws.closed:
562
+ await ws.close(code=1011, message=b"Failed to send welcome message")
563
+ await game_manager.delete_session(user_id)
564
+ return ws
565
 
566
  try:
567
  async for msg in ws:
 
570
  data = json.loads(msg.data)
571
  action = data.get('action')
572
 
573
+ logger.debug(f"Received {action} message from user {user_id}")
574
+
575
  if action == 'ping':
576
  # Respond to ping immediately
577
  await ws.send_json({
 
585
 
586
  except json.JSONDecodeError:
587
  logger.error(f"Invalid JSON from user {user_id}: {msg.data}")
588
+ if not ws.closed:
589
+ await ws.send_json({
590
+ 'error': 'Invalid JSON message',
591
+ 'success': False
592
+ })
593
  except Exception as e:
594
  logger.error(f"Error processing WebSocket message for user {user_id}: {str(e)}")
595
+ if not ws.closed:
596
+ await ws.send_json({
597
+ 'action': data.get('action') if 'data' in locals() else 'unknown',
598
+ 'success': False,
599
+ 'error': f'Error processing message: {str(e)}'
600
+ })
601
 
602
+ elif msg.type == WSMsgType.ERROR:
603
+ logger.error(f"WebSocket error for user {user_id}: {ws.exception()}")
604
+ break
605
+
606
+ elif msg.type == WSMsgType.CLOSE:
607
+ logger.info(f"WebSocket close received for user {user_id} (code: {msg.data}, message: {msg.extra})")
608
  break
609
 
610
+ elif msg.type == WSMsgType.CLOSING:
611
+ logger.info(f"WebSocket closing for user {user_id}")
612
+ break
613
+
614
+ elif msg.type == WSMsgType.CLOSED:
615
+ logger.info(f"WebSocket already closed for user {user_id}")
616
+ break
617
+
618
+ except Exception as ws_error:
619
+ logger.error(f"Unexpected WebSocket error for user {user_id}: {str(ws_error)}", exc_info=True)
620
  finally:
621
  # Cleanup session
622
+ try:
623
+ logger.info(f"Cleaning up session for user {user_id}")
624
+ await game_manager.delete_session(user_id)
625
+ logger.info(f"Connection closed for user {user_id}")
626
+ except Exception as cleanup_error:
627
+ logger.error(f"Error during session cleanup for user {user_id}: {str(cleanup_error)}")
628
 
629
  return ws
630