=head1 NAME

Protocol::WebSocket::XS - very fast WebSocket protocol implementation



=head1 SYNOPSIS

    use Protocol::WebSocket::XS::ClientParser;
    use Protocol::WebSocket::XS::ServerParser;

    my $client = Protocol::WebSocket::XS::ClientParser->new;
    my $req_str = $client->connect_request({
        uri           => "ws://example.com/",
        ws_key        => "dGhlIHNhbXBsZSBub25jZQ==",
        ws_protocol   => "chat",
        ws_extensions => [ [ 'permessage-deflate'] ],
        headers       => {
            'Origin'          => 'http://www.crazypanda.ru',
            'User-Agent'      => 'My-UA',
        },
    });

    my $server = Protocol::WebSocket::XS::ServerParser->new;
    my $req    = $server->accept($req_str);

    my $accept_reply_str = $req->error ? $server->accept_error : $server->accept_response;
    my $reply = $client->connect($accept_reply_str);   # => isa 'Protocol::WebSocket::XS::ConnectResponse'
    $client->established;                       # => success
    $client->is_deflate_active;                 # => success
    $server->is_deflate_active;                 # => success

    # control frames
    my $data_1 = $client->send_control(OPCODE_PING, "hello");
    my ($frame_1) = $server->get_frames($data_1);

    $frame_1->payload;                          # => 'hello'
    $frame_1->payload_length;                   # => 5
    $frame_1->is_control;                       # => success
    $frame_1->opcode;                           # => OPCODE_PING
    $frame_1->final;                            # => success

    # send message split by frame
    my $builder = $server->start_message(opcode => OPCODE_TEXT, final => 0, deflate => 0);
    my $data_2 = $builder->send("Lorem ");
    my $data_3 = $builder->send("ipsum ");
    my $data_4 = $builder->final(1)->send("dolor ");

    my $message_data = join('', $data_2, $data_3, $data_4);
    my ($message_1) = $client->get_messages($message_data);

    $message_1->opcode;                         # => OPCODE_TEXT
    $message_1->is_control;                     # => 0
    $message_1->payload_length;                 # => 18
    $message_1->payload;                        # => 'Lorem ipsum dolor '
    $message_1->frame_count;                    # => 3

    # convenient way just to send message
    my $data_5 = $client->send_message(deflate => 1, payload => 'sit amet, ');

    # pieces merged into single frame/message
    my @payload_pieces = ('consectetur ', 'adipiscing ', 'elit.');
    my $data_6 = $client->send_message(deflate => 0, payload => \@payload_pieces);
    my $fit = $server->get_frames($data_6);    # => isa 'Protocol::WebSocket::XS::FrameIterator'
    $fit->next;                                # => isa 'Protocol::WebSocket::XS::Frame'
    $fit->next;                                # => undef

    # pieces are send as frames; a bit faster, when you already have your data and compression
    # is turned off
    my $data_7 = $client->send_message_multiframe(deflate => 0, payload =>\@payload_pieces);
    my $mit = $server->get_messages($data_7);  # => isa 'Protocol::WebSocket::XS::MessageIterator'
    my $message_2 = $mit->next;                # => isa 'Protocol::WebSocket::XS::Message'
    $message_2->frame_count;                   # => 3

    # server/client configuration
    my $client2 = Protocol::WebSocket::XS::ClientParser->new;
    $client2->configure({
        max_frame_size     => 1024 * 10,
        max_message_size   => 1024 * 100,
        max_handshake_size => 1024 * 5,
        deflate            => {             # always on by default
            compression_threshold => 0,     # compress all TEXT-frames
        },
    });

    # completely disable compression; effective before connection establishment
    $client2->no_deflate;



=head1 DESCRIPTION

C<Protocol::WebSocket::XS> is a port of C<panda::protocol::websocket>, extremely fast server/client zero-copy
incremental WebSocket parser and serialization library (L<rfc6455|https://tools.ietf.org/html/rfc6455>) with Perl and C++ interface.

The library supports compression (a.k.a. per-message deflate extension, see
L<rfc7692|https://tools.ietf.org/html/rfc7692>) via C<zlib> C library, which
is enabled by default for all text messages exceeding TCP max segment
size (1410 bytes).

The module has dual Perl/C++ interface (see L<XS::Manifesto>) so further
XS-bindings can be written on the top of C<Protocol::WebSocket::XS> (see L<UniEvent::WebSocket>).

The <Protocol::WebSocket::XS> is B<not> drop-in replacement of <Protocol::WebSocket>,
as it uses sligthly different API.



=head1 PERFORMANCE

Compared to C<Protocol::WebSocket>. Tests were performed on Xeon v3-2687W 2.9Ghz, Debian 10.

Parsing websocket packet with 200 bytes payload.
    
                                 Rate   Protocol::WebSocket  Protocol::WebSocket::XS
    Protocol::WebSocket       68593/s                     --                    -97%
    Protocol::WebSocket::XS 2360644/s                  3342%                      --

    

=head1 CONSTANTS

=head2 Opcodes

=over

=item OPCODE_CONTINUE

=item OPCODE_TEXT

=item OPCODE_BINARY

=item OPCODE_CLOSE

=item OPCODE_PING

=item OPCODE_PONG

=back

=head2 Close codes

=over

=item CLOSE_DONE

=item CLOSE_AWAY

=item CLOSE_PROTOCOL_ERROR

=item CLOSE_INVALID_DATA

=item CLOSE_UNKNOWN

=item CLOSE_ABNORMALLY

=item CLOSE_INVALID_TEXT

=item CLOSE_BAD_REQUEST

=item CLOSE_MAX_SIZE

=item CLOSE_EXTENSION_NEEDED

=item CLOSE_INTERNAL_ERROR

=item CLOSE_TLS

=back



=head1 REFERENCE

L<Protocol::WebSocket::XS::ClientParser>

L<Protocol::WebSocket::XS::ServerParser>

L<Protocol::WebSocket::XS::Parser>

L<Protocol::WebSocket::XS::ConnectRequest>

L<Protocol::WebSocket::XS::ConnectResponse>

L<Protocol::WebSocket::XS::Message>

L<Protocol::WebSocket::XS::MessageIterator>

L<Protocol::WebSocket::XS::Frame>

L<Protocol::WebSocket::XS::FrameIterator>

L<Protocol::WebSocket::XS::FrameSender>

L<Protocol::WebSocket::XS::Error>



=head1 SEE ALSO

L<rfc6455|https://tools.ietf.org/html/rfc6455>

L<rfc7692|https://tools.ietf.org/html/rfc7692>

L<Protocol::HTTP>

L<Protocol::WebSocket>



=head1 AUTHOR

Pronin Oleg <syber@cpan.org>, Crazy Panda LTD

Ivan Baidakou <dmol@cpan.org>, Crazy Panda LTD



=head1 LICENSE

You may distribute this code under the same terms as Perl itself.

=cut
