cc-mek-scada/supervisor/session/rtu/txnctrl.lua
2023-09-03 17:54:39 -04:00

99 lines
2.2 KiB
Lua

--
-- MODBUS Transaction Controller
--
local util = require("scada-common.util")
local txnctrl = {}
local TIMEOUT = 2000 -- 2000ms max wait
-- create a new transaction controller
---@nodiscard
function txnctrl.new()
local self = {
list = {},
next_id = 0
}
---@class transaction_controller
local public = {}
local insert = table.insert
local remove = table.remove
-- get the length of the transaction list
---@nodiscard
function public.length()
return #self.list
end
-- check if there are no active transactions
---@nodiscard
function public.empty()
return #self.list == 0
end
-- create a new transaction of the given type
---@nodiscard
---@param txn_type integer
---@return integer txn_id
function public.create(txn_type)
local txn_id = self.next_id
insert(self.list, {
txn_id = txn_id,
txn_type = txn_type,
expiry = util.time() + TIMEOUT
})
self.next_id = self.next_id + 1
return txn_id
end
-- mark a transaction as resolved to get its transaction type
---@nodiscard
---@param txn_id integer
---@return integer|nil txn_type
function public.resolve(txn_id)
local txn_type = nil
for i = 1, public.length() do
if self.list[i].txn_id == txn_id then
local entry = remove(self.list, i)
txn_type = entry.txn_type
break
end
end
return txn_type
end
-- renew a transaction by re-inserting it with its ID and type
---@param txn_id integer
---@param txn_type integer
function public.renew(txn_id, txn_type)
insert(self.list, {
txn_id = txn_id,
txn_type = txn_type,
expiry = util.time() + TIMEOUT
})
end
-- close timed-out transactions
function public.cleanup()
local now = util.time()
util.filter_table(self.list, function (txn) return txn.expiry > now end)
end
-- clear the transaction list
function public.clear()
self.list = {}
end
return public
end
return txnctrl