NAME

Langertha::Skeid::Proxy::Realtime - One realtime session -- two WebSockets joined, bounded, ended once

VERSION

version 0.004

DESCRIPTION

The relay of the realtime route (skeid k95, ADR 0029). Langertha::Skeid::Proxy answers the handshake -- the client gate, the model, routing, admission, the node's key, the upstream WebSocket, the upgrade -- and then hands both open WebSockets to "start_session". From there a session is two transactions, the client's and the node's, and this module is everything that happens until one of them ends:

  • Text frames go across both ways in order. The client's are decoded and checked first ("client_frame" in Langertha::Skeid::Protocol::Realtime: a model the key was not granted is refused with an error event, the session's own is rewritten to the served one); the node's are read for usage and relayed as the bytes they came in. A binary frame from the client closes the session 1003, like a frame that is no JSON object.

  • Nothing grows without bound. A message above realtime.max_message_bytes closes the session 1009 (the transaction's own limit, set per session); bytes written to a peer that has not taken them yet are counted per direction, and past realtime.max_queued_bytes the session closes 1013. A session silent for realtime.idle_timeout seconds and one older than realtime.max_session_seconds are closed 1000, by timers (ADR 0005).

  • It ends once. Whichever side closes first, or a limit, the one finish callback runs -- request.finish, the usage event -- and then the other side is closed with the mapped code. Codes that cannot travel on the wire (1005, 1006, 1015) are mapped: a client that went away closes the node with 1000, a node that died closes the client with 1011.

  • A graceful stop of the process (the event loop's finish event, which the prefork worker emits on SIGQUIT) closes every open session 1001 first, so its finish callback and its usage event run before the worker exits.

The module does I/O only through the two transactions and Mojo::IOLoop timers, and knows no routing and no usage store: the finish callback is the proxy's.

start_session

my $session = $realtime->start_session(
  client          => $c->tx,            # established server WebSocket transaction
  upstream        => $up_tx,            # established client WebSocket transaction to the node
  requested_model => 'house-asr',
  served_model    => 'whisper-large',
  started         => time,              # when the handshake began
  limits          => { idle_timeout => 300, max_session_seconds => 3600,
                       max_message_bytes => 1048576, max_queued_bytes => 4194304 },
  finish          => sub { my ($result) = @_; ... },
);

Starts the relay. finish is called exactly once, with a hashref: ok, status_code, error_type, error_message (empty for a session that ended well), aborted and rejected (for request.finish), duration_ms, usage (the summed usage blocks, or undef), audio_seconds and content_bytes (absent when nothing measured them) and transcriptions. Returns the number of the session.

open_count

How many sessions are open.

shutdown

$realtime->shutdown;

Closes every open session 1001 ("going away"); their finish callbacks run first. Called from the event loop's finish event.

SEE ALSO

"Realtime route" in Langertha::Skeid::Proxy, Langertha::Skeid::Protocol::Realtime

SUPPORT

Issues

Please report bugs and feature requests on GitHub at https://github.com/Getty/langertha-skeid/issues.

IRC

Join #langertha on irc.perl.org or message Getty directly.

CONTRIBUTING

Contributions are welcome! Please fork the repository and submit a pull request.

AUTHOR

Torsten Raudssus <torsten@raudssus.de> https://raudssus.de/

COPYRIGHT AND LICENSE

This software is copyright (c) 2026 by Torsten Raudssus.

This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.