(websocket: WebSocket)
| 748 | |
| 749 | @app.websocket("/ws/chat") |
| 750 | async def websocket_endpoint(websocket: WebSocket): |
| 751 | if len(manager.active_connections) >= MAX_WS_CONNECTIONS: |
| 752 | await websocket.close(code=status.WS_1008_POLICY_VIOLATION) |
| 753 | return |
| 754 | |
| 755 | await manager.connect(websocket) |
| 756 | message_timestamps: List[float] = [] |
| 757 | try: |
| 758 | while True: |
| 759 | try: |
| 760 | message = await asyncio.wait_for( |
| 761 | websocket.receive_text(), timeout=WS_READ_TIMEOUT_SEC |
| 762 | ) |
| 763 | except asyncio.TimeoutError: |
| 764 | await websocket.close(code=status.WS_1001_GOING_AWAY) |
| 765 | return |
| 766 | |
| 767 | if len(message) > MAX_MESSAGE_SIZE: |
| 768 | await websocket.close(code=status.WS_1009_MESSAGE_TOO_BIG) |
| 769 | return |
| 770 | |
| 771 | now = time.time() |
| 772 | cutoff = now - 60 |
| 773 | message_timestamps = [ts for ts in message_timestamps if ts >= cutoff] |
| 774 | if len(message_timestamps) >= MAX_MESSAGES_PER_MINUTE: |
| 775 | await websocket.close(code=status.WS_1008_POLICY_VIOLATION) |
| 776 | return |
| 777 | message_timestamps.append(now) |
| 778 | |
| 779 | # Process the received message (currently unused but kept for future implementation) |
| 780 | # For now, just return dummy text |
| 781 | response = f"You sent: '{message}'. This is a dummy response from the Feast feature server." |
| 782 | |
| 783 | # Stream the response word by word |
| 784 | words = response.split() |
| 785 | for word in words: |
| 786 | await manager.send_message(word + " ", websocket) |
| 787 | await asyncio.sleep(0.1) # Add a small delay between words |
| 788 | except WebSocketDisconnect: |
| 789 | manager.disconnect(websocket) |
| 790 | |
| 791 | # Mount static files |
| 792 | static_dir_ref = importlib_resources.files(__spec__.parent) / "static" # type: ignore[name-defined, arg-type] |
nothing calls this directly
no test coverage detected