- Portiere Channels

- Portiere Plugins
- Stelle Plugin-Ladeprozess auf Redis um
- Plugin-Name wird in die Plugins-Tabelle eingefügt
This commit is contained in:
Andreas Bielawski 2016-06-18 12:51:13 +02:00
parent 90bd9a14d7
commit da14baa05b
7 changed files with 537 additions and 47 deletions

View File

@ -16,7 +16,7 @@ function bot:init(config) -- The function run when the bot is started or reloade
assert( assert(
config.bot_api_key and config.bot_api_key ~= '', config.bot_api_key and config.bot_api_key ~= '',
'You did not set your bot token in the config!' 'You did not set your bot token in the config!'
) )
self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/' self.BASE_URL = 'https://api.telegram.org/bot' .. config.bot_api_key .. '/'
@ -35,14 +35,18 @@ function bot:init(config) -- The function run when the bot is started or reloade
self.database.users = self.database.users or {} -- Table to cache userdata. self.database.users = self.database.users or {} -- Table to cache userdata.
self.database.users[tostring(self.info.id)] = self.info self.database.users[tostring(self.info.id)] = self.info
plugins = {}
self.plugins = {} -- Load plugins. self.plugins = {} -- Load plugins.
for _,v in ipairs(config.plugins) do enabled_plugins = load_plugins()
for k,v in pairs(enabled_plugins) do
local p = require('otouto.plugins.'..v) local p = require('otouto.plugins.'..v)
plugins[k] = p
print('loading plugin',v)
table.insert(self.plugins, p) table.insert(self.plugins, p)
self.plugins[k].name = v
if p.init then p.init(self, config) end if p.init then p.init(self, config) end
end end
print('Bot started successfully as:\n@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
print('@' .. self.info.username .. ', AKA ' .. self.info.first_name ..' ('..self.info.id..')')
self.last_update = self.last_update or 0 -- Set loop variables: Update offset, self.last_update = self.last_update or 0 -- Set loop variables: Update offset,
self.last_cron = self.last_cron or os.date('%M') -- the time of the last cron job, self.last_cron = self.last_cron or os.date('%M') -- the time of the last cron job,
@ -76,41 +80,8 @@ function bot:on_msg_receive(msg, config) -- The fn run whenever a message is rec
msg.text_lower = string.gsub(msg.text, '@'..string.lower(config.bot_user_name), "") msg.text_lower = string.gsub(msg.text, '@'..string.lower(config.bot_user_name), "")
msg = pre_process_msg(self, msg, config) msg = pre_process_msg(self, msg, config)
for _, plugin in ipairs(self.plugins) do
for _, trigger in pairs(plugin.triggers) do match_plugins(self, msg, config)
if string.match(msg.text_lower, trigger) then
local success, result = pcall(function()
-- trying to port matches to otouto
for k, pattern in pairs(plugin.triggers) do
matches = match_pattern(pattern, msg.text)
if matches then
break;
end
end
return plugin.action(self, msg, config, matches)
end)
if not success then
-- If the plugin has an error message, send it. If it does
-- not, use the generic one specified in config. If it's set
-- to false, do nothing.
if plugin.error then
utilities.send_reply(self, msg, plugin.error)
elseif plugin.error == nil then
utilities.send_reply(self, msg, config.errors.generic, true)
end
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
return
end
-- If the action returns a table, make that table the new msg.
if type(result) == 'table' then
msg = result
-- If the action returns true, continue.
elseif result ~= true then
return
end
end
end
end
end end
@ -162,6 +133,174 @@ function pre_process_msg(self, msg, config)
return new_msg return new_msg
end end
function bakk_match_plugins(self, msg, config)
-- Go over patterns. If one matches is enough.
for k, pattern in pairs(plugin.triggers) do
local matches = match_pattern(pattern, msg.text)
-- local matches = match_pattern(pattern, msg.text, true)
if matches then
print("msg matches: ", pattern)
if is_plugin_disabled_on_chat(plugin_name, msg) then
return nil
end
-- Function exists
--[[ if plugin.run then
if not plugin.notyping then send_typing(receiver, ok_cb, true) end
if not warns_user_not_allowed(plugin, msg) then
local result = plugin.run(msg, matches)
if result then
send_large_msg(receiver, result)
end
end
end ]]--
-- One pattern matches
return
end
end
end
function match_plugins(self, msg, config)
for _, plugin in ipairs(self.plugins) do
for _, trigger in pairs(plugin.triggers) do
if string.match(msg.text_lower, trigger) then
-- Check if Plugin is disabled
if is_plugin_disabled_on_chat(plugin.name, msg) then return end
local success, result = pcall(function()
-- trying to port matches to otouto
for k, pattern in pairs(plugin.triggers) do
matches = match_pattern(pattern, msg.text)
if matches then
break;
end
end
return plugin.action(self, msg, config, matches)
end)
if not success then
-- If the plugin has an error message, send it. If it does
-- not, use the generic one specified in config. If it's set
-- to false, do nothing.
if plugin.error then
utilities.send_reply(self, msg, plugin.error)
elseif plugin.error == nil then
utilities.send_reply(self, msg, config.errors.generic, true)
end
utilities.handle_exception(self, result, msg.from.id .. ': ' .. msg.text, config)
return
end
-- If the action returns a table, make that table the new msg.
if type(result) == 'table' then
msg = result
-- If the action returns true, continue.
elseif result ~= true then
return
end
end
end
end
end
function is_plugin_disabled_on_chat(plugin_name, msg)
local hash = get_redis_hash(msg, 'disabled_plugins')
local disabled = redis:hget(hash, plugin_name)
-- Plugin is disabled
if disabled == 'true' then
print('Plugin '..plugin_name..' ist in diesem Chat deaktiviert')
return true
else
return false
end
end
function load_plugins()
enabled_plugins = redis:smembers('telegram:enabled_plugins')
if not enabled_plugins[1] then
create_plugin_set()
end
return enabled_plugins
end
-- create plugin set if it doesn't exist
function create_plugin_set()
enabled_plugins = {
'control',
'blacklist',
'about',
'ping',
'whoami',
'nick',
'echo',
'imgblacklist',
'gImages',
'gSearch',
'wikipedia',
'hackernews',
'imdb',
'calc',
'urbandictionary',
'time',
'reddit',
'xkcd',
'slap',
'commit',
'pun',
'currency',
'shout',
'set',
'get',
'patterns',
'9gag',
'shell',
'adfly',
'twitter',
'rss',
'remind',
'youtube',
'youtube_search',
'youtube_channel',
'youtube_playlist',
'tagesschau_eil',
'twitter_send',
'respond',
'roll',
'quotes',
'pasteee',
'images',
'media',
'location_manager',
'creds',
'weather',
'forecast',
'expand',
'facebook',
'github',
'bitly',
'app_store',
'bitly_create',
'br',
'heise',
'tagesschau',
'wiimmfi',
'wikia',
'afk',
'stats',
'btc',
'cats',
'cleverbot',
'imgur',
'banhammer',
'channels',
'plugins',
'help',
'greetings'
}
print ('enabling a few plugins - saving to redis set telegram:enabled_plugins')
for _,plugin in pairs(enabled_plugins) do
redis:sadd("telegram:enabled_plugins", plugin)
end
end
function load_cred() function load_cred()
if redis:exists("telegram:credentials") == false then if redis:exists("telegram:credentials") == false then
-- If credentials hash doesnt exists -- If credentials hash doesnt exists

View File

@ -7,16 +7,17 @@ about.command = 'about'
about.doc = '`Sendet Informationen über den Bot.`' about.doc = '`Sendet Informationen über den Bot.`'
about.triggers = { about.triggers = {
'' '/about'
} }
function about:action(msg, config) function about:action(msg, config)
-- Filthy hack, but here is where we'll stop forwarded messages from hitting -- Filthy hack, but here is where we'll stop forwarded messages from hitting
-- other plugins. -- other plugins.
if msg.forward_from then return end -- disabled to restore old behaviour
-- if msg.forward_from then return end
local output = config.about_text .. '\nBrawlbot v2, basierend auf Otouto v'..bot.version..' von topkecleon.' local output = config.about_text .. '\nBrawlbot v2, basierend auf Otouto von topkecleon.'
if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id) if (msg.new_chat_participant and msg.new_chat_participant.id == self.info.id)
or msg.text_lower:match('^'..config.cmd_pat..'about') or msg.text_lower:match('^'..config.cmd_pat..'about')

