From 7f475070dda5ccb0614d04ced795b4b6cd05a642 Mon Sep 17 00:00:00 2001 From: ShadowNinja Date: Wed, 23 Oct 2013 09:37:21 -0400 Subject: [PATCH] Add an optional message queue to prevent flooding --- asyncoperations.lua | 14 ++++++++------ doc/irc.luadoc | 9 +++++++++ handlers.lua | 4 ++-- init.lua | 12 ++++++------ queue.lua | 45 +++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 70 insertions(+), 14 deletions(-) create mode 100644 queue.lua diff --git a/asyncoperations.lua b/asyncoperations.lua index a8ea2dd..f430c12 100644 --- a/asyncoperations.lua +++ b/asyncoperations.lua @@ -21,6 +21,8 @@ function meta:send(msg, ...) end end +meta.queue = meta.send + local function verify(str, errLevel) if str:find("^:") or str:find("%s%z") then error(("malformed parameter '%s' to irc command"):format(str), errLevel) @@ -32,28 +34,28 @@ end function meta:sendChat(target, msg) -- Split the message into segments if it includes newlines. for line in msg:gmatch("([^\r\n]+)") do - self:send("PRIVMSG %s :%s", verify(target, 3), line) + self:queue("PRIVMSG %s :%s", verify(target, 3), line) end end function meta:sendNotice(target, msg) -- Split the message into segments if it includes newlines. for line in msg:gmatch("([^\r\n]+)") do - self:send("NOTICE %s :%s", verify(target, 3), line) + self:queue("NOTICE %s :%s", verify(target, 3), line) end end function meta:join(channel, key) if key then - self:send("JOIN %s :%s", verify(channel, 3), verify(key, 3)) + self:queue("JOIN %s :%s", verify(channel, 3), verify(key, 3)) else - self:send("JOIN %s", verify(channel, 3)) + self:queue("JOIN %s", verify(channel, 3)) end end function meta:part(channel) channel = verify(channel, 3) - self:send("PART %s", channel) + self:queue("PART %s", channel) if self.track_users then self.channels[channel] = nil end @@ -83,5 +85,5 @@ function meta:setMode(t) mode = table.concat{mode, "-", verify(rem, 3)} end - self:send("MODE %s %s", verify(target, 3), mode) + self:queue("MODE %s %s", verify(target, 3), mode) end diff --git a/doc/irc.luadoc b/doc/irc.luadoc index c8c5d8e..ab50ad6 100644 --- a/doc/irc.luadoc +++ b/doc/irc.luadoc @@ -159,3 +159,12 @@ function irc:shutdown() -- Apart from nick, fields may be missing. To fill them in, enable user tracking and use irc:whois. -- @name User -- @class table + +-- If you need a simple queue you can enable one by requiring "irc.queue". +-- Doind so will add the following features: + +--- Queue a raw line of IRC to be sent to the server as soon as possible. +-- @param msg Line to be sent, excluding newline characters. +-- @param ... Format parameters for msg, with string.format semantics. [optional] +function irc:queue(msg, ...) + diff --git a/handlers.lua b/handlers.lua index cbd1c9e..5efe958 100644 --- a/handlers.lua +++ b/handlers.lua @@ -8,7 +8,7 @@ module "irc" handlers = {} handlers["PING"] = function(o, prefix, query) - o:send("PONG :%s", query) + o:queue("PONG :%s", query) end handlers["001"] = function(o, prefix, me) @@ -81,7 +81,7 @@ end local function needNewNick(o, prefix, target, badnick) local newnick = o.nickGenerator(badnick) - o:send("NICK %s", newnick) + o:queue("NICK %s", newnick) end -- ERR_ERRONEUSNICKNAME (Misspelt but remains for historical reasons) diff --git a/init.lua b/init.lua index d3c3369..2bafc85 100644 --- a/init.lua +++ b/init.lua @@ -119,17 +119,17 @@ function meta_preconnect:connect(_host, _port) self.socket = s setmetatable(self, meta) - self:send("CAP REQ multi-prefix") + self:queue("CAP REQ multi-prefix") self:invoke("PreRegister", self) - self:send("CAP END") + self:queue("CAP END") if password then - self:send("PASS %s", password) + self:queue("PASS %s", password) end - self:send("NICK %s", self.nick) - self:send("USER %s 0 * :%s", self.username, self.realname) + self:queue("NICK %s", self.nick) + self:queue("USER %s 0 * :%s", self.username, self.realname) self.channels = {} @@ -227,6 +227,6 @@ function meta:whois(nick) end function meta:topic(channel) - self:send("TOPIC %s", channel) + self:queue("TOPIC %s", channel) end diff --git a/queue.lua b/queue.lua new file mode 100644 index 0000000..61c73b0 --- /dev/null +++ b/queue.lua @@ -0,0 +1,45 @@ +local getmetatable = getmetatable +local clock = os.clock +local remove = table.remove +local insert = table.insert +local select = select + +module "irc" + +local meta = _META + +local old_new = new +function new(...) + local o = old_new(...) + o.messageQueue = {} + o.lastThought = 0 + o.recentMessages = 0 + return o +end + +local old_think = meta.think +function meta:think(...) + old_think(self, ...) -- Call old meta:think + + -- Handle outgoing message queue + self.recentMessages = self.recentMessages - ((clock() - self.lastThought) * 8000) + if self.recentMessages < 0 then + self.recentMessages = 0 + end + for i = 1, #self.messageQueue do + if self.recentMessages > 4 then + break + end + self:send(remove(self.messageQueue, 1)) + self.recentMessages = self.recentMessages + 1 + end + self.lastThought = clock() +end + +function meta:queue(msg, ...) + if select("#", ...) > 0 then + msg = msg:format(...) + end + insert(self.messageQueue, msg) +end +