Mercurial > prosody-hg
comparison core/configmanager.lua @ 3573:f31fa6520a4b
configmanager: Atomic reloads, and some other internal changes to achieve this
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Sun, 07 Nov 2010 20:38:01 +0000 |
| parents | bb494c3aa364 |
| children | 954b1159f2f3 |
comparison
equal
deleted
inserted
replaced
| 3572:fb7fc154a56a | 3573:f31fa6520a4b |
|---|---|
| 4 -- | 4 -- |
| 5 -- This project is MIT/X11 licensed. Please see the | 5 -- This project is MIT/X11 licensed. Please see the |
| 6 -- COPYING file in the source package for more information. | 6 -- COPYING file in the source package for more information. |
| 7 -- | 7 -- |
| 8 | 8 |
| 9 | |
| 10 | |
| 11 local _G = _G; | 9 local _G = _G; |
| 12 local setmetatable, loadfile, pcall, rawget, rawset, io, error, dofile, type, pairs, table, format = | 10 local setmetatable, loadfile, pcall, rawget, rawset, io, error, dofile, type, pairs, table, format = |
| 13 setmetatable, loadfile, pcall, rawget, rawset, io, error, dofile, type, pairs, table, string.format; | 11 setmetatable, loadfile, pcall, rawget, rawset, io, error, dofile, type, pairs, table, string.format; |
| 14 | 12 |
| 15 | 13 |
| 17 | 15 |
| 18 module "configmanager" | 16 module "configmanager" |
| 19 | 17 |
| 20 local parsers = {}; | 18 local parsers = {}; |
| 21 | 19 |
| 22 local config = { ["*"] = { core = {} } }; | 20 local config_mt = { __index = function (t, k) return rawget(t, "*"); end}; |
| 23 | 21 local config = setmetatable({ ["*"] = { core = {} } }, config_mt); |
| 24 local global_config = config["*"]; | |
| 25 | 22 |
| 26 -- When host not found, use global | 23 -- When host not found, use global |
| 27 setmetatable(config, { __index = function () return global_config; end}); | 24 local host_mt = { }; |
| 28 local host_mt = { __index = global_config }; | |
| 29 | 25 |
| 30 -- When key not found in section, check key in global's section | 26 -- When key not found in section, check key in global's section |
| 31 function section_mt(section_name) | 27 function section_mt(section_name) |
| 32 return { __index = function (t, k) | 28 return { __index = function (t, k) |
| 33 local section = rawget(global_config, section_name); | 29 local section = rawget(config["*"], section_name); |
| 34 if not section then return nil; end | 30 if not section then return nil; end |
| 35 return section[k]; | 31 return section[k]; |
| 36 end | 32 end |
| 37 }; | 33 }; |
| 38 end | 34 end |
| 47 return sec[key]; | 43 return sec[key]; |
| 48 end | 44 end |
| 49 return nil; | 45 return nil; |
| 50 end | 46 end |
| 51 | 47 |
| 52 function set(host, section, key, value) | 48 local function set(config, host, section, key, value) |
| 53 if host and section and key then | 49 if host and section and key then |
| 54 local hostconfig = rawget(config, host); | 50 local hostconfig = rawget(config, host); |
| 55 if not hostconfig then | 51 if not hostconfig then |
| 56 hostconfig = rawset(config, host, setmetatable({}, host_mt))[host]; | 52 hostconfig = rawset(config, host, setmetatable({}, host_mt))[host]; |
| 57 end | 53 end |
| 62 return true; | 58 return true; |
| 63 end | 59 end |
| 64 return false; | 60 return false; |
| 65 end | 61 end |
| 66 | 62 |
| 63 function _M.set(host, section, key, value) | |
| 64 return set(config, host, section, key, value); | |
| 65 end | |
| 66 | |
| 67 function load(filename, format) | 67 function load(filename, format) |
| 68 format = format or filename:match("%w+$"); | 68 format = format or filename:match("%w+$"); |
| 69 | 69 |
| 70 if parsers[format] and parsers[format].load then | 70 if parsers[format] and parsers[format].load then |
| 71 local f, err = io.open(filename); | 71 local f, err = io.open(filename); |
| 72 if f then | 72 if f then |
| 73 local ok, err = parsers[format].load(f:read("*a"), filename); | 73 local new_config, err = parsers[format].load(f:read("*a"), filename); |
| 74 f:close(); | 74 f:close(); |
| 75 if ok then | 75 if new_config then |
| 76 fire_event("config-reloaded", { filename = filename, format = format }); | 76 setmetatable(new_config, config_mt); |
| 77 end | 77 config = new_config; |
| 78 return ok, "parser", err; | 78 fire_event("config-reloaded", { |
| 79 filename = filename, | |
| 80 format = format, | |
| 81 config = config | |
| 82 }); | |
| 83 end | |
| 84 return not not new_config, "parser", err; | |
| 79 end | 85 end |
| 80 return f, "file", err; | 86 return f, "file", err; |
| 81 end | 87 end |
| 82 | 88 |
| 83 if not format then | 89 if not format then |
| 109 do | 115 do |
| 110 local loadstring, pcall, setmetatable = _G.loadstring, _G.pcall, _G.setmetatable; | 116 local loadstring, pcall, setmetatable = _G.loadstring, _G.pcall, _G.setmetatable; |
| 111 local setfenv, rawget, tostring = _G.setfenv, _G.rawget, _G.tostring; | 117 local setfenv, rawget, tostring = _G.setfenv, _G.rawget, _G.tostring; |
| 112 parsers.lua = {}; | 118 parsers.lua = {}; |
| 113 function parsers.lua.load(data, filename) | 119 function parsers.lua.load(data, filename) |
| 120 local config = { ["*"] = { core = {} } }; | |
| 121 | |
| 114 local env; | 122 local env; |
| 115 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below | 123 -- The ' = true' are needed so as not to set off __newindex when we assign the functions below |
| 116 env = setmetatable({ | 124 env = setmetatable({ |
| 117 Host = true, host = true, VirtualHost = true, | 125 Host = true, host = true, VirtualHost = true, |
| 118 Component = true, component = true, | 126 Component = true, component = true, |
| 122 function (settings_table) | 130 function (settings_table) |
| 123 config[__currenthost or "*"][k] = settings_table; | 131 config[__currenthost or "*"][k] = settings_table; |
| 124 end; | 132 end; |
| 125 end, | 133 end, |
| 126 __newindex = function (t, k, v) | 134 __newindex = function (t, k, v) |
| 127 set(env.__currenthost or "*", "core", k, v); | 135 set(config, env.__currenthost or "*", "core", k, v); |
| 128 end | 136 end |
| 129 }); | 137 }); |
| 130 | 138 |
| 131 rawset(env, "__currenthost", "*") -- Default is global | 139 rawset(env, "__currenthost", "*") -- Default is global |
| 132 function env.VirtualHost(name) | 140 function env.VirtualHost(name) |
| 134 error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s", | 142 error(format("Host %q clashes with previously defined %s Component %q, for services use a sub-domain like conference.%s", |
| 135 name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0); | 143 name, config[name].core.component_module:gsub("^%a+$", { component = "external", muc = "MUC"}), name, name), 0); |
| 136 end | 144 end |
| 137 rawset(env, "__currenthost", name); | 145 rawset(env, "__currenthost", name); |
| 138 -- Needs at least one setting to logically exist :) | 146 -- Needs at least one setting to logically exist :) |
| 139 set(name or "*", "core", "defined", true); | 147 set(config, name or "*", "core", "defined", true); |
| 140 return function (config_options) | 148 return function (config_options) |
| 141 rawset(env, "__currenthost", "*"); -- Return to global scope | 149 rawset(env, "__currenthost", "*"); -- Return to global scope |
| 142 for option_name, option_value in pairs(config_options) do | 150 for option_name, option_value in pairs(config_options) do |
| 143 set(name or "*", "core", option_name, option_value); | 151 set(config, name or "*", "core", option_name, option_value); |
| 144 end | 152 end |
| 145 end; | 153 end; |
| 146 end | 154 end |
| 147 env.Host, env.host = env.VirtualHost, env.VirtualHost; | 155 env.Host, env.host = env.VirtualHost, env.VirtualHost; |
| 148 | 156 |
| 149 function env.Component(name) | 157 function env.Component(name) |
| 150 if rawget(config, name) and rawget(config[name].core, "defined") and not rawget(config[name].core, "component_module") then | 158 if rawget(config, name) and rawget(config[name].core, "defined") and not rawget(config[name].core, "component_module") then |
| 151 error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s", | 159 error(format("Component %q clashes with previously defined Host %q, for services use a sub-domain like conference.%s", |
| 152 name, name, name), 0); | 160 name, name, name), 0); |
| 153 end | 161 end |
| 154 set(name, "core", "component_module", "component"); | 162 set(config, name, "core", "component_module", "component"); |
| 155 -- Don't load the global modules by default | 163 -- Don't load the global modules by default |
| 156 set(name, "core", "load_global_modules", false); | 164 set(config, name, "core", "load_global_modules", false); |
| 157 rawset(env, "__currenthost", name); | 165 rawset(env, "__currenthost", name); |
| 158 local function handle_config_options(config_options) | 166 local function handle_config_options(config_options) |
| 159 rawset(env, "__currenthost", "*"); -- Return to global scope | 167 rawset(env, "__currenthost", "*"); -- Return to global scope |
| 160 for option_name, option_value in pairs(config_options) do | 168 for option_name, option_value in pairs(config_options) do |
| 161 set(name or "*", "core", option_name, option_value); | 169 set(config, name or "*", "core", option_name, option_value); |
| 162 end | 170 end |
| 163 end | 171 end |
| 164 | 172 |
| 165 return function (module) | 173 return function (module) |
| 166 if type(module) == "string" then | 174 if type(module) == "string" then |
| 167 set(name, "core", "component_module", module); | 175 set(config, name, "core", "component_module", module); |
| 168 return handle_config_options; | 176 return handle_config_options; |
| 169 end | 177 end |
| 170 return handle_config_options(module); | 178 return handle_config_options(module); |
| 171 end | 179 end |
| 172 end | 180 end |
| 196 | 204 |
| 197 if not ok then | 205 if not ok then |
| 198 return nil, err; | 206 return nil, err; |
| 199 end | 207 end |
| 200 | 208 |
| 201 return true; | 209 return config; |
| 202 end | 210 end |
| 203 | 211 |
| 204 end | 212 end |
| 205 | 213 |
| 206 return _M; | 214 return _M; |
