Software /
code /
prosody
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 |
parent | 3515:bb494c3aa364 |
child | 3609: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; |