Привет, Хабровчане!

Сегодня вы ознакомитесь со статьей, в которой будет рассказано, как создать бота, используя C# на .NET Core, и о том, как его завести на удаленном сервере.

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

Надеюсь, данная статья поможет многим начинающим.

Предыстория


Все началось в одну бессонную осеннюю ночь, которую я проводил на Discord – сервере. Так как я относительно недавно к нему присоединился, я стал его изучать вдоль и поперёк. Обнаружив текстовый канал «Вакансии», я заинтересовался, открыл его, и отыскал среди не интересующих меня предложений, это:

«Программист (разработчик бота)
Требования:

  • знание языков программирования;
  • способность к самообучению.

Пожелания:

  • умение разбираться в чужом коде;
  • знание функционала DISCORD.

Задачи:

  • разработка бота;
  • поддержка и сопровождение работы бота.

Ваша выгода:

  • Возможность поддержать и повлиять на приглянувшийся проект;
  • Приобретение опыта работы в команде;
  • Возможность продемонстрировать и улучшить имеющиеся навыки.»


Это мгновенно меня заинтересовало. Да, за данную работу не платили, но от тебя никаких обязательств не требовали, да и в портфолио лишним не будет. Поэтому я написал админу сервера, и он попросил написать бота, который будет показывать статистику игрока в World of Tanks.

Подготовительный этап



Discrod
Прежде, чем приступить к написанию нашего бота, его необходимо создать для Discord. Вам необходимо:

  1. Войти в Discord аккаунт по ссылке
  2. Во вкладе “Applications” нажать на кнопку “New Application” и назвать бота
  3. Получить токен бота, войдя в вашего бота и найдя в списке “Settings” вкладку “Bot”
  4. Сохранить где-нибудь токен

Wargaming

Также, необходимо создать приложение в Wargaming, чтобы получить доступ к API Wargaming. Тут тоже все просто:

  1. Заходим в аккаунт Wargaming по данной ссылке
  2. Заходим в «Мои приложения» и нажимаем на кнопку «Добавить новое приложение», дав имя приложения и выбрав его тип
  3. Сохраняем ID приложения

Software

Тут уже имеется свобода выбора. Кто-то использует Visual Studio, кто-то Rider, кто-то вообще мощный, и пишет код в Vim (все же настоящие программисты используют только клавиатуру, верно?). Однако, чтобы не реализовывать Discord API, можно использовать неофициальную библиотеку для C# “DSharpPlus”. Его можно установить либо из NuGet, либо самому собрав исходники с репозитория.

Для тех, кто не знает, или забыл, как устанавливать приложения из NuGet.
Инструкция для Visual Studio

  1. Переходим во вкладку Проект – Управление пакетами NuGet;
  2. Нажимаем на обзор и в поле поиска вводим “DSharpPlus”;
  3. Выбираем и устанавливаем framework;
  4. PROFIT!


Подготовительный этап окончен, можно переходить к написанию бота.

Написание логики




Всю логику приложения рассматривать не будем, я лишь покажу, как работать с перехватом сообщений ботом, и как работать с Wargaming API.

Работа с Discord бот происходит через функцию static async Task MainTask(string[] args);
Чтобы вызвать данную функцию, в Main необходимо прописать

MainTask(args).ConfigureAwait(false).GetAwaiter().GetResult();

Далее, вам необходимо инициализировать своего бота:

discord = new DiscordClient(new DiscordConfiguration
{
    Token = token,
    TokenType = TokenType.Bot,
    UseInternalLogHandler = true,
    LogLevel = LogLevel.Debug
});

Где token – токен вашего бота.
Потом, через лямбду, прописываем необходимые команды, которые должен выполнять бот:
discord.MessageCreated += async e =>
{
    string message = e.Message.Content;
    if (message.StartsWith("&"))
    {
        await e.Message.RespondAsync(“Hello, ” + e.Author.Username);
    }
};

Где e.Author.Username – получение никнейма пользователя.

Таким образом, когда вы отправите любое сообщение, которое начинается с &, бот будет приветствовать вас.

В конце данной функции, необходимо прописать await discord.ConnectAsync(); и await Task.Delay(-1);

Это позволит выполнять команды на фоне, не занимая основной поток.

Теперь необходимо разобраться с Wargaming API. Тут все просто – пишете CURL-запросы, получаете ответ в виде JSON – строки, вытягиваете оттуда необходимые данные и делаете над ними манипуляции.

