Использование AWS Lambda, Twitter и Twilio для создания службы автоматизированных текстовых сообщений

Привет, товарищи кодеры! Вы когда-нибудь хотели удивлять своих друзей случайным изображением каждый час? Или, может быть, у вас есть супруг, который любит определенное животное, и вы хотите сделать его день, регулярно отправляя ему фотографии его любимого существа? Ну, вы в правильном месте! В этом уроке мы собираемся создать сервис текстовых сообщений со случайными изображениями под названием Possum Pics. Но не волнуйтесь, вы можете легко адаптировать этот пример для отправки любого типа изображения.

Обзор

Наш сервис случайных текстовых сообщений «Possum Pics» будет работать следующим образом:

  1. Он будет использовать API Twitter для получения случайного изображения из учетной записи Twitter «Поссум каждый час».
  2. Затем он отправит это изображение подписчикам с помощью Twilio API.
  3. Этот процесс будет автоматизирован с помощью AWS Lambda и будет выполняться каждый час.

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

Шаг 1. Настройка учетной записи разработчика Twitter

Во-первых, вам нужно создать учетную запись разработчика Twitter и сгенерировать ключи API. Следуй этим шагам:

  1. Перейдите на developer.twitter.com и войдите в свою учетную запись Twitter.
  2. Подайте заявку на получение учетной записи разработчика и дождитесь вашего одобрения. Не волнуйтесь, для этого мы можем использовать бесплатный базовый план.
  3. После утверждения создайте новое приложение и сгенерируйте ключи API (ключ потребителя, секрет потребителя и токен носителя).

Шаг 2. Настройка учетной записи Twilio

Затем настройте учетную запись Twilio и создайте ключи API:

  1. Зайдите на twilio.com и зарегистрируйтесь.
  2. Подтвердите свой номер телефона.
  3. Перейдите в Консоль Twilio и создайте новую Учетную запись.
  4. Следуйте инструкциям, чтобы получить бесплатный номер телефона в США и сгенерировать токен авторизации.

Шаг 3. Настройка учетной записи AWS

Теперь настройте учетную запись AWS, если у вас ее еще нет:

  1. Перейдите на aws.amazon.com и зарегистрируйте новый аккаунт.
  2. Войдите в Консоль управления AWS и перейдите к сервису Lambda.
  3. Создайте новую лямбда-функцию. Добавьте имя и оставьте все остальное без изменений.

Шаг 4: Написание кода

Давайте начнем кодировать наш сервис случайных текстовых сообщений с изображениями. Сначала создайте новый каталог проекта и инициализируйте его с помощью npm init. Установите необходимые зависимости:

npm install twitter twilio

Затем создайте следующие файлы в каталоге вашего проекта:

  1. index.js: основная точка входа нашей лямбда-функции.
  2. services/tweet.js: модуль для взаимодействия с Twitter API.
  3. services/text.js: модуль для взаимодействия с Twilio API.

services/tweet.js

Этот файл содержит модуль для взаимодействия с Twitter API. Он экспортирует функцию get, которая извлекает последний твит из указанной учетной записи. Вот посмотрите на готовый файл.

const Twitter = require('twitter');

var client = new Twitter({
    consumer_key: process.env.TWITTER_KEY,
    consumer_secret: process.env.TWITTER_SECRET,
    bearer_token: process.env.TWITTER_BEARER,
});

module.exports = {
    get: async function (account) {
        let tweets = await client.get('statuses/user_timeline', {
            screen_name: account,
        });

        return await client.get('statuses/show/' + tweets[0].id_str, {});
    }
}

Анализ кода

В этом разделе мы разберем файл services/tweet.js, шаг за шагом объясняя его функциональность.

Сначала мы импортируем библиотеку twitter:

const Twitter = require('twitter');

Эта библиотека позволяет нам взаимодействовать с Twitter API.

Далее мы инициализируем объект client с помощью ключей Twitter API:

var client = new Twitter({
    consumer_key: process.env.TWITTER_KEY,
    consumer_secret: process.env.TWITTER_SECRET,
    bearer_token: process.env.TWITTER_BEARER,
});

Мы создали новый экземпляр класса Twitter, передав в качестве конфигурации объект, содержащий наши ключи API, и назначили его client. Эти ключи извлекаются из переменных среды, которые мы установим позже в консоли AWS Lambda.

