Информация Гайд luairc - работаем с IRC серверами.

Добро пожаловать в гайд по luairc.

IRC (или Internet Relay Chat) - это протолок прикладного уровня для обмена сообщениями в режиме реального времени. В основном применяется для группового общения, но также позволяет общаться через личные сообщения, обмениваться данными, файлами и т.д.

Сегодня же мы рассмотрим не сам IRC, а библиотеку для LUA под названием luairc.

luairc - это библиотека IRC низкого уровня для LUA. Все функции вызывают исключения при ошибках. (со слов разработчика)
Репозиторий:




Скачивание и установка библиотеки.

Для установки библиотеки переходим на GitHub разработчика и скачиваем весь репозиторий.
Переходим в папку с игрой --> moonloader --> lib и закидываем туда следующие файлы:
1. asyncoperations.lua
2. handlers.lua
3. util.lua
4. init.lua

Закинули? Отлично. Берем файл init.lua и переименовываем в luairc.lua

Следующим этапом нам нужно установить зависимости к luairc, а именно LuaSocket.
Переходим в тему https://www.blast.hk/threads/16031/#post-140673 и скачиваем архив lua51-libs.rar
Из этого архива нас интересует папка luasocket. Открываем ее и все содержимое переносим в папку с игрой --> moonloader --> lib

Ну или загрузить прикрепленные файлы к этой статье.

На этом установка завершена.




Начинаем писать код.

Сейчас мы напишем примитивный скрипт для подключения к серверу.
Lua:
require 'luairc' -- подключаем нашу библиотеку
local connected = false -- переменная, которую мы будем устанавливать в true, когда мы подключены

local s = irc.new{nick = "Meow"} -- создаем новый IRC объект
s:connect("irc.example.net") -- подключаем наш объект к серверу "irc.example.net"
connected = true -- меняем значение переменной на true

function main() -- основная функция
    -- Тут могут быть ваши действия
    while true do -- обязателен бесконечный цикл
        wait(1000) -- обязательна задержка не менее 500 мс (рекомендация разработчика библиотеки)
        if connected then -- Проверяем подключены ли мы, иначе при вызове s:think() скрипт выдаст ошибку
            s:think() --[[ функция, которая обрабатывает входящие данные и отвечает на запросы сервера (такие как PING)
                            Данную функцию стоит вызывать достаточно часто, чтобы не истекло время ожидания сервера]]
        end
    end
end

К серверу мы подключились, запросы обрабатываем, информацию применяем.
Давайте теперь подключимся к каналу и начнем принимать первые сообщения

Lua:
require 'luairc'
local connected = false

local s = irc.new{nick = "Meow"}
s:connect("irc.example.net")
s:hook("OnChat", function(user, channel, message) -- Добавляем обработчик событий. Ниже рассмотрим все виды событий.
    print(string.format("[%s] %s: %s", channel, user.nick, message)) -- Готовим строку для вывода и выводим ее в лог. Немного ниже поговорим о структуре user
end)
s:join("#example") -- Подключаемся к каналу #example
connected = true

function main()
    while true do
        wait(1000)
        if connected then
            s:think()
        end
    end
end

