File Coverage

blib/lib/Mojolicious/Plugin/Multiplex.pm
Criterion Covered Total %
statement 20 20 100.0
branch 3 6 50.0
condition 1 3 33.3
subroutine 5 5 100.0
pod 1 1 100.0
total 30 35 85.7


line stmt bran cond sub pod time code
1             package Mojolicious::Plugin::Multiplex;
2              
3 1     1   711 use Mojo::Base 'Mojolicious::Plugin';
  1         2  
  1         6  
4              
5             our $VERSION = '1.0';
6             $VERSION = eval $VERSION;
7              
8 1     1   704 use Mojolicious::Plugin::Multiplex::Multiplexer;
  1         3  
  1         9  
9              
10 1     1   424 use File::Share ();
  1         24518  
  1         234  
11              
12             sub register {
13 1     1 1 56 my ($plugin, $app, $conf) = @_;
14              
15 1         3 push @{ $app->static->paths }, File::Share::dist_dir('Mojolicious-Plugin-Multiplex');
  1         7  
16              
17             # this is still a gray area it seems, but certainly this will be honored even
18             # if in the future they add some new preferred type
19 1         269 my $types = $app->types;
20             $types->type(mjs => ['application/javascript'])
21 1 50       24 unless exists $types->mapping->{mjs};
22              
23             $app->helper(multiplex => sub {
24 3     3   36052 my $c = shift;
25 3         12 my $tx = $c->tx;
26 3 50       21 return undef unless $tx->is_websocket;
27 3 50       24 $c->rendered(101) unless $tx->established;
28 3   33     818 return $c->stash->{'multiplex.multiplexer'} ||= Mojolicious::Plugin::Multiplex::Multiplexer->new(tx => $tx);
29 1         70 });
30             }
31              
32             1;
33              
34             =head1 NAME
35              
36             Mojolicious::Plugin::Multiplex - A websocket multiplexing layer for Mojolicious applications
37              
38             =head1 SYNOPSIS
39              
40             use Mojolicious::Lite;
41              
42             plugin 'Multiplex';
43              
44             get '/' => 'index';
45              
46             websocket '/multiplex' => sub {
47             my $c = shift;
48             my $multiplex = $c->multiplex;
49             $multiplex->on(subscribe => sub { ... });
50             $multiplex->on(message => sub { ... });
51             $multiplex->on(unsubscribe => sub { ... });
52             };
53              
54             __DATA__
55              
56             @@ index.html.ep
57              
58             %= javascript 'websocket_multiplex.js';
59            
67              
68             =head1 DESCRIPTION
69              
70             L implements a mechanism proposed by L for the multiplexing of data on a single websocket.
71             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.
72             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.
73              
74             Their proposal only includes a partially implemented reference implementation.
75             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.
76             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.
77              
78             On the server-side the logic is entirely up to the application author.
79             The module simply parses the multiplexed messages and emits events in accordance with them.
80             A typical use case may be to relay message to a bus, subscribing and unsubscribing from topics that it presents.
81             Another might be to stream updates to multiple types of data (perhaps in multiple parts of a single page application).
82             (Indeed those might not be distinct cases from each other).
83              
84             For reference, the distribution comes with an example which uses L as a message broker for a multi-channel chat application.
85             The example may also be seen on L.
86              
87             =head1 CAVEAT
88              
89             While I'm declaring this module stable and production worthy, I still don't nearly have enough tests.
90             The biggest reason for this is that I don't have a great way to test Perl and Javascript together.
91             Unfortunately PhantomJS declared defeat right as L was catching on.
92             A project to wrap its successor, headless Chrome, is stalled waiting for now, so we wait.
93             Contributions from people with experience in this area would be greatly appreciated.
94              
95             =head1 HELPERS
96              
97             =head2 multiplex
98              
99             my $multiplex = $c->multiplex;
100              
101             Establishes the WebSocket connection (if it hasn't been already) and returns an instance of L.
102             The multiplexer is attached to the websocket stream and begins listening for messages.
103             The multiplexer emits events for incoming messages and has methods to send outgoing messages; more details about those are contained in its own documentation.
104              
105             Note that for each websocket connection the same instance of the multiplexer will be returned on any subsequent call.
106             Though not prevented, the user is highly discouraged from sending other traffic over any websocket connection that is managed by a multiplexer.
107              
108             =head1 BUNDLED FILES
109              
110             =head2 websocket_multiplex.mjs
111              
112            
118              
119             Bundled with this plugin is a javascript module file called C which contains the front-end code to create a multiplexer.
120             It exports the C class, whose constructor takes as its only argument an existing WebSocket object or a url string to build one.
121             This then is used to open new channel objects via the C method which takes a topic string as an arugment.
122             Topics can be almost any string, however they must not contain a comma (a limitation of the protocol).
123             The resulting channel objects implement the same API as a WebSocket (though they do not inherit from it).
124              
125             The client-side multiplexer will also attempt to reconnect to closed sockets and when successful will automatically resubscribe to the channels that were subscribed.
126              
127             N.B. This library is the least stable of the entire project.
128             Use with caution.
129              
130             Also, this library will likely use very modern conventions, even going forward.
131             Older browsers are not the target for this file.
132             For those you want ...
133              
134             =head2 websocket_multiplex.js
135              
136            
137            
142              
143             This is the above javascript module but transpiled back to work on older browsers (and minified).
144             It sets the global symbol C when loaded.
145             In all other ways it works just like the above file.
146              
147             =head2 websocket_multiplex.js.map
148              
149             A file used to get better diagnostics from the minified javascript file.
150              
151             =head1 SOURCE REPOSITORY
152              
153             L
154              
155             =head1 AUTHOR
156              
157             Joel Berger, Ejoel.a.berger@gmail.comE
158              
159             =head1 ADDITIONAL THANKS
160              
161             John Susek
162              
163             =head1 COPYRIGHT AND LICENSE
164              
165             Copyright (C) 2016-2018 by Joel Berger
166              
167             This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself.
168              
169             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.
170              
171             =cut
172              
173