Microblogging example draft

http://www.defuze.org/oss/headstock/speakup.png

Requirements

Notes on requirements

  • If you use ejabberd 2.0.1, make sur you add the {registration_timeout, infinity}. option in the config file before the definition of the different modules. Restart the server to take effect. This is needed because mod_register now checks that no two registrations from the same IP happens before a given timeout. Here we just disable that option.
  • Deploy ejabberd as a local user. You don't need to run it as an admin user luckily so it can be deployed in your home directory.
  • It is assumed you'll deploy ejabberd as localhost
  • The code hasn't been extensively tested so thinks will break if you try a different version of the required modules. In each case take the latest available.
  • By default the HTTP server session engine uses memcached. If you can't run memcached you may simply edit the headstock/headtock/example/microblog/launcher.py module and replace the string memcached by ram.

Running

Once all the required packages have been deployed go to:

headstock/headtock/example/microblog

From that directory open two terminals.

  • In the first one run the following command: python launcher.py
  • In the second one run the command python jabber-service.py -d localhost -a localhost:5222

Using

Navigate with your browser to http://localhost:8080/. There enter your OpenID. If your provider supports the SReg extension and that you have defined a profile it'll prefill the next field.

Once the account is created the jabber service will normally see it and automatically create two Jabber accounts based on the given username, they'll look like:

  • username@localhost
  • username.microblogging@localhost

Open the file headstock/headtock/example/microblog/etc/password and copy the password for your username. Then from your favourite Jabber client login with the first JID and the password. Then add to your contact list the second JID (the one ending with .microblogging which is used internally by the service).

Once subscribed to each other you can just send a message to your new contact. Once that done, go to http://localhost:8080/username and you should see your message.

You may then go to http://localhost:8080/help to view more commands like follow:

Publish:  PI text
Publish to a node: PI [node] text
Publish text with geolocalisation: GEO text [long,lat]
Delete: DI itemId
Delete from a node: DI [node] itemId
Create a node: CN node
Delete a node: DN node
Purge a node: PN node
Subscribe to a node: SN node
Unsubscribe from a node: UN node
  • Note that whenever you may enter a node it's the full path to that node.
  • Note as well that itemId are URN UUID values for now.
  • Note that you may signout by doing http://localhost:8080/signout. That will solely clear the HTTP session. Nothing else for now.

That's it. It's probably buggy as hell but should give you and idea.

Under the hood

Under the hood the idea is that when a user creates an account two Jabber accounts are created .to interact with the application. One is internal only and the only is used by the user to drive the former one. Their communication for now is based on XMPP messages. The advantages is that it works with any existing Jabber clients, the drawback is that it ads one extra layer considering those messages are interpreted as PubSub? operations.

So those messages are parsed and transformed into appropriate PubSub? operation and sent to the PubSub? service. In some cases those messages also end up with HTTP requests towards the HTTP server which hosts an AtomPub service with collections dedicated to the user. For instance when publishing an item to a pubsub node, if the operation succeeded, and since the internal client automatically subscribed to the user's node, the pubsub service notifies with a XMPP message the internal client which in turn issue a POST request to the AtomPub service, sending an Atom entry.

All the commands are or will be mapped that way. For example purging a node means the internal client sends DELETE requests to remove all resources from the AtomPub service. So on and so on.

One side aspect of the design and tools chosen is that when you create a subnode and then publish an item to that node, the POSTed atom entry contains an atom:category element which has the @term attribute set to the name of the node. From the AtomPub service such entry is indexed and you can query it aftwerwards by navigating to http://localhost:8080/username/tag/node

That should display an Atom feed with the posted entry. This feed is created based on the indexed content.