The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

Dancer::Tutorial::WebSockets - How to build WebSocket apps with Dancer

DESCRIPTION

This tutorial will demonstrate building a simple WebSocket enabled app using Dancer and Web::Hippie. WebSockets are what all the cook kids are talking about these days. They make it possible to create push based applications. Instead of polling a server repeatedly for updates, the server pushes data to you as soon as it is available. Given Dancer's "light core" philosophy, WebSockets are not built in. So we will use a Plack Middleware called Web::Hippie to do the hard work for us.

Example

For this example to work, you will need a recent version of Dancer installed. You will also need to install Plack, Web::Hippie and Twiggy. This example has only been tested on the Chrome web browser. Firefox does not support WebSockets by default as of the publication of this tutorial. This example requires 2 files. First, create ./wsdemo.pl:

    #!/usr/bin/env perl
    use Dancer;
    use AnyMQ;
    use Plack::Builder;

    my $bus = AnyMQ->new;
    my $topic = $bus->topic('demo');

    get '/' => sub { template 'index' };

    # Web::Hippie routes
    get '/new_listener' => sub {
        request->env->{'hippie.listener'}->subscribe($topic);
    };
    get '/message' => sub {
        my $msg = request->env->{'hippie.message'};
        $topic->publish($msg);
    };

    builder {
        mount '/' => dance;
        mount '/_hippie' => builder {
            enable '+Web::Hippie';
            enable '+Web::Hippie::Pipe', bus => $bus;
            dance;
        };
    };

Now create the template file ./views/index.tt:

    <html>
    <head>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>

    <script>
    var socket;

    $(function() {
        // ws_path should be of the form ws://host/_hippie/ws
        var ws_path = "ws:<% request.base.opaque %>_hippie/ws";
        socket = new WebSocket(ws_path);
        socket.onopen = function() {
            $('#connection-status').text("Connected");
        };
        socket.onmessage = function(e) {
            var data = JSON.parse(e.data);
            if (data.msg) {
                var time = Date();
                $('ul').prepend('<li>' + time + ': ' + data.msg + '</li>');
            }
        };
    });

    function send_msg(message) {
        socket.send(JSON.stringify({ msg: message }));
    }
    </script>
    </head>

    <body>

    <h1 id="title">Dancer WebSocket Demo</h1>
    Connection Status:
    <span id="connection-status"> Disconnected </span>

    <div>
    <input value="Send Message" type=button onclick="send_msg('hello')"/>
    <input value="clear" type=button onclick="$('ul').empty()"/>
    </div>

    <span style="font-weight:bold"> Messages </span>
    <ul id="list"></ul>

    </body>
    </html>

To test your app, just run:

    plackup -s Twiggy wsdemo.pl

Now visit http://localhost:5000 in your browser. Clicking the Send Message button should add messages to the webpage. Open a second browser window and open the same url, http://localhost:5000. Clicking the Send Message button should add the same message to both windows.

REST Interface

You can interact with your app from external clients as well. Just add this route to your ./wsdemo.pl file right after the '/' route:

    any '/send_msg' => sub {
        $topic->publish({ msg => params->{msg} });
        return "sent message\n";
    };

Restart your application. Now you can send messages to your app with any http client:

    $ curl -d msg=shalom http://localhost:5000/send_msg

Or

    $ curl http://localhost:5000/send_msg?msg=salaam

Or just open the url http://localhost:5000/send_msg?msg=howdy in another browser window.