From b67d71c3b65bafe1375d66747fd29940b83564df Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Wed, 8 Aug 2018 12:23:09 +0200 Subject: add support for hooks and autojoin channels --- bot.lua | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 163 insertions(+), 14 deletions(-) diff --git a/bot.lua b/bot.lua index d218771..f35f742 100644 --- a/bot.lua +++ b/bot.lua @@ -1,6 +1,7 @@ local cqueues = require("cqueues") local socket = require("cqueues.socket") +local errno = require("cqueues.errno") local loop = cqueues.new() @@ -17,11 +18,21 @@ function irc.new(nick, username, password, realname) nick = nick or "albotty", username = username or "albotty", password = password, - realname = realname or "albotty" + realname = realname or "albotty", + hooks = {}, + channels = {} } return setmetatable(self, { __index = irc }) end +function irc:autojoin(channels) + for _,chan in pairs(channels) do + self.channels[chan] = self.channels[chan] or {} + self.channels[chan].autojoin = true + self.channels[chan].joined = false + end +end + function irc:connect(host, port) local hostname, password, tls, timeout if type(host) == "table" then @@ -34,11 +45,14 @@ function irc:connect(host, port) hostname = host end self.conn = socket.connect(hostname, port) - self.conn:settimeout(timeout or 30) + self.conn:settimeout(timeout or 10) self:send("NICK %s", self.nick) self:send("USER %s 0 * :%s", self.username, self.realname) +--[[ +-- self.conn:settimeout(-1) + local loop = cqueues.new() loop:wrap(function() for line in sess.conn:lines("*L") do @@ -56,6 +70,7 @@ function irc:connect(host, port) error("loop.step: "..err) end end +]]-- return self end @@ -72,11 +87,38 @@ function irc:send(msg, ...) if select("#", ...) > 0 then msg = msg:format(...) end - -- call send hook + self:run_hooks("OnSend", msg) self.conn:write(msg.."\r\n") self.conn:flush() end +function irc:send_chat(target, message) + for line in message:gmatch("([^\r\n]+)") do + self:send("PRIVMSG %s :%s", target, line) + end +end + +function irc:join(channel) + self.channels[channel] = self.channels[channel] or {} + self.channels[channel].joined = true + self:send("JOIN %s", channel) +end + +function irc:hook(event, id, func) + func = func or id + self.hooks[event] = self.hooks[event] or {} + self.hooks[event][id] = func + return self +end + +function irc:run_hooks(event, ...) + for id, func in pairs(self.hooks[event] or {}) do + if func(self, ...) then + return true + end + end +end + local function irc_parse(line) local prefix local lineStart = 1 @@ -126,9 +168,11 @@ end irc.callbacks["001"] = function(self, prefix, me) self.authed = true self.nick = me -end - -irc.callbacks["NOTICE"] = function(self, prefix, channel, msg) + for name, chan in pairs(self.channels) do + if chan.autojoin then + self:join(name) + end + end end irc.callbacks["NICK"] = function(self, prefix, newnick) @@ -143,12 +187,81 @@ irc.callbacks["NICK"] = function(self, prefix, newnick) if self.nick == user.nick then self.nick = newnick end + self:run_hooks("OnNick", user, newnick) end irc.callbacks["PING"] = function(self, prefix, query) - self:send("PONG :%", query) + self:send("PONG :%s", query) +end + +irc.callbacks["PRIVMSG"] = function(self, prefix, channel, message) + self:run_hooks("OnChat", parse_prefix(prefix), channel, message) +end + +irc.callbacks["NOTICE"] = function(self, prefix, channel, message) + self:run_hooks("OnNotice", parse_prefix(prefix), channel, message) +end + +irc.callbacks["JOIN"] = function(self, prefix, channel) + self:run_hooks("OnJoin", parse_prefix(prefix), channel) +end + +irc.callbacks["PART"] = function(self, prefix, channel, reason) + local user = parse_prefix(prefix) + self:run_hooks("OnPart", user, channel, reason) +end + +irc.callbacks["KICK"] = function(self, prefix, channel, kicked, reason) + self:run_hooks("OnKick", channel, kicked, parse_prefix(prefix), reason) +end + +irc.callbacks["QUIT"] = function(self, prefix, message) + local user = parse_prefix(prefix) + self:run_hooks("OnQuit", user, message) +end + +-- nick in use +irc.callbacks["432"] = function(self, prefix, target, badnick) + local n,i = string.match(self.nick, "(.*)(%d+)$") + local newnick + newnick = string.format("%s%d",n or self.nick, i+1) + self:send("NICK %s", newnick) end +irc.callbacks["433"] = irc.callbacks["422"] + +-- no topic +irc.callbacks["331"] = function(self, prefix, me, channel) + self:run_hooks("OnTopic", channel, nil) +end + +irc.callbacks["332"] = function(self, prefix, me, channel, topic) + self:run_hooks("OnTopic", channel, topic) +end + +irc.callbacks["333"] = function(self, prefix, me, channel, nick, time) + self:run_hooks("OnTopicInfo", channel, nick, tonumber(time)) +end + +irc.callbacks["TOPIC"] = function(self, prefix, channel, topic) + self:run_hooks("OnTopic", channel, topic) +end + +-- RPL_UMODEIS +irc.callbacks["221"] = function(self, prefix, user, modes) + self:run_hooks("OnUserMode", modes) +end + +-- RPL_CHANNELMODEIS +irc.callbacks["324"] = function(self, prefix, channel, modes) + self:run_hooks("OnChannelMode", channel, modes) +end + +irc.callbacks["MODE"] = function(self, prefix, target, modes, ...) + self:run_hooks("OnModeChange", parse_prefix(prefix), target, modes, ...) +end + + function irc:handle(line) local prefix, cmd, params = irc_parse(line) callback = self.callbacks[cmd] @@ -162,25 +275,61 @@ end function irc:step() - local line, why, errmsg = self.conn:read("*L") + local line, why = self.conn:read("*L") if not line or #line == 0 then - return nil + if why == errno.ETIMEDOUT then + self:run_hooks("OnTimeout") + end + return nil, why end self:handle(line) return line end +--------------------------------------------------------------------------- sess = irc.new() -sess:connect("chat.freenode.net", "6667") -print("CONNECTED!!!!!!!!!!!!!!!!!!!!!!!!!!!!11") +sess:hook("OnChat", function(self, user, channel, message) + print("PRIVMSG:") + print(" nick:", user.nick) + print(" channel:", channel) + print(" message:", message) + if channel == self.nick then + self:send_chat(user.nick, "Hi there") + else + self:send_chat(channel, "Hi "..user.nick) + end +end) -loop:wrap(function() - while sess:step() do - print("witing for next") +sess:hook("OnJoin", function(self, user, channel) + print("JOIN:") + print(" nick:", user.nick) + print(" channel:", channel) +end) + +sess:hook("OnKick", function(self, channel, kicked, user, reason) + print("Kicked:") + print((" %s kicked %s from %s"):format(user.nick, kicked, channel)) + if kicked == self.nick then + self:join(channel) end end) +sess:autojoin{"#alpine-test", "#alpine"} + +sess:connect("172.16.3.54", "6667") + + +print("CONNECTED!") + +loop:wrap(function() + repeat + local ok, err = sess:step() + print("DEBUG step:", ok, err) + until not ok and err ~= errno.ETIMEDOUT + return true --nil, err +end) + while not loop:empty() do local ok, err = loop:step() if not ok then -- cgit v1.2.3