File Coverage

blib/lib/Net/Async/WebSocket/Server.pm
Criterion Covered Total %
statement 42 47 89.3
branch 4 6 66.6
condition 2 2 100.0
subroutine 10 11 90.9
pod 4 4 100.0
total 62 70 88.5


line stmt bran cond sub pod time code
1             # You may distribute under the terms of either the GNU General Public License
2             # or the Artistic License (the same terms as Perl itself)
3             #
4             # (C) Paul Evans, 2010-2014 -- leonerd@leonerd.org.uk
5              
6             package Net::Async::WebSocket::Server;
7              
8 3     3   124468 use strict;
  3         14  
  3         93  
9 3     3   16 use warnings;
  3         6  
  3         84  
10 3     3   16 use base qw( IO::Async::Listener );
  3         6  
  3         1499  
11              
12 3     3   25793 use Carp;
  3         8  
  3         193  
13              
14             our $VERSION = '0.13';
15              
16 3     3   490 use Net::Async::WebSocket::Protocol;
  3         11  
  3         81  
17              
18 3     3   1350 use Protocol::WebSocket::Handshake::Server;
  3         19122  
  3         1265  
19              
20             =head1 NAME
21              
22             C - serve WebSocket clients using C
23              
24             =head1 SYNOPSIS
25              
26             use IO::Async::Loop;
27             use Net::Async::WebSocket::Server;
28              
29             my $server = Net::Async::WebSocket::Server->new(
30             on_client => sub {
31             my ( undef, $client ) = @_;
32              
33             $client->configure(
34             on_text_frame => sub {
35             my ( $self, $frame ) = @_;
36             $self->send_text_frame( $frame );
37             },
38             );
39             }
40             );
41              
42             my $loop = IO::Async::Loop->new;
43             $loop->add( $server );
44              
45             $server->listen(
46             service => 3000,
47             )->get;
48              
49             $loop->run;
50              
51             =head1 DESCRIPTION
52              
53             This subclass of L accepts WebSocket connections. When a
54             new connection arrives it will perform an initial handshake, and then pass the
55             connection on to the continuation callback or method.
56              
57             =cut
58              
59             =head1 EVENTS
60              
61             The following events are invoked, either using subclass methods or CODE
62             references in parameters:
63              
64             =head2 on_client
65              
66             $self->on_client( $client )
67             $on_client->( $self, $client )
68              
69             Invoked when a new client connects and completes its initial handshake.
70              
71             It will be passed a new instance of a L
72             object, wrapping the client connection.
73              
74             =head2 on_handshake
75              
76             Invoked when a handshake has been requested.
77              
78             $self->on_handshake( $client, $hs, $continue )
79             $on_handshake->( $self, $client, $hs, $continue )
80              
81             Calling C<$continue> with a true value will complete the handshake, false will
82             drop the connection.
83              
84             This is useful for filtering on origin, for example:
85              
86             on_handshake => sub {
87             my ( $self, $client, $hs, $continue ) = @_;
88              
89             $continue->( $hs->req->origin eq "http://localhost" );
90             }
91              
92             =cut
93              
94             sub new
95             {
96 2     2 1 9822 my $class = shift;
97 2         31 return $class->SUPER::new(
98             handle_class => "Net::Async::WebSocket::Protocol",
99             @_,
100             );
101             }
102              
103             sub on_accept
104             {
105 2     2 1 476 my $self = shift;
106 2         6 my ( $client ) = @_;
107              
108 2         32 my $hs = Protocol::WebSocket::Handshake::Server->new;
109              
110             $client->configure(
111             on_read => sub {
112 2     2   2120 my ( $client, $buffref, $closed ) = @_;
113              
114 2         14 $hs->parse( $$buffref ); # modifies $$buffref
115              
116 2 50       1760 if( $hs->is_done ) {
117             my $on_handshake = $self->can_event( "on_handshake" ) ||
118 2   100     49 sub { $_[3]->( 1 ) };
119              
120             $on_handshake->( $self, $client, $hs, sub {
121 2         20 my ( $ok ) = @_;
122              
123 2 50       8 unless( $ok ) {
124 0         0 $self->remove_child( $client );
125 0         0 return;
126             }
127              
128 2         11 $client->configure( on_read => undef );
129 2         170 $client->write( $hs->to_string );
130              
131 2         1451 $client->debug_printf( "HANDSHAKE done" );
132 2         22 $self->invoke_event( on_client => $client );
133 2         48 } );
134             }
135              
136 2         208 return 0;
137             },
138 2         34 );
139              
140 2         165 $self->add_child( $client );
141             }
142              
143             =head1 PARAMETERS
144              
145             The following named parameters may be passed to C or C:
146              
147             =over 8
148              
149             =item on_client => CODE
150              
151             =item on_handshake => CODE
152              
153             CODE references for event handlers.
154              
155             =back
156              
157             =cut
158              
159             sub configure
160             {
161 2     2 1 89 my $self = shift;
162 2         9 my %params = @_;
163              
164 2         8 foreach (qw( on_client on_handshake )) {
165 4 100       28 $self->{$_} = delete $params{$_} if exists $params{$_};
166             }
167              
168 2         15 $self->SUPER::configure( %params );
169             }
170              
171             sub listen
172             {
173 0     0 1   my $self = shift;
174 0           my %params = @_;
175              
176 0           $self->SUPER::listen(
177             socktype => 'stream',
178             %params,
179             );
180             }
181              
182             =head1 AUTHOR
183              
184             Paul Evans
185              
186             =cut
187              
188             0x55AA;