NAME
PAGI::Context::WebSocket - WebSocket context with protocol operations
SYNOPSIS
use PAGI::Context;
use Future::AsyncAwait;
# Simple echo — $ctx is all you need
async sub echo_handler {
my ($scope, $receive, $send) = @_;
my $ctx = PAGI::Context->new($scope, $receive, $send);
await $ctx->accept;
await $ctx->each_text(async sub {
my ($text) = @_;
await $ctx->send_text("Echo: $text");
});
}
# Event-dispatched chat with channels
async sub chat_handler {
my ($scope, $receive, $send) = @_;
my $ctx = PAGI::Context->new($scope, $receive, $send);
my $room = $ctx->path_param('room', strict => 0) // 'general';
my $user = $ctx->query('user') // 'anonymous';
await $ctx->accept;
my $reason = await $ctx
->on('websocket.receive', async sub {
my ($ctx, $event) = @_;
# handle incoming message
})
->on('chat.message', async sub {
my ($ctx, $event) = @_;
await $ctx->send_json($event);
})
->on_error(sub {
my ($ctx, $err, $source) = @_;
warn "[$source] $err";
})
->run;
}
DESCRIPTION
Returned by PAGI::Context->new(...) when $scope->{type} is 'websocket'. Inherits all shared methods from PAGI::Context (scope accessors, stash, session, event dispatcher) and adds WebSocket protocol operations delegated to PAGI::WebSocket.
This means handler code can use a single $ctx object for everything: dispatching events with on()/run(), sending messages with send_json(), reading query params with query(), and so on.
Underlying object access
my $ws = $ctx->websocket; # or $ctx->ws
The underlying PAGI::WebSocket object is still available if you need direct access. In most cases you should not need it.
Methods NOT delegated
The following PAGI::WebSocket methods are not available on $ctx. They are intentionally omitted because PAGI::Context has its own versions with different semantics:
on()— On$ctx, this is the generic event dispatcher ("on" in PAGI::Context) that accepts any event type string. On PAGI::WebSocket, it is a Socket.IO-style dispatcher limited tomessage,close,error.on_error()— On$ctx, callbacks receive($ctx, $error, $source). On PAGI::WebSocket, they receive($error).on_close(),on_message()— PAGI::WebSocket-specific callback registration. Use$ctx->on('websocket.disconnect', ...)and$ctx->on('websocket.receive', ...)instead.run()— On$ctx, this is the generic event dispatch loop ("run" in PAGI::Context). On PAGI::WebSocket, it only dispatcheson_messagecallbacks.
CONNECTION LIFECYCLE
accept
await $ctx->accept;
await $ctx->accept(subprotocol => 'chat');
await $ctx->accept(headers => [['x-custom', 'value']]);
Accepts the WebSocket connection. Optionally specify a subprotocol and additional response headers.
close
await $ctx->close;
await $ctx->close(4000, 'Custom reason');
Closes the connection. Default code is 1000 (normal closure). Idempotent — calling multiple times only sends close once.
SEND METHODS
send_text, send_bytes, send_json
await $ctx->send_text("Hello!");
await $ctx->send_bytes("\x00\x01\x02");
await $ctx->send_json({ action => 'greet', name => 'Alice' });
Send a message. Dies if connection is closed.
try_send_text, try_send_bytes, try_send_json
my $sent = await $ctx->try_send_json($data);
Returns true if sent, false if failed or closed. Does not throw. Useful for broadcasting to multiple clients.
send_text_if_connected, send_bytes_if_connected, send_json_if_connected
await $ctx->send_json_if_connected($data);
Silent no-op if connection is closed. Useful for fire-and-forget.
RECEIVE METHODS
receive_text, receive_bytes, receive_json
my $text = await $ctx->receive_text;
my $bytes = await $ctx->receive_bytes;
my $data = await $ctx->receive_json;
Wait for a specific frame type, skipping others. Returns undef on disconnect. receive_json dies on invalid JSON.
ITERATION HELPERS
each_message, each_text, each_bytes, each_json
await $ctx->each_text(async sub {
my ($text) = @_;
await $ctx->send_text("Got: $text");
});
Loop until disconnect, calling callback for each message.
STATE INSPECTION
is_connected
if ($ctx->is_connected) { ... }
Overrides the base class method. Returns true if the WebSocket handshake is complete and the connection is not yet closed. The base PAGI::Context version checks the TCP-level pagi.connection object; this version checks WebSocket protocol state, which is what handler code actually cares about.
is_closed
if ($ctx->is_closed) { ... }
True after close or disconnect.
close_code, close_reason
my $code = $ctx->close_code; # 1000, 4000, etc.
my $reason = $ctx->close_reason; # 'Normal closure'
Available after connection closes.
subprotocols
my $protos = $ctx->subprotocols; # ['chat', 'json']
Requested subprotocols from the client.
QUERY PARAMETERS
query
my $value = $ctx->query('user');
my $value = $ctx->query('page', strict => 1);
Returns a single query parameter value. Accepts strict and raw options.
query_params
my $params = $ctx->query_params; # Hash::MultiValue
All query parameters as Hash::MultiValue.
raw_query, raw_query_params
my $val = $ctx->raw_query('name');
my $params = $ctx->raw_query_params;
Skip UTF-8 decoding, return raw bytes after URL decoding.
HEADER EXTRAS
header_all
my @cookies = $ctx->header_all('cookie');
All values for a multi-value header. The base class header() method returns only the last value; header_all returns all of them.
http_version
my $ver = $ctx->http_version; # '1.1' or '2'
KEEPALIVE
keepalive
await $ctx->keepalive(30); # Ping every 30 seconds
await $ctx->keepalive(30, 20); # Ping every 30s, pong timeout 20s
Enables WebSocket protocol-level ping/pong keepalive.
SEE ALSO
PAGI::Context, PAGI::WebSocket, PAGI::Context::SSE, PAGI::Context::HTTP
1 POD Error
The following errors were encountered while parsing the POD:
- Around line 96:
Non-ASCII character seen before =encoding in '—'. Assuming UTF-8