diff --git a/examples/lsayirc.lua b/examples/lsayirc.lua index 12ebbcf..28cce35 100644 --- a/examples/lsayirc.lua +++ b/examples/lsayirc.lua @@ -1,4 +1,22 @@ +----- +-- An Lsyncd+IRC-Bot Config +-- +-- Logs into an IRC channel and tells there everything that happens in the +-- watched directory tree. +-- +-- The challenge coding Lsyncd configs taking use of TCP sockets is +-- that they must not block! Otherwise Lsyncd will block, no longer +-- empty the kernels monitor queue, no longer collecting zombie processes, +-- no longer spawning processes (this example doesnt do any, but maybe you +-- might want to do that as well), blocking is just bad. +-- +-- This demo codes just minimal IRC functionality. +-- it does not respond to anything else than IRC PING messages. + +-- Requires "luasocket" to be installed require("socket") + +-- For demo reasons, do not detach settings.nodaemon = true hostname = "irc.freenode.org" --hostname = "127.0.0.1" @@ -6,75 +24,82 @@ port = 6667 nick = "lbot01" chan = "##lfile01" ------ -- this blocks until the connection is established --- for once this ok since Lsyncd didnt yet start. +-- for once lets say this ok since Lsyncd didnt yet actually +-- start. local ircSocket, err = socket.connect(hostname, port) if not ircSocket then log("Error", "Cannot connect to IRC: ", err) terminate(-1) end ------ --- from now it must not block! +-- from now on, the socket must not block! ircSocket:settimeout(0) ------- --- Buffer for stuff to send and receive on IRC: +-- Buffers for stuff to send and receive on IRC: local ircWBuf = "" local ircRBuf = "" -local writeIrc + +-- Predeclaration for functions calling each other +local writeIRC ----- --- Called when the IRC socket can be written +-- Called when the IRC socket can be written again. +-- This happens when writeIRC (see below) couldnt write +-- its buffer in one go, call it again so it can continue its task. local function ircWritey(fd) - writeIrc() + writeIRC() end ---- --- Called when socket can be read +-- Called when there is data on the socket local function ircReady(socket) local l, err, ircRBuf = ircSocket:receive("*l", ircRBuf) if not l then - if errr ~= "timeout" then + if err ~= "timeout" then log("Error", "IRC connection failed: ", err) terminate(-1) end else ircRBuf = "" - return end log("Normal", "ircin :", l) --- answers ping messages local ping = l:match("PING :(.*)") if ping then - writeIRC("PONG :", ping) + writeIRC("PONG :", ping, "\n") end end ----- -- Writes on IRC socket -function writeIrc(...) +-- Do not forget to add an "/n". +function writeIRC(...) + -- Appends all arbuments into the write buffer ircWBuf = ircWBuf..table.concat({...}) + -- Gives it to the socket and sees how much it accepted local s, err = ircSocket:send(ircWBuf) - if not s then + -- If it cant the socket terminated. + if not s and err~="\n" then log("Error", "IRC connection failed: ", err) terminate(-1) end - --- log what has been send, but dont log the linefeed. + --- logs what has been send, without the linefeed. if (ircWBuf:sub(s, s) == "\n") then - log("Normal", "ircout: ", ircWBuf:sub(1, s - 1)) + log("Normal", "ircout:", ircWBuf:sub(1, s - 1)) else log("Normal", "ircout: ", ircWBuf:sub(1, s), "\\") end + ---- reduces the buffer by the amount of data sent. ircWBuf = ircWBuf:sub(s + 1, -1) - -- when the write buffer is empty unregister from core - -- this script no longer wants to be called when it can write - -- on the socket. If the buffer is filled register at the core. + -- when the write buffer is empty tell the core to no longer + -- call ircWritey if data can be written on the socket. There + -- is nothing to be written. If there is data in the buffer + -- asks to be called as soon it can be written again if ircWBuf == "" then observefd(ircSocket:getfd(), ircReady, nil) else @@ -82,34 +107,31 @@ function writeIrc(...) end end -writeIrc("NICK ", nick, "\n") -writeIrc("USER ", nick, " 0 * :testbot", "\n") -writeIrc("JOIN ", chan, "\n") - ----- --- Lets the Lsyncd core watch the IRCs filedescriptor --- and call ircReady and ircWritey when they are --- ready for transfer -observefd(ircSocket:getfd(), ircReady, ircWritey) +-- Aquires the nick on IRC and joins the configured channel +-- This will also register the ircReady/ircWritey function at the core +-- to be called when the socket is ready to be read/written. +writeIRC("NICK ", nick, "\n") +writeIRC("USER ", nick, " 0 * :lsyncd-sayirc-bot", "\n") +writeIRC("JOIN ", chan, "\n") +-- As action tells on IRC what the action is, then instead of +-- spawning somthing, it discards the event. local function action(inlet) -- event2 is the target of a move event local event, event2 = inlet.getEvent() if not event2 then - writeIrc("PRIVMSG ",chan," :",event.etype," ", + writeIRC("PRIVMSG ",chan," :",event.etype," ", event.path, "\n") else - writeIrc("PRIVMSG ",chan," :",event.etype," ", + writeIRC("PRIVMSG ",chan," :",event.etype," ", event.path," -> ",event2.path, "\n") end inlet.discardEvent(event) end +-- Watch a directory, and use a second for delay to aggregate events a little. +sync{source = "src", + action = action, + delay = 1, + onMove = true} - -sync{source= "src", action= action, delay= 1 } - - -for k, v in pairs(_G) do - print(k, v) -end