Автоматизация обновления URL-адресов веб-крючков Twilio

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

Прошло (проверяю заметки) около 7
лет с тех пор, как я в последний раз писал что-то, связанное с ruby, и, вероятно, 5 лет
с тех пор, как я выступал с докладами или презентациями.

Не думаю, что я осознавал, насколько я выдохся после нескольких бурных лет как в личном, так и в профессиональном плане.
как в личном, так и в профессиональном плане. Было здорово почувствовать, что я должен решить проблему
проблему просто ради удовольствия и даже был вынужден написать об этом.

С учетом всего вышесказанного, я уже зарвался, так что потерпите.

Недавно я работал над сайд-проектом, который использует Twilio для отправки и получения текстовых сообщений.
Я всегда считал SMS действительно мощным инструментом, который можно добавить в арсенал любого приложения, поскольку он использует то, что пользователи уже используют много раз в день.
что пользователи уже используют много раз в день. В недавнем отчете компания Twilio даже
сообщила, что 96% сообщений читаются в течение трех минут после получения, а 90% – в течение трех секунд!

В этой статье мы не будем подробно останавливаться на отправке текстовых сообщений. Если вы хотите получить
больше информации о том, как отправлять текстовые сообщения, то
twilio-ruby gem есть несколько примеров.

Телефонные номера Twilio имеют веб-крючки как для голосовой связи, так и для SMS. Эти веб-крючки
вызываются каждый раз, когда на ваш телефонный номер Twilio поступает входящее текстовое сообщение или телефонный звонок.

Пример входящего сообщения

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

Отправка запросов Webhook в ваше локальное окружение

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

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

Запуск Ngrok в вашем Procfile

С переходом Rails 7 на использование foreman и Procfiles для запуска и запуска
сервисов, я добавил ngrok как собственный процесс, чтобы он всегда был доступен.

пример Procfile.dev


# Procfile.dev
web: bin/rails server -p $PORT
css: yarn build:css --watch
js: yarn build --reload
worker: bundle exec sidekiq
stripe: stripe listen --forward-to $PORT/webhooks/stripe
ngrok: ngrok http --log=stdout $PORT
Войти в полноэкранный режим Выход из полноэкранного режима

Обновление URL-адресов веб-крючков Twilio

Когда ngrok запущен, теперь есть URL, на который можно направить ваши веб-крючки.
Один из вариантов обновления URL веб-крючков – взять URL ngrok, зайти в консоль Twilio и обновить его.
в консоль Twilio и обновить URL webhook для голоса и смс.

Это было хорошо для меня… некоторое время.

Моя основная проблема с этой установкой заключается в том, что каждый раз, когда я перезапускаю свои службы, URL ngrok
меняется и его нужно обновлять снова. Это может привести к большому количеству обновлений при
запуске и остановке служб и ошибок, когда забываешь обновить
URL каждый раз.

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

Именно тогда я почувствовал желание найти способ автоматизировать эту процедуру, когда она мне понадобится.

Покопавшись в документации Twilio, я нашел несколько опций для установки
URL веб-крючков с помощью их гема ruby.

Еще немного покопавшись, я нашел конечную точку для ngrok, которую можно запросить, чтобы получить
его публичный URL.

Теперь мы готовим на газе. Имея URL нашего локального экземпляра ngrok и способ
программно обновлять URL веб-крючков, у нас есть две необходимые части.

Следующий шаг – решить, как выполнять этот код, когда нам нужны обновления.
Для меня это была задача rake. Это дает мне хороший повторяющийся способ обновления
URL, когда это необходимо.

Задача Rake для обновления URL-адресов

Прежде чем я начну рассматривать подробности, вот код задачи rake. На сайте
зависимостями для задачи rake являются запущенный экземпляр ngrok, twilio-ruby
gem (я использую версию 5.67.1),
и, если вы хотите, чтобы в вашем терминале было больше цвета, чтобы было легче заметить, гем colorize.

Вот пример задачи rake

