Создание бота для Twitter с использованием AWS Lambda and Go
Большинство людей слышали об AWS, и разработчики начали изучать, как его можно использовать для дальнейшего повышения качества своих проектов. Недавно я начал процесс становления одним из этих людей. Пока что это было поучительное глубокое погружение в различные услуги, которые они предлагают. Трудно сориентироваться в чем-то столь же масштабном, как AWS, поэтому в процессе обучения я решил сосредоточиться на проектах, которые, по моему мнению, были бы крутыми, и посмотреть, как AWS может помочь облегчить то, что я создаю.
Один из проектов, в который я хотел войти - это бот для Twitter, использующий новый язык Go, который я изучал. Простой твиттер-бот легко настроить. Их API упрощает взаимодействие, и существуют тысячи библиотек, которые используют его API. Я за все, что облегчает мою работу. Посмотрим, насколько проще я могу сделать это с помощью AWS Lambda.
Lambda - это вычислительная служба для запуска кода в облаке. С помощью которого вы можете создавать функции и триггеры для запуска этих функций, а Lambda запускает ваш код без необходимости предоставлять сервер. Это бессерверно. Я понял, что это уникально подходит для таких вещей, как регулярно планируемый бот Twitter. С Lambda мне не нужно запускать EC2 или локальную виртуальную машину и постоянно запускать моего бота. Я могу просто установить расписание и создать бота, и Lambda запустится, выполнит мою функцию и отключится.
Бесплатные сервисы Lambda также являются отличным вариантом использования, потому что первые 1 миллион запросов в месяц бесплатны. После чего вы платите 0,20 доллара за каждый дополнительный миллион запросов. Этот Twitter бот представляет собой сервис для отрыгивания цитат, поэтому вероятность того, что он когда-либо превысит это значение, очень мала.
Настройка приложения Twitter
API Twitter находится в версии 1.1 с 2016 года. Однако в 2020 году они начали выпуск версии v2. Перестроенные с нуля, они также пересмотрели свои цены. Для наших целей мы все еще можем использовать уровень бесплатного пользования. Если вы перейдете на портал разработчиков Twitter, вы можете перейти на панель управления и настроить новое приложение. Мы предполагаем, что вы уже создали учетную запись разработчика в Twitter.
После настройки учетной записи разработчика мы можем перейти на портал приложений. Здесь мы можем щелкнуть в правом верхнем углу, чтобы создать новое приложение.
Для настройки приложения требуется некоторая информация. Вам необходимо предоставить информацию о приложении и веб-сайте, если приложение будет прикреплено к одному из них. Как только это будет настроено, мы можем получить наши ключи и токены и начать доступ к Twitter через библиотеку API.
Примечание: обязательно проверьте разрешения для своего приложения Twitter. По умолчанию установлены разрешения на чтение. Итак, если к концу вы увидите ошибки разрешений от API, это может быть виновником. Обязательно установите минимально необходимые разрешения. Здесь мы делаем бота для публикации твитов, поэтому нам нужны разрешения «на чтение и запись». Мне не нужна возможность писать кому-либо, поэтому я выбрал «Читать и писать». Итак, перейдите в раздел «Ключи и токены», скопируйте свой ключ потребителя, секрет потребителя, маркер доступа и секрет доступа. Теперь, когда мы получили наши полномочия, мы готовы к вечеринке
Код бота Twitter
Создание настраиваемой библиотеки для работы с API предпочтительнее для любой производственной системы, так как она позволяет выполнять необходимую настройку. Для наших целей нам нужно только открыть поток и отправить через него твит для публикации. Итак, я решил использовать библиотеку Anaconda, которая все еще использует версию 1.1 API Twitter.
Первое, что мы делаем - настраиваем нашу среду разработки. Я использую VS Code с плагином Go. Я также использую среду Windows для всего. Позже я вернусь к тому, почему это не лучшая идея. Мы также собираемся использовать модули Go для отслеживания наших зависимостей. Go 1.11 и выше могут поддерживать модули Go, и все, что выше Go 1.13, будет использовать их по умолчанию. Имея это в виду, мы настроили наш файловый каталог как таковой
- Bot
- go.mod
Делаем cd
в корень нашего проекта и запускаем:
go mod init bot/main
Теперь у нас есть наш каталог и наш файл мода, в котором размещены наши зависимости. Далее мы создаем наш бот-файл.
- Bot
- go.mod
- bot.go
- quotes.json
Вы также заметите, что есть файл JSON с именем quotes.json, именно здесь мы будем хранить наши котировки. Теперь мы можем приступить к строительству. Первым делом мы добавляем наши зависимости. Я добавил несколько здесь и объясню необходимость в них по ходу дела.
Следующая часть, которую вы увидите, - это наши типы данных, которые мы создали для бота.
Здесь мы создали структуры для хранения некоторых данных. Структуры в Go - это способ группировать связанные данные. Я обнаружил, что это одни из самых полезных коллекций типов данных для выполнения множества задач. Первый с именем APICred
- это всего лишь способ разместить и повторно использовать учетные данные API, которые мы взяли из созданного нами приложения Twitter.
Следующие структуры предназначены для объекта цитаты, который мы будем извлекать из файла JSON. У нас есть структура, созданная для отдельных кавычек и одна для массива вышеупомянутых структур QuoteObject. Это упрощает получение всех наших котировок и использование списка для настройки логики нашего бота. Это не идеальное решение, так как предполагает, что мы всегда будем брать все цитаты из списка. Это не масштабируемое решение, поскольку мы не хотели бы брать все записи, скажем, из базы данных, а затем сортировать их вручную. Однако для этого примера с низким порогом это работает.
Краткое примечание: Вы заметите, что для ключей структуры все они начинаются с заглавной буквы. Это хорошая практика, потому что для меня это выглядит аккуратнее, и при работе с такими вещами, как данные JSON, могут возникнуть некоторые проблемы. При демаршалировании данных в поля структуры эти поля экспортируются, только если они написаны с заглавной буквы. Это позволяет пакету JSON использовать имена полей для демаршалинга данных из файла JSON для использования в нашем боте. Я узнал об этом после того, как увидел, что мои данные оказываются пустыми при извлечении цитат из файла. Вы также можете увидеть проблему в этой статье о переполнении стека и сэкономить время.
Еще одна вещь, которую следует отметить в структурах - это теги или аннотации, прикрепленные к ключам структуры. Во многих случаях в этом может не быть необходимости. Как и в случае, когда все названо одинаково в полях JSON и полях структуры. Упаковка должна быть достаточно умной, чтобы соответствовать им. Однако я программирую настолько оборонительно, насколько это возможно, поэтому теги JSON позволяют мне напрямую сопоставлять их. Аннотации сообщают пакету JSON, что поле TweetId должно соответствовать полю tweetid в файле JSON. Теги делают это для всех. Поле QuoteList возьмет весь этот блок «цитат» из файла JSON. Это также работает при работе с двоичной информацией JSON или BSON, например, при получении информации из Mongo DB.
Вот следующий блок кода для упрощения некоторых функций в нашем боте:
А теперь еще немного веселья. При работе с локальными файлами, такими как токены, ключи, параметры БД и т.д., мы будем использовать файл .env и импортировать его в наш код. В этом случае мы не используем это локально или на производственной машине, мы создаем функцию AWS Lambda! Переменные env можно установить на панели инструментов Lambda. Что касается кода, нам не нужно загружать библиотеку среды, мы можем просто использовать библиотеку os для загрузки переменных среды непосредственно из AWS. Выше мы создаем новый экземпляр APICred, называем его env и возвращаем его из функции. Здесь мы используем именование возвращаемого типа Go в сигнатуре функции для инициализации нашего возвращаемого элемента. Затем мы устанавливаем поля, и мы готовы устроить вечеринку по Twitterverse.
Следующая функция - это вспомогательная функция для создания случайного индекса, используемого для случайного поиска цитаты для публикации в Твиттере. Мы используем библиотеку math / rand вместе с функцией Seed, чтобы получить случайный индекс в пределах того диапазона котировок, который у нас есть. Мы обслуживаем минимальное значение индекса, которое всегда должно быть 0 (может быть, в следующий раз сделаем константу?) И максимальное значение. В этом случае мы подсчитаем количество записей (кавычек) и будем использовать это как максимальное значение. Мы делаем это для того, чтобы всегда иметь возможность найти индекс с имеющимся у нас диапазоном котировок. Другими словами, если у нас есть десять кавычек, мы хотим вернуть индекс от 0 до 10 и использовать его для сопоставления с полем tweetid в файле JSON и получить цитату. Функция «Seed» здесь важна, поскольку функция рандом детерминирована. Поскольку он будет возвращать одно и то же значение каждый раз, когда вы его запускаете. По этой причине функция rand считается псевдослучайной. Если Seed не вызывается, rand по умолчанию будет использовать Seed(1), который каждый раз будет получать одно и то же число. Используя функцию Seed для установки начального числа при каждом запуске и используя время Unix, убедитесь, что введено число int64, представляющее время, которое изменяется каждую секунду.
Затем мы придумываем логику, чтобы получить нашу цитату:
Эта функция используется для получения цитаты и возврата ее в виде строки нашему объекту API, который затем отправляет строку в Twitter. Первая часть - это захват файла и возврат файлового объекта с помощью функции os.Open. Предполагалось, что файл JSON находится в том же каталоге, что и файл бота. В противном случае выдается ошибка. Мы создали Defer quote_file.Close(), так что все остальные логики в наших пробегах функций и Defer работают в прошлом. Благодаря этому наш файл остается открытым, пока мы не закончим. Это отлично подходит для управления потоком.
Затем нам нужно преобразовать то, что находится в файлах, в список байтов [], чтобы мы могли демаршалировать данные. Вызов функции Ioutil.ReadAll позволяет присвоить содержимое файла в объект байт. После этого мы демаршалируем данные с помощью пакета json. Здесь мы устанавливаем демаршалинг объекта quotes_bytes в указатель на наш объект котировок, который инициализируется в строке выше. Здесь наши аннотации работают и заставляют все работать автоматически. Мы устанавливаем некоторую обработку ошибок, а затем приступаем к работе, чтобы получить нашу цитату.
Мы устанавливаем максимальное количество объектов цитаты, ссылаясь на поле QuoteList и подсчитывая количество объектов в массиве. Затем мы получаем наш random_tweetid, который будет брать случайный индекс от нуля до максимального количества котировок. Наконец, мы получаем нашу цитату, вызывая поле Quote из одного из случайных индексов в нашем QuoteList, который возвращает цитату, готовую к отправке в Twitter.
Последняя часть нашего бота собирает все вместе и выполняет:
Мы загружаем переменные среды, используя структуру APICred, и используя библиотеку Anaconda, мы устанавливаем наш ключ и секрет потребителя, а затем создаем экземпляр API, используя токен доступа и секрет. Теперь, когда у нас есть все возможности, мы вызываем нашу функцию GrabQuote, которая берет случайную цитату из нашего файла JSON и устанавливает ее в переменную tweet . В вызове функции PostTweet вы можете увидеть, что мы передаем нашу цитату через объект tweet, а также передаем url.Value{}, который мы можем вызвать из импорта библиотеки net / url. Если вы посмотрите исходник Anaconda, в функции PostTweet значения url используются для установки некоторых обязательных полей API. После того, как они установлены, библиотека создает канал для передачи всех полей в API. Хорошая идея - погрузиться в то, как исходный код библиотеки. Вы должны знать, как работает каждая строка в вашей программе. Это включает в себя знание того, как библиотека обрабатывает входы и выходы. На всякий случай мы настраиваем обработку ошибок для PostTweet и отправляем твит через API на временную шкалу.
У каждой программы Go есть главная функция, в которой все вызывается. Здесь мы используем библиотеку AWS Lambda for Go для вызова нашей функции. Lambda.Start() , как лямбда будет вызывать нашу функцию. В нашем случае мы размещаем всю логику в функции SendTweet и используем логику в main () для ее вызова. Если бы мы создавали сказать об API мы создадим функцию - обработчик , который вызывается из lambda.Start() функция. В нашем случае я решил ничего не возвращать, однако Lambda позволяет возвращать от 0 до 2 аргументов. Это удобно для возврата журналов событий и / или ошибок. AWS Lambda предлагает отличные инструменты для регистрации действий вашей функции, а возвращаемые данные отражают то, как они записываются. Если параметр возвращает, один из возвратов должен реализовывать ошибку в соответствии с документами. Таким образом, вы можете сказать вернуть журнал успеха с некоторой информацией, которую вы хотите отслеживать, и ошибкой, когда что-то пойдет не так. AWS Lambda также позволяет передавать от 0 до 2 аргументов функции. В документации говорится, что при передаче аргумента требуется контекст. Я это еще не тестировал, но буду, и наверное напишу об этом.
Наш бот готов! Давайте веселиться.
Но подождите, мы еще не можем веселиться!
Перед этим нам нужно настроить способ запуска нашего бота. Было бы отстойно запускать это вручную каждый раз, когда я хочу отправить цитату. Можно также открыть альтернативную учетную запись и сделать это вручную. Было бы еще хуже, если бы нужно было подготовить облачный экземпляр для работы в течение всего дня ради публикации твита один или два раза в день. К черту, давайте использовать Lambda.
Настройка лямбда-функции
Предположим, что у нас уже есть учетная запись AWS. Если нет настраивай, полезно ее иметь. Теперь, когда мы настроены, найдите свою Консоль управления AWS и выполните поиск сервисов для Lambda:
Щелкните «Лямбда», и вы попадете на экран «Лямбда». Здесь вы можете найти список всех ваших приложений, функций и слоев. В дополнение ко всему у вас есть панель, предназначенная для мониторинга всего вашего Lambda.
Он покажет количество используемых вами функций, объем памяти, используемый вашими функциями, ваш параллелизм и множество других вещей. Мы упомянули цены на Lambda; Цены варьируются в зависимости от суммы, которую вы выделяете. Цена также учитывает продолжительность времени, необходимого для выполнения ваших функций, а также количество запросов. Для нас мы используем гораздо меньше, чем разрешено на уровне бесплатного пользования, поскольку на данный момент мы вызываем только один раз в день. Это изменится по мере дальнейшего развития проекта.
Теперь давайте создадим функцию:
На следующем экране у нас есть некоторая информация, которую нужно заполнить. Первый - это параметры авторинга. Здесь мы можем оставить установленную по умолчанию опцию «Автор с нуля». Также есть возможность использовать чертежи для разработки нашего приложения. Если вы выберете это, вам будет предоставлен список различных уже созданных примеров проектов, которые вы можете использовать для быстрой разработки приложений. Вы также можете отфильтровать то, что ищете. Это упрощает быстрое создание прототипа приложения и начало поддержки серверной части. Существует также еще один вариант - Обзор хранилища бессерверных приложений, где у вас есть аналогичное решение для быстрого запуска приложений. Для наших целей мы собираемся писать с нуля.
Мы вводим имя нашей функции и выбираем среду выполнения. Мы вернемся к среде выполнения, но не забудьте выбрать Go 1.x, который настроит нас на использование Golang в качестве нашего функционального языка. Для разрешений мы по умолчанию создаем новую роль с базовыми разрешениями Lambda, что пока нормально. Если у вас есть существующие роли, созданные в вашей консоли IAM, вы можете свободно использовать их. Просто убедитесь, что у роли есть правильные разрешения на запуск лямбда-функций. Вы также можете создать новую роль из шаблонов политик AWS, что позволит вам создать роль с помощью шаблонов политик, созданных AWS.
Теперь мы готовы приступить к нашей функции. Мы попадаем на домашнюю страницу функции. Здесь мы можем приступить к настройке всего:
Первое, что мы собираемся сделать, это установить переменные среды. Как я уже упоминал выше, мы не загружаем библиотеку env и получаем наши переменные напрямую из AWS. Вот где мы их настраиваем:
Если вы прокрутите вниз, вы попадете в раздел с названием « Переменные среды» , нажмите кнопку « Изменить» , и вы попадете на следующую страницу, где мы сможем настроить наши переменные. Если вы нажмете Добавить переменную среды, вы можете начать вводить все необходимые переменные. В нашем случае мы настроили один для ключа потребителя, секрета потребителя, ключа доступа и секрета доступа. Как отмечено в нашем коде, мы будем импортировать их в наш код с помощью os.GetEnvфункция. AWS даже отмечает на полях, как это делается для каждого языка. Итак, специя. AWS позволяет нам также настроить шифрование для наших переменных. Это позволит зашифровать конфиденциальную информацию (например, учетные данные API) на консоли Lambda и при использовании API. AWS предоставляет службу API управления ключами для шифрования и дешифрования вашей конфиденциальной информации. Я не буду вдаваться в подробности, как использовать API здесь, но настройка шифрования, вероятно, является хорошей идеей, поэтому я напишу об этом в какой-то момент. Как только все наши переменные установлены, мы можем вернуться на главную страницу и загрузить наш код.
Код функции обычно доступен для редактирования в разделе «Код функции». Там настроена IDE Cloud9 для просмотра и редактирования нашего кода. Я использовал его, и это полезный инструмент. Однако я не думаю, что он совместим со средой выполнения Golang. Я вернусь к этому, когда столкнулся с проблемами при создании моей функции.
Теперь нам нужно связать наш код и поместить его в AWS с помощью нашей недавно созданной функции. Как упоминалось выше, я использовал Windows для создания этого пакета, поэтому я расскажу о том, что я сделал, как это отражено в документации. Однако я столкнулся с проблемами при использовании Windows для этого. Основываясь на моих экспериментах и некоторых отзывах некоторых умных людей, я обнаружил, что мне нужно использовать конечную точку на основе Unix для создания проекта. Я расскажу, почему позже.
Как только у нас будет все готово для работы со стороны AWS, мы готовы создавать наш пакет. Итак, CMD ваш путь к корню пакета. Теперь мы настроим нашу среду сборки на Linux с помощью этой команды:
Set GOOS=linux
Мы делаем это, чтобы настроить команду сборки, чтобы компилятор использовал двоичный файл Linux. Насколько я могу судить, это известная проблема с использованием Windows для всего этого. На момент публикации это не было решено, но я уверен, что исправление будет. Ранее, когда мы устанавливали нашу среду выполнения на Go 1.x, мы также устанавливали серверную операционную систему, которая запускает нашу функцию. Когда мы говорим «бессерверный», мы имеем в виду чужие серверы. В этом случае при настройке времени выполнения Go мы настраиваем ОС для запуска операционной системы Amazon Linux Amazon Linux - это серверная операционная система, предназначенная для работы сервисов на базе AWS. Вы также можете создавать образы с помощью Amazon Linux для запуска множества вещей.
После того, как мы установили двоичный файл, мы можем собрать наш пакет:
go build -o main bot.go
Важно убедиться, что наш исполняемый файл называется main. Поскольку основная функция - это точка вызова, и мы собираемся настроить обработчик для запуска main. Нам нужно загрузить исполняемый файл, созданный командой сборки, в нашу функцию Lambda в виде zip-файла. Итак, мы отправляем наш основной исполняемый файл в zip-файл. В нашем случае нам нужно заархивировать основной исполняемый файл и файл quotes.json, так как он нам понадобится для наших цитат. Я сделал это вручную, но есть команда, которую вы можете запустить, чтобы все заархивировать. Показано ниже:
%USERPROFILE%\Go\bin\build-lambda-zip.exe -output main.zip main
Краткое примечание: насколько я могу судить, когда вы заархивируете содержимое пакета с помощью Windows, оно сохраняет разрешения Windows. Сохранение разрешений POSIX - известная проблема при использовании кроссплатформенности Lambda. Разрешения POSIX - это стандарт Unix, который определяет структуру разрешений, используемую для взаимодействия с файлами и приложениями. Насколько я могу судить, эти разрешения устанавливаются неправильно при выполнении всего этого в Windows. Однако, когда я использовал свой Mac (ОС на базе Unix), я смог без проблем собрать и протестировать свою функцию.
После того, как мы заархивируем наш исполняемый файл и наш файл цитат, мы можем перейти к «Код функции» и загрузить наш zip-архив:
Выберите опцию «Загрузить как zip», и мы сможем загрузить наш недавно созданный zip-файл.
Последний шаг - прокрутите вниз до раздела « Основные настройки » и выберите « Изменить» . На странице редактирования основных настроек мы можем установить описание, изменить время выполнения, отредактировать обработчик, установить память, установить период ожидания и отредактировать правило выполнения. Следует отметить одну вещь: память, которую вы можете установить на все, что захотите. 512 МБ по умолчанию - это нормально, особенно в нашем случае. Но учтите, что чем больше памяти, тем дороже это может стоить. Кроме того, вам может не понадобиться вся установленная вами память, и это может привести к ненужным расходам. Для наших целей это нормально там, где оно есть.
Нам нужно отредактировать обработчик и установить для него значение main . Как я упоминал выше, мы используем основной обработчик для вызова нашего исполняемого файла в Lambda. Итак, убедитесь, что когда вы создаете свой пакет, вы называете его основным, чтобы обработчик работал.
Поздравляю! Теперь, когда мы настроены, но подождите! Мы должны это проверить. В правом верхнем углу домашней страницы функции есть раскрывающийся список для выбора теста для запуска. Щелчок по нему дает нам возможность настроить новый тест. Вы можете использовать это для настройки обычных сценариев, крайних случаев или любых других конкретных тестов, которые вы хотите запустить. Нам просто нужно нажать «Настроить тестовые события», и откроется страница создания теста:
Здесь мы захотим выбрать Создать новое тестовое событие, которое позволит нам выбрать шаблон события. Шаблон Hello World по умолчанию пока подходит, но есть встроенные тестовые шаблоны, которые вы можете выбрать в зависимости от ваших потребностей. Как только этот тест будет создан, его можно использовать в качестве тестового шаблона для нашей функции. Вы можете оставить JSON по умолчанию там и не забудьте назвать свое тестовое событие. JSON можно редактировать в соответствии с тем, что вы используете. Например, мы можем проверить возможность запуска функции Lambda через триггер Alexa.
Таким образом, тестовый файл JSON будет тем местом, куда вы передадите информацию о сеансе echo API. На данный момент по умолчанию все в порядке, когда мы закончим, нажмите Create. Теперь мы можем протестировать нашу функцию:
Ура! У нас все сработало. Что теперь? Что ж, я думаю, мы хотели бы запускать этого бота по расписанию. Lambda допускает множество различных триггеров, но для наших целей мы хотим работать по регулярному расписанию. Как работа cron. Для этого мы нажимаем кнопку « Добавить триггер» в разделе «Конструктор» на главной странице функции.
Затем мы попадаем на страницу триггера, где мы хотим найти EventBridge (формально CloudWatch Events).
Затем мы нажимаем выбрать правило для EventBridge:
Мы можем повторно использовать старые правила, которые мы создали, или выбрать опцию « Создать новое правило» . Это открывает множество вариантов конфигурации. Мы можем установить имя правила, независимо от того, запланировано ли оно или основано на событии, и если мы хотим включить триггер. Мы хотим запланировать его ежедневное выполнение, поэтому мы выбираем опцию Schedule expression и затем вводим cron (0 12 * *? *) В качестве нашего выражения. Это отличный справочник по синтаксису cron. Он настроен на ежедневное выполнение в полдень. Имейте в виду, что для выражений cron используется UTC. Это будет выполняться каждый день в полдень по всемирному координированному времени. Затем нажимаем "Сохранить". Готово! Мы официально добавили фоновый шум Твиттера!