Расширение REST API Flask с помощью WebSockets

В настоящее время я работаю над расширением моего существующего REST API, созданного с помощью Flask-RESTPlus, с поддержкой WebSocket. Идея состоит в том, чтобы создать модель Web Thing (Gateway ). «Вещи» в моем случае использования динамически добавляются или удаляются.

Текущая настройка позволяет потребителю получать последние значения из вещи, например. датчик температуры, используя HTTP-запрос GET к /thingId/properties/temperature. Значения на самом деле потребляются из Kafka и временно хранятся в Redis.

Теперь мне интересно, как я могу расширить эту настройку и позволить потребителю не только опрашивать последние значения, но и подписываться на свойство Thing с помощью WebSockets. У меня есть рабочее решение, в котором я создаю «Комнаты» для каждого свойства, но для этого требуются два отдельных сервера и дублирование конечных точек.

Для REST у меня

@app.route('/<thingId>/properties/<propertyId>')
    # get latest datapoint
    return latestDatapoint

Для Flask-SocketIO у меня

@socketio.on('join')
def on_join(data):
    username = data['username']
    room = data['room'] # e.g. /thingId/properties/temperature
    join_room(room)
    send(username + ' has entered the room.', room=room)

а затем я пересылаю данные в нужную комнату по мере их поступления от Кафки. Затем на стороне клиента мне нужно подключиться к серверу WebSocket и присоединиться к комнате.

socket.on('connection', function(socket){
  socket.emit('join', 'some room');
});

Эта реализация работает, но я очень надеялся на альтернативный рабочий процесс, как показано на рисунке ниже, где клиент подключается к той же конечной точке, что и в REST API, но с протоколом WebSocket вместо присоединения к комнатам и т. д. Подписки Web Thing

Есть ли у вас какие-либо идеи, если это уже существует или возможно реализовать?


person Pieter Moens    schedule 06.01.2020    source источник


Ответы (1)


У меня есть рабочее решение, в котором я создаю «Комнаты» для каждого свойства, но для этого требуются два отдельных сервера и дублирование конечных точек.

Сервер Socket.IO и ваш HTTP-сервер не обязательно должны быть отдельными. Во всех поддерживаемых конфигурациях вы можете размещать приложения HTTP и Socket.IO на одном сервере.

Я также не вижу дублирования конечных точек, но, возможно, это потому, что вы считаете обработчики событий Socket.IO конечными точками, хотя на самом деле это не так. Socket.IO имеет единую конечную точку в смысле HTTP, поскольку весь трафик Socket.IO проходит по одному URL-адресу. Ваши обработчики событий — это просто функции, которые вызываются, когда определенные события появляются в конечной точке Socket.IO.

где клиент подключается к той же конечной точке, которая используется в REST API, но с протоколом WebSocket вместо присоединения к комнатам и т. д.

Итак, вы хотите, чтобы ваш клиент устанавливал отдельное соединение WebSocket для каждой вещи, которую он хочет посмотреть? Это кажется мне немного ресурсоемким и не очень масштабируемым. Если клиенту нужно посмотреть 100 вещей, ему придется поддерживать 100 соединений WebSocket. Имейте в виду, что большинство браузеров ограничивают количество соединений WebSocket, которые они могут открывать одновременно, как на странице, так и глобально.

Socket.IO — это протокол более высокого уровня, построенный на основе WebSocket и HTTP. Если вы по-прежнему предпочитаете использовать WebSocket напрямую, вы можете взять любой из доступных серверов WebSocket с открытым исходным кодом и реализовать свое приложение с его помощью вместо Socket.IO. Вот несколько вариантов Python, которые приходят мне в голову:

Вы потеряете несколько полезных вещей, которые предлагает Socket.IO:

  • Автоматические переподключения
  • Автоматическая поддержка клиентов, отличных от WebSocket, посредством длительного опроса
  • Диспетчеризация на основе событий
  • Номера

Поэтому вам нужно убедиться, что это не важные функции, или вы можете реализовать их самостоятельно непосредственно на сервере WebSocket.

person Miguel    schedule 07.01.2020
comment
Привет, Мигель. Спасибо за ваш ответ :) На мой вопрос меня вдохновила книга Доминика Гинара и Влада Трифы «Создание сети вещей». Он включает фрагменты модульного приложения Node.JS. Он имеет плагины для нескольких датчиков (например, DHT), которые содержат значения датчиков. С конечными точками REST вы можете просто опросить последнее значение, но, открыв соединение WebSocket по URL-адресу (конечная точка), вы можете обновить протокол, который регистрирует наблюдателя в свойстве датчика, который будет постоянно отправлять значение при обновлении. - person Pieter Moens; 07.01.2020
comment
Это действительно устанавливает соединение для каждого наблюдаемого свойства. Далее я рассмотрю плюсы и минусы попытки настроить что-то подобное по сравнению с использованием протокола более высокого уровня, такого как Socket.IO. В настоящее время я просматриваю строки gevent-websocket в сочетании с Flask (gist.github.com/lrvick/ 1185629) - person Pieter Moens; 07.01.2020
comment
Как я уже сказал в своем ответе, открытие нескольких подключений через веб-сокет расточительно, и вы рискуете достичь максимального предела подключений для браузера. Одно соединение через веб-сокет (Socket.IO или нет) имеет достаточную пропускную способность для обработки всех ваших наблюдаемых вещей. - person Miguel; 08.01.2020