Back to documentation
#!/usr/bin/env perl
# ABSTRACT: A message broker for WebSockets
# PODNAME: mercury
our $VERSION = '0.017';

use strict;
use warnings;

require Mojolicious::Commands;
Mojolicious::Commands->start_app('Mercury');

__END__

=head1 SYNOPSIS

    mercury broker [-l <listen>]

=head1 DESCRIPTION

This is a message broker that enables some common messaging patterns over
WebSockets.

WebSockets are a powerful tool, enabling many features previously impossible,
difficult, or ugly for web developers to implement. Where once only an HTTP
request could get data from a server, now a persistent socket can allow the
server to send updates without the client needing to specifically request it.

=head2 Server-side Communication

WebSockets do not need to be a communication channel purely between browser and
server. The Mojolicious web framework has excellent support for WebSockets.
Using that support, we can communicate between different server processes.

This solves the problem with client-to-client communication in a parallelized
web server where all clients may not be connected to the same server process.
The server processes can use a central message broker to coordinate and pass
messages from one client to another.

=head2 Message Bus

A message bus allows for all connected peers to send and receive messages in a
group.

Requesting a WebSocket from the URL C</bus/fry> joins the peer-to-peer message
bus topic C<fry>. All peers joined to the same topic will receive all the
messages published to that topic by other peers.

This is useful for sharing state changes between multiple peers, for example,
in a forking web app server like L<Hypnotoad> or L<Starman>.

=head2 Pub/Sub Messaging

The pub/sub pattern allows for 1-to-many delivery of messages from one
publisher to any number of active subscribers.

Requesting a WebSocket from the URL C</sub/leela> creates a subscription to the
topic C<leela>. Requesting a WebSocket from the URL C</pub/leela> allows
sending messages to the C<leela> topic, which are then received by all the
subscribers.

Topics are heirarchical to allow for broad subscriptions without requring more
sockets. A subscription to the topic C<wong> receives all messages published to
the topic C<wong> or any child topic like C<wong/amy> or C<wong/leo>.

This pattern is useful for keeping clients informed of backend processes,
tapping into an event or logging stream.

=head2 Push/Pull

Push/pull deals out messages in a round-robin manner. Pushers send messages
which are handled by a single puller.

Handlers request WebSockets from the URL C</pull/bender>. Senders request
WebSockets from the URL C</push/bender>. Senders send messages which will
be received by a single handler.

This pattern is useful for load balancing incoming updates, or creating
processing pipelines using multiple push/pull endpoints.

=head2 Example App

In C<development> mode (the default), the broker provides an example
application to test the messaging patterns.

You can change the mode by using the C<-m> flag to the L<C<mercury broker>
command|Mercury::Command::mercury::broker> or the C<MOJO_MODE> environment
variable.

=head1 CONFIGURATION

You can have an optional configuration file C<mercury.conf> in the current
working directory. The configuration file is a Perl hash, with the broker
configuration in the C<broker> key, like so:

    # mercury.conf
    {
        broker => {
            listen => "http://*:4000",
            allow_origin => [
                'example.com',
            ],
        },
    }

The individual configuration keys are:

=head2 listen

    # mercury.conf
    {
        broker => {
            listen => "http://*:4000",
        },
    }

You can set the default for the C<-l|--listen> option in the configuration
file.

=head2 allow_origin

    # mercury.conf
    {
        broker => {
            allow_origin => [
                'example.com',
            ],
        },
    }

Instead of CORS (used by Ajax), WebSockets send an C<Origin> header with the
initial handshake. This header contains the protocol, host, and port used by
the page requesting the socket.

As a basic security measure, you can configure the allowed origin values with
the C<allow_origin> configuration key. When this is set, only WebSocket
handshakes with an C<Origin> header matching one of the values will be allowed.
If there is no C<Origin> header, or the header does not match, the connection
will be denied with a C<401 Unauthorized> response.

C<allow_origin> key can be a single string, or an array of strings, containing
a string to match against the incoming C<Origin> header. The C<*> character is
a wildcard.

Each of the following examples will match the origin
C<http://www.example.com:3000>.

    example.com
    *.example.com
    *://www.example.com
    http://www.example.com:*

This is not a comprehensive security measure. The server is trusting that the
client is not lying about its C<Origin>. The client can claim any origin it
wants.

=head1 USAGE

=head2 Mojolicious

To use Mercury to communicate between Mojolicious server processes, use
L<Mojo::UserAgent's websocket method|Mojo::UserAgent/websocket>.

=head2 Dancer

To use Mercury inside of a L<Dancer> or L<Dancer2> app, you can use
L<AnyEvent::WebSocket::Client> with the L<Twiggy> PSGI server.

=head2 Catalyst

Like Dancer, you can use L<AnyEvent::WebSocket::Client> and L<Twiggy> to use
Mercury in your Catalyst app.

=head2 JavaScript

For simple applications that only need some peer-to-peer message passing, you
can directly connect clients to Mercury.

=head1 SEE ALSO

=over 4

=item L<The Mercury web site|http://preaction.me/mercury>

=item L<Mojolicious::Plugin::Mercury>

You can use this plugin to create your own message broker with custom
authentication and logging, custom messaging patterns, and more.

=item L<socket.io|http://socket.io>

A JavaScript WebSocket messaging library (client and server). For a
socket.io-compatible server written in Perl, see L<PocketIO>.

=item L<zeromq|http://zeromq.org>

A socket library that provides communication patterns for scalability.
The inspiration to build Mercury (Mercury requires only Perl 5.10 or higher).
For a Perl API to ZeroMQ, see L<ZMQ::FFI>.

=item L<nanomsg|http://nanomsg.org>

A socket library that provides communication patterns for scalability. The
successor to ZeroMQ. The inspiration of the features provided by Mercury. For a
Perl API, see L<NanoMsg::Raw>.

=back