aproxy/config.lua
Claude c01c6d0ba1 Change wantedScripts to ordered list format
This ensures scripts execute in the order they appear in the config file,
resolving the TODO in the README. The config format has been changed from
a table with script names as keys to an ordered list of script entries.

Changes:
- ctx.lua: Use ipairs() instead of pairs() to iterate in order
- config.lua: Update validation to handle new list structure
- conf.lua: Update example config to use new format
- README.md: Remove TODO and clarify execution order

New config format:
wantedScripts = {
    {name = 'script1', config = {...}},
    {name = 'script2', config = {...}}
}
2025-11-23 17:16:23 -03:00

123 lines
4.1 KiB
Lua

local env_config_path = os.getenv('APROXY_CONFIG_PATH')
local DEFAULT_CONFIG_PATH = ".;/etc/aproxy"
local config_path = env_config_path or DEFAULT_CONFIG_PATH
local function findConfigFile()
for _, config_directory in ipairs(string.split(config_path, ";")) do
local possible_config_path = config_directory .. "/" .. "conf.lua"
local fd, res = io.open(possible_config_path, "rb")
if fd then
log('config found at ' .. possible_config_path)
local data = fd:read("*a")
fd:close()
return data
else
log('config not found at ' .. possible_config_path .. ':' .. tostring(res))
end
end
return nil
end
local function insertError(errors, key, message)
errors[key] = errors[key] or {}
table.insert(errors[key], message)
return errors
end
local function fakeTableSchema(value_schema)
return setmetatable({ __list = true }, {
__index = function ()
return value_schema
end
})
end
local SPECIAL_KEYS = {__list = true}
local function validateSchema(schema, input, errors_in)
local errors = errors_in or {}
if schema.__list then
-- generate full schema for lists that are same size as input
for k, _ in pairs(input) do schema[k] = schema.__schema_value end
end
for key, field_schema in pairs(schema) do
if not SPECIAL_KEYS[key] then
assert(field_schema, 'schema not provided')
local input_value = input[key]
local input_type = type(input_value)
local wanted_type = field_schema.type
local actual_wanted_type = wanted_type
if wanted_type == 'list' then
actual_wanted_type = 'table'
end
if input_type == actual_wanted_type then
if wanted_type == 'table' then
-- recursive schema validation for generic tables
errors[key] = errors[key] or {}
validateSchema(field_schema.schema, input_value, errors[key])
if next(errors[key]) == nil then
errors[key] = nil
end
elseif wanted_type == 'list' then
-- for lists (which only have schemas for values), interpret
-- it differently
errors[key] = errors[key] or {}
validateSchema(fakeTableSchema(field_schema.schema), input_value, errors[key])
if next(errors[key]) == nil then
errors[key] = nil
end
end
else
insertError(
errors, key,
string.format('wanted %s but got %s', tostring(wanted_type), tostring(input_type))
)
end
end
end
return errors
end
local function validateConfigFile(config_object)
local all_schema_errors = {}
for _, script_entry in ipairs(config_object.wantedScripts) do
local module_name = script_entry.name
local module_config = script_entry.config
local module_manifest = require('scripts.' .. module_name)
local config_schema = module_manifest.config
local schema_errors = validateSchema(config_schema, module_config)
if schema_errors then
all_schema_errors[module_name] = schema_errors
end
end
return all_schema_errors
end
local function loadConfigFile(options_in)
local options = options_in or {}
local config_file_data = assert(findConfigFile(), 'no config file found, config path: ' .. config_path)
local config_file_function = assert(loadstring(config_file_data))
local config_object = config_file_function()
if options.validate then
local schema_errors = validateConfigFile(config_object)
local total_count = table.pprint(schema_errors, {call=function() end})
if total_count > 0 then
log('CONFIG ERROR')
table.pprint(schema_errors, {call=log})
end
end
return config_object
end
return {
loadConfigFile=loadConfigFile,
validateSchema=validateSchema,
}