Discord е платформа за съобщения в реално време, която се таксува като „гласов и текстов чат за геймърите“. Поради хлъзгавия си интерфейс, лекотата на използване и обширните функции, Discord преживява бърз растеж и става все по-популярен дори сред онези, които имат малък интерес към видео игрите. Между май 2017 г. и май 2018 г. потребителската му база се е увеличила от 45 милиона потребители на повече от 130 милиона , с повече от два пъти повече ежедневни потребители от Отпуснат .
Една от най-атрактивните характеристики на Discord от chatbot developer’s Перспективата е неговата стабилна поддръжка за програмируеми ботове, които помагат за интегрирането на Discord с външния свят и осигуряват на потребителите по-ангажиращо изживяване. Ботовете са повсеместни в Discord и предлагат широк спектър от услуги, включително помощ за модериране, игри, музика, търсене в интернет, обработка на плащания и др.
В този урок за ботове за Discord ще започнем, като обсъдим потребителския интерфейс на Discord и неговите API за REST и WebSocket за ботове, преди да преминем към урок, където ще напишем прост бот за Discord в JavaScript. И накрая, ще чуем от разработчика на, по определени показатели, най-популярния бот на Discord и неговия опит при разработването и поддържането на неговата значителна инфраструктура и кодова база.
Преди да обсъдим техническите подробности, важно е да разберем как потребителят взаимодейства с Discord и как Discord се представя на потребителите. Начинът, по който се представя на ботовете, е концептуално сходен (но разбира се невизуален). Всъщност официалните приложения на Discord са изградени върху същите API, които използват ботовете. Технически е възможно да стартирате бот в обикновен потребителски акаунт с малко модификации, но това е забранено от Общите условия на Discord. Ботовете са задължени да работят в бот акаунти.
Ето поглед към версията на браузъра един на приложението Discord, работещо в Chrome.
един Потребителският интерфейс на Discord за настолното приложение е практически същият като уеб приложението, пакетирано с Electron. Приложението за iOS е изградено с React Native. Приложението за Android е роден код на Android Java.
Нека го разбием.
Изцяло вляво е списъкът със сървъри, на които съм член. Ако сте запознати със Slack, сървърът е аналог на работното пространство на Slack и представлява група потребители, които могат да взаимодействат помежду си в рамките на един или повече канали в сървъра. Сървърът се управлява от неговия създател и / или от персонала, който те изберат и решат да делегират отговорности. Създателят и / или персоналът определят правилата, структурата на каналите в сървъра и управляват потребителите.
В моя случай, API на Discord server е в горната част на моя списък със сървъри. Това е чудесно място да получите помощ и да говорите с други разработчици. По-долу е сървърът, който създадох, наречен Тест . Ще тестваме бота, който създаваме по-късно там. Под него има бутон за създаване на нов сървър. Всеки може да създаде сървър с няколко кликвания.
как да хакна номера на кредитни карти
Имайте предвид, че докато терминът, използван в потребителския интерфейс на Discord, е Сървър , терминът, използван в документацията за разработчици и API е Гилдия . След като преминем към разговори по технически теми, ще преминем към разговори Гилдии . Двата термина са взаимозаменяеми.
Точно вдясно от списъка със сървъри е списъкът с канали за сървъра, който разглеждам в момента (в случая сървърът на API за Discord). Каналите могат да бъдат разделени на произволен брой категории. В сървъра за API на Discord категориите включват ИНФОРМАЦИЯ, ОБЩИ и LIBS, както е показано. Всеки канал функционира като чат стая, където потребителите могат да обсъждат каквато и тема да е посветена на канала. Каналът, който гледаме в момента (информация), има по-светъл фон. Каналите, които имат нови съобщения от последния им преглед, имат бял цвят на текста.
Това е изгледът на канала, където можем да видим за какво говорят потребителите в канала, който гледаме в момента. Тук можем да видим едно съобщение, видимо само частично. Това е списък с връзки към сървъри за поддръжка за отделни библиотеки на ботове Discord. Администраторите на сървъра са конфигурирали този канал така, че обикновените потребители като мен да не могат да изпращат съобщения в него. Администраторите използват този канал като табло за публикуване на важна информация, където може лесно да се види и няма да бъде заглушен от чата.
Изцяло вдясно е списък с потребителите, които в момента са онлайн на този сървър. Потребителите са организирани в различни категории и имената им имат различни цветове. Това е резултат от роли че имат. Ролята описва под каква категория (ако има такава) трябва да се появи потребителят, какъв трябва да е цветът на името му и какви разрешения има в сървъра. Потребителят може да има повече от една роля (и много често го прави) и има някаква математическа математика, която определя какво ще се случи в този случай. Най-малко всеки потребител има ролята @everyone. Други роли се създават и назначават от сървърния персонал.
Това е въвеждането на текст, където бих могъл да пиша и да изпращам съобщения, ако ми беше позволено. Тъй като нямам разрешение да изпращам съобщения в този канал, не мога да въвеждам тук.
Това е текущият потребител. Зададох потребителското си име на „Аз“, за да не се объркам и защото съм ужасен в избора на имена. Под моето потребителско име е номер (# 9484), който е моят дискриминатор. Може да има много други потребители с име „Аз“, но аз съм единственият „Аз # 9484“. Също така е възможно да задам псевдоним за себе си на база сървър, така че да мога да бъда известен с различни имена в различни сървъри.
Това са основните части на потребителския интерфейс на Discord, но има и много повече. Лесно е да започнете да използвате Discord, дори без да създавате акаунт, така че не се колебайте да отделите минута, за да се размотавате. Можете да влезете в Discord, като посетите началната страница на Discord , щракнете върху „отвори Discord в браузър“, изберете потребителско име и евентуално изиграйте освежаващ кръг или два от „щракнете върху снимките на автобуса“.
API на Discord се състои от две отделни части: WebSocket и REST API. Най-общо казано, WebSocket API се използва за получаване на събития от Discord в реално време, докато REST API се използва за извършване на действия вътре в Discord.
Приложението WebSocket API се използва за получаване на събития от Discord, включително създаване на съобщения, изтриване на съобщения, събития на потребителски удар / забрана, актуализации на разрешения на потребители и много други. Комуникацията от бот с API на WebSocket, от друга страна, е по-ограничена. Един бот използва WebSocket API, за да поиска връзка, да се идентифицира, да пулсира, да управлява гласови връзки и да направи още няколко основни неща. Можете да прочетете повече подробности в Discord’s документация за шлюз (единична връзка с API на WebSocket се нарича шлюз). За извършване на други действия се използва REST API.
Събитията от API на WebSocket съдържат полезен товар, включително информация, която зависи от вида на събитието. Например всички Създаване на съобщение събитията ще бъдат придружени от потребителски обект, представляващ автора на съобщението. Обаче потребителският обект сам по себе си не съдържа цялата информация, която трябва да се знае за потребителя. Например няма включена информация за разрешенията на потребителя. Ако се нуждаете от повече информация, можете да поискате REST API за нея, но поради причини, обяснени по-нататък в следващия раздел, обикновено трябва да получите достъп до кеша, който трябва да сте изградили от полезни товари, получени от предишни събития. Има редица събития, които доставят полезен товар, съответстващ на разрешенията на потребителя, включително, но не само Създаване на гилдия , Актуализация на ролята на гилдията , и Актуализация на канала .
Бот може да присъства в максимум 2500 гилдии на връзка WebSocket. За да позволи на бот да присъства в повече гилдии, ботът трябва да реализира шардинг и да отвори няколко отделни WebSocket връзки към Discord. Ако вашият бот работи в рамките на един процес на един възел, това е просто добавена сложност за вас, която може да изглежда ненужна. Но ако вашият бот е много популярен и трябва да има своя back-end, разпределен в отделни възли, поддръжката на Sharding за разчленяване прави това много по-лесно, отколкото би било в противен случай.
API Discord REST се използва от ботовете за извършване на повечето действия, като изпращане на съобщения, ритане / забрана на потребители и актуализиране на потребителски разрешения (най-общо аналогично на събитията, получени от API на WebSocket). API REST може също да се използва за заявки за информация; обаче ботовете разчитат основно на събития от API на WebSocket и кешират информацията, получена от събитията WebSocket.
Причините за това са няколко. Заявка за REST API за получаване на потребителска информация всеки път, когато a Създаване на съобщение полученото събитие, например, не се мащабира поради ограниченията на скоростта на REST API. Освен това е излишен в повечето случаи, тъй като API на WebSocket предоставя необходимата информация и трябва да я имате в кеша си.
Има някои изключения обаче и понякога може да се наложи информация, която не присъства в кеша ви. Когато бот първоначално се свърже с шлюз WebSocket, a Готов събитие и едно Създаване на гилдия събитие на гилдия, в което ботът присъства в този парче, първоначално се изпраща на бота, за да може той да попълни кеша си с текущото състояние. The Създаване на гилдия събития за силно населени гилдии включват само информация за онлайн потребители. Ако ботът ви трябва да получи информация за офлайн потребител, съответната информация може да не присъства в кеша ви. В този случай има смисъл да се направи заявка към REST API. Или, ако ви се налага често да получавате информация за офлайн потребители, вместо това можете да изберете да изпратите Поискайте членове на гилдията opcode към API на WebSocket, за да поискате членове на офлайн гилдията.
Друго изключение е, ако приложението ви изобщо не е свързано с API на WebSocket. Например, ако вашият бот има уеб табло за управление, в което потребителите могат да влязат и да променят настройките на бота на своя сървър. Таблото за управление в мрежата може да работи в отделен процес, без никакви връзки към WebSocket API и без кеш данни от Discord. Може да се наложи само от време на време да направи няколко заявки за REST API. При този тип сценарии има смисъл да разчитате на REST API, за да получите необходимата информация.
Въпреки че винаги е добра идея да имате разбиране за всяко ниво на вашия технологичен стек, директното използване на API на Discord WebSocket и REST отнема много време, излага на грешки, като цяло е ненужно и всъщност опасно.
Раздорът осигурява a куриран списък на официално проверени библиотеки и предупреждава, че:
Използването на персонализирани реализации или несъответстващи библиотеки, които злоупотребяват с API или причиняват прекомерни ограничения на скоростта, може да доведе до трайна забрана.
Библиотеките, официално проверени от Discord, обикновено са зрели, добре документирани и разполагат с пълно покритие на Discord API. Повечето разработчици на ботове никога няма да имат основателна причина да разработят персонализирана реализация, освен от любопитство или смелост!
Понастоящем официално проверените библиотеки включват реализации за Crystal, C #, D, Go, Java, JavaScript, Lua, Nim, PHP, Python, Ruby, Rust и Swift. Може да има две или повече различни библиотеки за избрания от вас език. Изборът кой да използвате може да бъде трудно решение. В допълнение към проверката на съответната документация, може да искате да се присъедините към неофициален Discord API сървър и да разберете каква общност стои зад всяка библиотека.
Да се залавяме за работа. Ще създадем Discord бот, който виси на нашия сървър и слуша уеб куки от Ko-fi . Ko-fi е услуга, която ви позволява лесно да приемате дарения във вашия акаунт в PayPal. Много е лесно да настроите уеб куки там, за разлика от PayPal, където трябва да имате бизнес акаунт, така че е чудесно за демонстрационни цели или обработка на дарения в малък мащаб.
Когато потребител дари $ 10 или повече, ботът ще им присвои Premium Member
роля, която променя цвета на името им и ги премества в горната част на списъка на онлайн потребителите. За този проект ще използваме Node.js и Discord API библиотека, наречена Eris (връзка към документация: https://abal.moe/Eris/). Eris не е единствената JavaScript библиотека. Вместо това можете да изберете discord.js. Кодът, който ще напишем, би бил много подобен и в двата случая.
Като страна, Patreon, друг дарител, предоставя официален бот за Discord и поддържа конфигурирането на ролите на Discord като предимства на сътрудниците. Ще приложим нещо подобно, но разбира се по-основно.
Кодът за всяка стъпка от урока е достъпен на GitHub ( https://github.com/mistval/premium_bot ). Някои от стъпките, показани в тази публикация, пропускат непроменен код за краткост, така че следвайте предоставените връзки към GitHub, ако смятате, че може да пропуснете нещо.
Преди да започнем да пишем код, се нуждаем от бот акаунт. Преди да можем да създадем акаунт за бот, се нуждаем от потребителски акаунт. За да създадете потребителски акаунт, следвайте инструкциите тук .
След това, за да създадем акаунт за бот, ние:
1) Създайте приложение в портал за разработчици .
2) Попълнете някои основни подробности за приложението (обърнете внимание на показания тук ИД на КЛИЕНТ - той ще ни трябва по-късно).
3) Добавете потребител на бот, свързан към приложението.
4) Изключете превключвателя PUBLIC BOT и отбележете показания токен на бота (това ще ни трябва и по-късно). Ако някога изтече вашия бот токен, например като го публикувате в изображение в публикация в ApeeScape Blog, наложително е да го регенерирате незабавно. Всеки, който притежава вашия бот токен, може да контролира акаунта на бота ви и да причини потенциално сериозни и постоянни проблеми за вас и вашите потребители.
5) Добавете бота към вашата тестова гилдия. За да добавите бот към гилдия, заменете клиентския му идентификатор (показан по-рано) в следния URI и навигирайте до него в браузър.
https://discordapp.com/api/oauth2/authorize?scope=bot&client_id=XXX
След като щракнете върху оторизиране, ботът вече е в моята тестова гилдия и мога да го видя в списъка с потребители. Офлайн е, но скоро ще го поправим.
Ако приемем, че имате Node.js инсталиран, създайте проект и инсталирайте Eris (бот библиотеката, която ще използваме), Express (рамка за уеб приложения, която ще използваме за създаване на слушател на уеб куки) и парсер на тялото (за анализиране на тела на webhook).
mkdir premium_bot cd premium_bot npm init npm install eris express body-parser
Нека започнем с бебешки стъпки. Първо просто ще получим бота онлайн и ще отговорим на нас. Можем да направим това в 10-20 реда код. Вътре в нов файл bot.js трябва да създадем екземпляр на Eris Client, да му предадем нашия бот маркер (придобит, когато създадохме бот приложение по-горе), да се абонираме за някои събития в клиентския екземпляр и да му кажем да се свърже с Discord . За демонстрационни цели ще закодираме нашия бот-маркер във файла bot.js, но създаването на отделен конфигурационен файл и освобождаването му от контрол на източника е добра практика.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step1.js )
елементи и принципи на дизайнерските дефиниции
const eris = require('eris'); // Create a Client instance with our bot token. const bot = new eris.Client('my_token'); // When the bot is connected and ready, log to console. bot.on('ready', () => { console.log('Connected and ready.'); }); // Every time a message is sent anywhere the bot is present, // this event will fire and we will check if the bot was mentioned. // If it was, the bot will attempt to respond with 'Present'. bot.on('messageCreate', async (msg) => { const botWasMentioned = msg.mentions.find( mentionedUser => mentionedUser.id === bot.user.id, ); if (botWasMentioned) { try { await msg.channel.createMessage('Present'); } catch (err) { // There are various reasons why sending a message may fail. // The API might time out or choke and return a 5xx status, // or the bot may not have permission to send the // message (403 status). console.warn('Failed to respond to mention.'); console.warn(err); } } }); bot.on('error', err => { console.warn(err); }); bot.connect();
Ако всичко върви добре, когато стартирате този код със собствения си бот токен, Connected and ready.
ще бъде отпечатан на конзолата и ще видите как ботът ви влиза онлайн във вашия тестов сървър. Можете да споменете2вашия бот или като щракнете с десния бутон върху него и изберете „Споменаване“, или като напишете името му, предшествано от @. Ботът трябва да отговори, като каже „Присъства“.
2 Споменаването е начин да привлечете вниманието на друг потребител, дори ако той не присъства. Редовният потребител, когато се спомене, ще бъде уведомен чрез известие на работния плот, мобилно известяване и / или малка червена икона, която се появява над иконата на Discord в системната област. Начинът (ите), по който потребителят е уведомен, зависи от неговите настройки и състоянието му онлайн. От друга страна, ботовете не получават никакви специални известия, когато са споменати. Те получават редовно събитие Създаване на съобщения, както при всяко друго съобщение, и могат да проверят спомените, прикачени към събитието, за да определят дали са били споменати.
Сега, след като знаем, че можем да получим бот онлайн, нека се отървем от сегашния си Създаване на съобщение обработчик на събития и създайте нов, който ни позволява да информираме бота, че сме получили плащане от потребител.
За да информираме бота за плащане, ще издадем команда, която изглежда така:
pb!addpayment @user_mention payment_amount
Например, pb!addpayment @Me 10.00
да запишете плащане от $ 10,00, направено от мен.
The пб! част се нарича префикс на командата. Добра конвенция е да изберете префикс, с който трябва да започват всички команди към вашия бот. Това създава мярка за пространство на имена за ботове и помага да се избегне сблъсък с други ботове. Повечето ботове включват команда за помощ, но представете си бъркотията, ако сте имали десет бота във вашата гилдия и всички те са отговорили на помогне ! Използване на pb! тъй като префиксът не е надеждно решение, тъй като може да има и други ботове, които също използват същия префикс. Повечето популярни ботове позволяват префиксът им да бъде конфигуриран на база на гилдия, за да се предотврати сблъсък. Друга възможност е да използвате собственото споменаване на бота като негов префикс, въпреки че това прави издаването на команди по-подробно.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step2.js )
const eris = require('eris'); const PREFIX = 'pb!'; const bot = new eris.Client('my_token'); const commandHandlerForCommandName = {}; commandHandlerForCommandName['addpayment'] = (msg, args) => { const mention = args[0]; const amount = parseFloat(args[1]); // TODO: Handle invalid command arguments, such as: // 1. No mention or invalid mention. // 2. No amount or invalid amount. return msg.channel.createMessage(`${mention} paid $${amount.toFixed(2)}`); }; bot.on('messageCreate', async (msg) => { const content = msg.content; // Ignore any messages sent as direct messages. // The bot will only accept commands issued in // a guild. if (!msg.channel.guild) { return; } // Ignore any message that doesn't start with the correct prefix. if (!content.startsWith(PREFIX)) { return; } // Extract the parts of the command and the command name const parts = content.split(' ').map(s => s.trim()).filter(s => s); const commandName = parts[0].substr(PREFIX.length); // Get the appropriate handler for the command, if there is one. const commandHandler = commandHandlerForCommandName[commandName]; if (!commandHandler) { return; } // Separate the command arguments from the command prefix and command name. const args = parts.slice(1); try { // Execute the command. await commandHandler(msg, args); } catch (err) { console.warn('Error handling command'); console.warn(err); } }); bot.on('error', err => { console.warn(err); }); bot.connect();
Да пробваме.
Не само получихме бота да отговори на pb!addpayment
команда, но създадохме обобщен модел за работа с команди. Можем да добавим още команди, само като добавим още манипулатори към commandHandlerForCommandName
речник. Тук имаме предимствата на проста командна рамка. Работата с команди е толкова основна част от създаването на бот, че много хора са написали и командни рамки с отворен код, които можете да използвате, вместо да пишете свои собствени. Командните рамки често ви позволяват да посочите охлаждания, необходими потребителски разрешения, псевдоними на команди, описания на команди и примери за използване (за автоматично генерирана помощна команда) и др. Eris се предлага с вграден командна рамка .
Говорейки за разрешения, нашият бот има малко проблеми със сигурността. Всеки може да изпълни addpayment
команда. Нека го ограничим, така че само собственикът на бота да може да го използва. Ще рефакторираме commandHandlerForCommandName
речник и той да съдържа JavaScript обекти като свои стойности. Тези обекти ще съдържат execute
свойство с манипулатор на команди и botOwnerOnly
свойство с булева стойност. Също така ще закодираме потребителския си идентификатор в секцията с константи на бота, за да знае кой е неговият собственик. Можете да намерите вашия потребителски идентификатор, като активирате режима за програмисти в настройките на Discord, след което щракнете с десния бутон на вашето потребителско име и изберете Copy ID.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step3.js )
const eris = require('eris'); const PREFIX = 'pb!'; const BOT_OWNER_ID = '123456789'; const bot = new eris.Client('my_token'); const commandForName = {}; commandForName['addpayment'] = { botOwnerOnly: true, execute: (msg, args) => { const mention = args[0]; const amount = parseFloat(args[1]); // TODO: Handle invalid command arguments, such as: // 1. No mention or invalid mention. // 2. No amount or invalid amount. return msg.channel.createMessage(`${mention} paid $${amount.toFixed(2)}`); }, }; bot.on('messageCreate', async (msg) => { try { const content = msg.content; // Ignore any messages sent as direct messages. // The bot will only accept commands issued in // a guild. if (!msg.channel.guild) { return; } // Ignore any message that doesn't start with the correct prefix. if (!content.startsWith(PREFIX)) { return; } // Extract the parts and name of the command const parts = content.split(' ').map(s => s.trim()).filter(s => s); const commandName = parts[0].substr(PREFIX.length); // Get the requested command, if there is one. const command = commandForName[commandName]; if (!command) { return; } // If this command is only for the bot owner, refuse // to execute it for any other user. const authorIsBotOwner = msg.author.id === BOT_OWNER_ID; if (command.botOwnerOnly && !authorIsBotOwner) { return await msg.channel.createMessage('Hey, only my owner can issue that command!'); } // Separate the command arguments from the command prefix and name. const args = parts.slice(1); // Execute the command. await command.execute(msg, args); } catch (err) { console.warn('Error handling message create event'); console.warn(err); } }); bot.on('error', err => { console.warn(err); }); bot.connect();
Сега ботът гневно ще откаже да изпълни addpayment
команда, ако някой друг освен собственика на бота се опита да го изпълни.
След това нека ботът присвои Premium Member
роля на всеки, който дари десет долара или повече. В горната част на файла bot.js:
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step4.js )
const eris = require('eris'); const PREFIX = 'pb!'; const BOT_OWNER_ID = '523407722880827415'; const PREMIUM_CUTOFF = 10; const bot = new eris.Client('my_token'); const premiumRole = { name: 'Premium Member', color: 0x6aa84f, hoist: true, // Show users with this role in their own section of the member list. }; async function updateMemberRoleForDonation(guild, member, donationAmount) { // If the user donated more than , give them the premium role. if (guild && member && donationAmount >= PREMIUM_CUTOFF) { // Get the role, or if it doesn't exist, create it. let role = Array.from(guild.roles.values()) .find(role => role.name === premiumRole.name); if (!role) { role = await guild.createRole(premiumRole); } // Add the role to the user, along with an explanation // for the guild log (the 'audit log'). return member.addRole(role.id, 'Donated or more.'); } } const commandForName = {}; commandForName['addpayment'] = { botOwnerOnly: true, execute: (msg, args) => { const mention = args[0]; const amount = parseFloat(args[1]); const guild = msg.channel.guild; const userId = mention.replace(//, (match, group1) => group1); const member = guild.members.get(userId); // TODO: Handle invalid command arguments, such as: // 1. No mention or invalid mention. // 2. No amount or invalid amount. return Promise.all([ msg.channel.createMessage(`${mention} paid $${amount.toFixed(2)}`), updateMemberRoleForDonation(guild, member, amount), ]); }, };
Сега мога да опитам да кажа pb!addpayment @Me 10.00
и ботът трябва да ми присвои Premium Member
роля.
Ами сега, в конзолата се появява грешка при липсващи разрешения.
DiscordRESTError: DiscordRESTError [50013]: Missing Permissions index.js:85 code:50013
Ботът няма разрешение за управление на роли в тестовата гилдия, така че не може да създава или да назначава роли. Бихме могли да дадем на бота администраторска привилегия и никога повече няма да имаме такъв проблем, но както при всяка система, най-добре е само да дадем на потребителя (или в този случай бот) минималните привилегии, които те изискват
Можем да дадем на бота разрешение за управление на роли, като създадем роля в настройките на сървъра, разрешим разрешението за управление на роли за тази роля и присвоим ролята на бота.
Сега, когато се опитвам да изпълня командата отново, ролята се създава и ми се възлага и имам изискан цвят на името и специална позиция в списъка с членове.
В командния манипулатор имаме TODO коментар, който предполага, че трябва да проверим за невалидни аргументи. Нека се погрижим за това сега.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step5.js )
const commandForName = {}; commandForName['addpayment'] = { botOwnerOnly: true, execute: (msg, args) => { const mention = args[0]; const amount = parseFloat(args[1]); const guild = msg.channel.guild; const userId = mention.replace(//, (match, group1) => group1); const member = guild.members.get(userId); const userIsInGuild = !!member; if (!userIsInGuild) { return msg.channel.createMessage('User not found in this guild.'); } const amountIsValid = amount && !Number.isNaN(amount); if (!amountIsValid) { return msg.channel.createMessage('Invalid donation amount'); } return Promise.all([ msg.channel.createMessage(`${mention} paid $${amount.toFixed(2)}`), updateMemberRoleForDonation(guild, member, amount), ]); }, };
Ето пълния код до момента:
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step5.js )
const eris = require('eris'); const PREFIX = 'pb!'; const BOT_OWNER_ID = '123456789'; const PREMIUM_CUTOFF = 10; const bot = new eris.Client('my_token'); const premiumRole = { name: 'Premium Member', color: 0x6aa84f, hoist: true, // Show users with this role in their own section of the member list. }; async function updateMemberRoleForDonation(guild, member, donationAmount) { // If the user donated more than , give them the premium role. if (guild && member && donationAmount >= PREMIUM_CUTOFF) { // Get the role, or if it doesn't exist, create it. let role = Array.from(guild.roles.values()) .find(role => role.name === premiumRole.name); if (!role) { role = await guild.createRole(premiumRole); } // Add the role to the user, along with an explanation // for the guild log (the 'audit log'). return member.addRole(role.id, 'Donated or more.'); } } const commandForName = {}; commandForName['addpayment'] = { botOwnerOnly: true, execute: (msg, args) => { const mention = args[0]; const amount = parseFloat(args[1]); const guild = msg.channel.guild; const userId = mention.replace(//, (match, group1) => group1); const member = guild.members.get(userId); const userIsInGuild = !!member; if (!userIsInGuild) { return msg.channel.createMessage('User not found in this guild.'); } const amountIsValid = amount && !Number.isNaN(amount); if (!amountIsValid) { return msg.channel.createMessage('Invalid donation amount'); } return Promise.all([ msg.channel.createMessage(`${mention} paid $${amount.toFixed(2)}`), updateMemberRoleForDonation(guild, member, amount), ]); }, }; bot.on('messageCreate', async (msg) => { try { const content = msg.content; // Ignore any messages sent as direct messages. // The bot will only accept commands issued in // a guild. if (!msg.channel.guild) { return; } // Ignore any message that doesn't start with the correct prefix. if (!content.startsWith(PREFIX)) { return; } // Extract the parts and name of the command const parts = content.split(' ').map(s => s.trim()).filter(s => s); const commandName = parts[0].substr(PREFIX.length); // Get the requested command, if there is one. const command = commandForName[commandName]; if (!command) { return; } // If this command is only for the bot owner, refuse // to execute it for any other user. const authorIsBotOwner = msg.author.id === BOT_OWNER_ID; if (command.botOwnerOnly && !authorIsBotOwner) { return await msg.channel.createMessage('Hey, only my owner can issue that command!'); } // Separate the command arguments from the command prefix and name. const args = parts.slice(1); // Execute the command. await command.execute(msg, args); } catch (err) { console.warn('Error handling message create event'); console.warn(err); } }); bot.on('error', err => { console.warn(err); }); bot.connect();
Това трябва да ви даде добра основна представа за това как да създадете бот за Discord. Сега ще видим как да интегрираме бота с Ko-fi. Ако искате, можете да създадете уеб кука във вашия табло в Ko-fi, уверете се, че вашият рутер е конфигуриран да препраща порт 80 и изпращайте реални тестови уеб куки на живо. Но просто ще използвам Пощальон за да симулира заявки.
Уеб куки от Ko-fi доставят полезни товари, които изглеждат така:
data: { 'message_id':'3a1fac0c-f960-4506-a60e-824979a74e74', 'timestamp':'2017-08-21T13:04:30.7296166Z', 'type':'Donation','from_name':'John Smith', 'message':'Good luck with the integration!', 'amount':'3.00', 'url':'https://ko-fi.com' }
Нека създадем нов изходен файл, наречен webhook_listener.js и използваме Express, за да слушаме webhooks. Ще имаме само един експресен маршрут и това е за демонстрационни цели, така че няма да се притесняваме много за използването на идиоматична структура на директориите. Просто ще сложим цялата логика на уеб сървъра в един файл.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/webhook_listener_step6.js )
const express = require('express'); const app = express(); const PORT = process.env.PORT || 80; class WebhookListener { listen() { app.get('/kofi', (req, res) => { res.send('Hello'); }); app.listen(PORT); } } const listener = new WebhookListener(); listener.listen(); module.exports = listener;
След това нека изискаме новия файл в горната част на bot.js, така че слушателят да стартира, когато стартираме bot.js.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step6.js )
const eris = require('eris'); const webhookListener = require('./webhook_listener.js');
След като стартирате бота, трябва да видите „Здравейте“, когато отидете до http: // localhost / kofi във вашия браузър.
обработка на изключения за почивка на пружинно зареждане
Сега нека имаме WebhookListener
обработва данните от webhook и излъчва събитие. И сега, след като тествахме, че браузърът ни има достъп до маршрута, нека променим маршрута на POST маршрут, тъй като уеб куката от Ko-fi ще бъде POST заявка.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step7.js )
const express = require('express'); const bodyParser = require('body-parser'); const EventEmitter = require('events'); const PORT = process.env.PORT || 80; const app = express(); app.use(bodyParser.json()); class WebhookListener extends EventEmitter { listen() { app.post('/kofi', (req, res) => { const data = req.body.data; const { message, timestamp } = data; const amount = parseFloat(data.amount); const senderName = data.from_name; const paymentId = data.message_id; const paymentSource = 'Ko-fi'; // The OK is just for us to see in Postman. Ko-fi doesn't care // about the response body, it just wants a 200. res.send({ status: 'OK' }); this.emit( 'donation', paymentSource, paymentId, timestamp, amount, senderName, message, ); }); app.listen(PORT); } } const listener = new WebhookListener(); listener.listen(); module.exports = listener;
След това трябва да накараме бота да изслуша събитието, да реши кой потребител е дарил и да му възложи роля. За да решим кой потребител е дарил, ще се опитаме да намерим потребител, чието потребителско име е подниз от съобщението, получено от Ko-fi. Донорите трябва да бъдат инструктирани да предоставят своето потребителско име (с дискриминатора) в съобщението, отколкото пишат, когато правят дарението си.
В долната част на bot.js:
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step7.js )
function findUserInString(str) { const lowercaseStr = str.toLowerCase(); // Look for a matching username in the form of username#discriminator. const user = bot.users.find( user => lowercaseStr.indexOf(`${user.username.toLowerCase()}#${user.discriminator}`) !== -1, ); return user; } async function onDonation( paymentSource, paymentId, timestamp, amount, senderName, message, ) { try { const user = findUserInString(message); const guild = user ? bot.guilds.find(guild => guild.members.has(user.id)) : null; const guildMember = guild ? guild.members.get(user.id) : null; return await updateMemberRoleForDonation(guild, guildMember, amount); } catch (err) { console.warn('Error handling donation event.'); console.warn(err); } } webhookListener.on('donation', onDonation); bot.connect();
В onDonation
функция, виждаме две представяния на потребител: като потребител и като член. И двете представляват едно и също лице, но обектът Член съдържа специфична за гилдията информация за Потребителя, като техните роли в гилдията и псевдонима им. Тъй като искаме да добавим роля, трябва да използваме членското представяне на потребителя. Всеки потребител в Discord има по едно представителство за всяка гилдия, в която се намира.
Сега мога да използвам Postman за тестване на кода.
Получавам код за състоянието 200 и получавам ролята, предоставена ми в сървъра.
Ако съобщението от Ko-fi не съдържа валидно потребителско име; нищо обаче не се случва. Донорът не получава роля и ние не знаем, че сме получили осиротяло дарение. Нека добавим дневник за регистриране на дарения, включително дарения, които не могат да бъдат приписани на член на гилдията.
Първо трябва да създадем регистрационен канал в Discord и да получим идентификатора на неговия канал. Идентификаторът на канала може да бъде намерен с помощта на инструментите за разработчици, които могат да бъдат активирани в настройките на Discord. След това можете да щракнете с десния бутон върху всеки канал и да кликнете върху „Копиране на идентификатор“.
Идентификаторът на регистрационния канал трябва да бъде добавен към секцията с константи на bot.js.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step8.js )
const LOG_CHANNEL_ID = '526653321109438474';
И тогава можем да напишем logDonation
функция.
(GitHub код връзка: https://github.com/mistval/premium_bot/blob/master/src/bot_step8.js )
function logDonation(member, donationAmount, paymentSource, paymentId, senderName, message, timestamp) { const isKnownMember = !!member; const memberName = isKnownMember ? `${member.username}#${member.discriminator}` : 'Unknown'; const embedColor = isKnownMember ? 0x00ff00 : 0xff0000; const logMessage = { embed: { title: 'Donation received', color: embedColor, timestamp: timestamp, fields: [ { name: 'Payment Source', value: paymentSource, inline: true }, { name: 'Payment ID', value: paymentId, inline: true }, { name: 'Sender', value: senderName, inline: true }, { name: 'Donor Discord name', value: memberName, inline: true }, { name: 'Donation amount', value: donationAmount.toString(), inline: true }, { name: 'Message', value: message, inline: true }, ], } } bot.createMessage(LOG_CHANNEL_ID, logMessage); }
Сега можем да актуализираме onDonation
за да извикате регистрационната функция:
async function onDonation( paymentSource, paymentId, timestamp, amount, senderName, message, ) { try { const user = findUserInString(message); const guild = user ? bot.guilds.find(guild => guild.members.has(user.id)) : null; const guildMember = guild ? guild.members.get(user.id) : null; return await Promise.all([ updateMemberRoleForDonation(guild, guildMember, amount), logDonation(guildMember, amount, paymentSource, paymentId, senderName, message, timestamp), ]); } catch (err) { console.warn('Error updating donor role and logging donation'); console.warn(err); } }
Сега мога да извикам webhook отново, първо с валидно потребителско име, а след това и без едно, и получавам две хубави регистрационни съобщения в лог канала.
Преди това просто изпращахме низове до Discord, за да се показват като съобщения. По-сложният JavaScript обект, който създаваме и изпращаме на Discord в новия logDonation
функция е специален тип съобщение, посочено като a богат вграден . Вграждането ви дава скеле за създаване на атрактивни съобщения като показаните. Само ботовете могат да създават вграждания, а потребителите не.
Сега сме уведомени за дарения, регистрираме ги и възнаграждаваме нашите поддръжници. Можем също да добавяме дарения ръчно с командата addpayment, в случай че потребител забрави да посочи потребителското си име, когато дарява. Нека го наречем ден.
Попълненият код за този урок е достъпен на GitHub тук https://github.com/mistval/premium_bot
Успешно създадохме бот, който може да ни помогне да проследим даренията. Това ли е нещо, което всъщност можем да използваме? Е, може би. Той обхваща основите, но не много повече. Ето някои недостатъци, над които бихте могли да помислите първо:
Premium Member
и ако се присъединят отново, няма да си го върнат. Трябва да съхраняваме плащания по потребителски идентификатор в база данни, така че ако премиум член се присъедини, можем да му върнем ролята и може би ще им изпратим хубаво съобщение за добре дошли, ако сме били толкова склонни.Premium Member
ролята, когато общите плащания от потребител достигнат $ 10, би помогнала тук.Premium Member
роля безплатно. Изглежда, че Ko-fi не подписва уеб куки, така че ще трябва да разчитате или на никой, който не знае адреса на уеб куката ви (лош), или на белия списък на IP (малко по-добре).Има над дузина уебсайтове за изброяване на ботове на Discord и предоставянето им на широката общественост, включително DiscordBots.org и Discord.Bots.gg . Въпреки че ботовете на Discord са най-вече набезите на любители на малки времена, някои ботове се радват на огромна популярност и поддържането им се превръща в сложна и взискателна работа.
По преброяване на гилдии, Rythm в момента е най-разпространеният бот на Discord. Rythm е музикален бот, чиято специалност е свързване с гласови канали в Discord и възпроизвеждане на музика, поискана от потребителите. Понастоящем Rythm присъства в над 2 850 000 гилдии, съдържащи общо население от около 90 милиона потребители, и в своя пик възпроизвежда аудио за около 100 000 едновременни потребители в 20 000 отделни гилдии. Създателят и основен разработчик на Rythm, ImBursting, любезно се съгласи да отговори на няколко въпроса за това какво е да разработиш и поддържаш мащабен бот като Rythm.
Интервюиращ: Можете ли да ни кажете малко за архитектурата на високо ниво на Rythm и как се хоства?
ImBursting: Rythm се мащабира на 9 физически сървъра, всеки от тях има 32 ядра, 96 GB RAM и 10 gbps връзка. Тези сървъри се разполагат в център за данни с помощта на малка хостинг компания GalaxyGate.
Представям си, че когато сте започнали да работите по Rythm, не сте го проектирали така, че да се мащабира близо до толкова, колкото има. Можете ли да ни разкажете за начина, по който е започнал Rythm, и за неговото техническо развитие с течение на времето?
Първата еволюция на Rythm е написана на Python, който не е много ефективен език, така че по времето, когато ударихме 10 000 сървъра (след много опити за мащабиране) разбрах, че това е най-голямото препятствие и затова започнах да прекодирам бота в Java, причината като аудио библиотеки на Java бяха много по-оптимизирани и като цяло беше по-подходящ език за такова огромно приложение. След прекодиране, производителността се подобри десетократно и за известно време запази проблемите. И тогава стигнахме до крайъгълен камък от 300 000 сървъра, когато проблемите отново започнаха да се появяват, и в този момент осъзнах, че се изисква повече мащабиране, тъй като един JVM просто не беше в състояние да се справи с всичко това. Така че бавно започнахме да внедряваме подобрения и основни промени като настройване на събирача на боклук и разделяне на гласови връзки на отделни микроуслуги с помощта на сървър с отворен код, наречен Lavalink. Това подобри производителността доста, но последният кръг от инфраструктурата беше, когато разделихме това на 9 отделни клъстера, за да работим на 9 физически сървъра, и направихме персонализиран шлюз и статистика микросервизи, за да сме сигурни, че всичко работи гладко, както на една машина.
Забелязах, че Rythm има версия на канарче и получавате помощ от други разработчици и персонал. Предполагам, че вие и вашият екип трябва да положите много усилия, за да сте сигурни, че нещата са направени правилно. Можете ли да ни кажете за това какви процеси са свързани с актуализирането на Rythm?
Rythm canary е алфа ботът, който използваме за тестване на прясно направени функции и подобрения на производителността, преди обикновено да ги внедрим в Rythm 2, за да тестваме в по-широк мащаб и след това да произвеждаме Rythm. Най-големият проблем, с който се сблъскваме, е наистина дългите пъти за рестартиране поради ограниченията за скоростта на Discord и това е причината да се опитам да направя всичко възможно, за да се уверя, че актуализацията е готова, преди да реша да я натисна.
Получавам много помощ от разработчици доброволци и хора, които искрено искат да помогнат на общността, искам да се уверя, че всичко е направено правилно и че хората винаги ще получават отговори на своите въпроси и ще получават възможно най-добрата подкрепа, което означава, че съм постоянно в търсене на нови възможности.
Дните на Discord като ново дете в блока отминаха и сега е една от най-големите платформи за комуникация в реално време в света. Докато ботовете на Discord са до голяма степен набезите на любители на малки времена, може да видим увеличаване на търговските възможности, тъй като населението на услугата продължава да се увеличава. Някои компании, като гореспоменатия Patreon, вече са влезли.
В тази статия видяхме общ преглед на потребителския интерфейс на Discord, общ преглед на неговите приложни програмни интерфейси (API), пълен урок по програмиране на ботове на Discord и трябваше да чуем какво е да работиш с бот в корпоративен мащаб. Надявам се да дойдете да се интересувате от технологията и да се чувствате така, сякаш разбирате основите на това как работи.
Chatbots обикновено са забавни, освен когато техните отговори на сложните ви запитвания имат интелектуалната дълбочина на чаша вода. За да осигурите страхотен UX за вашите потребители, вижте Сривът в чата - когато чатботът се провали от ApeeScape Design Blog за 5 дизайнерски проблема, които трябва да се избягват.
Свързани: JS Best Practices: Създайте Discord Bot с TypeScript и Dependency InjectionDiscord ботът е автоматизиран чат бот, който работи на Discord, популярна платформа за текстова и гласова комуникация. Ботовете са повсеместни в Discord и могат да бъдат програмирани да предоставят много различни услуги.
Някои често срещани роли, които ботовете изпълняват, включват модерация, игра на игри с потребители, възпроизвеждане на музика в гласови канали, търсене в интернет и обработка на плащания. Ботовете запълват и безброй други общи и нишови роли.
Eris (https://abal.moe/Eris/) и discord.js (https://discord.js.org/#/) са двете официално проверени JavaScript библиотеки. Понякога можете да видите кода на бота, който зависи от по-стари, неподдържани библиотеки или от незакачени библиотеки. Те обикновено трябва да се избягват.
Бот библиотека се грижи за подробностите при взаимодействието с API на WebSocket и REST на Discord, така че да можете да кодирате на по-високо ниво на абстракция. Много библиотеки включват и функции от по-високо ниво като командни рамки.
A +, ако сте казали „незабавно го регенерирайте в портала за разработчици на Discord“. Изтичането на токени е често срещано явление, особено сред начинаещите разработчици и последствията могат да бъдат тежки. Уеб роботите наблюдават GitHub за изтекли ботони, а компрометираните ботове се използват за нечисти цели.
Всеки, който има акаунт в Discord, може да влезе в портала за разработчици на Discord (https://discordapp.com/developers/applications/), да регистрира приложение, да създаде потребител на бот и да придобие бот токен. Оттам можете да използвате библиотека на Discord по ваш избор, за да програмирате вашия бот.