A PubSubHubbub to XMPP Gateway

At first glance, both rssCloud and PubSubHubbub have an interesting shortcoming that makes them difficult to use for desktop feed readers. Since both of them require HTTP callbacks to a publicly accessibly endpoint, a user is required to open up a port on their firewall.

It turns out that a subtle difference in the specifications gives PubSubHubbub a big edge in this case. While rssCloud requires your callback endpoint to live at the IP address you make your request from, PubSubHubbub allows you to subscribe any endpoint you wish by specifying a hub.callback url.

So how do we turn this into a real-time feed for desktop clients? Simple: we implement a PubSubHubbub subscriber on a publicly-available, always-on server that receives PubSubHubbub update events and wraps them in XMPP. The XMPP events are transmitted to the desktop client, where it can then process them as if it received the callbacks directly.

The server application doesn’t need to be smart. Only the “subscribe” and “publish” modes of PubSubHubbub’s protocol are required. All it needs to do is correctly route the update subscriptions to the correct XMPP account. In fact, with Google AppEngine’s new XMPP support, you can this in a few dozen lines of code, as I’ve done here:

A PubSubHubbub to XMPP gateway, hosted on Google AppEngine

Try out the gateway by entering your XMPP ID on the main page. This will give you a callback URL that you can use on Google’s main PubSubHubbub hub. Enter the URL for any PubSubHubbub-enabled field as the topic.

The code is simple, though not very robust:

@SuppressWarnings("serial")
public class Subscribe extends HttpServlet {
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		resp.setStatus(204);
		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));
		
		byte[] buffer = new byte[10 * 1024];
		req.getInputStream().read(buffer);
		xmpp.sendMessage(new MessageBuilder().withBody(
				"Got update: " + new String(buffer))
				.withRecipientJids(jid).build());
	}
	
	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setStatus(200);
		resp.setContentType("text/plain");

		XMPPService xmpp = XMPPServiceFactory.getXMPPService();
		JID jid = new JID(req.getPathInfo().substring(1));

		if (req.getParameter("hub.mode").equals("subscribe"))
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Subscribing to " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());
		else
			xmpp.sendMessage(new MessageBuilder().withBody(
					"Unsubscribing from " + req.getParameter("hub.topic"))
					.withRecipientJids(jid).build());

		resp.getOutputStream().print(req.getParameter("hub.challenge"));
		resp.getOutputStream().flush();
	}
}

Postscript: I really hope that PubSubHubbub gets a new name.

14 Responses to “A PubSubHubbub to XMPP Gateway”

  1. […] – This post explains how the requirement of public server for callback can be worked around for desktop […]

  2. […] A quieter window.name transport for IE A PubSubHubbub to XMPP Gateway […]

  3. […] A PubSubHubbub to XMPP Gateway « grack.com (tags: xmpp pubhubsubbub) […]

  4. Ha… it’s funny, gating between PSHB and XMPP (via AMQP) was one of the first things we did with RabbitHub back in June: just added both RabbitHub and the RabbitMQ XMPP adapter to a regular deployment of RabbitMQ. See http://github.com/tonyg/rabbithub/tree/master#example for an illustration of what we built.

    • Matt Mastracci says:

      Tony,

      Thanks for the pointer – that’s awesome. RabbitMQ is a great product, we looked at it earlier for our product. Glad to see that it fits into the PSHB world so well!

  5. […] A PubSubHubbub to XMPP Gateway ? grack.com (tags: readme xmpp pubsub) […]

  6. I don’t see why you couldn’t do the same with rssCloud.

    • I couldn’t do this today on AppEngine because of rssCloud’s IP-address-as-endpoint requirement. It took me less than an hour to hook it up on Google’s servers thanks to their pre-written XMPP libraries.

  7. […] Google App Engine finns det kod som kopplar ihop Pubsubhubbub-uppdateringar med XMPP. Enklare uttryckt innebär det att du kan få uppdateringar direkt till din chattklient (iChat, […]

  8. Thejesh GN says:

    This is cool. Thanks. Now I will subscribe all those feeds onto jabber.

  9. […] PubSubHubbub vers XMPP Matt Mastracci a mis à disposition une passerelle PubSubHubbub vers XMPP sur […]

  10. […] not have to live on the same domain where the request is initiated. This means you can implement a PubSubHubbub subscriber on a public server and then route the updates using XMPP (also open), or something similar, to the desktop […]