namespace :development do
  desc "updates twilio webhook urls to ngrok url"
  task set_twilio_webhooks: :environment do
    return unless Rails.env.development?
    begin
      response = JSON.parse(Net::HTTP.get(URI("http://localhost:4040/api/tunnels")))
      ngrok_url = response.dig("tunnels", 1, "public_url")
    rescue Errno::ECONNREFUSED
      puts "*******NGROK not running*******".yellow
    end
    if ngrok_url
      puts ngrok_url.green
      account_sid = Rails.application.credentials.dig(:twilio)[:account_sid]
      auth_token = Rails.application.credentials.dig(:twilio)[:auth_token]
      development_incoming_phone_number = Rails.application.credentials.dig(:twilio)[:auth_token]
      twilio_client = Twilio::Client.new(account_sid, auth_token)
      twilio_client.api.v2010.accounts(account_sid).incoming_phone_numbers(developemnt_incoming_phone_number)
        .update(sms_url: "#{ngrok_url}/webhooks/twilio",
          sms_fallback_url: "#{ngrok_url}/webhooks/twilio_fallback",
          voice_url: "#{ngrok_url}/webhooks/twilio_voice",
          voice_fallback_url: "#{ngrok_url}/webhooks/twilio_voice_fallback")
      puts "Webhook URLs updated!".green
    rescue Twilio::REST::RestError => e
      puts e
    end
    end
  end
end
Войти в полноэкранный режим Выйти из полноэкранного режима

Подробности

Теперь давайте немного углубимся в суть происходящего.

Внутри задачи rake первое, что я делаю, это убеждаюсь, что мы находимся в разделе

required, но я подумал, что это хорошая проверка, чтобы случайно не обновить
информацию вне нашей среды development.

После того, как мы убедились, что находимся в нашей среде dev, нам нужно найти URL-адрес
запущенного экземпляра ngrok. Ngrok имеет конечную точку API, работающую на порту 4040 для
текущих туннелей. Эта конечная точка возвращает XML-ответ с информацией о
текущих туннелях. Возвращается 2 туннеля, и я беру тот, у которого
именем command_line (http), который является вторым из возвращенных.

Обычно в качестве библиотеки HTTP в ruby используется HTTParty, но я хотел настроить это, используя
библиотеку ruby Net::HTTP, чтобы не вводить еще одну зависимость.

Убедившись, что мы находимся в среде development, Net::HTTP затем делает
запрос к конечной точке ngrok и анализирует ответ XML.

Вот несколько примеров ответа, который он отправляет обратно.

Усеченный ответ Ngrok

<tunnelListResource>
  <Tunnels>
  </Tunnels>
  <Tunnels>
  </Tunnels>
  <URI>/api/tunnels</URI>
</tunnelListResource>
Вход в полноэкранный режим Выход из полноэкранного режима

Одиночный туннельный объект

<Tunnels>
  <Name>command_line</Name>
  <URI>/api/tunnels/command_line</URI>
  <PublicURL>https://7be0-72-42-102-194.ngrok.io</PublicURL>
  <Proto>https</Proto>
  <Config>
  <Addr>http://localhost:80</Addr>
  <Inspect>true</Inspect>
  </Config>
  <Metrics>
  <Conns>
  </Conns>
  <HTTP>
  <Count>0</Count>
  <Rate1>0</Rate1>
  <Rate5>0</Rate5>
  <Rate15>0</Rate15>
  <P50>0</P50>
  <P90>0</P90>
  <P95>0</P95>
  <P99>0</P99>
  </HTTP>
  </Metrics>
</Tunnels>
Войти в полноэкранный режим Выход из полноэкранного режима

Задача rake берет разобранный XML и захватывает 2-й возвращенный туннель. Почему вы
спросите вы?

Честно говоря, это, скорее всего, было первое, что сработало из StackOverflow, и я пошел дальше.
дальше.

<PublicURL> для обоих туннелей, похоже, всегда одинаковы, так что, возможно.
возможно, любой из них будет работать.

