If you look for WAMP abbreviation over Internet, you will probably find that WAMP = Windows + Apache + MySQL + PHP – which was popular web stack some time ago (but who wants to run web server on Windows today? And other components now also have viable alternatives). But in this article I’d like to talk about WAMP = Web Application Messaging Protocol. WAMP is available as WebSocket subprotocol, but also can work on plain TCP or Unix domain sockets.
Key difference from plain WebSocket or similar protocols is that WAMP is routed protocol – it requires central router server to work. This enables loose coupling of components – because each component just need to connect to the central router, however the router then becomes a single point of failure. As per now there is no model nor implementation for multiple interconnected routers and inter-routers protocol(s), so this limits large scale implementations.
Also WAMP is not very common protocol – it has been designed and maintained by small German company Tavendo, which also maintains reference router implementation crossbar.io and client libraries for Python, Javascript, Android and C++ – autobahn. WAMP protocol is also IETF draft (but draft is expired, so question is if it makes to standard or not).
Yet for small to medium size projects, experiments with micro-services and real time communication this protocol looks attractive and I decided to give it a try in my current project.
Main advantage of WAMP is it’s simplicity and clearly designed client libraries (at least from what I have seen in Python and Javascript). WAMP provides two basic messaging models: Publish – Subscribe and Remote Procedure Call (RPC) – both are very easy to use – events and remote procedures are identified by generic URIs. Just to give you idea here is definition of remote method, and publishing in Python:
class Demo(ApplicationSession): async def onJoin(self, details): def run_task(task_name, *args, **kwargs): log.debug( 'Request for run task %s %s %s', task_name, args, kwargs) self.session.publish('my.update', task_name, status='started') self.register(run_task, 'my.remote.proc') # more code then needed to run this class
and remote method call and subscription in Javascript:
var currentSession = null; let task_updated = function (args, kwargs, details) { console.log('Task update', args, kwargs, details); } let connection = new autobahn.Connection({ url: 'ws://127.0.0.1:8880/ws', realm: 'realm1' }); connection.onopen = function (session) { console.log('Connection opened', session); session.subscribe('eu.zderadicka.asexor.task_update', task_updated); currentSession=session }; //Somewhere later in code - currentSession.call('my.remote.proc', ['dummy task', 'arg'], {'other_arg': 'value'}).then( function(res) { console.log('Task result is'+ res); });
Messages in WAMP are based on JSON format – so basically anything that is JSON serializable could be an argument or result of remote procedure or content of published event. Internally WAMP can leverage more efficient data serialization like MessagePack, UBJSON or CBOR. (serializers are basically pluggable into protocol).
As WAMP is intended to be used on both private and public networks security is indeed an important part of the protocol. It can leverage SSL/TSL channel encryption for both Websocket or raw socket and the protocol itself offers authentication ( token, challenge-response, Websocket based …) and authorization. Authorization allows to granularly define who can call, register procedure or publish, subscribe event based on procedure/event URI and user authentication credentials.
In my use-case I required clients (browser) to be able to submit various potentially long running tasks to server and receive instant updates about tasks progress and final results. Here is the solution architecture:
Idea is to extend regular Single Page Application (browser client communicating with RESTful API server) with WAMP real time communication for specific tasks (conversion of ebooks). Clients can easily submit requests for long running task via RPC and subscribe to updates via WAMP publish-subscribe model.
So we need server side component to schedule and launch tasks (conversion programs) in separate processes. It also talks WAMP and implements RPC to schedule task and publishes tasks updates. This component is implemented in Python with autobahn library. Autobahn library enforces asynchronous programming style using either twisted or asyncio. I choose asyncio, because
a) it’s now part of python standard libraries (and new async
keywords in 3.5 are really cool) and
b) I think it cleaner and easier to use that twisted (I never liked Twisted library very much – it always seems to me, how to say it, ehmm “twisted”).
Crossbar.io is written in twisted and can run twisted server components within same process. However asyncio components need to run in separate process and connect to the router via WAMP. For server side I would prefer some efficient communication – ideally unix domain socket, (Websocket overhead here would be useless). Small problem was that autobahn library did not have WAMP raw socket support for asyncio. Fortunately it was not so difficult to add it – so I added it via this pull request.
The proof of concept tasks scheduler/manager called ASEXOR (ASynchronous EXecutOR) is available here on github.
But WAMP has many other applications – look for instance at this example of simple system real time monitoring solution (with Django frontend). Or look at these demos. Or IoT Cookbook.
Conclusion
WAMP is a nice, simple protocol, which could be used for real time communication in many different scenarios. It’s very easy to start to play with it (especially in Python and Javascript) and could be quickly plugged into existing web application. Or new inventive applications can be created around this protocol.
My only worry for now would be scalability of WAMP solution in massive deployment.