]> git.lizzy.rs Git - luairc.git/blobdiff - test/luabot.lua
add signal handling to the luabot test
[luairc.git] / test / luabot.lua
index 6c9b43a8881db9cd9cc59b322e002a60d92fa4f5..456e118a0fac36af936459944146b4c332fd238c 100644 (file)
 #!/usr/bin/env lua
 
+local sig = require 'signal'
 local irc = require 'irc'
 irc.DEBUG = true
 
 local nick = "luabot"
-local pre_code = [[
-io = nil
-os = nil
-loadfile = nil
-dofile = nil
-package = nil
-require = nil
-module = nil
-debug = nil
-]]
+local channel = "#doytest"
+local network = "irc.freenode.org"
 
-irc.register_callback("connect", function()
-    irc.join("#doytest")
-end)
+local envs = {}
 
-irc.register_callback("channel_msg", function(channel, from, message)
-    local for_me, code = message:match("^(" .. nick .. ". )(.*)")
-    if for_me then
+local function create_env()
+    return {
+        _VERSION =      _VERSION,
+        assert =         assert,
+        collectgarbage = collectgarbage,
+        error =          error,
+        getfenv =        getfenv,
+        getmetatable =   getmetatable,
+        ipairs =         ipairs,
+        loadstring =     loadstring,
+        next =           next,
+        pairs =          pairs,
+        pcall =          pcall,
+        rawequal =       rawequal,
+        rawget =         rawget,
+        rawset =         rawset,
+        select =         select,
+        setfenv =        setfenv,
+        setmetatable =   setmetatable,
+        tonumber =       tonumber,
+        tostring =       tostring,
+        type =           type,
+        unpack =         unpack,
+        xpcall =         xpcall,
+        coroutine =      coroutine,
+        math =           math,
+        string =         string,
+        table =          table,
+    }
+end
+
+local commands = {
+    eval = function(target, from, code)
         code = code:gsub("^=", "return ")
-        local fn, err = loadstring(pre_code .. code)
+        local fn, err = loadstring(code)
         if not fn then
-            irc.say(channel.name, from .. ": Error loading code: " .. err)
+            irc.say(target, from .. ": Error loading code: " .. code .. err:match(".*(:.-)$"))
             return
         else
+            setfenv(fn, envs[from])
+            sig.signal("ALRM", error)
+            sig.alarm(5)
             local result = {pcall(fn)}
+            sig.alarm(0)
+            sig.signal("ALRM", "default")
             local success = table.remove(result, 1)
             if not success then
-                irc.say(channel.name, from .. ": Error running code: " .. result[1])
+                local err = result[1]:match(".*: (.-)$")
+                if err == "ALRM" then err = "timed out" end
+                irc.say(target, from .. ": Error running code: " .. code ..
+                                        ": " .. err)
             else
-                irc.say(channel.name, from .. ": " .. table.concat(result, ", "))
+                if result[1] == nil then
+                    irc.say(target, from .. ": nil")
+                else
+                    for i, v in ipairs(result) do result[i] = tostring(v) end
+                    irc.say(target, from .. ": " .. table.concat(result, ", "))
+                end
             end
         end
+    end,
+    clear = function(target, from)
+        irc.say(target, from .. ": Clearing your environment")
+        envs[from] = create_env()
+    end,
+    help = function(target, from, arg)
+        if arg == "" or not arg then
+            irc.say(target, from .. ": Commands: !clear, !eval, !help")
+        elseif arg == "eval" then
+            irc.say(target, from .. ": Evaluates a Lua statement in your own persistent environment")
+        elseif arg == "clear" then
+            irc.say(target, from .. ": Clears your personal environment")
+        end
+    end
+}
+
+irc.register_callback("connect", function()
+    irc.join(channel)
+end)
+
+irc.register_callback("channel_msg", function(channel, from, message)
+    message = message:gsub("^" .. nick .. "[:,>] ", "!eval ")
+    local is_cmd, cmd, arg = message:match("^(!)([%w_]+) ?(.-)$")
+    if is_cmd and commands[cmd] then
+        envs[from] = envs[from] or create_env()
+        commands[cmd](channel.name, from, arg)
+    end
+end)
+
+irc.register_callback("private_msg", function(from, message)
+    message = message:gsub("^" .. nick .. "[:,>] ", "!eval ")
+    local is_cmd, cmd, arg = message:match("^(!)([%w_]+) ?(.-)$")
+    envs[from] = envs[from] or create_env()
+    if is_cmd and commands[cmd] then
+        commands[cmd](from, from, arg)
+    else
+        commands["eval"](from, from, message)
+    end
+end)
+
+irc.register_callback("nick_change", function(from, old_nick)
+    if envs[old_nick] and not envs[from] then
+        envs[from] = envs[old_nick]
+        envs[old_nick] = nil
     end
 end)
 
-irc.connect{network = "irc.freenode.net", nick = nick}
+irc.connect{network = network, nick = nick}