I have an application that allows multiple bots to connect to it via /ws/{bot_id} endpoint. I'm storing all the connections inside websockets
dict. When someone makes a POST request I want to pass some data to the websocket connection, but it's not letting me because the connection is already closed somehow:
RuntimeError: Unexpected ASGI message 'websocket.send', after sending 'websocket.close' or response already completed
import asyncio
from fastapi import FastAPI, WebSocket
app = FastAPI()
websockets: dict[int, WebSocket] = {}
@app.websocket("/ws/{bot_id}")
async def websocket_endpoint(websocket: WebSocket, bot_id: int):
websockets[bot_id] = websocket
await websocket.accept()
@app.post("/bot/{bot_id}/start_lobby")
async def start_lobby(bot_id: int):
websocket = websockets.get(bot_id)
await websocket.send_text("START")
@app.post("/bot/{bot_id}/quit_lobby")
async def destroy_lobby(bot_id: int):
websocket = websockets.get(bot_id)
await websocket.send_text("DELETE")
Here's the minimal code on a bot client that listens to everything (stdout is always empty):
def websocket_connection():
with connect("ws://localhost:8000/ws/1") as websocket:
while True:
message = websocket.recv()
if message == "START":
start_lobby()
elif message == "DELETE":
destroy_lobby()
websocket.send("BOT 1: RECEIVED")
print(f"Received: {message}")
You need to keep open connection with client.
Example to fix ws handler
@app.websocket("/ws/{bot_id}")
async def websocket_endpoint(websocket: WebSocket, bot_id: int):
websockets[bot_id] = websocket
await websocket.accept()
while True:
data = await websocket.receive()
print(data)
Logs:
Server
INFO: 127.0.0.1:49200 - "POST /bot/1/start_lobby HTTP/1.1" 200 OK
{'type': 'websocket.receive', 'text': 'BOT 1: RECEIVED'}
Client
starting lobby
Received: START