cc-mek-scada/coordinator/session/apisessions.lua

176 lines
4.8 KiB
Lua
Raw Normal View History

2023-07-10 03:31:56 +00:00
local log = require("scada-common.log")
local mqueue = require("scada-common.mqueue")
local util = require("scada-common.util")
2023-07-10 03:31:56 +00:00
local config = require("coordinator.config")
local iocontrol = require("coordinator.iocontrol")
2023-07-10 03:31:56 +00:00
local pocket = require("coordinator.session.pocket")
local apisessions = {}
local self = {
2023-06-21 23:04:39 +00:00
nic = nil,
next_id = 0,
sessions = {}
}
-- PRIVATE FUNCTIONS --
-- handle a session output queue
2023-06-06 23:41:09 +00:00
---@param session pkt_session_struct
local function _api_handle_outq(session)
-- record handler start time
local handle_start = util.time()
-- process output queue
while session.out_queue.ready() do
-- get a new message to process
local msg = session.out_queue.pop()
if msg ~= nil then
if msg.qtype == mqueue.TYPE.PACKET then
-- handle a packet to be sent
2023-06-21 23:04:39 +00:00
self.nic.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message)
elseif msg.qtype == mqueue.TYPE.COMMAND then
-- handle instruction/notification
elseif msg.qtype == mqueue.TYPE.DATA then
-- instruction/notification with body
end
end
-- max 100ms spent processing queue
if util.time() - handle_start > 100 then
2023-08-26 15:54:58 +00:00
log.warning("API: out queue handler exceeded 100ms queue process limit")
log.warning(util.c("API: offending session: ", session))
break
end
end
end
-- cleanly close a session
2023-06-06 23:41:09 +00:00
---@param session pkt_session_struct
local function _shutdown(session)
session.open = false
session.instance.close()
-- send packets in out queue (namely the close packet)
while session.out_queue.ready() do
local msg = session.out_queue.pop()
if msg ~= nil and msg.qtype == mqueue.TYPE.PACKET then
2023-06-21 23:04:39 +00:00
self.nic.transmit(config.PKT_CHANNEL, config.CRD_CHANNEL, msg.message)
end
end
2023-08-26 15:54:58 +00:00
log.debug(util.c("API: closed session ", session))
end
-- PUBLIC FUNCTIONS --
-- initialize apisessions
2023-06-21 23:04:39 +00:00
---@param nic nic
function apisessions.init(nic)
self.nic = nic
end
-- find a session by remote port
---@nodiscard
2023-06-06 23:41:09 +00:00
---@param source_addr integer
---@return pkt_session_struct|nil
function apisessions.find_session(source_addr)
for i = 1, #self.sessions do
2023-06-06 23:41:09 +00:00
if self.sessions[i].s_addr == source_addr then return self.sessions[i] end
end
return nil
end
-- establish a new API session
---@nodiscard
2023-06-06 23:41:09 +00:00
---@param source_addr integer
---@param version string
---@return integer session_id
2023-06-06 23:41:09 +00:00
function apisessions.establish_session(source_addr, version)
---@class pkt_session_struct
local pkt_s = {
open = true,
version = version,
2023-06-06 23:41:09 +00:00
s_addr = source_addr,
in_queue = mqueue.new(),
out_queue = mqueue.new(),
2023-06-06 23:41:09 +00:00
instance = nil ---@type pkt_session
}
2023-06-06 23:41:09 +00:00
local id = self.next_id
2023-06-06 23:41:09 +00:00
pkt_s.instance = pocket.new_session(id, source_addr, pkt_s.in_queue, pkt_s.out_queue, config.API_TIMEOUT)
table.insert(self.sessions, pkt_s)
2023-06-06 23:41:09 +00:00
local mt = {
---@param s pkt_session_struct
__tostring = function (s) return util.c("PKT [", id, "] (@", s.s_addr, ")") end
}
setmetatable(pkt_s, mt)
2023-07-10 03:31:56 +00:00
iocontrol.fp_pkt_connected(id, version, source_addr)
2023-08-26 15:54:58 +00:00
log.debug(util.c("API: established new session: ", pkt_s))
2023-06-06 23:41:09 +00:00
self.next_id = id + 1
-- success
2023-06-06 23:41:09 +00:00
return pkt_s.instance.get_id()
end
-- attempt to identify which session's watchdog timer fired
---@param timer_event number
function apisessions.check_all_watchdogs(timer_event)
for i = 1, #self.sessions do
2023-06-06 23:41:09 +00:00
local session = self.sessions[i] ---@type pkt_session_struct
if session.open then
local triggered = session.instance.check_wd(timer_event)
if triggered then
2023-08-26 15:54:58 +00:00
log.debug(util.c("API: watchdog closing session ", session, "..."))
_shutdown(session)
end
end
end
end
-- iterate all the API sessions
function apisessions.iterate_all()
for i = 1, #self.sessions do
2023-06-06 23:41:09 +00:00
local session = self.sessions[i] ---@type pkt_session_struct
if session.open and session.instance.iterate() then
_api_handle_outq(session)
else
session.open = false
end
end
end
-- delete all closed sessions
function apisessions.free_all_closed()
local f = function (session) return session.open end
2023-06-06 23:41:09 +00:00
---@param session pkt_session_struct
local on_delete = function (session)
2023-08-26 15:54:58 +00:00
log.debug(util.c("API: free'ing closed session ", session))
end
util.filter_table(self.sessions, f, on_delete)
end
-- close all open connections
function apisessions.close_all()
for i = 1, #self.sessions do
2023-06-06 23:41:09 +00:00
local session = self.sessions[i] ---@type pkt_session_struct
if session.open then _shutdown(session) end
end
apisessions.free_all_closed()
end
return apisessions