Как использовать веб-сокеты для отправки сообщения конкретному пользователю с помощью Flask?

На веб-сайте, который я создаю с помощью Flask, люди могут отправлять друг другу комментарии. Когда пользователь получает PM, я хочу реализовать уведомление, аналогичное тому, как это делает Stackru. Поскольку SO реализует это с помощью веб-сокетов, я начал изучать веб-сокеты с этого руководства по реализации Flask-socketIO (которое работает с http://socket.io/).

Я скачал пример, созданный в учебнике, и я понимаю его код. Что я не понимаю, однако:

  1. Как я могу узнать, открыт ли зарегистрированный пользователь и подключен ли он к веб-сокетам?
  2. Как я могу отправить сообщение этому конкретному пользователю?

Итак, допустим, у меня есть простой маршрут, по которому люди могут отправлять PM другому пользователю:

@app.route('/admin/pm', methods=['GET', 'POST'])
@login_required
def pms():
    if request.method == 'POST':
        savePM(g.user.id, request.form['toUserId'], request.form['text'])
        # How do I emit a message here to the user to whom this message is sent?
    return render_template('sendPM.html')

Мой комментарий уже говорит это: как отправить сообщение пользователю, которому это сообщение было отправлено оттуда? Все советы приветствуются!

[EDIT] Следуя советам Мигеля, я подумал о создании комнаты с названием user.idИтак, теперь я создал следующие события подключения и отключения:

@socketio.on('connect', namespace='/test')
@login_required
def websocketConnect():
    join_room(g.user.id)
    emit('my response', {'data': 'Connected'}, room=g.user.id)

@socketio.on('disconnect', namespace='/test')
@login_required
def websocketDisconnect():
    leave_room(g.user.id)
    print('Client disconnected')

Но при подключении я получаю трассировку стека ниже. Разве не g объект, созданный по маршрутам socketio?

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/gevent/greenlet.py", line 327, in run
    result = self._run(*self.args, **self.kwargs)
  File "/Library/Python/2.7/site-packages/socketio/virtsocket.py", line 403, in _receiver_loop
    retval = pkt_ns.process_packet(pkt)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 164, in process_packet
    return self.call_method_with_acl('recv_connect', packet)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 240, in call_method_with_acl
    return self.call_method(method_name, packet, *args)
  File "/Library/Python/2.7/site-packages/socketio/namespace.py", line 282, in call_method
    return method(*args)
  File "/Library/Python/2.7/site-packages/flask_socketio/__init__.py", line 79, in recv_connect
    self.socketio._dispatch_message(app, self, 'connect')
  File "/Library/Python/2.7/site-packages/flask_socketio/__init__.py", line 137, in _dispatch_message
    ret = self.messages[namespace.ns_name][message](*args)
  File "/Library/Python/2.7/site-packages/flask_login.py", line 758, in decorated_view
    return func(*args, **kwargs)
  File "/Users/kramer65/repos/vg/app/views/webviews.py", line 418, in websocketConnect
    join_room(g.user.id)
  File "/Library/Python/2.7/site-packages/werkzeug/local.py", line 338, in __getattr__
    return getattr(self._get_current_object(), name)
AttributeError: '_AppCtxGlobals' object has no attribute 'user'

1 ответ

Решение

Как я могу узнать, открыт ли зарегистрированный пользователь и подключен ли он к веб-сокетам?

Это зависит от вас, чтобы отслеживать это. Когда пользователь подключается к конечной точке сокета, вы получите connect событие, и тут же вы можете зарегистрировать пользователя как подключенного. Обработчик события подключения имеет доступ к sessionТаким образом, если вошедшие в систему пользователи имеют свой идентификатор или псевдоним, записанные в сеансе, вы можете получить доступ к ним в обработчике сокетов.

Кроме того, когда пользователь уходит, вы получите disconnect событие.

Как я могу отправить сообщение этому конкретному пользователю?

Самый простой способ идентифицировать пользователей - это поместить их в комнаты, а затем отправлять сообщения в эти комнаты. Если вам нужно обращаться к пользователям индивидуально, просто поместите каждого пользователя в отдельную комнату, названную в честь псевдонима или идентификатора пользователя. Идеальное место для управления пользовательскими комнатами, опять же, connect а также disconnect обработчики событий.

Не совсем то, что вы хотите, но я написал немного более сложный пример, который использует комнаты:

https://github.com/miguelgrinberg/Flask-SocketIO-Chat

Другие вопросы по тегам