View File

@ -151,8 +151,8 @@ function banhammer:pre_process(msg, self, config)
msg.entities = '' msg.entities = ''
end end
else -- else
print('Whitelist not enabled or is sudo') -- print('Whitelist not enabled or is sudo')
end end
return msg return msg

View File

@ -0,0 +1,90 @@
local channels = {}
local bindings = require('otouto.bindings')
local utilities = require('otouto.utilities')
local redis = (loadfile "./otouto/redis.lua")()
channels.command = 'channel <nur für Superuser>'
function channels:init(config)
channels.triggers = {
"^/channel? (enable)",
"^/channel? (disable)"
}
channels.doc = [[*
]]..config.cmd_pat..[[channel* _<enable>_/_<disable>_: Aktiviert/deaktiviert den Bot im Chat]]
end
-- Checks if bot was disabled on specific chat
function channels:is_channel_disabled(msg)
local hash = 'chat:'..msg.chat.id..':disabled'
local disabled = redis:get(hash)
if not disabled or disabled == "false" then
return false
end
return disabled
end
function channels:enable_channel(msg)
local hash = 'chat:'..msg.chat.id..':disabled'
local disabled = redis:get(hash)
if disabled then
print('Setting redis variable '..hash..' to false')
redis:set(hash, false)
return 'Channel aktiviert'
else
return 'Channel ist nicht deaktiviert!'
end
end
function channels:disable_channel(msg)
local hash = 'chat:'..msg.chat.id..':disabled'
local disabled = redis:get(hash)
if disabled ~= "true" then
print('Setting redis variable '..hash..' to true')
redis:set(hash, true)
return 'Channel deaktiviert'
else
return 'Channel ist bereits deaktiviert!'
end
end
function channels:pre_process(msg, self, config)
-- If is sudo can reeanble the channel
if is_sudo(msg, config) then
if msg.text == "/channel enable" then
channels:enable_channel(msg)
end
end
if channels:is_channel_disabled(msg) then
print('Channel wurde deaktiviert')
msg.text = ''
msg.text_lower = ''
msg.entities = ''
end
return msg
end
function channels:action(msg, config)
if msg.from.id ~= config.admin then
utilities.send_reply(self, msg, config.errors.sudo)
return
end
-- Enable a channel
if matches[1] == 'enable' then
utilities.send_reply(self, msg, channels:enable_channel(msg))
return
end
-- Disable a channel
if matches[1] == 'disable' then
utilities.send_reply(self, msg, channels:disable_channel(msg))
return
end
end
return channels

