changeset 317:4f78f5020aa9

mod_admin_web: Get rid of the mod_pubsub dependency
author Florian Zeitz <florob@babelmonkeys.de>
date Fri, 14 Jan 2011 01:54:39 +0100
parents c86fc337d56f
children 84caab2bc02c
files mod_admin_web/admin_web/mod_admin_web.lua mod_admin_web/admin_web/www_files/js/main.js
diffstat 2 files changed, 160 insertions(+), 37 deletions(-) [+]
line wrap: on
line diff
--- a/mod_admin_web/admin_web/mod_admin_web.lua	Tue Jan 11 18:13:23 2011 +0500
+++ b/mod_admin_web/admin_web/mod_admin_web.lua	Fri Jan 14 01:54:39 2011 +0100
@@ -15,18 +15,22 @@
 --   <in/> / <out/>
 -- </session>
 
-local stanza = require "util.stanza";
+local st = require "util.stanza";
 local uuid_generate = require "util.uuid".generate;
+local is_admin = require "usermanager".is_admin;
+local pubsub = require "util.pubsub";
 local httpserver = require "net.httpserver";
+local jid_bare = require "util.jid".bare;
 local lfs = require "lfs";
 local open = io.open;
 local stat = lfs.attributes;
 
 local host = module:get_host();
-local service = config.get("*", "core", "webadmin_pubsub_host") or ("pubsub." .. host);
+local service;
 
 local http_base = (prosody.paths.plugins or "./plugins/") .. "admin_web/www_files";
 
+local xmlns_adminsub = "http://prosody.im/adminsub";
 local xmlns_c2s_session = "http://prosody.im/streams/c2s";
 local xmlns_s2s_session = "http://prosody.im/streams/s2s";
 
@@ -51,14 +55,14 @@
 		id = uuid_generate();
 		idmap[name] = id;
 	end
-	local item = stanza.stanza("item", { id = id }):tag("session", {xmlns = xmlns_c2s_session, jid = name}):up();
+	local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_c2s_session, jid = name}):up();
 	if session.secure then
 		item:tag("encrypted"):up();
 	end
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	hosts[service].modules.pubsub.service:publish(xmlns_c2s_session, service, id, item);
+	service:publish(xmlns_c2s_session, host, id, item);
 	module:log("debug", "Added client " .. name);
 end
 
@@ -66,8 +70,8 @@
 	local name = session.full_jid;
 	local id = idmap[name];
 	if id then
-		local notifier = stanza.stanza("retract", { id = id });
-		hosts[service].modules.pubsub.service:retract(xmlns_c2s_session, service, id, notifier);
+		local notifier = st.stanza("retract", { id = id });
+		service:retract(xmlns_c2s_session, host, id, notifier);
 	end
 end
 
@@ -78,7 +82,7 @@
 		id = uuid_generate();
 		idmap[name.."_"..type] = id;
 	end
-	local item = stanza.stanza("item", { id = id }):tag("session", {xmlns = xmlns_s2s_session, jid = name})
+	local item = st.stanza("item", { id = id }):tag("session", {xmlns = xmlns_s2s_session, jid = name})
 		:tag(type):up();
 	if session.secure then
 		item:tag("encrypted"):up();
@@ -86,7 +90,7 @@
 	if session.compressed then
 		item:tag("compressed"):up();
 	end
-	hosts[service].modules.pubsub.service:publish(xmlns_s2s_session, service, id, item);
+	service:publish(xmlns_s2s_session, host, id, item);
 	module:log("debug", "Added host " .. name .. " s2s" .. type);
 end
 
@@ -94,8 +98,8 @@
 	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 = stanza.stanza("retract", { id = id });
-		hosts[service].modules.pubsub.service:retract(xmlns_s2s_session, service, id, notifier);
+		local notifier = st.stanza("retract", { id = id });
+		service:retract(xmlns_s2s_session, host, id, notifier);
 	end
 end
 
@@ -133,7 +137,7 @@
 	local f, err = open(full_path, "rb");
 	if not f then return response_404; end
 	local data = f:read("*a");
-	data = data:gsub("%%PUBSUBHOST%%", service);
+	data = data:gsub("%%ADMINSUBHOST%%", host);
 	f:close();
 	if not data then
 		return response_403;
@@ -161,10 +165,12 @@
 
 prosody.events.add_handler("server-started", function ()
 	local host_session = prosody.hosts[host];
-	if not select(2, hosts[service].modules.pubsub.service:get_nodes(service))[xmlns_s2s_session] then
-		local ok, errmsg = hosts[service].modules.pubsub.service:create(xmlns_s2s_session, service);
+	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")
 		end
 	end
 
@@ -179,10 +185,12 @@
 		end
 	end
 
-	if not select(2, hosts[service].modules.pubsub.service:get_nodes(service))[xmlns_c2s_session] then
-		local ok, errmsg = hosts[service].modules.pubsub.service:create(xmlns_c2s_session, service);
+	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
 
@@ -193,12 +201,74 @@
 	end
 end);
 
+function simple_broadcast(node, jids, item)
+	item = st.clone(item);
+	item.attr.xmlns = nil; -- Clear the pubsub namespace
+	local message = st.message({ from = module.host, type = "headline" })
+		:tag("event", { xmlns = xmlns_adminsub .. "#event" })
+			:tag("items", { node = node })
+				:add_child(item);
+	for jid in pairs(jids) do
+		module:log("debug", "Sending notification to %s", jid);
+		message.attr.to = jid;
+		core_post_stanza(hosts[host], message);
+	end
+end
+
+function get_affiliation(jid)
+	local bare_jid = jid_bare(jid);
+	if is_admin(bare_jid, host) then
+		return "member";
+	else
+		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)
@@ -216,3 +286,57 @@
 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;
