mod_admin_web/admin_web/mod_admin_web.lua
changeset 319 ba2e78661ea8
parent 317 4f78f5020aa9
child 328 73001ddff453
--- a/mod_admin_web/admin_web/mod_admin_web.lua	Wed Jan 19 20:18:38 2011 +0100
+++ b/mod_admin_web/admin_web/mod_admin_web.lua	Fri Jan 21 04:10:40 2011 +0100
@@ -25,8 +25,9 @@
 local open = io.open;
 local stat = lfs.attributes;
 
-local host = module:get_host();
-local service;
+module:set_global();
+
+local service = {};
 
 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files";
 
@@ -48,7 +49,7 @@
 
 local idmap = {};
 
-function add_client(session)
+function add_client(session, host)
 	local name = session.full_jid;
 	local id = idmap[name];
 	if not id then
@@ -62,20 +63,20 @@
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	service:publish(xmlns_c2s_session, host, id, item);
+	service[host]:publish(xmlns_c2s_session, host, id, item);
 	module:log("debug", "Added client " .. name);
 end
 
-function del_client(session)
+function del_client(session, host)
 	local name = session.full_jid;
 	local id = idmap[name];
 	if id then
 		local notifier = st.stanza("retract", { id = id });
-		service:retract(xmlns_c2s_session, host, id, notifier);
+		service[host]:retract(xmlns_c2s_session, host, id, notifier);
 	end
 end
 
-function add_host(session, type)
+function add_host(session, type, host)
 	local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
 	local id = idmap[name.."_"..type];
 	if not id then
@@ -90,16 +91,16 @@
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	service:publish(xmlns_s2s_session, host, id, item);
+	service[host]:publish(xmlns_s2s_session, host, id, item);
 	module:log("debug", "Added host " .. name .. " s2s" .. type);
 end
 
-function del_host(session, type)
+function del_host(session, type, host)
 	local name = (type == "out" and session.to_host) or (type == "in" and session.from_host);
 	local id = idmap[name.."_"..type];
 	if id then
 		local notifier = st.stanza("retract", { id = id });
-		service:retract(xmlns_s2s_session, host, id, notifier);
+		service[host]:retract(xmlns_s2s_session, host, id, notifier);
 	end
 end
 
@@ -137,7 +138,6 @@
 	local f, err = open(full_path, "rb");
 	if not f then return response_404; end
 	local data = f:read("*a");
-	data = data:gsub("%%ADMINSUBHOST%%", host);
 	f:close();
 	if not data then
 		return response_403;
