LeetCode - популярная платформа для подготовки к собеседованиям по программированию, предоставляющая задачи на алгоритмы и структуры данных. Чтобы улучшить свои навыки и изучить свои успехи, пользователи могут хотеть получить информацию о своем профиле на LeetCode, такую как решенные задачи, статистика по времени и другие данные.
В данной статье будет рассмотрено, как можно написать программу на Golang для получения информации о пользователе с помощью API LeetCode. Для разработки будет использоваться библиотека graphql на Golang, чтобы отправить запросы к API LeetCode и получить необходимые данные о пользователе. Для простоты взаимодействия с пользователями будет использован Telegram API. Стоит добавить, что для Телеграм бота не нужно покупать отдельный хостинг, можно все сделать локально, нужно только доступ к интернету.
Почему Golang, а не Python?
Выбор между Golang и Python для разработки ботов зависит от конкретных требований проекта, но есть несколько аспектов, в которых Golang может оказаться более предпочтительным выбором по сравнению с Python:
Производительность: Golang обычно обладает более высокой производительностью и эффективностью исполнения кода по сравнению с Python. Это может быть критично для ботов, которые должны обрабатывать большие объемы данных или выполнять сложные вычисления.
Кроссплатформенность: Golang поддерживает кроссплатформенность, что означает, что боты, разработанные на Golang, могут легко работать на различных операционных системах без необходимости внесения изменений в код.
Статическая типизация: Golang является языком программирования со статической типизацией, что может помочь обнаружить ошибки на ранних этапах разработки и сделать код более надежным.
Многопоточность: Golang имеет встроенную поддержку горутин, которые облегчают параллельное выполнение операций, что особенно полезно для ботов, работающих с большим количеством одновременных запросов.
Эффективность работы с конкурентностью: Golang имеет механизмы управления конкурентностью, такие как каналы (channels) и слабые блокировки (mutexes), что облегчает создание многозадачных ботов.
Хотя Python также является популярным и мощным языком программирования для разработки ботов благодаря своей легкости и простоте в использовании, Golang может быть предпочтительным выбором, особенно если важны производительность, эффективность и работа с высокой нагрузкой.
Разработка
Перед тем как начать разрабатывать необходимо установить необходимые для работы библиотеки.
go install -v github.com/go-telegram-bot-api/telegram-bot-api/v5 go install -v github.com/machinebox/graphql
Для удобства поддержки и читаемости необходимо организовать код, храня различную функциональность в отдельных файлах. Начнем с того, что есть некая точка входа main.go через которую запускается бот:
main.go
package main import ( "log" ) func check(err error) { if err != nil { log.Println(err) } } func main() { startBot() }
После точки входа следует создать файл telegram.go, в котором будет происходить логика работы Телеграм бота, такая как: получение информации от пользователя, отправка ответа пользователю, отправка инструкции использования пользователю:
telegram.go
package main import ( "strconv" botAPI "github.com/go-telegram-bot-api/telegram-bot-api/v5" ) func isCallbackQuery(update *botAPI.Update) bool { return update.CallbackQuery != nil && update.CallbackQuery.Message.Text != "" } func isStartMessage(update *botAPI.Update) bool { return update.Message != nil && update.Message.Text == "/start" } func getKeyboardRow(buttonText string, buttonCode string) []botAPI.InlineKeyboardButton { return botAPI.NewInlineKeyboardRow(botAPI.NewInlineKeyboardButtonData(buttonText, buttonCode)) } func renderingMenu(bot *botAPI.BotAPI, chatId int64) { msg := botAPI.NewMessage(chatId, "Select action") msg.ReplyMarkup = botAPI.NewInlineKeyboardMarkup( getKeyboardRow(left+" "+"Information about bot"+" "+right, "info"), ) bot.Send(msg) } func updateProccessing(update *botAPI.Update, bot *botAPI.BotAPI) { var message string choice := update.CallbackQuery.Data if choice == "info" { message = "My functionality: \n Get username information from leetcode. You only need to send the username in a message and get the result immediately" } msg := botAPI.NewMessage(update.CallbackQuery.From.ID, message) bot.Send(msg) } func startBot() { var message string bot, err := botAPI.NewBotAPI(token) check(err) updateConfig := botAPI.NewUpdate(0) updateConfig.Timeout = timeout updates := bot.GetUpdatesChan(updateConfig) for update := range updates { if isCallbackQuery(&update) { updateProccessing(&update, bot) } else { if isStartMessage(&update) { message = "Hi everyone! \nIt's a telegram bot. You can get information from leetcode by username. If you need more information than click info." renderingMenu(bot, update.Message.Chat.ID) } else { username := getUsersInfo(update.Message.Text) if username.MatchedUser.Username == "" { message = cancel+"Information: \nusername: user not found" } else { message = "Information: \nusername: " + username.MatchedUser.Username message += "\n" + solved + "solved: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[0].Count) + " / " +strconv.Itoa(username.AllQuestionsCount[0].Count) message += "\n" + easy + "Easy: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[1].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[1].Count) message += "\n" + middle + "Middle: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[2].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[2].Count) message += "\n" + hard + "Hard: " + strconv.Itoa(username.MatchedUser.SubmitStats.AcSubmissionNum[3].Count) + " / " + strconv.Itoa(username.AllQuestionsCount[3].Count) } } msg := botAPI.NewMessage(update.Message.Chat.ID, message) msg.ReplyToMessageID = update.Message.MessageID bot.Send(msg) } } }
Следующая функциональность бота - работа с graphql. Для удобства использования были созданы структуры и определены к ним поля, которые используются в graphql запросах и вынесено в отдельный файл model.go:
model.go
package main type Submission struct { Count int `json:"count"` Difficulty string `json:"difficulty"` } type UserProfileData struct { MatchedUser MatchedUser `json:"matchedUser"` AllQuestionsCount []Submission `json:"allQuestionsCount"` } type SubmitStats struct { AcSubmissionNum []Submission `json:"acSubmissionNum"` } type MatchedUser struct { Username string `json: username` SubmitStats SubmitStats `json:"submitStats"` }
Для общения с API LeetCode был создан graphql.go. Для простоты использования были созданы функции, которые возвращают graphql запросы. Основная функция осуществляет запрос к API и возвращает структуру, в которой хранится информация о пользователе: имя пользователя, сколько всего решил задач и сколько по каждому уровню сложности было решено:
graphql.go
package main import ( "context" "github.com/machinebox/graphql" ) func getQueryUserInfo() string { return `query ($username: String!) { matchedUser(username: $username) { username submitStats { acSubmissionNum { difficulty count } } } }` } func getQueryQntyQuestions() string { return `{ allQuestionsCount { difficulty count } }` } func getUsersInfo(username string) UserProfileData { var requestUser UserProfileData client := graphql.NewClient("https://leetcode.com/graphql") query := getQueryQntyQuestions() request := graphql.NewRequest(query) ctx := context.Background() err := client.Run(ctx, request, &requestUser) check(err) query = getQueryUserInfo() request = graphql.NewRequest(query) request.Var("username", username) err = client.Run(ctx, request, &requestUser) if err != nil { check(err) } return requestUser }
Для хранения константных информаций: токен, таймаут, эмодзи, если нужно, создан constants.go:
constants.go
package main const ( token = "Your Token" left = "\U000025B6" right = "\U000025C0" easy = "\U0001F4D7" hard = "\U0001F4D5" middle = "\U0001F4D9" solved = "\U00002705" cancel = "\U0001F6AB" timeout = 5 )
Проверка работоспособности
Предстоит протестировать бот. Для проверки будет взят username автор�� статьи и несуществующий пользователь(к существующему пользователю допишется цифра). Для начала предстоит проверка на существующем пользователе. Была получена данная информация, да эта информация верна, вот пользователь на LeetCode.



А теперь проверим на несуществующем. Бот ответил, что такого пользователя нет.


Вывод
Получение информации о пользователе с платформы LeetCode на языке программирования Golang может быть важным и полезным шагом для разработчиков, желающих улучшить свои навыки в алгоритмах и структурах данных. Используя API LeetCode, можно получить доступ к различным данным о пользователе.