+		};
+	};
+});
+
--- a/mod_admin_web/admin_web/www_files/js/main.js	Tue Jan 11 18:13:23 2011 +0500
+++ b/mod_admin_web/admin_web/www_files/js/main.js	Fri Jan 14 01:54:39 2011 +0100
@@ -1,15 +1,15 @@
 var BOSH_SERVICE = '/http-bind/';
-var show_log = false;
+var show_log = true;
 
-Strophe.addNamespace('C2SPUBSUB', 'http://prosody.im/streams/c2s');
-Strophe.addNamespace('S2SPUBSUB', 'http://prosody.im/streams/s2s');
-Strophe.addNamespace('PUBSUB', 'http://jabber.org/protocol/pubsub');
+Strophe.addNamespace('C2SSTREAM', 'http://prosody.im/streams/c2s');
+Strophe.addNamespace('S2SSTREAM', 'http://prosody.im/streams/s2s');
+Strophe.addNamespace('ADMINSUB', 'http://prosody.im/adminsub');
 Strophe.addNamespace('CAPS', 'http://jabber.org/protocol/caps');
 
 var localJID = null;
 var connection   = null;
 
-var pubsubHost = '%PUBSUBHOST%';
+var adminsubHost = '%ADMINSUBHOST%';
 
 function log(msg) {
     var entry = $('<div></div>').append(document.createTextNode(msg));
@@ -32,10 +32,10 @@
         jid = items[i].getElementsByTagName('session')[0].attributes['jid'].value;
 
         entry = $('<li id="' + id + '">' + jid + '</li>');
-        if (e.getElementsByTagName('encrypted')[0]) {
+        if (items[i].getElementsByTagName('encrypted')[0]) {
             entry.append('<img src="images/encrypted.png" title="encrypted" alt=" (encrypted)" />');
         }
-        if (e.getElementsByTagName('compressed')[0]) {
+        if (items[i].getElementsByTagName('compressed')[0]) {
             entry.append('<img src="images/compressed.png" title="compressed" alt=" (compressed)" />');
         }
 
@@ -60,10 +60,10 @@
         id = items[i].attributes['id'].value;
         jid = items[i].getElementsByTagName('session')[0].attributes['jid'].value;
         entry = $('<li id="' + id + '">' + jid + '</li>');
-        if (e.getElementsByTagName('encrypted')[0]) {
+        if (items[i].getElementsByTagName('encrypted')[0]) {
             entry.append('<img src="images/encrypted.png" title="encrypted" alt=" (encrypted)" />');
         }
-        if (e.getElementsByTagName('compressed')[0]) {
+        if (items[i].getElementsByTagName('compressed')[0]) {
             entry.append('<img src="images/compressed.png" title="compressed" alt=" (compressed)" />');
         }
         entry.appendTo('#c2s');
@@ -76,11 +76,11 @@
     return true;
 }
 
-function _cbPubSub(e) {
+function _cbAdminSub(e) {
     var node = e.getElementsByTagName('items')[0].attributes['node'].value;
-    if (node == Strophe.NS.C2SPUBSUB) {
+    if (node == Strophe.NS.C2SSTREAM) {
         _cbNewC2S(e);
-    } else if (node == Strophe.NS.S2SPUBSUB) {
+    } else if (node == Strophe.NS.S2SSTREAM) {
         _cbNewS2S(e);
     }
 
@@ -106,17 +106,16 @@
     } else if (status == Strophe.Status.CONNECTED) {
         log('Strophe is connected.');
         showDisconnect();
+        connection.addHandler(_cbAdminSub, Strophe.NS.ADMINSUB + '#event', 'message');
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                .c('subscribe', {node: Strophe.NS.C2SSTREAM}));
+        connection.send($iq({to: adminsubHost, type: 'set', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                .c('subscribe', {node: Strophe.NS.S2SSTREAM}));
+        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                .c('items', {node: Strophe.NS.S2SSTREAM}), _cbNewS2S);
+        connection.sendIQ($iq({to: adminsubHost, type: 'get', id: connection.getUniqueId()}).c('adminsub', {xmlns: Strophe.NS.ADMINSUB})
+                .c('items', {node: Strophe.NS.C2SSTREAM}), _cbNewC2S);
 	Adhoc.checkFeatures('#adhoc', connection.domain);
-        connection.addHandler(_cbPubSub, Strophe.NS.PUBSUB + '#event', 'message');
-        connection.send($iq({to: pubsubHost, type: 'set', id: connection.getUniqueId()}).c('pubsub', {xmlns: Strophe.NS.PUBSUB})
-                .c('subscribe', {node: Strophe.NS.C2SPUBSUB, jid: connection.jid}));
-        connection.send($iq({to: pubsubHost, type: 'set', id: connection.getUniqueId()}).c('pubsub', {xmlns: Strophe.NS.PUBSUB})
-                .c('subscribe', {node: Strophe.NS.S2SPUBSUB, jid: connection.jid}));
-        connection.sendIQ($iq({to: pubsubHost, type: 'get', id: connection.getUniqueId()}).c('pubsub', {xmlns: Strophe.NS.PUBSUB})
-                .c('items', {node: Strophe.NS.S2SPUBSUB}), _cbNewS2S);
-        connection.sendIQ($iq({to: pubsubHost, type: 'get', id: connection.getUniqueId()}).c('pubsub', {xmlns: Strophe.NS.PUBSUB})
-                .c('items', {node: Strophe.NS.C2SPUBSUB}), _cbNewC2S);
-
     }
 }