Пример работы с WargamingAPI
public Player FindPlayer(string searchNickname)
        {
            //https://api.worldoftanks.ru/wot/account/list/?application_id=y0ur_a@@_id_h3r3search=nickname
            urlRequest = resourceMan.GetString("url_find_player") + appID + "&search=" + searchNickname;
            Player player = null;
            string resultResponse = GetResponse(urlRequest);
            dynamic parsed = JsonConvert.DeserializeObject(resultResponse);

            string status = parsed.status;
            if (status == "ok")
            {
                int count = parsed.meta.count;
                if (count > 0)
                {
                    player = new Player
                    {
                        Nickname = parsed.data[0].nickname,
                        Id = parsed.data[0].account_id
                    };
                }
                else
                {
                    throw new PlayerNotFound("Игрок не найден");
                }
            }
            else
            {
                string error = parsed.error.message;
                if (error == "NOT_ENOUGH_SEARCH_LENGTH")
                {
                    throw new PlayerNotFound("Минимум три символа требуется");
                }
                else if (error == "INVALID_SEARCH")
                {
                    throw new PlayerNotFound("Неверный поиск");
                }
                else if (error == "SEARCH_NOT_SPECIFIED")
                {
                    throw new PlayerNotFound("Пустой никнейм");
                }
                else
                {
                    throw new Exception("Something went wrong.");
                }
            }

            return player;
        }


Внимание! Все токены и ID приложений хранить в открытом виде строго не рекомендуется! Как минимум – Discord банит такие токены, когда они попадают во всемирную сеть, как максимум – бот начинает пользоваться злоумышленниками.

Деплой на VPS – сервер




После того, как вы закончили с ботом, его необходимо разместить на сервере, который постоянно работает 24/7. Это связанно с тем, что когда работает ваше приложение, то работает и бот. Как только вы выключаете приложение, засыпает и ваш бот.

Много VPS серверов существует на этом свете, как на Windows, так и на Linux, однако в большинстве случаев, на Linux в разы дешевле размещать.

На Discord – сервере мне посоветовали vscale.io, и я тут же создал на нем виртуальный сервер на Ubuntu и залил бота. Я не буду описывать, как работает данный сайт, а сразу перейду к настройки бота.

Первым делом, вам необходимо установить необходимый софт, который будет запускать нашего бота, написанного на .NET Core. Как это сделать, описано здесь.

Далее, вам необходимо залить бота на Git – сервис, вроде GitHub и ему подобные и склонировать на VPS — сервер, или, другими путями скачать вашего бота. Учтите, что у вас будет только консоль, GUI не будет. Совсем.

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

  • Восстановить все зависимости: dotnet restore
  • Построить приложение: dotnet build name_project.sln -c Release
  • Перейти к построенной DLL;
  • dotnet name_of_file.dll

Поздравляю! Ваш бот запущен. Однако, бот, к несчастью, занимает консоль, и выйти из VPS – сервера так просто не выйдет. Также, в случае перезагрузки сервера, придется по новому запускать бота. Тут есть пару выходов из ситуации. Все они связаны с запуском при старте сервера:

  • Добавить запуск скрипта в /etc/init.d
  • Создать сервис, который будет запускаться при старте.

Подробно останавливаться на них не вижу смысла, достаточно подробно все описано в интернете.

Выводы


Я рад, что я взялся за это задание. Это был мой первый опыт разработки бота, и рад, что получил новые знания по C#, и работе с Linux.

Ссылка на Discord – сервер. Для тех, кто играет в игры Wargaming.
Ссылка на репозиторий, где лежит Discord bot.
Ссылка на репозиторий DSharpPlus.
Спасибо за внимание!

Комментарии (5)


  1. denismaster
    08.12.2019 00:29

    Вот интересно — а как наиболее правильно организовать Continuous Delivery/Deploy на VPS-сервер?


    1. hunterlan Автор
      08.12.2019 11:39

      denismaster
      Ну, можно попробовать костыли, и в скрипте прописать скачивание/клонирование вашего приложения, этот скрипт добавить в /etc/init.d. После обновления приложения, просто необходимо перезагрузить сервер. Но, это костыли, а других способов непрерывной доставки и непрерывного внедрения я пока не изучал.


    1. icCE
      08.12.2019 12:29

      Можно пойти разными путями.
      Но основные — это использовать git. С одной стороны вы заливаете код, с другой сервер его забирает. Можно использовать тут и jenkins, но как то оверкильнинько будет.
      Как вариант поставить задание в cron, можно задействовать папет или ансибел.
      В общем дальше уже как удобно. Можно и сам git в крон или некий скрипт.


    1. Alexsey
      08.12.2019 17:01

      У бота nadeko для этого есть вариант при каждом рестарте выкачивать из своего git репозитория последнюю версию исходников. Владельцу бота остается только выполнить команду .exit когда он хочет обновить бота.


  1. GennPen
    08.12.2019 12:51
    +1

    Далее, вам необходимо залить бота на Git – сервис, вроде GitHub и ему подобные и склонировать на VPS — сервер, или, другими путями скачать вашего бота.
    Самое простое и удобное — WinSCP

    После того, как вы скачали вашего бота, вам необходимо его запустить. Для этого, вам необходимо:
    А можно просто скомпилировать в «Self-contained», а чтобы не париться с кучей файлов — упаковать в один файл «Produce single file». Да, займет немного больше места, но зато не нужно задаваться вопросом какой .NET установлен, а просто взять и запустить.