The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

WebSocket::Server - WebSocket Server

SYNOPSIS

    use WebSocket::Server;
    use JSON;
    my $origin = 'http://localhost';
    my $j = JSON->new->relaxed->convert_blessed;
    my $ws = WebSocket::Server->new(
        debug => 3,
        connection_class => 'My::Connection',
        port => 8080,
        on_connect => sub
        {
            my( $serv, $conn ) = @_;
            # Set the code that will issue pong reply to ping queries from the client
            $conn->do_pong(sub
            {
                # WebSocket::Connection and a scalar of bytes received
                my( $c, $bytes ) = @_;
                # This is the default behaviour
                return( $c->pong( $bytes ) );
            });
            
            # See WebSocket::Connection for more information on the followings:
            $conn->on(
                handshake => sub
                {
                    my( $conn, $handshake ) = @_;
                    print( "Connection from ip '", $conn->ip, "' on port '", $conn->port, "'\n" );
                    print( "Query string: '", $handshake->request->uri->query, "'\n" );
                    print( "Origin is: '", $handshake->request->origin, "', ", ( $handshake->request->origin eq $origin ? '' : 'not ' ), "ok\n" );
                    # $conn->disconnect() unless( $handshake->request->origin eq $origin );
                },
                ping => \&on_ping,
                pong => \&on_pong,
                ready => sub
                {
                    my $conn = shift( @_ );
                    my $hash = { code => 200, type => 'user', message => "Hello" };
                    my $json = $j->encode( $hash );
                    $conn->send_utf8( $json );
                },
                utf8 => sub
                {
                    my( $conn, $msg ) = @_;
                    # $conn->send_utf8( $msg );
                    print( "Received message: '$msg'\n" );
                },
                disconnect => sub
                {
                    my( $conn, $code, $reason ) = @_;
                    print( "Client diconnected from ip '", $conn->ip, "'\n" );
                },
            );
        },
    ) || die( WebSocket::Server->error );
    $ws->start || die( $ws->error );

VERSION

    v0.2.0

DESCRIPTION

This is a server class for the WebSocket protocol.

CONSTRUCTOR

new

Instantiate a new WebSocket server object. This takes the following options:

extensions

Optional. One or more extension enabled for this server. For example permessage-deflate to enable message compression.

You can set this to either a string or a WebSocket::Extension object if you want, for example to set the extension parameters.

See rfc6455 section 9.1 for more information on extension.

Seel also "compression_threshold".

connection_class

This is optional and defaults to WebSocket::Connection. You can use this to set an alternative class to be used to handle incoming connections.

See "connection_class" for more details.

listen

Optional. A IO::Socket object, or one of its inheriting packages. This enables you to instantiate your own IO::Socket object and pass it here to be used. For example:

    my $ssl_server = IO::Socket::SSL->new(
        Listen             => 5,
        LocalPort          => 8080,
        Proto              => 'tcp',
        SSL_startHandshake => 0,
        SSL_cert_file      => '/path/to/server.crt',
        SSL_key_file       => '/path/to/server.key',
    ) or die "failed to listen: $!";
    my $server = WebSocket::Server->new( listen => $ssl_server ) || die( WebSocket::Server->error );
on_connect

A code reference that will be triggered upon connection from client.

It will be passed the the server object and the connection object (by default WebSocket::Connection, but this can be configured with connection_class).

See "on_connect" for more information.

on_shutdown

A code reference that will be triggered upon termination of the connection.

See "on_shutdown" for more information.

on_tick

A code reference that will be triggered for every tick.

See "on_tick" for more information.

port

The port number on which to connect.

silence_max

The maximum value for ping frequency.

tick_period

Frequency for the tick.

version

The version supported. Defaults to draft-ietf-hybi-17 which means version 13 (the latest as of 2021-09-24)

See also "version" to change this afterward.

watch_readable

An array reference of filehandle and subroutine callback as code reference. Each callback will be passed the WebSocket::Server object and the socket filehandle.

The callback is called when the filehandle provided becomes readable.

watch_writable

An array reference of filehandle and subroutine callback as code reference. Each callback will be passed the WebSocket::Server object and the socket filehandle.

The callback is called when the filehandle provided becomes writable.

If there are any issue with the instantiation, it will return undef and set an error WebSocket::Exception that can be retrieved with the error method inherited from Module::Generic

METHODS

compression_threshold

Inherited from WebSocket

Set or get the threshold in bytes above which the ut8 or binary messages will be compressed if the client and the server support compression and it is activated as an extension.

connection_class

Sets or gets a class name to be used to handle incoming connections. This defaults to WebSocket::Connection

This class name will be loaded in "start" and if any error occurs upon loading, "start" will set an error and return undef

