I'm developing a text game in Python implementing the networking part using Quart and websockets. I'm done with the single player part which is a simple single request- single response thing and next I want to implement a PvP part. Reading the Quart documentation I almost figured how to broadcast messages to both players. The implementation is done using asyncio.Queue() for reasons I partially understand. However when I removed the whole queue logic, things went a bit strange. That is, after the second player/websocket connects he gets both his message and the other player's message and the first player gets nothing. So it seems that asyncio.Queue() does more under the hood than a simple queue but I really don't understand what or why.
Below is the server code, I have both implementations demonstrated for anyone willing to see for himself.
import asyncio
from functools import wraps
from quart import Quart, websocket
app = Quart(__name__)
connected = set()
def collect_websocket(func):
@wraps(func)
async def wrapper(*args, **kwargs):
global connected
connected.add(websocket)
try:
return await func(*args, **kwargs)
finally:
connected.remove(websocket)
return wrapper
@app.websocket('/ws')
@collect_websocket
async def ws():
await websocket.send("Welcome")
await handler()
while True:
data = await websocket.receive()
await websocket.send(data)
async def handler():
if len(connected) > 1:
for c in connected:
await c.send("What do you do [a] [b] or [c]")
connected_websockets = set()
def collect_websocket_with_queue(func):
@wraps(func)
async def wrapper(*args, **kwargs):
global connected_websockets
queue = asyncio.Queue()
connected_websockets.add(queue)
try:
return await func(queue, *args, **kwargs)
finally:
connected_websockets.remove(queue)
return wrapper
@app.websocket('/queue')
@collect_websocket_with_queue
async def wsqueue(queue):
await websocket.send("Welcome")
await handlerQueue()
while True:
data = await queue.get()
await websocket.send(data)
async def handlerQueue():
if len(connected_websockets) > 1:
for queue in connected_websockets:
await queue.put("What do you do [a] [b] or [c]")
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000, debug=False)
Secondly, what I fail to achieve both with the queue and without is to make the code wait until both players send their input. What I tried was something like:
for c in connected:
await c.receive()
or for the implementation with queues:
for queue in connected:
await queue.get()
but none of these worked. How could that be achieved? Speaking with code:
async def handler():
if len(connected) > 1:
for c in connected:
await c.send("What do you do [a] [b] or [c]")
#############
# Function or block of code for getting both players input
############
for c in connected:
await c.send("That and that happened, now do what?")
#############
# Function or block of code for getting both players input
############
## repeat until winning condition is met
Of course in the future I'll have to implement the client handling situation better but for the time being I want to see the flow happening to figure out some decisions.
I'm open to different implementations and maybe tools if anyone has to suggest.
Thanks for your time.
PS: The websocket client testing is done using Postman's websocket feature and practically each client is represented by a different tab.