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

179 lines
5.1 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 iocontrol = require("coordinator.iocontrol")
2023-07-10 03:31:56 +00:00
local pocket = require("coordinator.session.pocket")
local apisessions = {}
local self = {
2024-02-19 02:34:25 +00:00
nic = nil, ---@type nic
config = nil, ---@type crd_config
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
2024-02-19 02:34:25 +00:00
self.nic.transmit(self.config.PKT_Channel, self.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
2024-02-19 02:34:25 +00:00
self.nic.transmit(self.config.PKT_Channel, self.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
---@param nic nic network interface
2024-02-19 02:34:25 +00:00
---@param config crd_config coordinator config
function apisessions.init(nic, config)
2023-06-21 23:04:39 +00:00
self.nic = nic
2024-02-19 02:34:25 +00:00
self.config = config
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
---@param source_addr integer pocket computer ID
2024-06-29 18:49:26 +00:00
---@param i_seq_num integer initial (most recent) sequence number
---@param version string pocket version
---@return integer session_id
function apisessions.establish_session(source_addr, i_seq_num, version)
2023-06-06 23:41:09 +00:00
---@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
pkt_s.instance = pocket.new_session(id, source_addr, i_seq_num, pkt_s.in_queue, pkt_s.out_queue, self.config.API_Timeout)
2023-06-06 23:41:09 +00:00
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