Теперь мы подключились к серверу, подключились к каналу и начали принимать сообщения, которые приходят в него.
Если бы такой канал и сервер существовали, то в логе мы бы увидели:
[#example] Brightside: Hello, World!, где
- #example - наш канал
- Brightside - имя того, кто прислал сообщение
- Hello, World! - само сообщение

Сообщения принимаем, читать можем, пора бы и ответить.
Lua:
require 'luairc'
local encoding = require 'encoding' -- Подключаем библиотеку encoding для кодирования строк в UTF-8
encoding.default = 'CP1251'
u8 = encoding.UTF8
local connected = false

local s = irc.new{nick = "Meow"}
s:connect("irc.example.net")
s:hook("OnChat", function(user, channel, message)
    print(string.format("[%s] %s: %s", channel, user.nick, message))
end)
s:join("#example")
connected = true

function main()
    sampRegisterChatCommand("irc.send", function(params) -- Для ответа создадим команду /irc.send
        if connected and params then -- Проверим, что мы подключены и ввели аргументы команды
            s:sendChat("#example", u8(params)) -- отправим сообщение, которое мы ввели в аргументах в канал #example
        end
    end)

    while true do
        wait(1000)
        if connected then
            s:think()
        end
    end
end

Теперь мы смогли ответить на сообщения. Давайте подключимся в еще один чат?
Lua:
require 'luairc'
local encoding = require 'encoding'
encoding.default = 'CP1251'
u8 = encoding.UTF8

local connected = false

local s = irc.new{nick = "Meow"}
s:connect("irc.example.net")
s:hook("OnChat", function(user, channel, message)
    print(string.format("[%s] %s: %s", channel, user.nick, message))
end)
s:join("#example")
s:join("#example2") -- Подключаемся к еще одному чату. Объявлять новый s:hook() не нужно, он может принимать сообщения со всех каналов одновременно.
connected = true

function main()
    sampRegisterChatCommand("irc.send", function(params) -- А наша команда /irc.send по-прежнему отправит сообщение в первый канал #example
        if connected and params then
            s:sendChat("#example", u8(params))
        end
    end)

    while true do
        wait(1000)
        if connected then
            s:think()
        end
    end
end

Мы рассмотрели базовые методы и основы работы с этой библиотекой.
Далее я предлагаю Вам ознакомиться со всеми возможными вызываемыми методами, структурами таблиц и списком хуков.





Структура таблицы user

Lua:
user = {
    nick, -- Ник пользователя (всегда предоставляется)
    username, -- Имя пользователя
    host, -- Имя хоста пользователя
    realname, -- Реальное имя пользователя
    access -- доступ пользователя внутри канала. Таблица, которая содержит поля op, halfop, voice
}

--[[
Все поля, кроме nick могу отсутствовать.
Чтобы заполнить их включите отслеживание пользователей и используйте s:whois()
--]]




Список всех методов.

МетодПрименение и описание
local s = irc.new(data)Создает новый IRC объект для подключения.
Аргумент data является таблицей.
Структура:
Lua:
data = {
      string nick, -- Обязательный параметр (Отображаемый ник)
      string username, -- Имя пользователя (Часть маски хоста)
      string realname, -- Реальное имя пользователя
      function nickGenerator, -- Генератор ников, в случае если nick не уникальный
      table hooks, -- Можно сразу передать таблицу s:hook()
      bool track_users -- Отслеживание информации о пользователе (по умолчанию - true)
 }
s:hook(name, id, f)Обработчик событий.
Аргументы:
name - имя события
id - уникальный тег (не обязателен, по умолчанию равен названию callback функции)
f - Callback функция
s:unhook(name, id)Удаляет обработчик событий
Аргументы:
name - имя события
id - уникальный тег
s:connect(host, port)Подключается на указанный IRC сервер
Аргументы:
host - адрес хоста
port - порт хоста (по умолчанию 6667)

Аргументом host можно передать таблицу:
Lua:
host = {
      string host, -- Хост сервера
      int tport, -- Порт сервера (по умолчанию 6667)
      int timeout, -- Таймаут при подключении (по умолчанию 30)
      string password, -- Пароль сервера
      bool secure, -- Включает TLS соединение
 }
s:disconnect(message)Отключается от сервера
Аргументы:
message - сообщение при выходе
s:think()Обрабатывает входящие данные и вызывает callback функции (если они указаны)
Используется только в бесконечном цикле.
local info = s:whois(nick)Показывает информацию о пользователе
Аргументы:
nick - ник для запроса
Возвращает таблицу:
Lua:
info = {
      userinfo,
      node,
      channels,
      account
 }
s:topic(channel)Отображает заголовок канала.
Используется для вызова хуков OnTopic и OnTopicInfo в любое время.
s:send(msg, ...)Отправляет "сырую" строку на IRC сервер
Аргументы:
msg - строка для отправки
... - форматирование строки.

Пример использования:
Lua:
local nick = "Meow"
 s:send("NICK %s", nick) -- пример с форматирование строки
 
 s:send("NICK Meow") -- пример без форматирования строки
s:sendChat(target, message)Отправляет сообщение в канал или пользователю
Аргументы:
target - Ник или канал
message - сообщение в UTF-8
s:join(channel, key)Вступает в канал/чат
Аргументы:
channel - название канала
key - пароль канала (не обязательно)
s:part(channel)Покидает канал.
Аргументы:
channel - название канала




Список всех хуков.


ХукОписание
PreRegister(table connection)Вызывается перед регистрацией.
Полезно для команд CAP и SASL
OnRaw(string line)Вызывается при получении любой строки ("сырых")
OnSend(string line)Вызывается, когда клиент отправляет любое сообщение
OnDisconnect(string message, bool errorOccurred)Вызывается, когда клиент отключается от сервера
OnChat(table user, string channel, string message)Вызывается, когда приходит сообщение (в канал / в личные)
OnJoin(table user, string channel)Вызывается, когда кто-то подключается к чату, где состоит клиент
OnPart(table user, string channel)Вызывается, когда кто-то покидает канал, где состоит клиент
OnQuit(table user, string message)Вызывается, когда кто-то покидает сервер из списка каналов, где состоит клиент
NickChange(table user, string newnick, string channel)Вызывается, когда кто-то изменяет ник из списка каналов, где состоит клиент
OnTopic(string channel, string topic)Вызывается, когда оператор канала изменяет заголовок канала
OnTopicInfo(string channel, string creator, string timeCreated)Вызывается с помощью s:topic(channel) и позволяет получить заголовок канала
OnKick(string channel, string nick, table kicker, string reason)Вызывается, когда оператор канала кикает любого пользователя (kicker имеет структуру user)
OnModeChange(table user, string target (channel/usernick), string modes, ...) (... - содержит аргументы параметра)Вызывается, когда любого из пользователей изменяются параметры внутри канала (например +b - блокировка / -b - разблокировка)




Cписок всех команд для "сырой" отправки через s:send()

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




В заключении.

Библиотека luairc легка для освоения, но с помощью нее можно придумать множество различных скриптов.
Возможно я не так явно раскрыл тему, но я готов помочь вам в данной теме с освоением данной библиотеки.

Что можно сделать с этой библиотекой?
Обычный межсерверный чат, к примеру.
Тут, кстати говоря, и можете посмотреть пример реализации.


Спасибо за внимание.


Как спастись от краша скрипта при "Ping timeout": https://www.blast.hk/threads/94258/#post-792278
 

Вложения

  • luairc.rar
    84.9 KB · Просмотры: 309
Последнее редактирование:

MISTER_GONWIK

Всефорумный гонщик
Всефорумный модератор
1,262
1,752
Не очень правильно выставлять статус подключенности самому, в библиотеке нет проверки на подключенность?
 

meowprd

Тот самый Котовский
Автор темы
Проверенный
1,278
718
Не очень правильно выставлять статус подключенности самому, в библиотеке нет проверки на подключенность?
К сожалению в библиотеки нет проверки.
Можно, конечно сделать по переменной local s = irc.new{nick = ""}, но тогда ее нужно определять прям перед самым коннектом, потому что она при s:disconnect() очищается вроде как.
 

#Kai-

Известный
705
292
Ждем чаты среди серверов?

Или это как старая версия где по-моему если свернуть игру скрипт крашится через время, что-то такое было.
 

meowprd

Тот самый Котовский
Автор темы
Проверенный
1,278
718
Ждем чаты среди серверов?

Или это как старая версия где по-моему если свернуть игру скрипт крашится через время, что-то такое было.
Чат уже есть, как пример, но версия рабочая.
Библиотека все та же, да, но скрипт не будет крашиться, если включить работу в свернутом режиме.



--------------------------------------------------------------------------------------------------
Небольшая информация о том, как сделать чтобы скрипт не крашился при timeout.

заходим в папку lib > открываем файл luairc.lua
переходим к строкам 163 и 164 и комментируем их.
Строку 162 оставляем.
1626204850835.png

1626204873114.png

Затем вновь заходим в папку lib > открываем файл handlers.lua
Переходим к строкам 172 и 173 и комментируем их.
1626204926488.png

1626204949934.png

Переходим к нашему основному скрипту
В месте где мы подключаемся к каналам добавляем хук OnDisconnect
1626205048373.png

И добавляем callback функцию с проверками при отключении.
1626205093672.png

Аргумент error будет равен true, если произошла ошибка (чаще всего timeout)
И если происходит какая либо ошибка - мы просто отключаем клиента от сервера.
Это поможет спасти скрипты от крашей, но нужно будет переподключаться к серверу.
 
Последнее редактирование:
  • Нравится
Реакции: Ya Zaregalsya и atizoff

The Spark

Известный
655
683
Очень давно переделывал эту либу под свои нужды. Из главных особенностей, это:
1) Игра не зависает при подключении
2) В самой либе есть проверка на подключение к сокету (meta.__isConnected)
3) В самой либе есть проверка на подключение к каналу (meta.__isJoined)
4) Показ состояния подключения (meta.__Status)
4) Не крашит при выкидывании аккаунта из канала (неактив, кик или бан)
5) Вместо вызова error, в некоторых случаях, вызывается лог в консоль об ошибках
6) Из ника подключения выкидываются все спец. символы, т.к с ними крашит
Делал для себя, может что-то пригодится вам.
P/s юзал ircluxe.ru, но он 1 раз лёг на 3 месяца, сейчас снова работает.
 

