File Coverage

blib/lib/Mojolicious/Plugin/Multiplex.pm
Criterion Covered Total %
statement 18 18 100.0
branch 2 4 50.0
condition 1 3 33.3
subroutine 5 5 100.0
pod 1 1 100.0
total 27 31 87.1


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Multiplex;
2              
3 1     1   867 use Mojo::Base 'Mojolicious::Plugin';
  1         4  
  1         8  
4              
5             our $VERSION = '0.05';
6             $VERSION = eval $VERSION;
7              
8 1     1   794 use Mojolicious::Plugin::Multiplex::Multiplexer;
  1         3  
  1         12  
9              
10 1     1   403 use File::Share ();
  1         8251  
  1         263  
11              
12             sub register {
13 1     1 1 84 my ($plugin, $app, $conf) = @_;
14              
15 1         4 push @{ $app->static->paths }, File::Share::dist_dir('Mojolicious-Plugin-Multiplex');
  1         10  
16              
17             $app->helper(multiplex => sub {
18 3     3   57114 my $c = shift;
19 3         18 my $tx = $c->tx;
20 3 50       30 return undef unless $tx->is_websocket;
21 3 50       37 $c->rendered(101) unless $tx->established;
22 3   33     1045 return $c->stash->{'multiplex.multiplexer'} ||= Mojolicious::Plugin::Multiplex::Multiplexer->new(tx => $tx);
23 1         288 });
24             }
25              
26             1;
27              
28             =head1 NAME
29              
30             Mojolicious::Plugin::Multiplex - A websocket multiplexing layer for Mojolicious applications
31              
32             =head1 SYNOPSIS
33              
34             use Mojolicious::Lite;
35              
36             plugin 'Multiplex';
37              
38             get '/' => 'index';
39              
40             websocket '/multiplex' => sub {
41             my $c = shift;
42             my $multiplex = $c->multiplex;
43             $multiplex->on(subscribe => sub { ... });
44             $multiplex->on(message => sub { ... });
45             $multiplex->on(unsubscribe => sub { ... });
46             };
47              
48             __DATA__
49              
50             @@ index.html.ep
51              
52             %= javascript 'websocket_multiplex';
53            
61              
62             =head1 CAUTION
63              
64             This module is in its infancy and things can and will change in incompatible ways until this warning is removed.
65             That said, the author is using it for real work so hopefully incompatible changes will be minimal (for his own sanity).
66              
67             =head1 DESCRIPTION
68              
69             L implements a mechanism proposed by L for the multiplexing of data on a single websocket.
70             Rather than proposing both a protocol and a programmatic api to use it, they L a very simple protocol and reusing the api of the existing Javascript WebSocket api.
71             This has the immediate advantage (beyond having to dream up a client api) that existing front-end code that is written for a WebSocket can immediately use the multiplexer with no changes necessary.
72              
73             Their proposal only includes a partially implemented reference implementation.
74             This module extends the protocol slightly in order to enough of the L<"WebSocket API"|https://developer.mozilla.org/en-US/docs/Web/API/WebSocket> to be useful.
75             More extensions may be necessary if the API is to be completely implemented, however those last few details are rarely used and will likely not be missed.
76              
77             On the server-side the logic is entirely up to the application author.
78             The module simply parses the multiplexed messages and emits events in accordance with them.
79             A typical use case may be to relay message to a bus, subscribing and unsubscribing from topics that it presents.
80             Another might be to stream updates to multiple types of data (perhaps in multiple parts of a single page application).
81             (Indeed those might not be distinct cases from each other).
82              
83             For reference, the distribution comes with an example which uses L as a message broker for a multi-channel chat application.
84             The example may also be seen on L.
85              
86             =head1 HELPERS
87              
88             =head2 multiplex
89              
90             my $multiplex = $c->multiplex;
91              
92             Establishes the WebSocket connection (if it hasn't been already) and returns an instance of L.
93             The multiplexer is attached to the websocket stream and begins listening for messages.
94             The multiplexer emits events for incoming messages and has methods to send outgoing messages; more details about those are contained in its own documentation.
95              
96             Note that for each websocket connection the same instance of the multiplexer will be returned on any subsequent call.
97             Though not prevented, the user is highly discouraged from sending other traffic over any websocket connection that is managed by a multiplexer.
98              
99             =head1 BUNDLED FILES
100              
101             =head2 websocket_multiplex.js
102              
103             # in your template
104             %= javascript 'websocket_multiplex.js';
105              
106             var ws = new WebSocket(url);
107             var multiplex = new WebSocketMultiplex(ws);
108             var channel = multiplex.channel(topic);
109              
110             Bundled with this plugin is a javascript file which provides the front-end code to create a multiplexer entitled C.
111             It provides the new class C whose constructor takes as its only argument an existing WebSocket object.
112             This then is used to open new channel objects via the C method which takes a topic string as an arugment.
113             Topics can be almost any string, however they must not contain a comma (a limitation of the protocol).
114             The resulting channel objects implement the same API as a WebSocket (though they do not inherit from it).
115              
116             The client-side multiplexer will also attempt to reconnect to closed sockets and when successful will automatically resubscribe to the channels that were subscribed.
117              
118             N.B. This library is the least stable of the entire project.
119             Use with caution.
120              
121             =head1 SOURCE REPOSITORY
122              
123             L
124              
125             =head1 AUTHOR
126              
127             Joel Berger, Ejoel.a.berger@gmail.comE
128              
129             =head1 COPYRIGHT AND LICENSE
130              
131             Copyright (C) 2016 by Joel Berger
132              
133             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
134              
135             The multiplexer protocol and javascript code (both extended by this project) are copyright their original authors and by their nature are assumed to be in the public domain.
136              
137             =cut
138              
139