mirror of
https://github.com/vxcontrol/soldr-modules.git
synced 2026-07-21 08:55:22 -04:00
240 lines
8.4 KiB
Lua
240 lines
8.4 KiB
Lua
local cjson = require("cjson.safe")
|
|
local glue = require("glue")
|
|
local protocol = require("protocol/protocol")
|
|
|
|
require("engine")
|
|
require("protocol/actions_validator")
|
|
|
|
local smodule = {}
|
|
smodule.quit_handler = function() end
|
|
smodule.agent_connected_handler = function(_) end
|
|
smodule.agent_disconnected_handler = function(_) end
|
|
smodule.update_config_handler = function(_, _) end
|
|
|
|
-- TODO: use common shared uuid library
|
|
local crc32 = require("crc32")
|
|
math.randomseed(crc32(tostring({})))
|
|
local function make_uuid()
|
|
local template = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'
|
|
return string.gsub(template, '[xy]', function(c)
|
|
local v = (c == 'x') and math.random(0, 0xf) or math.random(8, 0xb)
|
|
return string.format('%x', v)
|
|
end)
|
|
end
|
|
|
|
smodule.unload_dependencies = function()
|
|
if smodule.action_engine ~= nil then
|
|
smodule.action_engine:free()
|
|
smodule.action_engine = nil
|
|
end
|
|
if smodule.event_engine ~= nil then
|
|
smodule.event_engine:free()
|
|
smodule.event_engine = nil
|
|
end
|
|
if smodule.action_validator ~= nil then
|
|
smodule.action_validator:free()
|
|
smodule.action_validator = nil
|
|
end
|
|
collectgarbage("collect")
|
|
end
|
|
|
|
smodule.load_dependencies = function()
|
|
local action_config_schema = __config.get_action_config_schema()
|
|
local current_event_config = __config.get_current_event_config()
|
|
local fields_schema = __config.get_fields_schema()
|
|
local module_info = __config.get_module_info()
|
|
|
|
smodule.module_config = cjson.decode(__config.get_current_config()) or {}
|
|
|
|
smodule.unload_dependencies()
|
|
|
|
smodule.action_engine = CActionEngine(
|
|
nil,
|
|
__args and __args.debug
|
|
)
|
|
smodule.event_engine = CEventEngine(
|
|
fields_schema, current_event_config, module_info, __gid .. ".",
|
|
__args and __args.debug
|
|
)
|
|
smodule.action_validator = CActionsValidator(
|
|
fields_schema, action_config_schema)
|
|
end
|
|
|
|
-- getting agent ID by dst token and agent type
|
|
local function get_agent_id_by_dst(dst, atype)
|
|
for client_id, client_info in pairs(__agents.get_by_dst(dst)) do
|
|
if client_id == dst then
|
|
if tostring(client_info.Type) == atype or atype == "any" then
|
|
return tostring(client_info.ID), client_info
|
|
end
|
|
end
|
|
end
|
|
return "", {}
|
|
end
|
|
|
|
-- getting agent source token by ID and agent type
|
|
local function get_agent_src_by_id(id, atype)
|
|
for client_id, client_info in pairs(__agents.get_by_id(id)) do
|
|
if tostring(client_info.Type) == atype or atype == "any" then
|
|
return tostring(client_id), client_info
|
|
end
|
|
end
|
|
return "", {}
|
|
end
|
|
|
|
smodule.push_event_for_action = function(agent_id, event_name, action_name, event_data, actions)
|
|
assert(agent_id ~= nil and agent_id ~= "", "agent id must be defined")
|
|
assert(event_name ~= nil and event_name ~= "", "event name must be defined")
|
|
assert(action_name ~= nil and action_name ~= "", "action name must be defined")
|
|
event_data = event_data or {}
|
|
actions = actions or {}
|
|
|
|
if action_name ~= "" then
|
|
local action_full_name = __config.ctx.name .. "." .. action_name
|
|
if glue.indexof(action_full_name, actions) == nil then
|
|
table.insert(actions, action_full_name)
|
|
end
|
|
end
|
|
smodule.push_event(agent_id, event_name, event_data, actions)
|
|
end
|
|
|
|
smodule.push_event = function(agent_id, event_name, event_data, actions)
|
|
assert(agent_id ~= nil and agent_id ~= "", "agent id must be defined")
|
|
assert(event_name ~= nil and event_name ~= "", "event name must be defined")
|
|
event_data = event_data or {}
|
|
actions = actions or {}
|
|
|
|
local event = {
|
|
__module = __config.ctx.name,
|
|
name = event_name, data = event_data,
|
|
actions = actions,
|
|
}
|
|
local result, actions_list = smodule.event_engine:push_event(event)
|
|
|
|
-- result value defines if there are actions that need to be executed
|
|
if result then
|
|
for action_id, action_result in ipairs(smodule.action_engine:exec(agent_id, actions_list)) do
|
|
__log.infof("action '%s' was requested and executed with result: %s", action_id, action_result)
|
|
end
|
|
end
|
|
end
|
|
|
|
smodule.start = function(action_handlers, data_callback, background_process)
|
|
__api.add_cbs({
|
|
data = function(src, data)
|
|
local msg_data = cjson.decode(data) or {}
|
|
local return_dst = msg_data.__retaddr
|
|
local vxagent_id = get_agent_id_by_dst(src, "VXAgent")
|
|
if vxagent_id ~= "" and return_dst ~= nil and return_dst ~= "" then
|
|
msg_data.__retaddr = nil
|
|
return __api.send_data_to(return_dst, cjson.encode(msg_data))
|
|
end
|
|
|
|
-- msg from browser or external
|
|
if data_callback ~= nil then
|
|
return data_callback(src, nil)
|
|
end
|
|
return false
|
|
end,
|
|
|
|
action = function(src, data, action_name)
|
|
local action_data = cjson.decode(data) or {}
|
|
|
|
action_data.__cid = action_data.__cid or make_uuid()
|
|
|
|
local response = {
|
|
__retaddr = action_data.__retaddr,
|
|
__cid = action_data.__cid,
|
|
__msg_type = protocol.message_name.action_response,
|
|
name = action_name,
|
|
request_data = cjson.decode(cjson.encode(action_data)),
|
|
}
|
|
|
|
local result, error, reason = smodule.action_validator:validate(action_name, action_data.data)
|
|
if not result then
|
|
response.status = "error"
|
|
response.error = error
|
|
response.reason = reason
|
|
return __api.send_data_to(src, cjson.encode(response))
|
|
end
|
|
|
|
-- Server module can handle action on it's own
|
|
local action_handler = (action_handlers or {})[action_name]
|
|
if action_handler ~= nil then
|
|
response.error, response.response_data = action_handler(action_data.data)
|
|
response.status = (response.error == nil) and "success" or "error"
|
|
return __api.send_data_to(src, cjson.encode(response))
|
|
end
|
|
|
|
-- Server module can't handle action so it need to be proxied to the agent
|
|
local id, _ = get_agent_id_by_dst(src, "any")
|
|
local dst, _ = get_agent_src_by_id(id, "VXAgent")
|
|
if dst == "" then
|
|
response.status, response.error = "error", protocol.connection_errors.common
|
|
return __api.send_data_to(src, cjson.encode(response))
|
|
else
|
|
response.__aid = id
|
|
end
|
|
|
|
__log.debugf("action '%s' was proxied", action_name)
|
|
__api.send_msg_to(src, cjson.encode({
|
|
__msg_type = protocol.message_name.action_proxied,
|
|
__cid = action_data.__cid,
|
|
name = action_name,
|
|
}), protocol.message_type.info)
|
|
|
|
action_data.__retaddr = src
|
|
return __api.send_action_to(dst, cjson.encode(action_data), action_name)
|
|
end,
|
|
|
|
control = function(cmtype, data)
|
|
__log.debugf("receive control msg '%s' with payload: %s", cmtype, data)
|
|
|
|
if cmtype == "update_config" then
|
|
local previous_config = smodule.module_config
|
|
smodule.load_dependencies()
|
|
if smodule.update_config_handler then
|
|
smodule.update_config_handler(previous_config, smodule.module_config)
|
|
end
|
|
end
|
|
if cmtype == "quit" then
|
|
if smodule.quit_handler then
|
|
smodule.quit_handler()
|
|
end
|
|
end
|
|
if cmtype == "agent_connected" then
|
|
if smodule.agent_connected_handler then
|
|
smodule.agent_connected_handler(data)
|
|
end
|
|
end
|
|
if cmtype == "agent_disconnected" then
|
|
if smodule.agent_disconnected_handler then
|
|
smodule.agent_disconnected_handler(data)
|
|
end
|
|
end
|
|
return true
|
|
end,
|
|
})
|
|
|
|
smodule.load_dependencies()
|
|
|
|
__log.infof("module '%s' was started", __config.ctx.name)
|
|
|
|
if background_process ~= nil then
|
|
while not __api.is_close() do
|
|
background_process()
|
|
__api.await(1000)
|
|
end
|
|
else
|
|
__api.await(-1)
|
|
end
|
|
|
|
smodule.unload_dependencies()
|
|
|
|
__log.infof("module '%s' was stopped", __config.ctx.name)
|
|
|
|
return "success"
|
|
end
|
|
|
|
return smodule
|