Вложения

  • luaircv2.lua
    5.4 KB · Просмотры: 122

Ya Zaregalsya

Известный
387
135
Как избавиться от зависаний при загрузке скрипта?
Очень давно переделывал эту либу под свои нужды. Из главных особенностей, это:
1) Игра не зависает при подключении
2) В самой либе есть проверка на подключение к сокету (meta.__isConnected)
3) В самой либе есть проверка на подключение к каналу (meta.__isJoined)
4) Показ состояния подключения (meta.__Status)
4) Не крашит при выкидывании аккаунта из канала (неактив, кик или бан)
5) Вместо вызова error, в некоторых случаях, вызывается лог в консоль об ошибках
6) Из ника подключения выкидываются все спец. символы, т.к с ними крашит
Делал для себя, может что-то пригодится вам.
P/s юзал ircluxe.ru, но он 1 раз лёг на 3 месяца, сейчас снова работает.
С твоей либой не подключается к каналу эспер.нет.
 
Последнее редактирование:

The Spark

Известный
655
683
Вынужден поднять из-за большого спроса.
Уже не первый человек пишет мне что-то про IRC и как это юзать. Поэтому я дописал, тестовый скрипт, который отправлял всем нуждающимся.
Там всё расписано, каждая функция и евент. Кому лень открывать:

