|
|
|
@ -24,6 +24,7 @@ itte.confs = {
|
|
|
|
|
itte.config = {
|
|
|
|
|
debug = false,
|
|
|
|
|
admin_handlers = { "connect", "quit", "reload", "servers", "join", "part" },
|
|
|
|
|
task_handler_prefix = "th_",
|
|
|
|
|
messages = {
|
|
|
|
|
connect_success = "Connected to {{server}}.",
|
|
|
|
|
help = "Service codes available: {{codes}}",
|
|
|
|
@ -56,6 +57,8 @@ itte.config = {
|
|
|
|
|
redact = { "********" },
|
|
|
|
|
send = { "send" },
|
|
|
|
|
svrs_not_found = { "config", "Error: servers not found." },
|
|
|
|
|
task_added = { "task", "Task `{{name}}` added." },
|
|
|
|
|
task_activated = { "task", "Task `{{name}}` activated at {{ts}}." },
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -78,6 +81,7 @@ itte.docs._h = {}
|
|
|
|
|
-- Internal only: track application state
|
|
|
|
|
itte.state = {
|
|
|
|
|
connected = false,
|
|
|
|
|
timeout = 0.1,
|
|
|
|
|
}
|
|
|
|
|
itte.contexts = {}
|
|
|
|
|
|
|
|
|
@ -143,16 +147,19 @@ function itte.get_config(reload)
|
|
|
|
|
if itte_handlers ~= nil then itte.handlers = itte_handlers end
|
|
|
|
|
if itte_admins ~= nil then itte.admins = itte_admins end
|
|
|
|
|
|
|
|
|
|
-- If reloading, reconstruct the context tables.
|
|
|
|
|
-- This only works if the name name has not changed between reloads.
|
|
|
|
|
if reload then
|
|
|
|
|
-- Reconstruct the context tables
|
|
|
|
|
-- This only works if the server name has not changed between reloads.
|
|
|
|
|
for name, prop in pairs(itte.servers) do
|
|
|
|
|
cxt_old = itte.contexts[name]
|
|
|
|
|
itte.contexts[name] = prop
|
|
|
|
|
itte.contexts[name].name = name
|
|
|
|
|
itte.contexts[name].cmds = itte.get_commands(prop)
|
|
|
|
|
itte.contexts[name].con = cxt_old.con
|
|
|
|
|
itte.contexts[name].con:settimeout(0.5)
|
|
|
|
|
itte.contexts[name].con:settimeout(itte.state.timeout)
|
|
|
|
|
|
|
|
|
|
-- Reconstruct the task coroutines
|
|
|
|
|
itte.add_tasks(itte.contexts[name])
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
@ -307,7 +314,7 @@ function itte.init_socket(name, svr)
|
|
|
|
|
context.con = ssl.wrap(context.con, con_params)
|
|
|
|
|
context.con:dohandshake()
|
|
|
|
|
-- Set a short timeout to be non-blocking
|
|
|
|
|
context.con:settimeout(0.1)
|
|
|
|
|
context.con:settimeout(itte.state.timeout)
|
|
|
|
|
|
|
|
|
|
-- Set context and global states
|
|
|
|
|
context.state.connected = true
|
|
|
|
@ -385,6 +392,7 @@ function itte.disconnect_server(name)
|
|
|
|
|
util.debug(itte.config.debugs.exit[1], itte.config.debugs.exit[2],
|
|
|
|
|
itte.config.debug)
|
|
|
|
|
itte.state.connected = false
|
|
|
|
|
os.exit()
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
@ -767,6 +775,12 @@ function itte._h.help(cxt, msg)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local custom_h = util.table_keys(itte.handlers)
|
|
|
|
|
-- Remove task handlers
|
|
|
|
|
for h = 1, #custom_h do
|
|
|
|
|
if string.find(custom_h[h], itte.config.task_handler_prefix) == 1 then
|
|
|
|
|
custom_h[h] = nil
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
local codes = cxt.code_prefix .. table.concat(custom_h, ", " ..
|
|
|
|
|
cxt.code_prefix)
|
|
|
|
|
-- Core service codes are shown only to admins
|
|
|
|
@ -810,7 +824,7 @@ end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
|
-- Service code mapping and runtime
|
|
|
|
|
-- Service code and taskd task mapping
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
itte.docs.listen = [[ (name_str, data_str)
|
|
|
|
@ -838,9 +852,12 @@ function itte.listen(name, str)
|
|
|
|
|
util.debug(itte.config.debugs.listen[1], str, itte.config.debug)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Ignore calls to task handlers
|
|
|
|
|
if (string.find(msg.code, itte.config.task_handler_prefix) == 1) then
|
|
|
|
|
do return end
|
|
|
|
|
-- Check for the service code in the functions table before attempting to
|
|
|
|
|
-- call the function.
|
|
|
|
|
if util.has_key(itte._h, msg.code) then
|
|
|
|
|
elseif util.has_key(itte._h, msg.code) then
|
|
|
|
|
itte._h[msg.code](cxt, msg)
|
|
|
|
|
-- Check the handlers table
|
|
|
|
|
elseif util.has_key(itte.handlers, msg.code) then
|
|
|
|
@ -872,6 +889,83 @@ function itte.add_listener(cxt)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
itte.docs.add_tasks = [[ (context_table)
|
|
|
|
|
Create coroutines for tasks.
|
|
|
|
|
]]
|
|
|
|
|
function itte.add_tasks(cxt)
|
|
|
|
|
-- Exit function if there are no tasks for the context
|
|
|
|
|
if (cxt.tasks == nil) or (cxt.tasks == {}) then
|
|
|
|
|
do return end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Construct a task coroutine and call its handler function when resumed
|
|
|
|
|
local co = function(name, task)
|
|
|
|
|
if util.has_key(itte.handlers, task.handler) then
|
|
|
|
|
local ts = os.date("%Y-%m-%d %H:%M:%S", os.time())
|
|
|
|
|
local task_str = string.gsub(itte.config.debugs.task_activated[2],
|
|
|
|
|
"{{name}}", name)
|
|
|
|
|
task_str = string.gsub(task_str, "{{ts}}", ts)
|
|
|
|
|
util.debug(itte.config.debugs.task_activated[1], task_str,
|
|
|
|
|
itte.config.debug)
|
|
|
|
|
itte.handlers[task.handler](cxt, task)
|
|
|
|
|
-- Suspend coroutine to be reactivated later
|
|
|
|
|
coroutine.yield(co)
|
|
|
|
|
task.done = true
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
-- Initialise task coroutine
|
|
|
|
|
for name, task in pairs(cxt.tasks) do
|
|
|
|
|
task.co = coroutine.create(co)
|
|
|
|
|
task.done = false
|
|
|
|
|
util.debug(itte.config.debugs.task_added[1],
|
|
|
|
|
string.gsub(itte.config.debugs.task_added[2], "{{name}}", name),
|
|
|
|
|
itte.config.debug)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
itte.docs.check_tasks = [[ (context_table)
|
|
|
|
|
Compare task times to the current time and resume a task's coroutine if
|
|
|
|
|
the task interval or time match the current time.
|
|
|
|
|
]]
|
|
|
|
|
function itte.check_tasks(cxt)
|
|
|
|
|
-- Exit function if there are no tasks for the context
|
|
|
|
|
if (cxt.tasks == nil) or (cxt.tasks == {}) then
|
|
|
|
|
do return end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
local dt = util.split_str(os.date("%w %Y %m %d %H %M", os.time()))
|
|
|
|
|
-- Support preset minute intervals
|
|
|
|
|
local interval_min = { 5, 10, 15, 20, 30 }
|
|
|
|
|
for name, task in pairs(cxt.tasks) do
|
|
|
|
|
local task_min = string.sub(task.time, string.find(task.time, ":") + 1,
|
|
|
|
|
string.find(task.time, ":") + 2)
|
|
|
|
|
if (util.has_key(interval_min, tonumber(task.interval:sub(1, -2))) and
|
|
|
|
|
tonumber(dt[6]) % tonumber(task.interval:sub(1, -2)) == 0) or
|
|
|
|
|
(task.interval == "hourly" and task_min == dt[6]) or
|
|
|
|
|
(task.interval == "daily" and task.time == dt[5] .. ":" .. dt[6]) or
|
|
|
|
|
(task.interval == "weekly" and task.weekday == dt[1] and
|
|
|
|
|
task.time == dt[5] .. ":" .. dt[6]) or
|
|
|
|
|
(task.interval == "monthly" and task.day == dt[4] and
|
|
|
|
|
task.time == dt[5] .. ":" .. dt[6])
|
|
|
|
|
then
|
|
|
|
|
-- Run only once per interval
|
|
|
|
|
while not task.done do
|
|
|
|
|
coroutine.resume(task.co, name, task)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
-- Reset the done flag after running task
|
|
|
|
|
task.done = false
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
|
-- Runtime
|
|
|
|
|
-- ---------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
itte.docs.run = [[ ()
|
|
|
|
|
Run the client.
|
|
|
|
|
]]
|
|
|
|
@ -882,12 +976,19 @@ function itte.run()
|
|
|
|
|
itte.connect_server(name)
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if itte.state.connected then
|
|
|
|
|
for _, cxt in pairs(itte.contexts) do
|
|
|
|
|
itte.add_tasks(cxt)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
while itte.state.connected do
|
|
|
|
|
for _, cxt in pairs(itte.contexts) do
|
|
|
|
|
itte.add_listener(cxt)
|
|
|
|
|
itte.check_tasks(cxt)
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|