Cro
The Cro project is being transferred to the Raku community. Find out more.

Cro::HTTP::Router::WebSocket

This exports a subroutine web-socket that is to be used inside of a Cro::HTTP::Router get handler. This makes it easy to use WebSockets inside of a HTTP application built using the router.

Basic usage§

The web-socket subroutine takes a code block, which will - per new WebSocket connection - receive a Supply argument. This Supply will emit a Cro::WebSocket::Message for each message received from the client. The block is expected to return a Supply that will emit messages to be sent to the client.

Thus, a highly simplified chat server might be written as:

my $chat = Supplier.new;

get -> 'chat' {
    web-socket -> $incoming {
        supply {
            whenever $incoming -> $message {
                $chat.emit(await $message.body-text);
            }
            whenever $chat -> $text {
                emit $text;
            }
        }
    }
}

Receiving close messages§

If the block passed to web-socket has two parameters, the second one shall be passed a Promise that will be kept with any Close message sent by the client, or alternatively when the socket is closed from the server side.

my $chat = Supplier.new;

get -> 'chat' {
    web-socket -> $incoming, $close {
        supply {
            whenever $incoming -> $message {
                $chat.emit(await $message.body-text);
            }
            whenever $chat -> $text {
                emit $text;
            }
            whenever $close {
                $chat.emit("A user left the chat");
            }
        }
    }
}

Body parsing and serialization§

Body parsers (implementing the Cro::BodyParser role) and body serializers (implementing the Cro::BodySerializer role) may be passed to web-socket. These allow for easier processing of, for example, JSON messages.

use Cro::WebSocket::BodyParsers;
use Cro::WebSocket::BodySerializers;

# Receives JSON messages like:
#   { "input": "देवनागरी" }
# And produces messages like:
#   { "result": 5 }
get -> 'graphemes' {
    web-socket
        :body-parsers(Cro::WebSocket::BodyParser::JSON),
        :body-serializers(Cro::WebSocket::BodySerializer::JSON),
        -> $incoming {
            supply whenever $incoming -> $message {
                my $json = await $message.body;
                emit { result => $json<input>.chars };
            }
        }
}

Since working with JSON is so common, there is a shortcut :json argument to web-socket that configures the body parser and serializer as seen in the previous example, reducing it to just:

get -> 'graphemes' {
    web-socket :json, -> $incoming {
        supply whenever $incoming -> $message {
            my $json = await $message.body;
            emit { result => $json<input>.chars };
        }
    }
}