View File

@ -8,7 +8,7 @@ local cmd_pat -- Prevents the command from being uncallable.
function control:init(config) function control:init(config)
cmd_pat = config.cmd_pat cmd_pat = config.cmd_pat
control.triggers = utilities.triggers(self.info.username, cmd_pat, control.triggers = utilities.triggers(self.info.username, cmd_pat,
{'^'..cmd_pat..'script'}):t('reload', true):t('halt').table {'^'..cmd_pat..'script'}):t('restart', true):t('halt').table
end end
function control:action(msg, config) function control:action(msg, config)
@ -19,7 +19,7 @@ function control:action(msg, config)
if msg.date < os.time() - 1 then return end if msg.date < os.time() - 1 then return end
if msg.text_lower:match('^'..cmd_pat..'reload') then if msg.text_lower:match('^'..cmd_pat..'restart') then
for pac, _ in pairs(package.loaded) do for pac, _ in pairs(package.loaded) do
if pac:match('^otouto%.plugins%.') then if pac:match('^otouto%.plugins%.') then
package.loaded[pac] = nil package.loaded[pac] = nil

228
otouto/plugins/plugins.lua Normal file
View File

@ -0,0 +1,228 @@
local plugin_manager = {}
local bindings = require('otouto.bindings')
local utilities = require('otouto.utilities')
local redis = (loadfile "./otouto/redis.lua")()
function plugin_manager:init(config)
plugin_manager.triggers = {
"^/plugins$",
"^/plugins? (enable) ([%w_%.%-]+)$",
"^/plugins? (disable) ([%w_%.%-]+)$",
"^/plugins? (enable) ([%w_%.%-]+) (chat) (%d+)",
"^/plugins? (enable) ([%w_%.%-]+) (chat)",
"^/plugins? (disable) ([%w_%.%-]+) (chat) (%d+)",
"^/plugins? (disable) ([%w_%.%-]+) (chat)",
"^/plugins? (reload)$",
"^/(reload)$"
}
plugin_manager.doc = [[*
]]..config.cmd_pat..[[plugins*: Listet alle Plugins auf
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_: Aktiviert/deaktiviert Plugin
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_ chat: Aktiviert/deaktiviert Plugin im aktuellen Chat
*]]..config.cmd_pat..[[plugins* _enable/disable_ _<Plugin>_ _<chat#id>_: Aktiviert/deaktiviert Plugin in diesem Chat
*]]..config.cmd_pat..[[reload*: Lädt Plugins neu]]
end
plugin_manager.command = 'plugins <nur für Superuser>'
-- Returns the key (index) in the config.enabled_plugins table
function plugin_manager:plugin_enabled(name, chat)
for k,v in pairs(enabled_plugins) do
if name == v then
return k
end
end
-- If not found
return false
end
-- Returns true if file exists in plugins folder
function plugin_manager:plugin_exists(name)
for k,v in pairs(plugins_names()) do
if name..'.lua' == v then
return true
end
end
return false
end
function plugin_manager:list_plugins()
local text = ''
for k, v in pairs(plugins_names()) do
-- ✔ enabled, ❌ disabled
local status = ''
-- Check if is enabled
for k2, v2 in pairs(enabled_plugins) do
if v == v2..'.lua' then
status = ''
end
end
if not only_enabled or status == '' then
-- get the name
v = string.match (v, "(.*)%.lua")
text = text..v..' '..status..'\n'
end
end
return text
end
function plugin_manager:reload_plugins(self, config, plugin_name, status)
self.plugins = {}
load_plugins()
for _,v in ipairs(enabled_plugins) do
local p = require('otouto.plugins.'..v)
print('loading plugin',v)
table.insert(self.plugins, p)
if p.init then p.init(self, config) end
end
if plugin_name then
return 'Plugin '..plugin_name..' wurde '..status
else
return 'Plugins neu geladen'
end
end
function plugin_manager:enable_plugin(self, config, plugin_name)
print('checking if '..plugin_name..' exists')
-- Check if plugin is enabled
if plugin_manager:plugin_enabled(plugin_name) then
return 'Plugin '..plugin_name..' ist schon aktiviert'
end
-- Checks if plugin exists
if plugin_manager:plugin_exists(plugin_name) then
-- Add to redis set
redis:sadd('telegram:enabled_plugins', plugin_name)
print(plugin_name..' saved to redis set telegram:enabled_plugins')
-- Reload the plugins
return plugin_manager:reload_plugins(self, config, plugin_name, 'aktiviert')
else
return 'Plugin '..plugin_name..' existiert nicht'
end
end
function plugin_manager:disable_plugin(self, config, name, chat)
-- Check if plugins exists
if not plugin_manager:plugin_exists(name) then
return 'Plugin '..name..' existiert nicht'
end
local k = plugin_manager:plugin_enabled(name)
-- Check if plugin is enabled
if not k then
return 'Plugin '..name..' ist nicht aktiviert'
end
-- Disable and reload
redis:srem('telegram:enabled_plugins', name)
print(name..' saved to redis set telegram:enabled_plugins')
return plugin_manager:reload_plugins(self, config, name, 'deaktiviert')
end
function plugin_manager:disable_plugin_on_chat(msg, plugin)
if not plugin_manager:plugin_exists(plugin) then
return "Plugin existiert nicht!"
end
if not msg.chat then
hash = 'chat:'..msg..':disabled_plugins'
else
hash = get_redis_hash(msg, 'disabled_plugins')
end
local disabled = redis:hget(hash, plugin)
if disabled ~= 'true' then
print('Setting '..plugin..' in redis hash '..hash..' to true')
redis:hset(hash, plugin, true)
return 'Plugin '..plugin..' für diesen Chat deaktiviert.'
else
return 'Plugin '..plugin..' wurde für diesen Chat bereits deaktiviert.'
end
end
function plugin_manager:reenable_plugin_on_chat(msg, plugin)
if not plugin_manager:plugin_exists(plugin) then
return "Plugin existiert nicht!"
end
if not msg.chat then
hash = 'chat:'..msg..':disabled_plugins'
else
hash = get_redis_hash(msg, 'disabled_plugins')
end
local disabled = redis:hget(hash, plugin)
if disabled == nil then return 'Es gibt keine deaktivierten Plugins für disen Chat.' end
if disabled == 'true' then
print('Setting '..plugin..' in redis hash '..hash..' to false')
redis:hset(hash, plugin, false)
return 'Plugin '..plugin..' wurde für diesen Chat reaktiviert.'
else
return 'Plugin '..plugin..' ist nicht deaktiviert.'
end
end
function plugin_manager:action(msg, config)
if msg.from.id ~= config.admin then
utilities.send_reply(self, msg, config.errors.sudo)
return
end
-- Show the available plugins
if matches[1] == '/plugins' then
utilities.send_reply(self, msg, plugin_manager:list_plugins())
return
end
-- Reenable a plugin for this chat
if matches[1] == 'enable' and matches[3] == 'chat' then
local plugin = matches[2]
if matches[4] then
local id = matches[4]
print("enable "..plugin..' on chat#id'..id)
utilities.send_reply(self, msg, plugin_manager:reenable_plugin_on_chat(id, plugin))
return
else
print("enable "..plugin..' on this chat')
utilities.send_reply(self, msg, plugin_manager:reenable_plugin_on_chat(msg, plugin))
return
end
end
-- Enable a plugin
if matches[1] == 'enable' then
local plugin_name = matches[2]
print("enable: "..matches[2])
utilities.send_reply(self, msg, plugin_manager:enable_plugin(self, config, plugin_name))
return
end
-- Disable a plugin on a chat
if matches[1] == 'disable' and matches[3] == 'chat' then
local plugin = matches[2]
if matches[4] then
local id = matches[4]
print("disable "..plugin..' on chat#id'..id)
utilities.send_reply(self, msg, plugin_manager:disable_plugin_on_chat(id, plugin))
return
else
print("disable "..plugin..' on this chat')
utilities.send_reply(self, msg, plugin_manager:disable_plugin_on_chat(msg, plugin))
return
end
end
-- Disable a plugin
if matches[1] == 'disable' then
print("disable: "..matches[2])
utilities.send_reply(self, msg, plugin_manager:disable_plugin(self, config, matches[2]))
return
end
-- Reload all the plugins!
if matches[1] == 'reload' then
utilities.send_reply(self, msg, plugin_manager:reload_plugins(self, config))
return
end
end
return plugin_manager

View File

@ -589,8 +589,40 @@ utilities.char = {
em_dash = '' em_dash = ''
} }
-- taken from http://stackoverflow.com/a/11130774/3163199
function scandir(directory)
local i, t, popen = 0, {}, io.popen
for filename in popen('ls -a "'..directory..'"'):lines() do
i = i + 1
t[i] = filename
end
return t
end
-- Returns at table of lua files inside plugins
function plugins_names()
local files = {}
for k, v in pairs(scandir("otouto/plugins")) do
-- Ends with .lua
if (v:match(".lua$")) then
table.insert(files, v)
end
end
return files
end
-- Function name explains what it does.
function file_exists(name)
local f = io.open(name,"r")
if f ~= nil then
io.close(f)
return true
else
return false
end
end
-- Returns a table with matches or nil -- Returns a table with matches or nil
--function match_pattern(pattern, text, lower_case)
function match_pattern(pattern, text) function match_pattern(pattern, text)
if text then if text then
local matches = { string.match(text, pattern) } local matches = { string.match(text, pattern) }