Теперь давайте погрузимся в основную часть кода — функцию get:

module.exports = {
    get: async function (account) {

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

Внутри функции get мы получаем временную шкалу пользователя:

        let tweets = await client.get('statuses/user_timeline', {
            screen_name: account,
        });

Мы используем метод client.get() для вызова конечной точки statuses/user_timeline Twitter API, передавая объект, содержащий свойство screen_name, установленное в параметр account. Этот метод возвращает обещание, которое мы await получаем для получения массива твитов.

Затем мы получаем детали последнего твита:

        return await client.get('statuses/show/' + tweets[0].id_str, {});

Мы снова используем метод client.get() для вызова конечной точки statuses/show Twitter API. На этот раз мы передаем идентификатор последнего твита (например, tweets[0].id_str) как часть URL-адреса конечной точки. Мы также передаем пустой объект в качестве второго параметра, потому что нам не нужно указывать какие-либо дополнительные параметры. Этот метод возвращает обещание, которое мы await получаем, чтобы получить полную информацию о последнем твите. Наконец, мы возвращаем этот объект твита вызывающей стороне.

services/text.js

Этот файл содержит модуль для взаимодействия с Twilio API. Он экспортирует функцию send, которая отправляет указанное изображение на номер телефона.

const client = require('twilio')(process.env.TWILIO_ACCOUNT, process.env.TWILIO_AUTH);

module.exports = {
    send: function (body, mediaUrl, to) {
        client.messages
            .create({
                body: body,
                mediaUrl: mediaUrl,
                from: '+10000000000', // Replace with your Twilio phone number
                to: to,
            })
            .then(message => console.log(message.sid))
            .done();
    }
}

Анализ кода

В этом разделе мы разберем файл services/text.js, шаг за шагом объясняя его функциональность.

Сначала мы импортируем библиотеку twilio:

const client = require('twilio')(process.env.TWILIO_ACCOUNT, process.env.TWILIO_AUTH);

Эта библиотека позволяет нам взаимодействовать с Twilio API. Мы создаем новый экземпляр клиента twilio, вызывая библиотеку как функцию и передавая учетные данные нашей учетной записи Twilio. Эти учетные данные извлекаются из переменных среды, которые мы установим позже в консоли AWS Lambda.

Теперь давайте погрузимся в основную часть кода — функцию send:

module.exports = {
    send: function (body, mediaUrl, to) {

Мы экспортируем объект, содержащий функцию с именем send. Эта функция принимает три параметра:

  1. body: Сообщение для отправки вместе с изображением.
  2. mediaUrl: URL изображения для отправки.
  3. to: Номер телефона для отправки сообщения.

Внутри функции send мы создаем и отправляем сообщение с помощью Twilio API:

        client.messages
            .create({
                body: body,
                mediaUrl: mediaUrl,
                from: '+12345678901', // Replace with your Twilio phone number
                to: to,
            })

Мы используем метод client.messages.create() для создания и отправки сообщения. Мы передаем объект, содержащий необходимые свойства:

  1. body: Текст сообщения.
  2. mediaUrl: URL-адрес изображения.
  3. from: номер телефона Twilio, с которого нужно отправить сообщение. Замените примерный номер своим собственным номером телефона Twilio.
  4. to: номер телефона получателя.

Этот метод возвращает обещание, которое мы обрабатываем с помощью обратных вызовов .then() и .done():

В обратном вызове .then() мы записываем SID сообщения (уникальный идентификатор сообщения) в консоль. Обратный вызов .done() используется, чтобы сигнализировать о том, что цепочка промисов завершена.

index.js

Этот файл является основной точкой входа нашей лямбда-функции. Он будет извлекать случайное изображение из указанной учетной записи Twitter и отправлять его подписчикам с помощью Twilio API.

Мы также добавим некоторые секретные функции, чтобы добавить немного специй в сервис текстовых сообщений.

const tweet = require('./services/tweet');
const text = require('./services/text');

const account = ['PossumEveryHour','RaccoonEveryHr','RedPandaEveryHr'];
const message = ['Here\'s your possum of the hour :)', 'Oh no something\'s gone horribly wrong this hour. It\'s a raccoon!','Oh no something\'s gone horribly wrong this hour. It\'s a red panda!'];
const numbers = process.env.TWILIO_NUMBERS.split(',');

exports.handler = (event, context, callback) => {

    // Get possum vs raccoon account and message
    let i = Math.floor(Math.random() * 100) > 0 ? 0 : 1;
    i = i === 0 ? 0 : Math.floor(Math.random() * 2) + 1;

    // Get tweet
    tweet.get(account[i]).then((tweet) => {

        // Get image url
        let mediaUrl = tweet['extended_entities']['media'][0]['media_url'];

        console.log(mediaUrl);
        console.log(numbers);

        // Send to each number
        numbers.forEach(number => text.send(message[i], mediaUrl, number));
    }).catch((err) => {
        throw err;
    });
    callback(null, 'Finished');
};

Анализ кода

В этом разделе мы углубимся в файл index.js, разбив его по частям, чтобы объяснить его функциональность.

const tweet = require('./services/tweet');
const text = require('./services/text');

В начале файла мы импортируем модули tweet и text, которые обрабатывают взаимодействие с API Twitter и Twilio соответственно.

const account = ['PossumEveryHour','RaccoonEveryHr','RedPandaEveryHr'];
const message = ['Here\'s your possum of the hour :)', 'Oh no something\'s gone horribly wrong this hour. It\'s a raccoon!','Oh no something\'s gone horribly wrong this hour. It\'s a red panda!'];
const numbers = process.env.TWILIO_NUMBERS.split(',');

Далее мы объявляем три константы. Вот тут-то и появляется изюминка. Мы добавим пару дополнительных аккаунтов в Твиттере с разными животными и поддельные «сообщения об ошибках», которые будут отправляться, когда сообщение поступает не тому животному:

  1. account: Массив дескрипторов учетных записей Twitter. В этом примере у нас есть три аккаунта для опоссумов, енотов и красных панд.
  2. message: Массив сообщений, соответствующих отправляемому изображению. Каждый индекс в этом массиве соответствует такому же индексу в массиве account.
  3. numbers: Массив телефонных номеров для отправки изображения. Мы получаем эту информацию из переменной среды TWILIO_NUMBERS, которая должна быть строкой телефонных номеров, разделенных запятыми.

Теперь приступим к основной части кода — обработчику функции Lambda:

exports.handler = (event, context, callback) => {

Мы экспортируем функцию с именем handler, которая действует как точка входа нашей лямбда-функции. Эта функция запускается событием (например, заданием cron от Amazon EventBridge).

    let i = Math.floor(Math.random() * 100) > 0 ? 0 : 1;
    i = i === 0 ? 0 : Math.floor(Math.random() * 2) + 1;

Здесь мы генерируем случайный индекс i, чтобы решить, какую учетную запись Twitter и сообщение использовать. В этом примере у нас есть вероятность 99% выбрать учетную запись опоссума и вероятность 1% выбрать одну из двух других учетных записей (енота или красной панды).

    tweet.get(account[i]).then((tweet) => {

Мы используем функцию tweet.get() из модуля tweet для получения последнего твита из выбранной учетной записи. Эта функция возвращает обещание, которое мы обрабатываем с помощью обратного вызова .then().

        let mediaUrl = tweet['extended_entities']['media'][0]['media_url'];

Внутри обратного вызова мы извлекаем URL-адрес изображения из объекта extended_entities твита. В данном случае нас интересует только первый элемент мультимедиа в массиве media.

        console.log(mediaUrl);
        console.log(numbers);

В целях отладки мы записываем URL-адрес мультимедиа и список телефонных номеров в консоль.

        numbers.forEach(number => text.send(message[i], mediaUrl, number));
    }).catch((err) => {
        throw err;
    });

Мы перебираем массив numbers и отправляем выбранное изображение на каждый номер телефона с помощью функции text.send() из модуля text. Если во время этого процесса возникают какие-либо ошибки, мы их отлавливаем и выбрасываем.

    callback(null, 'Finished');

Наконец, мы заканчиваем выполнением обратного вызова, с помощью которого Lambda запустила функцию.

Шаг 5. Развертывание вашей лямбда-функции

Развертывание в AWS Lambda

  1. Заархивируйте каталог вашего проекта.
  2. В консоли AWS Lambda загрузите ZIP-файл.
  3. Установите переменные среды для вашей функции Lambda:
    TWITTER_KEY
    TWITTER_SECRET
    TWITTER_BEARER
    TWILIO_ACCOUNT
    TWILIO_AUTH
    TWILIO_NUMBERS
  4. Установите обработчик на index.handler.

Активировать лямбда-функцию

Теперь нам нужно настроить источник событий для запуска вашей функции Lambda каждый час. Для этого мы будем использовать AWS EventBridge. Чтобы настроить триггер EventBridge, выполните следующие действия.

  1. На странице консоли функций Lambda нажмите «Добавить триггер».
  2. Выберите «EventBridge (События CloudWatch)» и «Создать новое правило».
  3. Введите необходимые данные в форму «Создать правило»:
    — Название правила: possum-pics
    — Описание правила: Отправляет сообщение с изображением опоссума из Твиттера каждый час с с 6:00 до 23:00
    — Тип правила: Выражение расписания
    — Выражение расписания: cron(0/60 12–23,0–6 * * ? \*)
  4. Нажмите «Добавить», чтобы создать правило.

Расписание

Давайте отделим расписание от шага 3. Выражение cron cron(0/60 12-23,0-6 * * ? *) определяет триггер EventBridge, который будет срабатывать каждый час с 12:00 до 23:00 и с 12:00 до 6:00. Другими словами, он будет срабатывать каждый час, кроме 7:00 и 11:00 UTC (время, когда наши получатели могут спать). Выражение cron разбито следующим образом:

  • 0/60: это означает, что триггер сработает, когда поле минут равно 0 (т. е. в начале каждого часа).
  • 12-23,0-6: указывает часы, когда срабатывает триггер. Сюда входят часы с 12:00 до 23:00 (12–23) и с 12:00 до 6:00 (0–6).
  • *: это подстановочный знак, означающий, что триггер будет срабатывать каждый день месяца.
  • *: еще один подстановочный знак, означающий, что триггер будет срабатывать каждый месяц.
  • ?: это заполнитель для дня недели, указывающий, что триггер будет срабатывать независимо от дня недели.

Таким образом, триггер EventBridge с этим выражением cron будет срабатывать каждый час, кроме периода с 7:00 до 11:00. Вы можете настроить любое расписание, но помните, что Twilio взимает плату за каждый текст. Подробнее об этом в разделе Расходы ниже.

Настроив триггер EventBridge, вы успешно автоматизировали процесс отправки изображений опоссумов каждый час. Теперь вы можете наслаждаться очаровательными изображениями без ручного вмешательства.

Расходы

При использовании облачных сервисов важно учитывать связанные с этим расходы. В нашем примере мы использовали Twilio и AWS Lambda в качестве основных сервисов. Вот разбивка их затрат:

  1. Twilio. Стоимость использования Twilio зависит от количества телефонных номеров и сообщений, которые вы планируете отправлять. Отправляя текстовые сообщения по расписанию, которое мы использовали, Twilio берет около 10 долларов в месяц за каждый номер телефона. Обязательно посетите Страницу цен на Twilio для получения подробной информации о тарифах на обмен сообщениями.
  2. AWS Lambda: AWS Lambda предлагает щедрый уровень бесплатного пользования, который включает 1 миллион бесплатных запросов в месяц и 400 000 ГБ-секунд вычислительного времени в месяц. Помимо уровня бесплатного пользования, стоимость Lambda зависит от количества запросов и продолжительности выполнения вашей функции. Для наших целей это бесплатно. Страница с ценами на AWS Lambda.

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

Подведение итогов

Поздравляем! Вы успешно создали и развернули сервис случайных текстовых сообщений с изображениями с помощью Twitter, Twilio и AWS Lambda. Этот пример был построен для отправки изображений опоссумов, но вы можете легко изменить код, чтобы отправлять изображения любого типа. Возможности безграничны, так что вперед и получайте удовольствие от вашего нового сервиса!

Найдите полный исходный код Possum Pics в его репозитории GitHub и узнайте больше об этом и других подобных проектах на моем сайте.

Адаптировано с сайта alex-meddin.com