Files
soldr-modules/tests_framework/lua/mediator.lua
T
2022-11-22 02:21:28 +03:00

155 lines
3.9 KiB
Lua

local function Subscriber(fn, options)
return {
options = options or {},
fn = fn,
channel = nil,
id = math.random(1000000000), -- sounds reasonable, rite?
update = function(self, options)
if options then
self.fn = options.fn or self.fn
self.options = options.options or self.options
end
end
}
end
-- Channel class and functions --
local function Channel(namespace, parent)
return {
stopped = false,
namespace = namespace,
callbacks = {},
channels = {},
parent = parent,
addSubscriber = function(self, fn, options)
local callback = Subscriber(fn, options)
local priority = (#self.callbacks + 1)
options = options or {}
if options.priority and
options.priority >= 0 and
options.priority < priority
then
priority = options.priority
end
table.insert(self.callbacks, priority, callback)
return callback
end,
getSubscriber = function(self, id)
for i=1, #self.callbacks do
local callback = self.callbacks[i]
if callback.id == id then return { index = i, value = callback } end
end
local sub
for _, channel in pairs(self.channels) do
sub = channel:getSubscriber(id)
if sub then break end
end
return sub
end,
setPriority = function(self, id, priority)
local callback = self:getSubscriber(id)
if callback.value then
table.remove(self.callbacks, callback.index)
table.insert(self.callbacks, priority, callback.value)
end
end,
addChannel = function(self, namespace)
self.channels[namespace] = Channel(namespace, self)
return self.channels[namespace]
end,
hasChannel = function(self, namespace)
return namespace and self.channels[namespace] and true
end,
getChannel = function(self, namespace)
return self.channels[namespace] or self:addChannel(namespace)
end,
removeSubscriber = function(self, id)
local callback = self:getSubscriber(id)
if callback and callback.value then
for _, channel in pairs(self.channels) do
channel:removeSubscriber(id)
end
return table.remove(self.callbacks, callback.index)
end
end,
publish = function(self, result, ...)
for i = 1, #self.callbacks do
local callback = self.callbacks[i]
-- if it doesn't have a predicate, or it does and it's true then run it
if not callback.options.predicate or callback.options.predicate(...) then
-- just take the first result and insert it into the result table
local value, continue = callback.fn(...)
if value then table.insert(result, value) end
if not continue then return result end
end
end
if parent then
return parent:publish(result, ...)
else
return result
end
end
}
end
-- Mediator class and functions --
local Mediator = setmetatable(
{
Channel = Channel,
Subscriber = Subscriber
},
{
__call = function (fn, options)
return {
channel = Channel('root'),
getChannel = function(self, channelNamespace)
local channel = self.channel
for i=1, #channelNamespace do
channel = channel:getChannel(channelNamespace[i])
end
return channel
end,
subscribe = function(self, channelNamespace, fn, options)
return self:getChannel(channelNamespace):addSubscriber(fn, options)
end,
getSubscriber = function(self, id, channelNamespace)
return self:getChannel(channelNamespace):getSubscriber(id)
end,
removeSubscriber = function(self, id, channelNamespace)
return self:getChannel(channelNamespace):removeSubscriber(id)
end,
publish = function(self, channelNamespace, ...)
return self:getChannel(channelNamespace):publish({}, ...)
end
}
end
})
return Mediator