Если ngrok не запущен, мы получим ошибку Errno::ECONNREFUSED, поэтому мы можем
спасти эту ошибку, и выведем некоторый вывод желтым цветом, чтобы было легко понять, когда
что-то пошло не так

Захватите публичный урл Ngrok

  begin
    response = JSON.parse(Net::HTTP.get(URI("http://localhost:4040/api/tunnels")))
    ngrok_url = response.dig("tunnels", 1, "public_url")
  rescue Errno::ECONNREFUSED
    puts "*******NGROK not running*******".yellow
  end
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь у нас есть повторяемый и надежный способ получения URL-адреса ngrok в любой момент времени.
работает. Мы также получаем цветной вывод, чтобы дать нам быстрый визуальный индикатор того.
что все выглядит нормально.

Следующей частью является программное обновление конечных точек Twilio webhook с нашим
публичный URL для ngrok.

Пришлось изрядно покопаться, чтобы найти нужные конечные точки в twilio-ruby
но как только я нашел их, дальше все пошло гладко.

Обновление с помощью API Twilio

Есть несколько вещей, которые нам понадобятся для обновления URL веб-крючков Twilio. Сайт
первое, что нам нужно, это клиент с нашими ключами.

Чтобы создать клиент Twilio, вам нужно получить ваш account_sid и

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

Обновления Twilio

  account_sid = Rails.application.credentials.dig(:twilio)[:account_sid]
  auth_token = Rails.application.credentials.dig(:twilio)[:auth_token]
  development_incoming_phone_number = Rails.application.credentials.dig(:twilio)[:auth_token]
  twilio_client = Twilio::Client.new(account_sid, auth_token)
  twilio_client.api.v2010.accounts(account_sid).incoming_phone_numbers(developemnt_incoming_phone_number)
    .update(sms_url: "#{ngrok_url}/webhooks/twilio",
      sms_fallback_url: "#{ngrok_url}/webhooks/twilio_fallback",
      voice_url: "#{ngrok_url}/webhooks/twilio_voice",
      voice_fallback_url: "#{ngrok_url}/webhooks/twilio_voice_fallback")
  puts "Webhook URLs updated!".green
rescue Twilio::REST::RestError => e
  puts e
end
Вход в полноэкранный режим Выход из полноэкранного режима

Я включил настройку клиента Twilio в задачу rake, но это было сделано в основном для того, чтобы иметь
пример, который будет работать как есть без дополнительной настройки. Обычно я
настраиваю клиента Twilio в инициализаторе, чтобы свести дублирование к минимуму.

пример файла config/initializers/twilio.rb

Twilio.configure do |config|
  config.account_sid = Rails.application.credentials.dig(:twilio)[:account_sid]
  config.auth_token = Rails.application.credentials.dig(:twilio)[:auth_token]
end
Вход в полноэкранный режим Выйти из полноэкранного режима

Когда клиент создан, мы можем использовать ngrok_url в сочетании с конечной точкой
которая указывает на ваш обработчик веб-крючков, и обновить наши URL-адреса веб-крючков Twilio.

Если все идет по плану, мы выведем сообщение об успехе зеленым цветом.

Если все идет не так, как планировалось, мы спасаем Twilio::REST::RestError и
выводим ошибку.

Теперь, всякий раз, когда нам нужно обновить URL-адреса веб-крюков Twilio (или
или любой другой сторонний сервис в будущем), мы можем выполнить это:


$ bin/rails development:set_twilio_webhooks
Войти в полноэкранный режим Выйти из полноэкранного режима

Поиск способа автоматически запускать ngrok в моем Procfile и иметь возможность
программно получить его публичный URL, стало отличной находкой для моего рабочего процесса. Это
то, что можно
можно распространить на множество других сервисов, с которыми вы, возможно, захотите работать в своей среде разработки
среде.

Сообщите мне о других сервисах, которые вы автоматизируете!

Оцените статью
Procodings.ru
Добавить комментарий