The class specified will be instantiated with the following parameters:

  • debug

    An integer representing the debug level enabled for this object.

  • server

    The current server object.

  • socket

    The client socket accepted. This is an IO::Socket object.

  • subprotocol

    An array of protocols as set with "subprotocol"

connections

Returns the client connections currently active.

In list context, or if the legacy is turned on, this returns a regular array:

    for( $server->connections )
    {
        print( "Connection from ip '", $_->ip, "' on port '", $_->port, "'\n" );
    }

In any other context, including object context, this returns a Module::Generic::Array, such as:

    $server->connections->for(sub
    {
        my $conn = shift( @_ );
        print( "Connection from ip '", $conn->ip, "' on port '", $conn->port, "'\n" );
    });

disconnect

Provided with the client socket filehandle and this will close the connection for that client.

extensions

Set or get the extension enabled for this server. For example permessage-deflate to enable message compression.

You can set this to either a string or a WebSocket::Extension object if you want, for example to set the extension parameters.

See rfc6455 section 9.1 for more information on extension.

ip

Set or get the ip address to which the server is connected to.

is_ssl

Returns true if the server is using a ssl connection, false otherwise.

This value is set automatically upon calling "start".

legacy

Set or get the boolean value whether the method "connections" use the legacy pattern and returns a list of current connection objects, or if false, it returns an array object instead. This defaults to false.

listen

Get the IO::Socket (or any of its inheriting classes such as IO::Socket::INET or IO::Socket::SSL) server socket object.

This value is set automatically upon calling "start", or it can also be provided upon server object instantiation. See "new" option parameters.

on

Provided with an hash or hash reference of event name and code reference pairs and this will set those event handlers.

Possible event names are: accept, connect, shutdown, tick.

See below their corresponding method for more details.

See also WebSocket::Connection for event handlers that can be set when a connection has been established.

It returns the current object.

on_accept

Set or get the code reference for the event handler that is triggered afer a new client connection has been accepted.

The handler will be passed an hash reference containing the following properties:

  • server

    The current server object.

  • socket

    The client socket accepted. This is an IO::Socket object.

  • subprotocol

    An array of protocols as set with "subprotocol"

It expects a class object in returns that supports the same methods as in WebSocket::Connection, and at the very least error, is_ready, new, recv and send. If the object returned does not, then you should expect some errors occurring.

If nothing is returned, it will use the class specified with "connection_class" instead.

on_connect

Set or get the code reference for the event handler that is triggered when there is a new client connection, and after the connection has been established.

At this stage, no handshake has happened yet. This is just the server receiving a connection,

The handler is passed the server object and the connection object.

    use curry;
    $server->on_connect(sub
    {
        my( $s, $conn ) = @_;
        print( "Connection received from ip '", $conn->ip, "'\n" );
        $conn->do_pong( \&pong );
        $conn->max_recv_size(65536);
        $conn->max_send_size(65536);
        $conn->nodelay(1);
        # set handler for each event
        # See WebSocket::Connection for details on the arguments provided
        # You can also check out the example given in the symopsis
        $conn->on(
            handshake   => $self->curry::onconnect,
            ready       => $self->curry::onready,
            origin      => $self->curry::onorigin,
            utf8        => $self->curry::onmessage,
            binary      => $self->curry::onbinary,
            ping        => $self->curry::onping,
            pong        => $self->curry::onpong,
            disconnect  => $self->curry::onclose,
        );
    });

If the connect handler returns a defined, but false value, such as an empty string or 0, this will have WebSocket::Server close the client connection that was just accepted

The same could also be achieved by the handler like so:

    use Net::IP;
    my $banned = [qw( 192.168.2.0/24 )];
    $server->on_connect(sub
    {
        my( $s, $conn ) = @_;
        my $ip = Net::IP->new( $conn->ip );
        my $is_banned = grep( $ip->overlaps( Net::IP->new( $_ ) ) == $Net::IP::IP_A_IN_B_OVERLAP, @$banned );
        return(0) if( $is_banned );
        # or, alternatively:
        # if( $is_banned )
        # {
        #     # This will shutdown the TCP connection and close the filehandle of the socket
        #     $conn->disconnect;
        #     return;
        # }
        # Then, set the handlers
        $conn->on(
            handshake   => $self->curry::onconnect,
            ready       => $self->curry::onready,
            origin      => $self->curry::onorigin,
            utf8        => $self->curry::onmessage,
            binary      => $self->curry::onbinary,
            ping        => $self->curry::onping,
            disconnect  => $self->curry::onclose,
        );
    });

Any fatal error occurring in the callback are caught using try-catch with (Nice::Try), and if an error occurs, this method will raise a warning if warnings are enabled, and this will set an error and returns undef or an empty list depending on the context.

