scripts/lib: add a new settings manager lua library

This intends to reduce the amount of code needed to maintain
tables of settings values across different scripts
This commit is contained in:
George Kiagiadakis 2022-11-09 19:15:32 +02:00 committed by Julian Bouzas
parent 73870c528b
commit 57d4a8cb07

View file

@ -0,0 +1,124 @@
-- WirePlumber
--
-- Copyright © 2022 Collabora Ltd.
--
-- SPDX-License-Identifier: MIT
--
-- Settings manager helper
--
-- This sets up a lua table that will automatically populate itself with
-- values from the settings, falling back to the default values specified.
-- Any changes in the settings will automatically change the values of this
-- table.
--
-- Usage:
--
-- local settings_manager = require ("settings-manager")
-- local defaults = {
-- ["foo"] = true,
-- ["foo-bar"] = 3,
-- }
-- local settings = settings_manager.new ("example.prefix.", defaults)
--
-- The above "settings" table should now look like this internally:
-- {
-- foo = true, -- or the value specified in the Settings
-- foo_bar = 3, -- or the value specified in the Settings
-- }
--
-- Additionally, a "subscribe" method is present in the "settings" table, which
-- allows subscribing to changes of the values:
--
-- settings:subscribe ("foo-bar", function (new_value)
-- Log.info ("foo-bar value changed to " .. new_value)
-- end)
--
local settings_manager = {}
local private_api = {}
function private_api.subscribe (self, key, closure)
if not self.subscribers[key] then
self.subscribers[key] = {}
end
table.insert (self.subscribers, closure)
end
function private_api.call_subscribers (self, key, new_value)
if self.subscribers[key] then
for i, closure in ipairs (self.subscribers[key]) do
closure (new_value)
end
end
end
function private_api.update_value (self, key, json_value, default)
local new_value = json_value and json_value:parse () or default
-- only accept values that have the same type as the default value
if type (new_value) ~= type (default) then
new_value = default
end
-- store only if the new value is not equal to the default
self.values[key] = (new_value ~= default) and new_value or nil
return new_value
end
function settings_manager.new (_prefix, _defaults)
-- private storage table
local private = {
prefix = _prefix,
prefix_len = string.len (_prefix),
defaults = _defaults,
values = {},
subscribers = {},
}
setmetatable (private, { __index = private_api })
-- initialize with the values found in Settings
for key, default in pairs (private.defaults) do
local json_value = Settings.get (private.prefix .. key)
private:update_value (key, json_value, default)
end
-- subscribe for changes in Settings
Settings.subscribe (private.prefix .. "*", function (_, setting, json_value)
local key = string.sub (setting, private.prefix_len, -1)
local default = private.defaults[key]
-- unknown key, ignore it
if default == nil then
return
end
local new_value = private:update_value (key, json_value, default)
private:call_subscribers (key, new_value)
end)
-- return an empty table with a metatable that will resolve
-- keys to the values stored in `private` or their default values
return setmetatable ({}, {
__private = private,
__index = function (self, key)
if key == "subscribe" then
-- special case, "subscribe" is a method
return function (self, key, closure)
local private = getmetatable (self) ["__private"]
private:subscribe (key, closure)
end
else
local private = getmetatable (self) ["__private"]
key = string.gsub (key, "_", "-") -- foo_bar_baz -> foo-bar-baz
local value = private.values[key]
return (value ~= nil) and value or private.defaults[key]
end
end,
__newindex = function(_, key, _)
error ('Not allowed to modify configuration value')
end
})
end
return settings_manager