4
\$\begingroup\$

I am trying out websockets using the python async framework aiohttp. Basically I have created a game which will include multiple players and they will be able to chat using web sockets. There could be multiple game rooms and a player will be in a single room at a time. I believe I have the implementation right. Please look into it.

from aiohttp import web, WSMsgType
from bson.objectid import ObjectId

from models import Game

routes = web.RouteTableDef()
@routes.get('/ws/{game_id}/{player_id}')
async def create(request):
    game_id = request.match_info['game_id']
    player_id = request.match_info['player_id']

    ws_current = web.WebSocketResponse()
    ws_ready = ws_current.can_prepare(request)
    if not ws_ready.ok:
        msg = "Sorry, something went wrong!"
        return web.json_response({'error': msg})

    await ws_current.prepare(request)

    query = {'_id': ObjectId(game_id), 'active': True}
    game = await Game.find_game(query=query, db=request.app['mongodb'])

    if game is None:
        msg = "Game over, start a new game"
        await ws_current.send_json({'action': 'error', 'name': player_id, 'msg': game_id})
        await ws_current.close()
        return

    if not any(player_id == str(player['_id']) for player in game['players']):
        msg = "You have not joined the game"
        await ws_current.send_json({'action': 'error', 'name': player_id, 'msg': msg})
        await ws_current.close()
        return

    await ws_current.send_json({'action': 'connect', 'name': player_id})

    # notify other players that a new player has joined
    for player in game['players']:
        if str(player['_id']) in request.app['websockets']:
            player_ws = request.app['websockets'][str(player['_id'])]
            await player_ws.send_json({'action': 'join', 'name': player_id})

    request.app['websockets'][player_id] = ws_current

    while True:
        msg = await ws_current.receive()

        if msg.type == WSMsgType.text:
            if msg.data == 'close':
                await ws_current.close()
            else:
                for player in game['players']:
                    if str(player['_id']) in request.app['websockets']:
                        player_ws = request.app['websockets'][str(
                            player['_id'])]
                        if player_ws is not ws_current:
                            await player_ws.send_json(
                                {'action': 'sent', 'name': player_id, 'text': msg.data})
        elif msg.type == WSMsgType.ERROR:
            print('ws connection closed with exception %s' %
                  ws_current.exception())
        else:
            break

    if player_id in request.app['websockets']:
        del request.app['websockets'][player_id]

    # notify other players that the player has left
    for player in game['players']:
        if str(player['_id']) in request.app['websockets']:
            player_ws = request.app['websockets'][str(player['_id'])]
            await player_ws.send_json({'action': 'disconnect', 'name': player_id})

    return ws_current

But the code doesn't look very good or pythonic as they say. Could you please help me out with this and also if there are things I should change with the logic as well.

\$\endgroup\$
2
  • \$\begingroup\$ What is web? I have a feeling it's not PyPI's web package and I know of no such packages called web in the stdlib. Searching for it is also nigh impossible, since "web" is so generic. Without this information it would be impossible for me to answer this question. \$\endgroup\$ – Peilonrayz May 23 '20 at 13:11
  • \$\begingroup\$ @Peilonrayz It is just a module of aiohttp. I will update the question with the imports. \$\endgroup\$ – doctorsherlock May 23 '20 at 14:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.