Fingercomp 4 409 Опубликовано: 1 марта, 2020 Предисловие Я думал на новый сервер запилить прогу — мост между чатом сервера и IRC. У меня уже были такие программки: я насчитал минимум 6 различных версий мостов — каждая была немного переделанным клиентом IRC, который на дискете встроенной есть. Понять, в чём разница, даже с вимдиффом было сложно. Потому я плюнул и решил запилить полноценную ирколибу с красивой апишкой. Как это выглядит Вот полный код бота — моста. Скрытый текст local event = require("event") local thread = require("thread") local irc = require("irc") -- ① local events = irc.events local priority = events.priority local com = require("component") local chatbox = com.admin_chatbox local gpu = com.gpu local channel = assert(os.getenv("CONVERSATIONALIST_CHANNEL"), "channel not set") local MC_FORMAT = "§3[§lIRC§3] §7%s§8: §i%s" local IRC_FORMAT = "\x0315%s\x0f: %s" local IRC_JOIN_FORMAT = "\x0315* \x0309%s \x0315has joined the server." local IRC_QUIT_FORMAT = "\x0315* \x0305%s \x0315has left the server." local fg local function log(color, text) if fg ~= color then gpu.setForeground(color) fg = color end print(text) end local function sanitizeMessage(message) return message:gsub("§.?", ""):gsub("%c", "") end local client = irc.builder() -- ② :connection { -- ③ host = "irc.esper.net:6667", throttling = { -- ④ maxDelay = 2, maxThroughput = 5, }, } :auth { -- ⑤ username = "conversationalist", nickname = "s1-conversationalist", realname = "IRC-MC bridge relay", } :account { -- ⑥ nickname = "s1-conversationalist", password = assert(os.getenv("CONVERSATIONALIST_PASSWORD"), "no pass set"), } :bot { -- ⑦ channels = {channel}, } :execution { -- ⑧ threaded = true, reconnect = true, catchErrors = true, } :subscribe(events.irc.message, priority.normal, function(self, client, evt) -- ⑨ if evt.target ~= channel then return end local message = sanitizeMessage(evt.message) log(0xffdb80, ("IRC → %s: %s"):format(evt.source.nickname, message)) event.push("chat::message", evt.source.nickname, message) end) :subscribe(events.client.connected, priority.normal, -- ⑩ function(self, client, evt) log(0x00ff80, "* Connected") end) :subscribe(events.client.disconnected, priority.normal, function(self, client, evt) log(0xff0000, "* Disconnected") end) :subscribe(events.client.registered, priority.normal, function(self, client, evt) log(0x99ff80, "* Registered as " .. client.currentNickname) end) :subscribe(events.client.authenticated, priority.normal, function(self, client, evt) log(0x99ff80, "* Authenticated") end) :subscribe(events.client.error, priority.top, function(self, client, evt) log(0xff0000, ("Caught error: %s"):format(evt.traceback)) end) :build() -- ⑪ local chatThread = thread.create(function() -- ⑫ event.listen("chat::message", function(evt, nickname, message) chatbox.say(MC_FORMAT:format(nickname, message)) end) event.listen("chat_message", function(evt, addr, dim, x, y, z, dist, nickname, msg) log(0x66dbff, (" MC → %s: %s"):format(nickname, msg)) client:msg(channel, IRC_FORMAT:format(nickname, msg)) end) event.listen("player_join", function(evt, addr, dim, x, y, z, dist, nickname) log(0x66dbff, (" MC → %s has joined the server"):format(nickname)) client:msg(channel, IRC_JOIN_FORMAT:format(nickname)) end) event.listen("player_quit", function(evt, addr, dim, x, y, z, dist, nickname) log(0x66dbff, (" MC → %s has left the server"):format(nickname)) client:msg(channel, IRC_QUIT_FORMAT:format(nickname)) end) log(0x0092ff, "* Press ^C to quit...") repeat local evt = event.pull("interrupted") until evt end) client:run() -- ⑬ thread.waitForAny({client.thread, chatThread}) log(0xff4000, "* Quitting") client:stop("Quitting.") -- ⑭ gpu.setForeground(0xffffff) os.exit() -- ⑮ Сто двадцать шесть строчек. Прокомментирую некоторые из них. ① Подключаем либу и для укорачивания имён ещё вытаскиваем events, в которых хранятся все ивенты и priority. ② Создаем клиент с помощью билдера. ③ Через :connection задаём настройки соединения. Самое важное — адрес иркосервера. Порт обязателен. ④ Ирколиба знает меру в флуде. Опасаться, что бота выкосит флуд-фильтром, можно гораздо меньше. Это опционально, конечно. ⑤ Задаём ник бота, юзернейм и реалнейм. Юзернейм виден в хосте (nickname!username@domain.name), а реалнейм пишется в /whois. ⑥ Ирколиба умеет авторизовываться на сервере. Тоже опционально. ⑦ Эта группа выделена для ботоводческих настроек. Но пока там единственная опция — в какие каналы автоматически заходить. ⑧ Здесь задаются настройки исполнения. Опция threaded, по дефолту включённая, запустит бота в отдельном треде. Опция reconnect, также включённая по умолчанию, заставит бота переподключиться к серверу, если отвалится от него. Опция catchErrors перехватит ошибки в пользовательких листнерах; она отключена по умолчанию, чтобы не смущать. ⑨ Бот генерит ивенты для каждого сообщения. Так мы задаём обработчик для ивента. К слову, вместо функции здесь может быть корутина. ⑩ Есть и другие события. Например, irc.events.client.connected означает, что клиент соединился с сервером. А irc.events.client.authenticated говорит, что теперь можно слать сообщения. ⑪ Когда мы закончили конфигурировать бота, собираем через :build(). Если вместо него вызвать :buildAndRun(), бот тут же ещё и запустится. ⑫ Для удобства создадим ещё один тред, где будем работать с чатбоксом и ждать ^C. ⑬ Запускаем бота. Затем ждём завершения любого из двух потоков. ⑭ Когда это произошло, мы выключаем клиент, если он ещё подключен: тот выйдет с сообщением "Quitting." ⑮ Наконец, принудительно останавливаем потоки. На всякий случай. Красота ведь. Репозиторий Репа либы — на нашем гитлабе. Там же есть примеры использования и документация с описанием всего. Наконец, версия 1.0.0 лежит на хеле. Из-за баги в OC хпм крашиться может (фиксить лень), но можно попробовать скачать: $ hpm install libirc 9 1 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
Fingercomp Автор темы 4 409 Опубликовано: 8 марта, 2020 (изменено) Допилил версию 1.1.0. Теперь либа умеет трекать юзеров на канале, их префикс, аккаунты, ники, иные данные о них, режимы каналов. Досье целое собирает. Скачать можно через hpm. Только он не работает. Поэтому альтернативный вариант: тык.tar. Распаковывать можно программой tar (тырить из oppm). Документация для 1.1.0 лежит здесь. P. S. Совсем забыл. Ещё поддержку capabilities сделал. Если кто-то вообще понимает, что это такое. Изменено 8 марта, 2020 пользователем Fingercomp 5 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах
ArtHacker 38 Опубликовано: 15 марта, 2020 программа месяца) поздравляю. вот. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на других сайтах