From ae280f16e0283f0c819410c6c122d694369b0943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergiusz=20=27q3k=27=20Baza=C5=84ski?= Date: Sun, 22 Sep 2013 14:56:38 +0200 Subject: [PATCH] Plugins now work. --- core/bot.lua | 4 ++- core/plugin.lua | 71 +++++++++++++++++++++++++++++++++++++++++++++--- plugins/test.lua | 5 ++++ start.lua | 6 +--- 4 files changed, 76 insertions(+), 10 deletions(-) create mode 100644 plugins/test.lua diff --git a/core/bot.lua b/core/bot.lua index 9e722cd..9cd5831 100644 --- a/core/bot.lua +++ b/core/bot.lua @@ -54,4 +54,6 @@ function bot:AddCommand(Name, Arguments, Callback, Help, Access) self._commands[Name] = Command end - +function bot:RemoveCommand(Name) + self._commands[Name] = nil +end diff --git a/core/plugin.lua b/core/plugin.lua index bd651d0..67e012b 100644 --- a/core/plugin.lua +++ b/core/plugin.lua @@ -11,10 +11,15 @@ local API = {} -- All these functions start with the 'plugin_id' argument, which -- will be auto-bound to the plugin name when called from a plugin. -function API.HookAdd(plugin_id, event_name, hook_name, callback) +function API.AddHook(plugin_id, event_name, hook_name, callback) local HookName = plugin_id .. ':' .. hook_name local PluginHooks = Plugins[plugin_id].Hooks - PluginHooks[#PluginHooks + 1] = HookName + + local HookInfo = {} + HookInfo.EventName = event_name + HookInfo.HookName = HookName + + PluginHooks[#PluginHooks + 1] = Info hook.Add(event_name, HookName, function(...) local Args = {...} local Success, Message = pcall(callback(unpack(Args))) @@ -27,7 +32,7 @@ function API.HookAdd(plugin_id, event_name, hook_name, callback) end) end -function API.CommandAdd(plugin_id, command_name, arity, callback, access, help) +function API.AddCommand(plugin_id, command_name, arity, callback, access, help) bot:AddCommand(command_name, arity, callback, access, help) local PluginCommands = Plugins[plugin_id].Commands PluginCommands[#PluginCommands + 1] = command_name @@ -42,6 +47,10 @@ function API.Register(plugin_id, plugin_name, version, url, author) end +function API.CurrentTime(plugin_id) + return os.time() +end + function plugin.Create(plugin_id) local Plugin = {} Plugin.Hooks = {} @@ -57,6 +66,25 @@ function plugin.Create(plugin_id) Plugins[plugin_id].Env = plugin.PrepareEnvironment(plugin_id) end +function plugin.Unload(plugin_id) + if Plugins[plugin_id] == nil then + error("No such plugin.") + end + local Plugin = Plugins[plugin_id] + local HooksRemoved = 0 + local CommandsRemoved = 0 + for K, HookInfo in pairs(Plugin.Hooks) do + hook.Remove(HookInfo.EventName, HookInfo.HookName) + HooksRemoved = HooksRemoved + 1 + end + for K, CommandName in pairs(Plugin.Commands) do + bot:RemoveCommand(CommandName) + CommandsRemoved = CommandsRemoved + 1 + end + Plugins[plugin_id] = nil + return HooksRemoved, CommandsRemoved +end + function plugin.PrepareEnvironment(plugin_id) local function BindPluginID(f) return function(...) @@ -64,7 +92,7 @@ function plugin.PrepareEnvironment(plugin_id) return f(plugin_id, unpack(Args)) end end - + local Env = {} Env.table = require('table') Env.string = require('string') @@ -93,3 +121,38 @@ function plugin.RunCode(plugin_id, code) setfenv(Function, Plugins[plugin_id].Env) return pcall(Function) end + + +function plugin.AddRuntimeCommands() + bot:AddCommand('plugin-load', 1, function(Username, Channel, Name) + if not Name:match('([a-zA-Z0-9\-_]+)') then + Channel:Say("Invalid plugin name!") + return + end + if Plugins[Name] ~= nil then + Channel:Say(string.format("Plugin %s already loaded!", Name)) + return + end + local Filename = "plugins/" .. Name .. ".lua" + local File, Message = io.open(Filename, 'r') + if not File then + Channel:Say(string.format("Could not open plugin file %s: %s", Filename, Message)) + return + end + local Data = File:read('*a') + local Success, Message = plugin.RunCode(Name, Data) + if not Success then + Channel:Say(string.format("Could not run plugin code: " .. Message)) + return + end + Channel:Say(string.format("Loaded plugin %s succesfully (%i bytes).", Name, #Data)) + end, "Load a plugin from the plugins/ directory.", 100) + bot:AddCommand('plugin-unload', 1, function(Username, Channel, Name) + if Plugins[Name] ~= nil then + local Hooks, Commands = plugin.Unload(Name) + Channel:Say(string.format("Plugin unloaded (removed %i hooks and %i commands).", Hooks, Commands)) + else + Channel:Say("Plugin wasn't loaded.") + end + end, "Unload a previously loaded plugin.", 100) +end diff --git a/plugins/test.lua b/plugins/test.lua new file mode 100644 index 0000000..c4b4598 --- /dev/null +++ b/plugins/test.lua @@ -0,0 +1,5 @@ +local LoadTime = plugin.CurrentTime() + +plugin.AddCommand('test', 0, function(User, Channel) + Channel:Say(string.format("I've been loaded at %i.", LoadTime)) +end, "Test command!") diff --git a/start.lua b/start.lua index efe0154..cbde3a5 100644 --- a/start.lua +++ b/start.lua @@ -22,7 +22,7 @@ end) reactor:Initialize() bot:Initialize(irc, ',') - +plugin.AddRuntimeCommands() --[[bot:AddCommand('at', 0, function(Username, Channel) local Body, Code, Headers, Status = https.request('https://at.hackerspace.pl/api') if Code ~= 200 then @@ -37,9 +37,5 @@ bot:Initialize(irc, ',') end, "Show who's at the Warsaw Hackerspace.")]]-- -plugin.RunCode('test', [[plugin.CommandAdd('test', 0, function(Username, Channel) - Channel:Say('hello!') -end, "Test command.", 0)]]) - irc:Connect('irc.freenode.net', 6667, 'moonspeak', 'moonspeak', 'moonspeak') reactor:Run()