on_shutdown

Set or get the code reference for the event handler that is triggered before calling "disconnect" on every connected client and before the server is shutting down.

The callback is provided this server object as its sole argument.

Any fatal error occurring in the callback are caught using try-catch with (Nice::Try), and if an error occurs, this method will raise a warning if warnings are enabled.

on_tick

Set or get the code reference for the event handler that is triggered for every tick, if enabled by setting "tick_period" to a true value.

The handler is passed this server object.

Any fatal error occurring in the callback are caught using try-catch with (Nice::Try), and if an error occurs, this method will raise a warning if warnings are enabled.

port

Sets or gets the port on which this server is listening to.

shutdown

Shuts down the server connection, calls the event handler "on_shutdown", and calls disconnect on each active client connection passing them the code 1001

It returns the current server object.

silence_checkinterval

Sets or gets the interval in seconds. This is used to set the frequency of pings and also contribute to set the timeout.

silence_max

socket

This is an alias for "listen". It returns the server socket object.

start

Starts the server.

If a socket object has already been initiated and provided with the "new" option listen, then it will be used, otherwise, it will instantiate a new IO::Socket::INET connection. If a port option was provided in "new", it will be used, otherwise it will be auto allocated and the port assigned can then be retrieved using the "port" method.

For every client connection received, it will call the accept callback, if specified, providing it the server, socket, subprotocol values and expect an object back.

If the accept callback dies, this will be caught and this method start will set an error accordingly and return undef

If no connection object has been provided by the accept callback, it will instantiate a new connection object, using a class name specified with "connection_class" or by default WebSocket::Connection and call the "on_connect" event handler, passing it the server object and the connection object.

This connection class name will be loaded and if any error occurs upon loading, this will set an error and return undef

The class specified will be instantiated with the following parameters:

  • debug

    An integer representing the debug level enabled for this object.

  • server

    The current server object.

  • socket

    The client socket accepted. This is an IO::Socket object.

  • subprotocol

    An array of protocols as set with "subprotocol"

If tick_period option in "new" has been set, this will trigger the "on_tick" event handler at the tick_period interval.

stop

This just an alias for "shutdown"

subprotocol

Set or get an array object of WebSocket protocols. This array object will be passed to each new WebSocket::Connection object upon each connection received.

Returns a Module::Generic::Array object.

See rfc6455 for more information

tick_period

Set or get the tick interval period.

unwatch_readable

This takes one or more filehandle, and removes them from being watched.

It returns the current server object.

unwatch_writable

This takes one or more filehandle, and removes them from being watched.

It returns the current server object.

version

The version supported. Defaults to draft-ietf-hybi-17 which means version 13 (the latest as of 2021-09-24)

See rfc6455 section 4.4 for more information

Returns an array of WebSocket::Version objects, each stringifies to its numeric value.

versions

Set or get the list of supported protocol versions.

It can take inteer sucha s 13, which is the latest WebSocket rfc6455 protocol version, or one or more WebSocket::Version objects.

watch_readable

This takes a list or an array reference of filehandle and subroutine callback as code reference. Each callback will be passed the WebSocket::Server object and the socket filehandle.

The callback is called when the filehandle provided becomes readable.

It returns the current server object.

watch_writable

This takes a list or an array reference of filehandle and subroutine callback as code reference. Each callback will be passed the WebSocket::Server object and the socket filehandle.

The callback is called when the filehandle provided becomes writable.

It returns the current server object.

watched_readable

    my $code = $ws->watched_readable( $fh );
    my( $fh1, $code1, $fh2, $code2 ) = $ws->watched_readable;
    my @all = $ws->watched_readable;

If a file handle is provided as a unique argument, it returns the corresponding callback, if any.

Otherwise, if no argument is provided, it returns a list of file handle and their calback.

watched_writable

    my $code = $ws->watched_writable( $fh );
    my( $fh1, $code1, $fh2, $code2 ) = $ws->watched_writable;
    my @all = $ws->watched_writable;

If a file handle is provided as a unique argument, it returns the corresponding callback, if any.

Otherwise, if no argument is provided, it returns a list of file handle and their calback.

CREDITS

Graham Ollis for AnyEvent::WebSocket::Client, Eric Wastl for Net::WebSocket::Server, Vyacheslav Tikhanovsky aka VTI for Protocol::WebSocket

AUTHOR

Jacques Deguest <jack@deguest.jp>

SEE ALSO

WebSocket::Client

COPYRIGHT & LICENSE

Copyright(c) 2021-2023 DEGUEST Pte. Ltd.

You can use, copy, modify and redistribute this package and associated files under the same terms as Perl itself.