События:
Lua:
onIRCPlayerMessage(user, text) -- событие на получение сообщения
onIRCPlayerJoin(text) -- событие на подключение юзера к комнате
onIRCPlayerDisconnect(text) -- событие на отключения юзера из комнаты. Не реагирует на кик
onIRCConnect() -- срабатывает когда подключился к IRC
onIRCJoin() -- срабатывает когда подключился к комнтате
onIRCDisconnect(cause) -- срабатывает когда отключаешься от IRC
onIRCExit(cause) -- срабатывает когда отключаешься от комнаты

Функции:
Lua:
sendIRCMessage(text) -- отправить сообщение
IRCJoined() -- подключиться к комнате
IRCConnected() -- подключиться к IRC
-- отключение от комнаты и от IRC реализуется через либу, без прослоек, смотрите в тестовом скрипте

Команды для теста:
/irc.connect - подключиться к IRC
/irc.room - подключиться к комнате
/irc.send - отправить сообщение

Скрипт не крашит при потере соединения и кика с сервера. Используется либа https://www.blast.hk/threads/94258/post-792979
Название комнаты и роли меняйте в скрипте. IRC используется от ircluxe.ru, можете тестировать через веб клиент.
Вообще, по-хорошему, переписать либу
 

Вложения

  • ircTest.lua
    5.9 KB · Просмотры: 57
Последнее редактирование:
  • Нравится
Реакции: Vespan и kru_tin

Vespan

Чешский луашер
Проверенный
2,119
1,720
Lua:
-- при кике timeout вызываеться функция shutdown
local function getline(self, errlevel)
    local line, err = self.socket:receive("*l")

    if not line and err ~= "timeout" and err ~= "wantread" then
        meta.__Status = "Timeout exceeded"
        sampfuncsLog(meta.__Prefix .. 'Превышено время ожидания (2 мин).', -1)
        self:shutdown()
    end

    return line
end
function meta:shutdown()
    meta.__isJoined = false
    meta.__isConnected = false
    self.socket:close()
    setmetatable(self, nil)
end
-- которая отключает юзера от канала-сервера
-- кароче вот пример:
    sampRegisterChatCommand('irc',function()
        if s.__isConnected then
            s:shutdown()
        else
            s:connect("irc.ea.libera.chat")
        end
    end)
-- ввожу - отключает меня от irc сервера,все нормально
-- при повторном вводе у меня крашиться скрипт с ошибкой:
[18:08:56.309702] (system)    irc.lua: Loaded successfully.
[18:09:22.809061] (error)    irc.lua: D:\GTA\GTASHKA\moonloader\irc.lua:58: attempt to call method 'connect' (a nil value)
stack traceback:
    D:\GTA\GTASHKA\moonloader\irc.lua:58: in function <D:\GTA\GTASHKA\moonloader\irc.lua:54>
[18:09:22.810057] (error)    irc.lua: Script died due to an error. (0BEFA324)
--какрешить?
 

Dekster051

Новичок
16
6
Очень давно переделывал эту либу под свои нужды. Из главных особенностей, это:
1) Игра не зависает при подключении
2) В самой либе есть проверка на подключение к сокету (meta.__isConnected)
3) В самой либе есть проверка на подключение к каналу (meta.__isJoined)
4) Показ состояния подключения (meta.__Status)
4) Не крашит при выкидывании аккаунта из канала (неактив, кик или бан)
5) Вместо вызова error, в некоторых случаях, вызывается лог в консоль об ошибках
6) Из ника подключения выкидываются все спец. символы, т.к с ними крашит
Делал для себя, может что-то пригодится вам.
P/s юзал ircluxe.ru, но он 1 раз лёг на 3 месяца, сейчас снова работает.
как ты сделал что она не зависает при подключении?