bustin
This commit is contained in:
parent
3dd57d3bdc
commit
38c9e580b9
|
@ -6,87 +6,87 @@ local class = import("classes.baseclass")
|
||||||
local table_utils = import("table-utils")
|
local table_utils = import("table-utils")
|
||||||
local acl = class("ACL")
|
local acl = class("ACL")
|
||||||
function acl:__init()
|
function acl:__init()
|
||||||
self.user_rules = {}
|
self.user_rules = {}
|
||||||
self.group_rules = {}
|
self.group_rules = {}
|
||||||
end
|
end
|
||||||
function acl:set_user_rule(user_id,status)
|
function acl:set_user_rule(user_id,status)
|
||||||
assert(
|
assert(
|
||||||
(status == nil) or (status == 0) or (status == -1) or (status == 1),
|
(status == nil) or (status == 0) or (status == -1) or (status == 1),
|
||||||
"invalid status setting"
|
"invalid status setting"
|
||||||
)
|
)
|
||||||
self.user_rules[user_id] = status
|
self.user_rules[user_id] = status
|
||||||
end
|
end
|
||||||
function acl:set_group_rule(group_id,status)
|
function acl:set_group_rule(group_id,status)
|
||||||
assert(
|
assert(
|
||||||
(status == nil) or (status == 0) or (status == -1) or (status == 1),
|
(status == nil) or (status == 0) or (status == -1) or (status == 1),
|
||||||
"invalid status setting"
|
"invalid status setting"
|
||||||
)
|
)
|
||||||
self.group_rules[group_id] = status
|
self.group_rules[group_id] = status
|
||||||
end
|
end
|
||||||
function acl:check_user(user_id)
|
function acl:check_user(user_id)
|
||||||
if self.user_rules[user_id] and self.user_rules[user_id] ~= 0 then
|
if self.user_rules[user_id] and self.user_rules[user_id] ~= 0 then
|
||||||
return true,(self.user_rules[user_id] == 1)
|
return true,(self.user_rules[user_id] == 1)
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function acl:check_group(groups)
|
function acl:check_group(groups)
|
||||||
local allow = false
|
local allow = false
|
||||||
local found = false
|
local found = false
|
||||||
for k,v in pairs(groups) do
|
for k,v in pairs(groups) do
|
||||||
if self.group_rules[v] then
|
if self.group_rules[v] then
|
||||||
found = true
|
found = true
|
||||||
allow = self.group_rules[v]
|
allow = self.group_rules[v]
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
return found,(allow and allow == 1)
|
||||||
return found,(allow and allow == 1)
|
|
||||||
end
|
end
|
||||||
function acl:export_all_lists()
|
function acl:export_all_lists()
|
||||||
local lists = {
|
local lists = {
|
||||||
users = "",
|
users = "",
|
||||||
groups = ""
|
groups = ""
|
||||||
}
|
}
|
||||||
for k,v in pairs(self.user_rules) do
|
for k,v in pairs(self.user_rules) do
|
||||||
lists.users = lists.users..k..":"..tostring(v)..";\n"
|
lists.users = lists.users..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
for k,v in pairs(self.group_rules) do
|
for k,v in pairs(self.group_rules) do
|
||||||
lists.groups = lists.groups..k..":"..tostring(v)..";\n"
|
lists.groups = lists.groups..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
return lists
|
return lists
|
||||||
end
|
end
|
||||||
function acl:export_user_list()
|
function acl:export_user_list()
|
||||||
local list = ""
|
local list = ""
|
||||||
for k,v in pairs(self.user_rules) do
|
for k,v in pairs(self.user_rules) do
|
||||||
list = list..k..":"..tostring(v)..";\n"
|
list = list..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
function acl:export_group_list()
|
function acl:export_group_list()
|
||||||
local list = ""
|
local list = ""
|
||||||
for k,v in pairs(self.group_rules) do
|
for k,v in pairs(self.group_rules) do
|
||||||
list = list..k..":"..tostring(v)..";\n"
|
list = list..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
function acl:export_snapshot()
|
function acl:export_snapshot()
|
||||||
return {
|
return {
|
||||||
user_rules = bot_utils.deepcopy(self.user_rules),
|
user_rules = bot_utils.deepcopy(self.user_rules),
|
||||||
group_rules = bot_utils.deepcopy(self.group_rules)
|
group_rules = bot_utils.deepcopy(self.group_rules)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function acl:import_snapshot(t)
|
function acl:import_snapshot(t)
|
||||||
self.user_rules = t.user_rules
|
self.user_rules = t.user_rules
|
||||||
self.group_rules = t.group_rules
|
self.group_rules = t.group_rules
|
||||||
end
|
end
|
||||||
function acl:import_user_list(list)
|
function acl:import_user_list(list)
|
||||||
list:gsub("(%w+):(%d+)",function(id,status)
|
list:gsub("(%w+):(%d+)",function(id,status)
|
||||||
self.user_rules[id] = status
|
self.user_rules[id] = status
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
function acl:import_group_list(list)
|
function acl:import_group_list(list)
|
||||||
list:gsub("(%w+):(%d+)",function(id,status)
|
list:gsub("(%w+):(%d+)",function(id,status)
|
||||||
self.group_rules[id] = status
|
self.group_rules[id] = status
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
return acl
|
return acl
|
||||||
|
|
|
@ -1,32 +1,32 @@
|
||||||
--class generator (for the purpose of creating classes)
|
--class generator (for the purpose of creating classes)
|
||||||
return function(name)
|
return function(name)
|
||||||
local new_class = {}
|
|
||||||
new_class.__classname = name or "Object"
|
|
||||||
new_class.__index = new_class
|
|
||||||
new_class.__new = function(self,...)
|
|
||||||
local obj = {}
|
|
||||||
--set metamethod proetection measures
|
|
||||||
setmetatable(obj,{__index = function(obj,key)
|
|
||||||
if key:find("^__") then
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
return self[key]
|
|
||||||
end
|
|
||||||
end,
|
|
||||||
__name = new_class.__classname})
|
|
||||||
if self.__init then
|
|
||||||
self.__init(obj,...)
|
|
||||||
end
|
|
||||||
return obj
|
|
||||||
end
|
|
||||||
new_class.extend = function(self,name)
|
|
||||||
local new_class = {}
|
local new_class = {}
|
||||||
new_class.__classname = name or "Object"
|
new_class.__classname = name or "Object"
|
||||||
new_class.__index = new_class
|
new_class.__index = new_class
|
||||||
setmetatable(new_class,{__index = self,__call = function(...) return new_class.__new(...) end, __name = new_class.__classname.." (class)"})
|
new_class.__new = function(self,...)
|
||||||
|
local obj = {}
|
||||||
|
--set metamethod proetection measures
|
||||||
|
setmetatable(obj,{__index = function(obj,key)
|
||||||
|
if key:find("^__") then
|
||||||
|
return nil
|
||||||
|
else
|
||||||
|
return self[key]
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__name = new_class.__classname})
|
||||||
|
if self.__init then
|
||||||
|
self.__init(obj,...)
|
||||||
|
end
|
||||||
|
return obj
|
||||||
|
end
|
||||||
|
new_class.extend = function(self,name)
|
||||||
|
local new_class = {}
|
||||||
|
new_class.__classname = name or "Object"
|
||||||
|
new_class.__index = new_class
|
||||||
|
setmetatable(new_class,{__index = self,__call = function(...) return new_class.__new(...) end, __name = new_class.__classname.." (class)"})
|
||||||
|
return new_class
|
||||||
|
end
|
||||||
|
--make our class callable; on call, it will initialize a new instance of itself
|
||||||
|
setmetatable(new_class,{__call = function(...) return new_class.__new(...) end, __name = new_class.__classname.." (class)"})
|
||||||
return new_class
|
return new_class
|
||||||
end
|
|
||||||
--make our class callable; on call, it will initialize a new instance of itself
|
|
||||||
setmetatable(new_class,{__call = function(...) return new_class.__new(...) end, __name = new_class.__classname.." (class)"})
|
|
||||||
return new_class
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,84 +7,84 @@ local enum_perms = discordia.enums.permission
|
||||||
--The following method extends the ACL class to work with rule-specific features,
|
--The following method extends the ACL class to work with rule-specific features,
|
||||||
--such as the role position
|
--such as the role position
|
||||||
function command_acl:check_group(roles)
|
function command_acl:check_group(roles)
|
||||||
local found = false
|
local found = false
|
||||||
local highest_role = nil
|
local highest_role = nil
|
||||||
local highest_role_status = nil
|
local highest_role_status = nil
|
||||||
for k,v in pairs(roles) do
|
for k,v in pairs(roles) do
|
||||||
if self.group_rules[v.id] then
|
if self.group_rules[tostring(v.id)] then
|
||||||
found = true
|
found = true
|
||||||
if not highest_role then
|
if not highest_role then
|
||||||
highest_role = v
|
highest_role = v
|
||||||
highest_role_status = self.group_rules[v.id]
|
highest_role_status = self.group_rules[tostring(v.id)]
|
||||||
end
|
end
|
||||||
if v.position > highest_role.position then
|
if v.position > highest_role.position then
|
||||||
highest_role = v
|
highest_role = v
|
||||||
highest_role_status = self.group_rules[v.id]
|
highest_role_status = self.group_rules[tostring(v.id)]
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
local allow = highest_role_status
|
||||||
local allow = highest_role_status
|
return found,(allow and allow == 1)
|
||||||
return found,(allow and allow == 1)
|
|
||||||
end
|
end
|
||||||
--The following methods extend the ACL class to add the "perm" permissions
|
--The following methods extend the ACL class to add the "perm" permissions
|
||||||
--(the fallback when no rule/user permissions are found)
|
--(the fallback when no rule/user permissions are found)
|
||||||
function command_acl:__init()
|
function command_acl:__init()
|
||||||
self.user_rules = {}
|
self.user_rules = {}
|
||||||
self.group_rules = {}
|
self.group_rules = {}
|
||||||
self.perm_rules = {}
|
self.perm_rules = {}
|
||||||
end
|
end
|
||||||
function command_acl:check_perm(perms)
|
function command_acl:check_perm(perms)
|
||||||
local output = true
|
local output = true
|
||||||
for k,v in pairs(self.perm_rules) do
|
for k,v in pairs(self.perm_rules) do
|
||||||
if (bit.band(perms[1],enum_perms[v]) == 0) then
|
if (bit.band(perms[1],enum_perms[v]) == 0) then
|
||||||
output = false
|
output = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return output
|
return output
|
||||||
end
|
end
|
||||||
function command_acl:set_perm_rules(list)
|
function command_acl:set_perm_rules(list)
|
||||||
assert(type(list)=="table","table expected, got "..type(list))
|
assert(type(list)=="table","table expected, got "..type(list))
|
||||||
self.perm_rules = list
|
self.perm_rules = list
|
||||||
end
|
end
|
||||||
function command_acl:export_all_lists()
|
function command_acl:export_all_lists()
|
||||||
local lists = {
|
local lists = {
|
||||||
users = "",
|
users = "",
|
||||||
groups = "",
|
groups = "",
|
||||||
perm = ""
|
perm = ""
|
||||||
}
|
}
|
||||||
for k,v in pairs(self.user_rules) do
|
for k,v in pairs(self.user_rules) do
|
||||||
lists.users = lists.users..k..":"..tostring(v)..";\n"
|
lists.users = lists.users..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
for k,v in pairs(self.group_rules) do
|
for k,v in pairs(self.group_rules) do
|
||||||
lists.groups = lists.groups..k..":"..tostring(v)..";\n"
|
lists.groups = lists.groups..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
for k,v in pairs(self.perm_rules) do
|
for k,v in pairs(self.perm_rules) do
|
||||||
lists.perm = lists.perm..k..":"..tostring(v)..";\n"
|
lists.perm = lists.perm..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
return lists
|
return lists
|
||||||
end
|
end
|
||||||
function command_acl:export_perm_list()
|
function command_acl:export_perm_list()
|
||||||
local list = ""
|
local list = ""
|
||||||
for k,v in pairs(self.perm_rules) do
|
for k,v in pairs(self.perm_rules) do
|
||||||
list = list..k..":"..tostring(v)..";\n"
|
list = list..k..":"..tostring(v)..";\n"
|
||||||
end
|
end
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
function command_acl:export_snapshot()
|
function command_acl:export_snapshot()
|
||||||
return {
|
return {
|
||||||
user_rules = table_utils.deepcopy(self.user_rules),
|
user_rules = table_utils.deepcopy(self.user_rules),
|
||||||
group_rules = table_utils.deepcopy(self.group_rules),
|
group_rules = table_utils.deepcopy(self.group_rules),
|
||||||
perm_rules = table_utils.deepcopy(self.perm_rules)
|
perm_rules = table_utils.deepcopy(self.perm_rules)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function command_acl:import_snapshot(t)
|
function command_acl:import_snapshot(t)
|
||||||
self.user_rules = t.user_rules
|
self.user_rules = t.user_rules
|
||||||
self.group_rules = t.group_rules
|
self.group_rules = t.group_rules
|
||||||
self.perm_rules = t.perm_rules
|
self.perm_rules = t.perm_rules
|
||||||
end
|
end
|
||||||
function command_acl:import_perm_list()
|
function command_acl:import_perm_list()
|
||||||
list:gsub("(%w+):(%d+)",function(id,status)
|
list:gsub("(%w+):(%d+)",function(id,status)
|
||||||
self.perm_rules[id] = status
|
self.perm_rules[id] = status
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
return command_acl
|
return command_acl
|
||||||
|
|
|
@ -9,108 +9,108 @@ local command_handler = class("Command-handler")
|
||||||
local table_utils = import("table-utils")
|
local table_utils = import("table-utils")
|
||||||
local purify = import("purify")
|
local purify = import("purify")
|
||||||
function command_handler:__init(parent_server)
|
function command_handler:__init(parent_server)
|
||||||
self.server_handler = assert(parent_server,"parent server handler not provided")
|
self.server_handler = assert(parent_server,"parent server handler not provided")
|
||||||
self.command_pool = {}
|
self.command_pool = {}
|
||||||
self.prefixes = {}
|
self.prefixes = {}
|
||||||
self.command_meta = {
|
self.command_meta = {
|
||||||
plugins = {},
|
plugins = {},
|
||||||
categories = {}
|
categories = {}
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
function command_handler:add_prefix(prefix)
|
function command_handler:add_prefix(prefix)
|
||||||
local purified_prefix = purify.purify_escapes(prefix)
|
local purified_prefix = purify.purify_escapes(prefix)
|
||||||
self.prefixes[purified_prefix] = purified_prefix
|
self.prefixes[purified_prefix] = purified_prefix
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
function command_handler:remove_prefix(prefix)
|
function command_handler:remove_prefix(prefix)
|
||||||
local purified_prefix = purify.purify_escapes(prefix)
|
local purified_prefix = purify.purify_escapes(prefix)
|
||||||
if self.prefixes[purified_prefix] or table_utils.count(self.prefixes) <= 1 then
|
if self.prefixes[purified_prefix] or table_utils.count(self.prefixes) <= 1 then
|
||||||
self.prefix[purified_prefix] = nil
|
self.prefix[purified_prefix] = nil
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false, (
|
return false, (
|
||||||
(self.prefixes[purified_prefix] and "No such prefix") or
|
(self.prefixes[purified_prefix] and "No such prefix") or
|
||||||
"Cannot remove the last remaining prefix"
|
"Cannot remove the last remaining prefix"
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function command_handler:get_prefixes()
|
function command_handler:get_prefixes()
|
||||||
return table_utils.deepcopy(self.prefixes)
|
return table_utils.deepcopy(self.prefixes)
|
||||||
end
|
end
|
||||||
function command_handler:add_command(command)
|
function command_handler:add_command(command)
|
||||||
assert(type(command) == "table","command object expected")
|
assert(type(command) == "table","command object expected")
|
||||||
local purified_name = purify.purify_escapes(command.name)
|
local purified_name = purify.purify_escapes(command.name)
|
||||||
self.command_pool[purified_name] = command
|
self.command_pool[purified_name] = command
|
||||||
if not self.command_meta.plugins[command.parent.name] then
|
if not self.command_meta.plugins[command.parent.name] then
|
||||||
self.command_meta.plugins[command.parent.name] = {}
|
self.command_meta.plugins[command.parent.name] = {}
|
||||||
end
|
end
|
||||||
if not self.command_meta.categories[command.options.category] then
|
if not self.command_meta.categories[command.options.category] then
|
||||||
self.command_meta.categories[command.options.category] = {}
|
self.command_meta.categories[command.options.category] = {}
|
||||||
end
|
end
|
||||||
table.insert(self.command_meta.categories[command.options.category],command.name)
|
table.insert(self.command_meta.categories[command.options.category],command.name)
|
||||||
table.insert(self.command_meta.plugins[command.parent.name],command.name)
|
table.insert(self.command_meta.plugins[command.parent.name],command.name)
|
||||||
return command
|
return command
|
||||||
end
|
end
|
||||||
function command_handler:remove_command(command)
|
function command_handler:remove_command(command)
|
||||||
assert(type(command) == "table","command object expected")
|
assert(type(command) == "table","command object expected")
|
||||||
local purified_name = purify.purify_escapes(command.name)
|
local purified_name = purify.purify_escapes(command.name)
|
||||||
if self.command_pool[purified_name] then
|
if self.command_pool[purified_name] then
|
||||||
local command = self.command_pool[purified_name]
|
local command = self.command_pool[purified_name]
|
||||||
--not exactly optimal, but lists are lists. can't do much about them.
|
--not exactly optimal, but lists are lists. can't do much about them.
|
||||||
table_utils.remove_value(self.command_meta.plugins[command.parent.name],command.name)
|
table_utils.remove_value(self.command_meta.plugins[command.parent.name],command.name)
|
||||||
if #self.command_meta.plugins[command.parent.name] == 0 then
|
if #self.command_meta.plugins[command.parent.name] == 0 then
|
||||||
self.command_meta.plugins[command.parent.name] = nil
|
self.command_meta.plugins[command.parent.name] = nil
|
||||||
|
end
|
||||||
|
table_utils.remove_value(self.command_meta.categories[command.options.category],command.name)
|
||||||
|
if #self.command_meta.categories[command.options.category] == 0 then
|
||||||
|
self.command_meta.categories[command.options.category] = nil
|
||||||
|
end
|
||||||
|
self.command_pool[purified_name] = nil
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
table_utils.remove_value(self.command_meta.categories[command.options.category],command.name)
|
|
||||||
if #self.command_meta.categories[command.options.category] == 0 then
|
|
||||||
self.command_meta.categories[command.options.category] = nil
|
|
||||||
end
|
|
||||||
self.command_pool[purified_name] = nil
|
|
||||||
return true
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
function command_handler:get_command(name)
|
function command_handler:get_command(name)
|
||||||
local purified_name = purify.purify_escapes(assert(type(name) == "string") and name)
|
local purified_name = purify.purify_escapes(assert(type(name) == "string") and name)
|
||||||
if self.command_pool[purified_name] then
|
if self.command_pool[purified_name] then
|
||||||
return self.command_pool[purified_name]
|
return self.command_pool[purified_name]
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function command_handler:get_commands(name)
|
function command_handler:get_commands(name)
|
||||||
local list = {}
|
local list = {}
|
||||||
for k,v in pairs(self.command_pool) do
|
for k,v in pairs(self.command_pool) do
|
||||||
table.insert(list,k)
|
table.insert(list,k)
|
||||||
end
|
end
|
||||||
return list
|
return list
|
||||||
end
|
end
|
||||||
function command_handler:get_commands_metadata()
|
function command_handler:get_commands_metadata()
|
||||||
return table_utils.deepcopy(self.command_meta)
|
return table_utils.deepcopy(self.command_meta)
|
||||||
end
|
end
|
||||||
function command_handler:handle(message)
|
function command_handler:handle(message)
|
||||||
for name,command in pairs(self.command_pool) do
|
for name,command in pairs(self.command_pool) do
|
||||||
if command.options.regex then
|
if command.options.regex then
|
||||||
if message.content:match(command.options.regex) then
|
if message.content:match(command.options.regex) then
|
||||||
command:exec(message)
|
command:exec(message)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
if command.options.prefix then
|
if command.options.prefix then
|
||||||
for _,prefix in pairs(self.prefixes) do
|
for _,prefix in pairs(self.prefixes) do
|
||||||
if message.content:match("^"..prefix..name.."$") or message.content:match("^"..prefix..name.."%s") then
|
if message.content:match("^"..prefix..name.."$") or message.content:match("^"..prefix..name.."%s") then
|
||||||
command:exec(message)
|
command:exec(message)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if message.content:match("^"..name.."$") or message.content:match("^"..name.."%s") then
|
||||||
|
command:exec(message)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
|
||||||
if message.content:match("^"..name.."$") or message.content:match("^"..name.."%s") then
|
|
||||||
command:exec(message)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return command_handler
|
return command_handler
|
||||||
|
|
|
@ -7,178 +7,162 @@ local command = class("Command")
|
||||||
local acl = import("classes.command-acl")
|
local acl = import("classes.command-acl")
|
||||||
local discordia = import("discordia")
|
local discordia = import("discordia")
|
||||||
function command:__init(name,callback)
|
function command:__init(name,callback)
|
||||||
self.rules = acl()
|
assert(name:match("^[-_%w]+$"),"Name can only contain alphanumeric characters, underscores or dashes")
|
||||||
self.name = name
|
self.rules = acl()
|
||||||
self.timer = discordia.Date():toMilliseconds()
|
self.name = name
|
||||||
self.options = {
|
self.timer = discordia.Date():toMilliseconds()
|
||||||
allow_bots = false, --allow bots to execute the command
|
self.options = {
|
||||||
typing_decorator = false, --set if the bot should be "typing" while the command executes
|
allow_bots = false, --allow bots to execute the command
|
||||||
category = "None", --set category for the command
|
typing_decorator = false, --set if the bot should be "typing" while the command executes
|
||||||
prefix = true, --if true and if regex isn't enabled, check for prefix at the start. if not, don't check for prefix
|
category = "None", --set category for the command
|
||||||
regex = false, --check if the message matches this regular expression (should be a string)
|
prefix = true, --if true check for prefix at the start. if not, don't check for prefix
|
||||||
no_parsing = false, --check if you want to disable the message argument parsing process
|
no_parsing = false, --check if you want to disable the message argument parsing process
|
||||||
timeout = 1000, --set the timeout for a command
|
timeout = 1000, --set the timeout for a command
|
||||||
}
|
}
|
||||||
if type(callback) == "table" then
|
if type(callback) == "table" then
|
||||||
for k,v in pairs(callback.options or {}) do
|
for k,v in pairs(callback.options or {}) do
|
||||||
self.options[k] = v
|
self.options[k] = v
|
||||||
|
end
|
||||||
|
self.callback = callback.exec
|
||||||
|
self.args = callback.args or self.args
|
||||||
|
if callback.users then
|
||||||
|
for k,v in pairs(callback.users) do
|
||||||
|
self.rules:set_user_rule(k,v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if callback.roles then
|
||||||
|
for k,v in pairs(callback.roles) do
|
||||||
|
self.rules:set_group_rule(k,v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
callback.perms = callback.perms and self.rules:set_perm_rules(callback.perms)
|
||||||
|
callback.help = callback.help and self:set_help(callback.help,callback.usage)
|
||||||
|
elseif type(callback) == "function" then
|
||||||
|
self.callback = callback
|
||||||
end
|
end
|
||||||
self.callback = callback.exec
|
|
||||||
self.args = callback.args or self.args
|
|
||||||
if callback.users then
|
|
||||||
for k,v in pairs(callback.users) do
|
|
||||||
self.rules:set_user_rule(k,v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if callback.roles then
|
|
||||||
for k,v in pairs(callback.roles) do
|
|
||||||
self.rules:set_group_rule(k,v)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if callback.perms then
|
|
||||||
self.rules:set_perm_rules(callback.perms)
|
|
||||||
end
|
|
||||||
if callback.help then
|
|
||||||
self:set_help(callback.help,callback.usage)
|
|
||||||
end
|
|
||||||
elseif type(callback) == "function" then
|
|
||||||
self.callback = callback
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
--set the callback to be called on comm:exec(msg)
|
--set the callback to be called on comm:exec(msg)
|
||||||
function command:set_callback(fn)
|
function command:set_callback(fn)
|
||||||
assert(type(fn) == "function","function expected, got "..type(fn))
|
assert(type(fn) == "function","function expected, got "..type(fn))
|
||||||
self.callback = fn
|
self.callback = fn
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
--generate help using only description and usage, or nothing at all
|
--generate help using only description and usage, or nothing at all
|
||||||
function command:generate_help(description,usage)
|
function command:generate_help(description,usage)
|
||||||
assert(not description or (type(description) == "string"),"Description should be either string or nil, got "..type(description))
|
assert(not description or (type(description) == "string"),"Description should be either string or nil, got "..type(description))
|
||||||
assert(not usage or (type(usage) == "string"),"Usage should be either string or nil, got "..type(usage))
|
assert(not usage or (type(usage) == "string"),"Usage should be either string or nil, got "..type(usage))
|
||||||
local backup_usage_str
|
local backup_usage_str
|
||||||
if self.args then
|
if self.args then
|
||||||
backup_usage_str = self.name.." <"..table.concat(self.args,"> <")..">"
|
backup_usage_str = self.name.." <"..table.concat(self.args,"> <")..">"
|
||||||
else
|
else
|
||||||
backup_usage_str = "not defined"
|
backup_usage_str = "not defined"
|
||||||
end
|
end
|
||||||
local permissions = table.concat(self.rules:export_snapshot()["perms"] or {},"\n")
|
local permissions = table.concat(self.rules:export_snapshot()["perms"] or {"All"},"\n")
|
||||||
if permissions == "" then
|
self.help = {embed = {
|
||||||
permissions = "All"
|
title = "Help for ``"..self.name.."``",
|
||||||
end
|
description = description,
|
||||||
self.help = {embed = {
|
fields = {
|
||||||
title = "Help for ``"..self.name.."``",
|
{name = "Usage: ",value = usage or backup_usage_str},
|
||||||
description = description,
|
{name = "Perms: ",value = permissions}
|
||||||
fields = {
|
}
|
||||||
{name = "Usage: ",value = usage or backup_usage_str},
|
}}
|
||||||
{name = "Perms: ",value = permissions}
|
return self
|
||||||
}
|
|
||||||
}}
|
|
||||||
return self
|
|
||||||
end
|
end
|
||||||
--set the help message to be sent
|
--set the help message to be sent
|
||||||
function command:set_help(obj,usage)
|
function command:set_help(obj,usage)
|
||||||
if type(obj) == "string" then
|
if type(obj) == "table" then
|
||||||
self:generate_help(obj,usage)
|
self.help = obj
|
||||||
elseif type(obj) == "table" then
|
else
|
||||||
self.help = obj
|
self:generate_help(obj,
|
||||||
else
|
(type(usage) == "string" and usage)
|
||||||
error("Type "..type(obj).." cannot be set as a help message")
|
or "No description provided.")
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
--print the help message, or generate it if there is none
|
--print the help message, or generate it if there is none
|
||||||
function command:get_help()
|
function command:get_help()
|
||||||
if not self.help then
|
if not self.help then
|
||||||
self:generate_help("Description not defined")
|
self:generate_help("Description not defined")
|
||||||
end
|
end
|
||||||
return self.help
|
return self.help
|
||||||
end
|
end
|
||||||
function command:set_timeout_callback(fn)
|
function command:set_timeout_callback(fn)
|
||||||
assert(type(fn) == "function","function expected, got "..type(fn))
|
assert(type(fn) == "function","function expected, got "..type(fn))
|
||||||
self.timeout_callback = fn
|
self.timeout_callback = fn
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
--check the permissions for command
|
--check the permissions for command
|
||||||
function command:check_permissions(message)
|
function command:check_permissions(message)
|
||||||
if message.author.bot and (not self.options.allow_bots) then
|
if message.author.bot and (not self.options.allow_bots) then
|
||||||
return false
|
return false
|
||||||
end
|
|
||||||
if discordia.Date():toMilliseconds()-self.options.timeout < self.timer then
|
|
||||||
if self.timeout_callback then
|
|
||||||
self.timeout_callback(fn)
|
|
||||||
return false
|
|
||||||
end
|
end
|
||||||
end
|
if discordia.Date():toMilliseconds()-self.options.timeout < self.timer then
|
||||||
self.timer = discordia.Date():toMilliseconds()
|
if self.timeout_callback then
|
||||||
if self.rules:check_user(message.author.id) then
|
self.timeout_callback(message)
|
||||||
local found,allow = self.rules:check_user(message.author.id)
|
return false
|
||||||
return allow
|
end
|
||||||
end
|
end
|
||||||
if self.rules:check_group(message.member.roles) then
|
self.timer = discordia.Date():toMilliseconds()
|
||||||
local found,allow = self.rules:check_group(message.member.roles)
|
if self.rules:check_user(tostring(message.author.id)) then
|
||||||
return allow
|
local found,allow = self.rules:check_user(tostring(message.author.id))
|
||||||
end
|
return allow
|
||||||
return self.rules:check_perm(message.member:getPermissions(message.channel))
|
end
|
||||||
|
if self.rules:check_group(message.member.roles) then
|
||||||
|
local found,allow = self.rules:check_group(message.member.roles)
|
||||||
|
return allow
|
||||||
|
end
|
||||||
|
return self.rules:check_perm(message.member:getPermissions(message.channel))
|
||||||
end
|
end
|
||||||
--the main entry point for the command - execute the callback within after
|
--the main entry point for the command - execute the callback within after
|
||||||
--multiple checks
|
--multiple checks
|
||||||
function command:exec(message,args,opts)
|
function command:exec(message,args,opts)
|
||||||
local exec = self.callback
|
local exec = self.callback
|
||||||
if not self.callback then
|
if not self.callback then
|
||||||
error("Callback not set for command "..self.name)
|
error("Callback not set for command "..self.name)
|
||||||
end
|
end
|
||||||
if self.decorator then
|
if self.decorator then
|
||||||
self.callback = self.decorator(self.callback)
|
self.callback = self.decorator(self.callback)
|
||||||
end
|
end
|
||||||
local content
|
|
||||||
if self.options.regex then
|
|
||||||
content = message.content
|
|
||||||
else
|
|
||||||
local strstart,strend = message.content:find(self.name,1,true)
|
local strstart,strend = message.content:find(self.name,1,true)
|
||||||
content = message.content:sub(strend+1,-1)
|
content = message.content:sub(strend+1,-1)
|
||||||
end
|
if self:check_permissions(message) then
|
||||||
if self:check_permissions(message) then
|
if self.options.typing_decorator then
|
||||||
if self.options.typing_decorator then
|
message.channel:broadcastTyping()
|
||||||
message.channel:broadcastTyping()
|
|
||||||
end
|
|
||||||
local status,args,opts,err = import("air").parse(content,self.args,message.client,message.guild.id)
|
|
||||||
if status then
|
|
||||||
local callst,status,response = pcall(self.callback,message,args,opts)
|
|
||||||
if callst then
|
|
||||||
if type(status) == "boolean" then
|
|
||||||
if status then
|
|
||||||
message:addReaction("✅")
|
|
||||||
else
|
|
||||||
message:addReaction("❌")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
else
|
local status,args,opts,err = import("air").parse(content,self.args,message.client,message.guild.id)
|
||||||
message:addReaction("⚠️")
|
if status then
|
||||||
message:reply("An internal error occured: "..status)
|
local callst,status,response = pcall(self.callback,message,args,opts)
|
||||||
end
|
if callst then
|
||||||
else
|
if type(status) == "boolean" then
|
||||||
message:addReaction("❌")
|
message:addReaction((status and "✅") or "❌")
|
||||||
message:reply(err)
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
message:addReaction("⚠️")
|
||||||
|
message:reply("An internal error occured: "..status)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
message:addReaction("❌")
|
||||||
|
message:reply(err)
|
||||||
|
return
|
||||||
end
|
end
|
||||||
else
|
|
||||||
message:addReaction("❌")
|
message:addReaction("❌")
|
||||||
end
|
|
||||||
end
|
end
|
||||||
--add decorators for the callback
|
--add decorators for the callback
|
||||||
function command:set_decorator(fn)
|
function command:set_decorator(fn)
|
||||||
assert(type(fn) == "function","a decorator function expected, got "..type(fn))
|
assert(type(fn) == "function","a decorator function expected, got "..type(fn))
|
||||||
self.decorator = fn
|
self.decorator = fn
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
--get a list of all properties of the command
|
--get a list of all properties of the command
|
||||||
function command:get_properties()
|
function command:get_properties()
|
||||||
return {
|
return {
|
||||||
name = self.name,
|
name = self.name,
|
||||||
category = self.options.category,
|
category = self.options.category,
|
||||||
args = table_utils.deepcopy(self.args),
|
args = table_utils.deepcopy(self.args),
|
||||||
help = table_utils.deepcopy(self.help),
|
help = table_utils.deepcopy(self.help),
|
||||||
prefix = self.prefix
|
prefix = self.prefix
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
return command
|
return command
|
||||||
|
|
|
@ -2,94 +2,94 @@ local class = import("classes.baseclass")
|
||||||
local emitter_proxy = class("EmitterProxy")
|
local emitter_proxy = class("EmitterProxy")
|
||||||
|
|
||||||
function emitter_proxy:__init(emitter)
|
function emitter_proxy:__init(emitter)
|
||||||
self.original = emitter
|
self.original = emitter
|
||||||
self.callback_pool = {}
|
self.callback_pool = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:on(event,callback)
|
function emitter_proxy:on(event,callback)
|
||||||
if not self.callback_pool[event] then
|
if not self.callback_pool[event] then
|
||||||
self.callback_pool[event] = {}
|
self.callback_pool[event] = {}
|
||||||
end
|
end
|
||||||
self.callback_pool[event][callback] = callback
|
self.callback_pool[event][callback] = callback
|
||||||
self.original:on(event,callback)
|
self.original:on(event,callback)
|
||||||
return callback
|
return callback
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:once(event,callback)
|
function emitter_proxy:once(event,callback)
|
||||||
if not self.callback_pool[event] then
|
if not self.callback_pool[event] then
|
||||||
self.callback_pool[event] = {}
|
self.callback_pool[event] = {}
|
||||||
end
|
end
|
||||||
local wrapper = function(...)
|
local wrapper = function(...)
|
||||||
callback(...)
|
callback(...)
|
||||||
self.callback_pool[event][callback] = nil
|
self.callback_pool[event][callback] = nil
|
||||||
end
|
end
|
||||||
self.callback_pool[event][callback] = wrapper
|
self.callback_pool[event][callback] = wrapper
|
||||||
self.callback_pool[event][wrapper] = wrapper
|
self.callback_pool[event][wrapper] = wrapper
|
||||||
self.original:once(event,wrapper)
|
self.original:once(event,wrapper)
|
||||||
return callback
|
return callback
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:removeListener(event,callback)
|
function emitter_proxy:removeListener(event,callback)
|
||||||
if self.callback_pool[event] and self.callback_pool[event][callback] then
|
if self.callback_pool[event] and self.callback_pool[event][callback] then
|
||||||
self.callback_pool[event][callback] = nil
|
self.callback_pool[event][callback] = nil
|
||||||
self.original:removeListener(event,callback)
|
self.original:removeListener(event,callback)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:removeAllListeners(event,callback)
|
function emitter_proxy:removeAllListeners(event,callback)
|
||||||
if self.callback_pool[event] then
|
if self.callback_pool[event] then
|
||||||
for k,v in pairs(self.callback_pool[event]) do
|
for k,v in pairs(self.callback_pool[event]) do
|
||||||
self.original:removeListener(event,v)
|
self.original:removeListener(event,v)
|
||||||
|
end
|
||||||
|
self.callback_pool[event] = nil
|
||||||
end
|
end
|
||||||
self.callback_pool[event] = nil
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:listeners(event)
|
function emitter_proxy:listeners(event)
|
||||||
local copy = {}
|
local copy = {}
|
||||||
if self.callback_pool[event] then
|
if self.callback_pool[event] then
|
||||||
for k,v in pairs(self.callback_pool[event]) do
|
for k,v in pairs(self.callback_pool[event]) do
|
||||||
table.insert(copy,v)
|
table.insert(copy,v)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
return copy
|
||||||
return copy
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:listenerCount(event)
|
function emitter_proxy:listenerCount(event)
|
||||||
local count = 0
|
local count = 0
|
||||||
if event then
|
if event then
|
||||||
if self.callback_pool[event] then
|
if self.callback_pool[event] then
|
||||||
for k,v in pairs(self.callback_pool[event]) do
|
for k,v in pairs(self.callback_pool[event]) do
|
||||||
count = count + 1
|
count = count + 1
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for k,v in pairs(self.callback_pool) do
|
||||||
|
for k2,v2 in pairs(v) do
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
return count
|
||||||
for k,v in pairs(self.callback_pool) do
|
|
||||||
for k2,v2 in pairs(v) do
|
|
||||||
count = count + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return count
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:propogate(event,emitter)
|
function emitter_proxy:propogate(event,emitter)
|
||||||
if not self.callback_pool[event] then
|
if not self.callback_pool[event] then
|
||||||
self.callback_pool[event] = {}
|
self.callback_pool[event] = {}
|
||||||
end
|
end
|
||||||
local emitter_propogate_handler = function(...)
|
local emitter_propogate_handler = function(...)
|
||||||
emitter:emit(event,...)
|
emitter:emit(event,...)
|
||||||
end
|
end
|
||||||
self.callback_pool[event][emitter_propogate_handler] = emitter_propogate_handler
|
self.callback_pool[event][emitter_propogate_handler] = emitter_propogate_handler
|
||||||
self.original:on(event,emitter_propogate_handler)
|
self.original:on(event,emitter_propogate_handler)
|
||||||
return emitter_propogate_handler
|
return emitter_propogate_handler
|
||||||
end
|
end
|
||||||
|
|
||||||
function emitter_proxy:destroy()
|
function emitter_proxy:destroy()
|
||||||
for k,v in pairs(self.callback_pool) do
|
for k,v in pairs(self.callback_pool) do
|
||||||
for k2,v2 in pairs(v) do
|
for k2,v2 in pairs(v) do
|
||||||
self.original:removeListener(k,v2)
|
self.original:removeListener(k,v2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
return emitter_proxy
|
return emitter_proxy
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
local interface = {}
|
|
||||||
interface.wrapper = function(client,guild_id)
|
|
||||||
local new_i = {}
|
|
||||||
new_i.message = {}
|
|
||||||
new_i.message.get = function(channel,id)
|
|
||||||
local new_m = {}
|
|
||||||
local message = client.getMessage(id)
|
|
||||||
local new_m.content = message.content
|
|
||||||
local new_m.created_at = message.createdAt
|
|
||||||
local new_m.attachments = {}
|
|
||||||
for k,v in pairs(message.attachments) do
|
|
||||||
table.insert(new_m
|
|
|
@ -1,90 +0,0 @@
|
||||||
local RPC_server = import("classes.RPC-server")
|
|
||||||
local class = import("classes.baseclass")
|
|
||||||
local monitor = class("Monitor")
|
|
||||||
|
|
||||||
--we only generate proxies as far as 1 object deep.
|
|
||||||
--to provide seamlessness, metamethods that request object proxies from their
|
|
||||||
--pointers may be used on the client side
|
|
||||||
|
|
||||||
--pointers here mean tables that contain the __id and __type properties.
|
|
||||||
--they do not hold any info on the object besides its class name and id
|
|
||||||
|
|
||||||
--a lookup table of all classes that we do not ignore. we exclude client and containers
|
|
||||||
--because they might break the sandboxing. we *do not* want that.
|
|
||||||
local allowed_types = {
|
|
||||||
["guild"] = true,
|
|
||||||
["member"] = true,
|
|
||||||
["emoji"] = true,
|
|
||||||
["message"] = true,
|
|
||||||
["channel"] = true,
|
|
||||||
["role"] = true,
|
|
||||||
["user"] = true,
|
|
||||||
["invite"] = true,
|
|
||||||
["guildtextchannel"] = true,
|
|
||||||
["textchannel"] = true,
|
|
||||||
["iterable"] = true,
|
|
||||||
["cache"] = true,
|
|
||||||
["arrayiterable"] = true,
|
|
||||||
["filteretediterable"] = true,
|
|
||||||
["secondarycache"] = true,
|
|
||||||
["weakcache"] = true,
|
|
||||||
["tableiterable"] = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
--a lookup table of classes that can be explicitly converted to arrays.
|
|
||||||
local iterable_types = {
|
|
||||||
["iterable"] = true,
|
|
||||||
["cache"] = true,
|
|
||||||
["arrayiterable"] = true,
|
|
||||||
["filteretediterable"] = true,
|
|
||||||
["secondarycache"] = true,
|
|
||||||
["weakcache"] = true,
|
|
||||||
["tableiterable"] = true,
|
|
||||||
}
|
|
||||||
|
|
||||||
local comprehend_object = function(object)
|
|
||||||
local output
|
|
||||||
if (type(object) == "table") and (object.__class) then
|
|
||||||
--our object is an instance of a class
|
|
||||||
local class = object.__class.__name:lower()
|
|
||||||
if allowed_types[class] and (not iterable_types[class]) then
|
|
||||||
--our object can only be pointed to
|
|
||||||
output = {__id = object[k].id, __type = class}
|
|
||||||
else
|
|
||||||
--our object can be converted to an array
|
|
||||||
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--our object is either an atomic data type, a string or a table.
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local create_proxy = function(object)
|
|
||||||
local output = {}
|
|
||||||
for k,v in pairs(getmetatable(object).__getters) do
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local proto_api = {
|
|
||||||
msg = {
|
|
||||||
get = function(channel,id)
|
|
||||||
channel:getMessage(id)
|
|
||||||
end,
|
|
||||||
},
|
|
||||||
guild = {
|
|
||||||
|
|
||||||
},
|
|
||||||
member = {
|
|
||||||
|
|
||||||
},
|
|
||||||
channel = {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function monitor:__init(guild,options)
|
|
||||||
assert(guild,"No guild provided")
|
|
||||||
assert(options,"No options provided (arg 2)")
|
|
||||||
|
|
||||||
|
|
|
@ -12,130 +12,130 @@ local core = import("core")
|
||||||
local emitter_proxy = import("classes.emitter-proxy")
|
local emitter_proxy = import("classes.emitter-proxy")
|
||||||
local table_utils = import("table-utils")
|
local table_utils = import("table-utils")
|
||||||
function plugin_handler:__init(parent_server)
|
function plugin_handler:__init(parent_server)
|
||||||
assert(parent_server,"server handler to assign the plugin handler to has not been provided")
|
assert(parent_server,"server handler to assign the plugin handler to has not been provided")
|
||||||
self.server_handler = parent_server
|
self.server_handler = parent_server
|
||||||
self.plugins = {}
|
self.plugins = {}
|
||||||
self.plugin_info = {}
|
self.plugin_info = {}
|
||||||
self.plugin_paths = {}
|
self.plugin_paths = {}
|
||||||
self.server_handler.event_emitter:on("serverSaveConfig",function()
|
self.server_handler.event_emitter:on("serverSaveConfig",function()
|
||||||
print("[SERVER] Saving plugins configs")
|
print("[SERVER] Saving plugins configs")
|
||||||
for name,plugin in pairs(self.plugins) do
|
for name,plugin in pairs(self.plugins) do
|
||||||
self:save_plugin_config(name)
|
self:save_plugin_config(name)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:load_plugin_config(name)
|
function plugin_handler:load_plugin_config(name)
|
||||||
return file.readJSON(self.server_handler.config_path..name..".json",{})
|
return file.readJSON(self.server_handler.config_path..name..".json",{})
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:save_plugin_config(name)
|
function plugin_handler:save_plugin_config(name)
|
||||||
if self.plugins[name] then
|
if self.plugins[name] then
|
||||||
file.writeJSON(self.server_handler.config_path..name..".json",self.plugins[name].__env.config)
|
file.writeJSON(self.server_handler.config_path..name..".json",self.plugins[name].__env.config)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:add_plugin_folder(path)
|
function plugin_handler:add_plugin_folder(path)
|
||||||
assert(type(path) == "string","path should be a string, got "..type(path))
|
assert(type(path) == "string","path should be a string, got "..type(path))
|
||||||
table.insert(self.plugin_paths,path)
|
table.insert(self.plugin_paths,path)
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:scan_folder(path)
|
function plugin_handler:scan_folder(path)
|
||||||
local file = io.open(path.."/meta.json","r")
|
local file = io.open(path.."/meta.json","r")
|
||||||
if file then
|
if file then
|
||||||
local metadata,code,err = json.decode(file:read("*a"))
|
local metadata,code,err = json.decode(file:read("*a"))
|
||||||
if metadata and metadata.name then
|
if metadata and metadata.name then
|
||||||
self.plugin_info[metadata.name] = metadata
|
self.plugin_info[metadata.name] = metadata
|
||||||
self.plugin_info[metadata.name].path = path.."/"
|
self.plugin_info[metadata.name].path = path.."/"
|
||||||
self.plugin_info[metadata.name].loaded = false
|
self.plugin_info[metadata.name].loaded = false
|
||||||
end
|
end
|
||||||
file:close()
|
|
||||||
else
|
|
||||||
for k,v in pairs({"/init.lua","/main.lua"}) do
|
|
||||||
local file = io.open(path..v,"r")
|
|
||||||
if file then
|
|
||||||
local name = path:match("[^/]+$")
|
|
||||||
self.plugin_info[name] = {["main"]=v:gsub("/","")}
|
|
||||||
self.plugin_info[name].path = path.."/"
|
|
||||||
self.plugin_info[name].loaded = false
|
|
||||||
file:close()
|
file:close()
|
||||||
end
|
else
|
||||||
|
for k,v in pairs({"/init.lua","/main.lua"}) do
|
||||||
|
local file = io.open(path..v,"r")
|
||||||
|
if file then
|
||||||
|
local name = path:match("[^/]+$")
|
||||||
|
self.plugin_info[name] = {["main"]=v:gsub("/","")}
|
||||||
|
self.plugin_info[name].path = path.."/"
|
||||||
|
self.plugin_info[name].loaded = false
|
||||||
|
file:close()
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:update_plugin_info()
|
function plugin_handler:update_plugin_info()
|
||||||
for k,v in pairs(self.plugin_paths) do
|
for k,v in pairs(self.plugin_paths) do
|
||||||
if file.existsDir(v) then
|
if file.existsDir(v) then
|
||||||
file.ls(v):gsub("[^\n]+",function(c)
|
file.ls(v):gsub("[^\n]+",function(c)
|
||||||
self:scan_folder(v..c)
|
self:scan_folder(v..c)
|
||||||
end)
|
end)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:list_loadable()
|
function plugin_handler:list_loadable()
|
||||||
return table_utils.deepcopy(self.plugin_info)
|
return table_utils.deepcopy(self.plugin_info)
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:load(name)
|
function plugin_handler:load(name)
|
||||||
if not self.plugin_info[name] then
|
if not self.plugin_info[name] then
|
||||||
return false, "No such plugin"
|
return false, "No such plugin"
|
||||||
end
|
end
|
||||||
if not self.plugin_info[name].main then
|
if not self.plugin_info[name].main then
|
||||||
return false, "Plugin metadata entry doesn't specify the main file path or main file isn't found"
|
return false, "Plugin metadata entry doesn't specify the main file path or main file isn't found"
|
||||||
end
|
end
|
||||||
if self.plugin_info[name].loaded then
|
if self.plugin_info[name].loaded then
|
||||||
return false, "Plugin is already loaded"
|
return false, "Plugin is already loaded"
|
||||||
end
|
end
|
||||||
local environment = setmetatable({
|
local environment = setmetatable({
|
||||||
id = self.server_handler.id,
|
id = self.server_handler.id,
|
||||||
globals = self.server_handler.config,
|
globals = self.server_handler.config,
|
||||||
signals = emitter_proxy(self.server_handler.signal_emitter),
|
signals = emitter_proxy(self.server_handler.signal_emitter),
|
||||||
client = self.server_handler.client,
|
client = self.server_handler.client,
|
||||||
events = emitter_proxy(self.server_handler.event_emitter),
|
events = emitter_proxy(self.server_handler.event_emitter),
|
||||||
discordia = import("discordia"),
|
discordia = import("discordia"),
|
||||||
server = self.server_handler,
|
server = self.server_handler,
|
||||||
command_handler = self.server_handler.command_handler,
|
command_handler = self.server_handler.command_handler,
|
||||||
plugin_handler = self.server_handler.plugin_handler,
|
plugin_handler = self.server_handler.plugin_handler,
|
||||||
log = function() end,
|
log = function() end,
|
||||||
config = self:load_plugin_config(name),
|
config = self:load_plugin_config(name),
|
||||||
import = import,
|
import = import,
|
||||||
},{__index = _G})
|
},{__index = _G})
|
||||||
local plugin_meta = self.plugin_info[name]
|
local plugin_meta = self.plugin_info[name]
|
||||||
if file.exists(plugin_meta.path..plugin_meta.main) then
|
if file.exists(plugin_meta.path..plugin_meta.main) then
|
||||||
environment["plugin_path"] = plugin_meta.path
|
environment["plugin_path"] = plugin_meta.path
|
||||||
local plugin_content = file.read(plugin_meta.path..plugin_meta.main,"*a")
|
local plugin_content = file.read(plugin_meta.path..plugin_meta.main,"*a")
|
||||||
local plugin_loader,err = load(plugin_content,"plugin loader: "..plugin_meta.path..plugin_meta.main,nil,environment)
|
local plugin_loader,err = load(plugin_content,"plugin loader: "..plugin_meta.path..plugin_meta.main,nil,environment)
|
||||||
if plugin_loader then
|
if plugin_loader then
|
||||||
local plugin_object = plugin_loader()
|
local plugin_object = plugin_loader()
|
||||||
if plugin_object then
|
if plugin_object then
|
||||||
plugin_object.name = name
|
plugin_object.name = name
|
||||||
plugin_object:load(environment)
|
plugin_object:load(environment)
|
||||||
self.plugins[name] = plugin_object
|
self.plugins[name] = plugin_object
|
||||||
self.plugins[name].__env = environment
|
self.plugins[name].__env = environment
|
||||||
self.plugin_info[name].loaded = true
|
self.plugin_info[name].loaded = true
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false, "Plugin object missing"
|
return false, "Plugin object missing"
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
return false, err
|
return false, err
|
||||||
|
end
|
||||||
|
else
|
||||||
|
return false, "File specified as the main file is inaccessible"
|
||||||
end
|
end
|
||||||
else
|
|
||||||
return false, "File specified as the main file is inaccessible"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin_handler:unload(name)
|
function plugin_handler:unload(name)
|
||||||
if self.plugins[name] then
|
if self.plugins[name] then
|
||||||
self.plugins[name].__env.signals:destroy()
|
self.plugins[name].__env.signals:destroy()
|
||||||
self.plugins[name].__env.events:destroy()
|
self.plugins[name].__env.events:destroy()
|
||||||
self.plugins[name]:unload()
|
self.plugins[name]:unload()
|
||||||
self.plugin_info[name].loaded = false
|
self.plugin_info[name].loaded = false
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false,"Plugin is not loaded"
|
return false,"Plugin is not loaded"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return plugin_handler
|
return plugin_handler
|
||||||
|
|
|
@ -2,58 +2,58 @@ local class = import("classes.baseclass")
|
||||||
local plugin = class("Plugin")
|
local plugin = class("Plugin")
|
||||||
|
|
||||||
function plugin:__init()
|
function plugin:__init()
|
||||||
self.command_pool = {}
|
self.command_pool = {}
|
||||||
self.config = {}
|
self.config = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:load(environment)
|
function plugin:load(environment)
|
||||||
self.command_handler = environment.server.command_handler
|
self.command_handler = environment.server.command_handler
|
||||||
for k,v in pairs(self.command_pool) do
|
for k,v in pairs(self.command_pool) do
|
||||||
self.command_handler:add_command(v)
|
self.command_handler:add_command(v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:unload()
|
function plugin:unload()
|
||||||
if self.removal_callback then
|
if self.removal_callback then
|
||||||
self.removal_callback()
|
self.removal_callback()
|
||||||
end
|
end
|
||||||
for k,v in pairs(self.command_pool) do
|
for k,v in pairs(self.command_pool) do
|
||||||
self.command_handler:remove_command(v)
|
self.command_handler:remove_command(v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:for_all_commands(fn)
|
function plugin:for_all_commands(fn)
|
||||||
assert(type(fn)=="function","function expected, got "..type(fn))
|
assert(type(fn)=="function","function expected, got "..type(fn))
|
||||||
for k,v in pairs(self.command_pool) do
|
for k,v in pairs(self.command_pool) do
|
||||||
fn(v)
|
fn(v)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:for_every_new_command(fn)
|
function plugin:for_every_new_command(fn)
|
||||||
assert(type(fn)=="function","function expected, got "..type(fn))
|
assert(type(fn)=="function","function expected, got "..type(fn))
|
||||||
self.decorator = fn
|
self.decorator = fn
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:add_command(command_object)
|
function plugin:add_command(command_object)
|
||||||
if self.decorator then
|
if self.decorator then
|
||||||
self.fn(command_object)
|
self.fn(command_object)
|
||||||
end
|
end
|
||||||
command_object.parent = self
|
command_object.parent = self
|
||||||
self.command_pool[command_object] = command_object
|
self.command_pool[command_object] = command_object
|
||||||
--in post init state: we request the command handler to add the commands
|
--in post init state: we request the command handler to add the commands
|
||||||
--that way, we can link our plugin back to the command handler
|
--that way, we can link our plugin back to the command handler
|
||||||
if self.command_handler then
|
if self.command_handler then
|
||||||
self.command_handler:add_command(command_object)
|
self.command_handler:add_command(command_object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function plugin:remove_command(command_object)
|
function plugin:remove_command(command_object)
|
||||||
if self.command_pool[command_object] then
|
if self.command_pool[command_object] then
|
||||||
self.command_pool[command_object] = nil
|
self.command_pool[command_object] = nil
|
||||||
end
|
end
|
||||||
--remove command after post-init state
|
--remove command after post-init state
|
||||||
if self.command_handler then
|
if self.command_handler then
|
||||||
self.command_handler:remove_command(command_object)
|
self.command_handler:remove_command(command_object)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return plugin
|
return plugin
|
||||||
|
|
|
@ -8,96 +8,96 @@ local eventlist = import("eventlist")
|
||||||
local discordia = import("discordia")
|
local discordia = import("discordia")
|
||||||
|
|
||||||
local function check_partitioning(id,...)
|
local function check_partitioning(id,...)
|
||||||
args = {...}
|
args = {...}
|
||||||
v = args[1]
|
v = args[1]
|
||||||
if type(v) == "table" and v.guild and v.guild.id == id then
|
if type(v) == "table" and v.guild and v.guild.id == id then
|
||||||
return true
|
return true
|
||||||
elseif not (type(v) == "table") then
|
elseif not (type(v) == "table") then
|
||||||
return true
|
return true
|
||||||
elseif type(v) == "table" and (not v.guild) and (tostring(v):find("Guild: ")) and v.id == id then
|
elseif type(v) == "table" and (not v.guild) and (tostring(v):find("Guild: ")) and v.id == id then
|
||||||
return true
|
return true
|
||||||
elseif type(v) == "table" and (not v.guild) and (v.message) and (v.message.guild.id == id) then
|
elseif type(v) == "table" and (not v.guild) and (v.message) and (v.message.guild.id == id) then
|
||||||
return true
|
return true
|
||||||
else
|
else
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function server_handler:__init(client,guild,options)
|
function server_handler:__init(client,guild,options)
|
||||||
assert(type(client) == "table","discordia client expected, got "..type(client))
|
assert(type(client) == "table","discordia client expected, got "..type(client))
|
||||||
self.client = client
|
self.client = client
|
||||||
self.uptime = discordia.Date()
|
self.uptime = discordia.Date()
|
||||||
self.event_emitter = core.Emitter:new()
|
self.event_emitter = core.Emitter:new()
|
||||||
self.signal_emitter = core.Emitter:new()
|
self.signal_emitter = core.Emitter:new()
|
||||||
self.plugin_handler = plugin_handler(self)
|
self.plugin_handler = plugin_handler(self)
|
||||||
self.command_handler = command_handler(self)
|
self.command_handler = command_handler(self)
|
||||||
self.id = guild.id
|
self.id = guild.id
|
||||||
--conifgurable properties
|
--conifgurable properties
|
||||||
self.config_path = options.path or "./servers/%id/"
|
self.config_path = options.path or "./servers/%id/"
|
||||||
self.autosave = options.path or true
|
self.autosave = options.path or true
|
||||||
self.autosave_frequency = options.autosave_frequency or 10
|
self.autosave_frequency = options.autosave_frequency or 10
|
||||||
self.plugin_search_paths = options.plugin_search_paths or {"./plugins/"}
|
self.plugin_search_paths = options.plugin_search_paths or {"./plugins/"}
|
||||||
self.default_plugins = options.default_plugins or {"test"}
|
self.default_plugins = options.default_plugins or {"test"}
|
||||||
self.default_prefixes = options.default_prefixes or {"&","<@!"..self.client.user.id..">"}
|
self.default_prefixes = options.default_prefixes or {"&","<@!"..self.client.user.id..">"}
|
||||||
self.config = {}
|
self.config = {}
|
||||||
self.config_path = self.config_path:gsub("%%id",self.id)
|
self.config_path = self.config_path:gsub("%%id",self.id)
|
||||||
self:load_config()
|
self:load_config()
|
||||||
self.config["prefix"] = self.config["prefix"] or self.default_prefixes[1] or "(missing prefix)"
|
self.config["prefix"] = self.config["prefix"] or self.default_prefixes[1] or "(missing prefix)"
|
||||||
self.message_counter = 0
|
self.message_counter = 0
|
||||||
if self.autosave then
|
if self.autosave then
|
||||||
self.client:on("messageCreate",function(msg)
|
self.client:on("messageCreate",function(msg)
|
||||||
self.message_counter = self.message_counter + 1
|
self.message_counter = self.message_counter + 1
|
||||||
if math.fmod(self.message_counter,self.autosave_frequency) == 0 then
|
if math.fmod(self.message_counter,self.autosave_frequency) == 0 then
|
||||||
self:save_config()
|
self:save_config()
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
if not file.existsDir(self.config_path) then
|
if not file.existsDir(self.config_path) then
|
||||||
os.execute("mkdir -p "..self.config_path)
|
os.execute("mkdir -p "..self.config_path)
|
||||||
end
|
end
|
||||||
for k,v in pairs(eventlist) do
|
for k,v in pairs(eventlist) do
|
||||||
self.client:on(v,function(...)
|
self.client:on(v,function(...)
|
||||||
--check if the event is for this server, and then emit.
|
--check if the event is for this server, and then emit.
|
||||||
if check_partitioning(self.id,...) then
|
if check_partitioning(self.id,...) then
|
||||||
self.event_emitter:emit(v,...)
|
self.event_emitter:emit(v,...)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
self.client:on("messageCreate",function(msg)
|
self.client:on("messageCreate",function(msg)
|
||||||
if msg.guild and msg.guild.id == self.id then
|
if msg.guild and msg.guild.id == self.id then
|
||||||
self.command_handler:handle(msg)
|
self.command_handler:handle(msg)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
for _,path in pairs(self.plugin_search_paths) do
|
||||||
|
self.plugin_handler:add_plugin_folder(path)
|
||||||
|
end
|
||||||
|
self.plugin_handler:update_plugin_info()
|
||||||
|
for _,plugin_name in pairs(self.default_plugins) do
|
||||||
|
print("[SERVER] Loading plugin: "..tostring(plugin_name).." - ", self.plugin_handler:load(plugin_name))
|
||||||
|
end
|
||||||
|
for _,prefix in pairs(self.default_prefixes) do
|
||||||
|
self.command_handler:add_prefix(prefix)
|
||||||
end
|
end
|
||||||
end)
|
|
||||||
for _,path in pairs(self.plugin_search_paths) do
|
|
||||||
self.plugin_handler:add_plugin_folder(path)
|
|
||||||
end
|
|
||||||
self.plugin_handler:update_plugin_info()
|
|
||||||
for _,plugin_name in pairs(self.default_plugins) do
|
|
||||||
print("[SERVER] Loading plugin: "..tostring(plugin_name).." - ", self.plugin_handler:load(plugin_name))
|
|
||||||
end
|
|
||||||
for _,prefix in pairs(self.default_prefixes) do
|
|
||||||
self.command_handler:add_prefix(prefix)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function server_handler:load_config(path)
|
function server_handler:load_config(path)
|
||||||
print("[SERVER] Loading config")
|
print("[SERVER] Loading config")
|
||||||
if path then
|
if path then
|
||||||
self.config = file.readJSON(path,{})
|
self.config = file.readJSON(path,{})
|
||||||
else
|
else
|
||||||
self.config = file.readJSON(self.config_path.."config.json")
|
self.config = file.readJSON(self.config_path.."config.json")
|
||||||
end
|
end
|
||||||
self.event_emitter:emit("serverLoadConfig",self.config)
|
self.event_emitter:emit("serverLoadConfig",self.config)
|
||||||
end
|
end
|
||||||
|
|
||||||
function server_handler:save_config(path)
|
function server_handler:save_config(path)
|
||||||
print("[SERVER] Saving config")
|
print("[SERVER] Saving config")
|
||||||
if path then
|
if path then
|
||||||
file.writeJSON(path,self.config)
|
file.writeJSON(path,self.config)
|
||||||
else
|
else
|
||||||
file.writeJSON(self.config_path.."config.json",self.config)
|
file.writeJSON(self.config_path.."config.json",self.config)
|
||||||
end
|
end
|
||||||
self.event_emitter:emit("serverSaveConfig",self.config)
|
self.event_emitter:emit("serverSaveConfig",self.config)
|
||||||
end
|
end
|
||||||
return server_handler
|
return server_handler
|
||||||
|
|
|
@ -7,4 +7,29 @@ local save = command("save",{
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
plugin:add_command(save)
|
plugin:add_command(save)
|
||||||
|
local err = command("error",{
|
||||||
|
help = "Force error",
|
||||||
|
exec = function()
|
||||||
|
error("Errored successfully!")
|
||||||
|
end
|
||||||
|
})
|
||||||
|
plugin:add_command(err)
|
||||||
|
local perm_error = command("permerror",{
|
||||||
|
help = "Force permission error",
|
||||||
|
users = {
|
||||||
|
["245973168257368076"] = -1
|
||||||
|
},
|
||||||
|
exec = function(msg)
|
||||||
|
msg:reply([[o no he's hot]])
|
||||||
|
end
|
||||||
|
})
|
||||||
|
plugin:add_command(perm_error)
|
||||||
|
local return_error = command("return_error",{
|
||||||
|
help = "Force a return value error",
|
||||||
|
exec = function(msg)
|
||||||
|
msg:reply("nono :)")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
})
|
||||||
|
plugin:add_command(return_error)
|
||||||
return plugin
|
return plugin
|
||||||
|
|
Loading…
Reference in New Issue