@@ -164,47 +164,183 @@
 end
 
 prosody.events.add_handler("server-started", function ()
-	local host_session = prosody.hosts[host];
-	if not select(2, service:get_nodes(true))[xmlns_s2s_session] then
-		local ok, errmsg = service:create(xmlns_s2s_session, true);
-		if not ok then
-			module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
-		else
-			service:set_affiliation(xmlns_s2s_session, true, host, "owner")
+	for host_name, host_table in pairs(hosts) do
+		service[host_name] = pubsub.new({
+			broadcaster = function(node, jids, item) return simple_broadcast(node, jids, item, host_name) end;
+			normalize_jid = jid_bare;
+			get_affiliation = function(jid) return get_affiliation(jid, host_name) end;
+			capabilities = {
+				member = {
+					create = false;
+					publish = false;
+					retract = false;
+					get_nodes = true;
+
+					subscribe = true;
+					unsubscribe = true;
+					get_subscription = true;
+					get_subscriptions = true;
+					get_items = true;
+
+					subscribe_other = false;
+					unsubscribe_other = false;
+					get_subscription_other = false;
+					get_subscriptions_other = false;
+
+					be_subscribed = true;
+					be_unsubscribed = true;
+
+					set_affiliation = false;
+				};
+
+				owner = {
+					create = true;
+					publish = true;
+					retract = true;
+					get_nodes = true;
+
+					subscribe = true;
+					unsubscribe = true;
+					get_subscription = true;
+					get_subscriptions = true;
+					get_items = true;
+
+					subscribe_other = true;
+					unsubscribe_other = true;
+					get_subscription_other = true;
+					get_subscriptions_other = true;
+
+					be_subscribed = true;
+					be_unsubscribed = true;
+
+					set_affiliation = true;
+				};
+			};
+		});
+
+		if not select(2, service[host_name]:get_nodes(true))[xmlns_s2s_session] then
+			local ok, errmsg = service[host_name]:create(xmlns_s2s_session, true);
+			if not ok then
+				module:log("warn", "Could not create node " .. xmlns_s2s_session .. ": " .. tostring(errmsg));
+			else
+				service[host_name]:set_affiliation(xmlns_s2s_session, true, host_name, "owner")
+			end
 		end
-	end
 
-	for remotehost, session in pairs(host_session.s2sout) do
-		if session.type ~= "s2sout_unauthed" then
-			add_host(session, "out");
+		for remotehost, session in pairs(host_table.s2sout) do
+			if session.type ~= "s2sout_unauthed" then
+				add_host(session, "out", host_name);
+			end
+		end
+		for session in pairs(incoming_s2s) do
+			if session.to_host == host_name then
+				add_host(session, "in", host_name);
+			end
+		end
+
+		if not select(2, service[host_name]:get_nodes(true))[xmlns_c2s_session] then
+			local ok, errmsg = service[host_name]:create(xmlns_c2s_session, true);
+			if not ok then
+				module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
+			else
+				service[host_name]:set_affiliation(xmlns_c2s_session, true, host_name, "owner")
+			end
 		end
-	end
-	for session in pairs(incoming_s2s) do
-		if session.to_host == host then
-			add_host(session, "in");
+
+		for username, user in pairs(host_table.sessions or {}) do
+			for resource, session in pairs(user.sessions or {}) do
+				add_client(session, host_name);
+			end
 		end
-	end
+
+		host_table.events.add_handler("iq/host/http://prosody.im/adminsub:adminsub", function(event)
+			local origin, stanza = event.origin, event.stanza;
+			local adminsub = stanza.tags[1];
+			local action = adminsub.tags[1];
+			local reply;
+			if action.name == "subscribe" then
+				local ok, ret = service[host_name]:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+				if ok then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub });
+				else
+					reply = st.error_reply(stanza, "cancel", ret);
+				end
+			elseif action.name == "unsubscribe" then
+				local ok, ret = service[host_name]:remove_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
+				if ok then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub });
+				else
+					reply = st.error_reply(stanza, "cancel", ret);
+				end
+			elseif action.name == "items" then
+				local node = action.attr.node;
+				local ok, ret = service[host_name]:get_items(node, stanza.attr.from);
+				if not ok then
+					return origin.send(st.error_reply(stanza, "cancel", ret));
+				end
 
-	if not select(2, service:get_nodes(true))[xmlns_c2s_session] then
-		local ok, errmsg = service:create(xmlns_c2s_session, true);
-		if not ok then
-			module:log("warn", "Could not create node " .. xmlns_c2s_session .. ": " .. tostring(errmsg));
-		else
-			service:set_affiliation(xmlns_c2s_session, true, host, "owner")
-		end
-	end
+				local data = st.stanza("items", { node = node });
+				for _, entry in pairs(ret) do
+					data:add_child(entry);
+				end
+				if data then
+					reply = st.reply(stanza)
+						:tag("adminsub", { xmlns = xmlns_adminsub })
+							:add_child(data);
+				else
+					reply = st.error_reply(stanza, "cancel", "item-not-found");
+				end
+			elseif action.name == "adminfor" then
+				local data = st.stanza("adminfor");
+				for host_name in pairs(hosts) do
+					if is_admin(stanza.attr.from, host_name) then
+						data:tag("item"):text(host_name):up();
+					end
+				end
+				reply = st.reply(stanza)
+					:tag("adminsub", { xmlns = xmlns_adminsub })
+						:add_child(data);
+			else
+				reply = st.error_reply(stanza, "feature-not-implemented");
+			end
+			return origin.send(reply);
+		end);
 
-	for username, user in pairs(host_session.sessions or {}) do
-		for resource, session in pairs(user.sessions or {}) do
-			add_client(session);
-		end
+		host_table.events.add_handler("resource-bind", function(event)
+			add_client(event.session, host_name);
+		end);
+
+		host_table.events.add_handler("resource-unbind", function(event)
+			del_client(event.session, host_name);
+			service[host_name]:remove_subscription(xmlns_c2s_session, host_name, event.session.full_jid);
+			service[host_name]:remove_subscription(xmlns_s2s_session, host_name, event.session.full_jid);
+		end);
+
+		host_table.events.add_handler("s2sout-established", function(event)
+			add_host(event.session, "out", host_name);
+		end);
+
+		host_table.events.add_handler("s2sin-established", function(event)
+			add_host(event.session, "in", host_name);
+		end);
+
+		host_table.events.add_handler("s2sout-destroyed", function(event)
+			del_host(event.session, "out", host_name);
+		end);
+
+		host_table.events.add_handler("s2sin-destroyed", function(event)
+			del_host(event.session, "in", host_name);
+		end);
+
 	end
 end);
 
