cc-mek-scada/scada-common/psil.lua

83 lines
2.3 KiB
Lua
Raw Permalink Normal View History

--
-- Publisher-Subscriber Interconnect Layer
--
local util = require("scada-common.util")
local psil = {}
-- instantiate a new PSI layer
2023-02-21 15:31:05 +00:00
---@nodiscard
function psil.create()
local ic = {}
-- allocate a new interconnect field
---@key string data key
local function alloc(key)
ic[key] = { subscribers = {}, value = nil }
end
---@class psil
local public = {}
2023-02-21 15:31:05 +00:00
-- subscribe to a data object in the interconnect<br>
-- will call func() right away if a value is already avaliable
---@param key string data key
---@param func function function to call on change
function public.subscribe(key, func)
-- allocate new key if not found or notify if value is found
if ic[key] == nil then
alloc(key)
elseif ic[key].value ~= nil then
func(ic[key].value)
end
-- subscribe to key
table.insert(ic[key].subscribers, { notify = func })
end
-- unsubscribe a function from a given key
---@param key string data key
---@param func function function to unsubscribe
function public.unsubscribe(key, func)
if ic[key] ~= nil then
util.filter_table(ic[key].subscribers, function (s) return s.notify ~= func end)
end
end
-- publish data to a given key, passing it to all subscribers if it has changed
---@param key string data key
---@param value any data value
function public.publish(key, value)
if ic[key] == nil then alloc(key) end
if ic[key].value ~= value then
for i = 1, #ic[key].subscribers do
ic[key].subscribers[i].notify(value)
end
end
ic[key].value = value
end
2023-04-08 04:38:46 +00:00
-- publish a toggled boolean value to a given key, passing it to all subscribers if it has changed<br>
-- this is intended to be used to toggle boolean indicators such as heartbeats without extra state variables
---@param key string data key
function public.toggle(key)
if ic[key] == nil then alloc(key) end
2023-04-08 04:38:46 +00:00
ic[key].value = ic[key].value == false
2023-04-08 04:38:46 +00:00
for i = 1, #ic[key].subscribers do
ic[key].subscribers[i].notify(ic[key].value)
2023-04-08 04:38:46 +00:00
end
end
-- clear the contents of the interconnect
function public.purge() ic = {} end
return public
end
return psil