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