Узнайте, как создавать простые источники данных WebSocket с функциями приостановки

В этой истории мы узнаем, как связываться с различными сопрограммами и использовать их для реализации удаленного источника данных с функциями, которые выглядят как локальные функции. Эти функции представляют собой запрос, возвращающий ответ с использованием WebSocket под тканью.

Мотивация

Когда я писал источник данных, который внутренне использует соединение WebSocket, я заметил, что шаблон сокета отправки/получения увеличивает сложность программного обеспечения и сложность сопровождения. Отправьте запрос, и получение ответа в другой части кода заставит программиста объявить временные переменные для использования в коде ответа.

Представьте, если бы можно было отправить запрос и приостановить его до тех пор, пока не будет получен ответ, а затем возобновить его. Как и в приведенном ниже коде, источник данных предоставляет удобную функцию приостановки входа в систему, которая возвращает результат входа (полный код в конце):

SuspendMediator решает проблему

Что ж, с SuspendMediator это возможно! SuspendMediator — это моя реализация только с двумя методами: приостановить и возобновить.

Обратите внимание, что две функции получают ключ исключительно для идентификации запроса и ответа. Предположим, что этот запрос имеет идентификатор сообщения, отправленный обратно в ответ. Этот идентификатор может быть ключом к этому сообщению. Чем более «уникальным» является ключ, тем больше параллельных запросов может быть, потому что дубликаты ключей должны ожидать в очереди запросов. Это ограничение необходимо для того, чтобы SuspendMediator знал, кто однозначно сопоставляет отправленный запрос с полученным ответом.

Выполнение

SuspendMediator может иметь несколько реализаций, с очередью для запросов или без, с тайм-аутами запроса/очереди и так далее.

Очередь запросов используется для кэширования запросов с одним и тем же ключом или предотвращения параллельных запросов:

  • НЕТ ОЧЕРЕДИ: Выполнения с разными ключами могут выполняться параллельно, но когда SuspendMediator обнаруживает дублирующийся ключ, выдает ошибку в методе приостановки.
  • ENQUEUE SAME KEY: Выполнения с разными ключами могут выполняться параллельно и ставить в очередь дубликаты ключей.
  • ОБЕСПЕЧЬТЕ ПОРЯДОК: Избегайте параллельных казней. Он отправляет их один за другим, ожидая ответа по порядку.

У нас может быть два типа тайм-аута:

  • Тайм-аут очереди: тайм-аут используется, когда у нас есть дубликаты ключей, и необходимо подождать в очереди, чтобы выполнить запрос.
  • Время ожидания запроса: время ожидания, используемое для предотвращения ожидания ответа, который никогда не будет получен.

Хватит болтать. Покажите мне код:

Примеры использования SuspendMediator

Основная цель SuspendMediator — взаимодействие между сопрограммами. Предположим, что пинг-понг из трех сопрограмм умножает число на два несколько раз.

Выход:

Coroutine 1 - result1 Success(5)
Coroutine 2 - result2 Success(10)
Coroutine 3 - result3 Success(20)
Coroutine 1 - result4 Success(40)

Сопрограмма 1 приостанавливается с помощью ключа 1 до тех пор, пока сопрограмма 2 не возобновит работу этого ключа со значением 5. Сопрограмма 1 возобновляет получение значения и отправляет двойное это значение с помощью ключа 2. Значение ключа 3 создается в сопрограмме 2 и отправляется сопрограмме 3, и скоро. Обратите внимание, что SuspendMediator — это не производитель/потребитель, а способ двунаправленной связи между сопрограммами.

Более интересным примером является использование функции обратного вызова функции приостановки. Когда действие вызывается и возвращает true, гарантируется, что ключ готов для возобновления другого вызова сопрограммы с этим ключом.

Возвращаясь к примеру входа в систему в начале истории, представьте себе этот простой протокол строки входа:

Request: 1|username|password
Response: 1|loginResult

Обратите внимание, что первое поле представляет тип сообщения (логин), который в этом примере имеет значение 1, и мы можем использовать его в качестве ключа сообщения. Протокол может быть реализован с использованием запечатанных классов следующим образом:

Давайте посмотрим пример кода DataSource с использованием SuspendMediator:

Когда вызывается функция входа в систему, функция приостанавливается до тех пор, пока в очереди queuedSuspendMediator не останется ключа со значением 1, поскольку queueMode равно ENQUEUE_SAME_KEY. В простом случае очередь пуста или не имеет ключа 1, поэтому приостановка не требуется.

После этого вызывается WebSocket sendMessage со значением LoginRequest. Когда сервер отвечает, прослушиватель анализирует сообщение и вызывает функцию возобновления с сообщением LoginResult.

Заключение

С SuspendMediator мы можем писать более простые коды с меньшей сложностью временных переменных для сообщений запроса и ответа. WebSocket DataSource — один из многих вариантов использования SuspendMediator.

Спасибо за прочтение. Оставайтесь с нами, чтобы узнать больше.