fusionpbx/resources/install/scripts/fax_queue/tasks.lua

260 lines
7.1 KiB
Lua

local Database = require "resources.functions.database"
local Settings = require "resources.functions.lazy_settings"
local db
local date_utc_now_sql
local now_add_sec_sql
if database.type == 'pgsql' then
date_utc_now_sql = "NOW() at time zone 'utc'"
now_add_sec_sql = "NOW() at time zone 'utc' + interval '%s second'"
elseif database.type == 'mysql' then
date_utc_now_sql = "UTC_TIMESTAMP()"
now_add_sec_sql = "DATE_ADD(UTC_TIMESTAMP(), INTERVAL %s SECOND)"
elseif database.type == 'sqlite' then
date_utc_now_sql = "datetime('now')"
now_add_sec_sql = "datetime('now', '%s seconds')"
else
error("unsupported database type: " .. database.type)
end
-- Broken on FS 1.4 with native postgresql
-- Fixed on 1.6.0
-- Also works with ODBC
local ignore_affected_rows = true
if dbh_affected_rows_broken ~= nil then
ignore_affected_rows = dbh_affected_rows_broken
end
local Q850_TIMEOUT = {
[17] = 60;
}
local select_task_common_sql = [[
select
t1.fax_task_uuid as uuid,
t1.fax_uuid as fax_uuid,
t3.domain_name,
t3.domain_uuid,
t1.task_status as status,
t1.task_uri as uri,
t1.task_dial_string as dial_string,
t1.task_dtmf as dtmf,
t1.task_fax_file as fax_file,
t1.task_wav_file as wav_file,
t1.task_no_answer_counter as no_answer_counter,
t1.task_no_answer_retry_counter as no_answer_retry_counter,
t1.task_retry_counter as retry_counter,
t2.fax_send_greeting as greeting
from v_fax_tasks t1
inner join v_fax t2 on t2.fax_uuid = t1.fax_uuid
inner join v_domains t3 on t2.domain_uuid = t3.domain_uuid
where t1.task_interrupted <> 'true'
]]
local next_task_sql = select_task_common_sql .. [[
and t1.task_status = 0 and t1.task_next_time < ]] .. date_utc_now_sql .. [[
and t2.fax_send_channels > (select count(*) from v_fax_tasks as tasks
where tasks.fax_uuid = t1.fax_uuid and
tasks.task_status > 0 and tasks.task_status <= 2
)
order by t1.task_next_time
]]
local select_task_sql = select_task_common_sql .. "and t1.fax_task_uuid='%s'"
local aquire_task_sql = [[
update v_fax_tasks set task_status = 1, task_lock_time = ]] .. date_utc_now_sql .. [[
where fax_task_uuid = '%s' and task_status = 0
]]
local wait_task_sql = [[
update v_fax_tasks
set task_status = %s,
task_lock_time = NULL,
task_no_answer_counter = %s,
task_no_answer_retry_counter = %s,
task_retry_counter = %s,
task_next_time = ]] .. now_add_sec_sql .. [[
where fax_task_uuid = '%s'
]]
local remove_task_task_sql = [[
delete from v_fax_tasks
where fax_task_uuid = '%s'
]]
local release_task_sql = [[
update v_fax_tasks
set task_status = 0, task_lock_time = NULL,
task_next_time = ]] .. now_add_sec_sql .. [[
where fax_task_uuid = '%s'
]]
local release_stuck_tasks_sql = [[
update v_fax_tasks
set task_status = 0, task_lock_time = NULL,
task_next_time = ]] .. date_utc_now_sql .. [[
where task_lock_time < ]] .. now_add_sec_sql:format('-3600') .. [[
]]
local remove_finished_tasks_sql = [[
delete from v_fax_tasks where task_status > 3
]]
local function serialize(task, header)
local str = header or ''
for k, v in pairs(task) do
str = str .. ('\n %q = %q'):format(tostring(k), tostring(v))
end
return str
end
local function get_db()
if not db then
db = assert(Database.new('system'))
end
return db
end
local function next_task()
local db = get_db()
while true do
local task, err = db:first_row(next_task_sql)
if not task then return nil, err end
local ok, err = db:query( aquire_task_sql:format(task.uuid) )
if not ok then return nil, err end
local rows = db:affected_rows()
if ignore_affected_rows then
rows = 1
end
if rows == 1 then
task.no_answer_counter = tonumber(task.no_answer_counter)
task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter)
task.retry_counter = tonumber(task.retry_counter)
return task
end
end
end
local function select_task(fax_task_uuid)
local db = get_db()
local task, err = db:first_row(select_task_sql:format(fax_task_uuid))
if not task then return nil, err end
task.no_answer_counter = tonumber(task.no_answer_counter)
task.no_answer_retry_counter = tonumber(task.no_answer_retry_counter)
task.retry_counter = tonumber(task.retry_counter)
return task
end
local function wait_task(task, answered, q850)
local db = get_db()
local interval = 30
local settings = Settings.new(db, task.domain_name, task.domain_uuid)
task.status = 0
if not answered then
interval = Q850_TIMEOUT[q850 or 17] or interval
end
if not answered then
local fax_send_no_answer_retry_limit = tonumber(settings:get('fax', 'send_no_answer_retry_limit', 'numeric')) or 0
task.no_answer_retry_counter = task.no_answer_retry_counter + 1
if task.no_answer_retry_counter >= fax_send_no_answer_retry_limit then
task.no_answer_retry_counter = 0
task.no_answer_counter = task.no_answer_counter + 1
local fax_send_no_answer_limit = tonumber(settings:get('fax', 'send_no_answer_limit', 'numeric')) or 0
if task.no_answer_counter >= fax_send_no_answer_limit then
task.status = 4
else
interval = tonumber(settings:get('fax', 'send_no_answer_interval', 'numeric')) or interval
end
else
interval = tonumber(settings:get('fax', 'send_no_answer_retry_interval', 'numeric')) or interval
end
else
task.retry_counter = task.retry_counter + 1
local fax_send_retry_limit = tonumber(settings:get('fax', 'send_retry_limit', 'numeric')) or 0
if task.retry_counter >= fax_send_retry_limit then
task.status = 4
else
interval = tonumber(settings:get('fax', 'send_retry_interval', 'numeric')) or interval
task.task_seq_call_counter = 0
end
end
local sql = wait_task_sql:format(
tostring(task.status),
tostring(task.no_answer_counter),
tostring(task.no_answer_retry_counter),
tostring(task.retry_counter),
tostring(interval),
task.uuid
)
print(sql)
local ok, err = db:query( sql )
if not ok then return nil, err end
return task
end
local function remove_task(task)
local db = get_db()
local sql = remove_task_task_sql:format(task.uuid)
local ok, err = db:query( sql )
if not ok then return nil, err end
return db:affected_rows()
end
local function release_task(task)
local db = get_db()
local interval = 30
local sql = release_task_sql:format(
tostring(interval),
task.uuid
)
local ok, err = db:query( sql )
if not ok then return nil, err end
return task
end
local function cleanup_tasks()
local db = get_db()
db:query(release_stuck_tasks_sql)
db:query(remove_finished_tasks_sql)
end
return {
release_db = function()
if db then
db:release()
db = nil
end
end;
next_task = next_task;
wait_task = wait_task;
select_task = select_task;
remove_task = remove_task;
release_task = release_task;
cleanup_tasks = cleanup_tasks;
}