-function simple_broadcast(node, jids, item)
+function simple_broadcast(node, jids, item, host)
 	item = st.clone(item);
 	item.attr.xmlns = nil; -- Clear the pubsub namespace
-	local message = st.message({ from = module.host, type = "headline" })
+	local message = st.message({ from = host, type = "headline" })
 		:tag("event", { xmlns = xmlns_adminsub .. "#event" })
 			:tag("items", { node = node })
 				:add_child(item);
@@ -215,7 +351,7 @@
 	end
 end
 
-function get_affiliation(jid)
+function get_affiliation(jid, host)
 	local bare_jid = jid_bare(jid);
 	if is_admin(bare_jid, host) then
 		return "member";
@@ -223,120 +359,3 @@
 		return "none";
 	end
 end
-
-module:hook("iq/host/http://prosody.im/adminsub:adminsub", function(event)
-	local origin, stanza = event.origin, event.stanza;
-	local adminsub = stanza.tags[1];
-	local action = adminsub.tags[1];
-	local reply;
-	if action.name == "subscribe" then
-		local ok, ret = service:add_subscription(action.attr.node, stanza.attr.from, stanza.attr.from);
-		if ok then
-			reply = st.reply(stanza)
-				:tag("adminsub", { xmlns = xmlns_adminsub });
-		else
-			reply = st.error_reply(stanza, "cancel", ret);
-		end
-	elseif action.name == "items" then
-		local node = action.attr.node;
-		local ok, ret = service:get_items(node, stanza.attr.from);
-		if not ok then
-			return origin.send(st.error_reply(stanza, "cancel", ret));
-		end
-
-		local data = st.stanza("items", { node = node });
-		for _, entry in pairs(ret) do
-			data:add_child(entry);
-		end
-		if data then
-			reply = st.reply(stanza)
-				:tag("adminsub", { xmlns = xmlns_adminsub })
-					:add_child(data);
-		else
-			reply = st.error_reply(stanza, "cancel", "item-not-found");
-		end
-	else
-		reply = st.error_reply(stanza, "feature-not-implemented");
-	end
-	return origin.send(reply);
-end);
-
-module:hook("resource-bind", function(event)
-	add_client(event.session);
-end);
-
-module:hook("resource-unbind", function(event)
-	del_client(event.session);
-	service:remove_subscription(xmlns_c2s_session, host, event.session.full_jid);
-	service:remove_subscription(xmlns_s2s_session, host, event.session.full_jid);
-end);
-
-module:hook("s2sout-established", function(event)
-	add_host(event.session, "out");
-end);
-
-module:hook("s2sin-established", function(event)
-	add_host(event.session, "in");
-end);
-
-module:hook("s2sout-destroyed", function(event)
-	del_host(event.session, "out");
-end);
-
-module:hook("s2sin-destroyed", function(event)
-	del_host(event.session, "in");
-end);
-
-service = pubsub.new({
-	broadcaster = simple_broadcast;
-	normalize_jid = jid_bare;
-	get_affiliation = get_affiliation;
-	capabilities = {
-		member = {
-			create = false;
-			publish = false;
-			retract = false;
-			get_nodes = true;
-
-			subscribe = true;
-			unsubscribe = true;
-			get_subscription = true;
-			get_subscriptions = true;
-			get_items = true;
-
-			subscribe_other = false;
-			unsubscribe_other = false;
-			get_subscription_other = false;
-			get_subscriptions_other = false;
-
-			be_subscribed = true;
-			be_unsubscribed = true;
-
-			set_affiliation = false;
-		};
-
-		owner = {
-			create = true;
-			publish = true;
-			retract = true;
-			get_nodes = true;
-
-			subscribe = true;
-			unsubscribe = true;
-			get_subscription = true;
-			get_subscriptions = true;
-			get_items = true;
-
-			subscribe_other = true;
-			unsubscribe_other = true;
-			get_subscription_other = true;
-			get_subscriptions_other = true;
-
-			be_subscribed = true;
-			be_unsubscribed = true;
-
-			set_affiliation = true;
-		};
-	};
-});
-