.. _library_http_websocket_session:

``http_websocket_session``
==========================

This library provides the next WebSocket slice on top of the
``http_websocket_messages`` library. It adds a state term for
incremental reads, surfaces interleaved control messages while a
fragmented text or binary message is still pending, applies role-aware
client and server masking when writing messages, and can automatically
orchestrate close replies and optional pong replies.

This library is a pure state-machine layer working on binary streams: it
does not create threads and does not depend on socket support. The
higher-level callback-driven session loops, keepalive and idle-timeout
policies, and the registry-backed broadcast helpers for upgraded
``http_socket_transport`` connections are provided by the
``http_websocket_service`` library.

This library can be used with backend Prolog systems that support
unbound integer arithmetic.

API documentation
-----------------

Open the
`../../apis/library_index.html#http_websocket_session <../../apis/library_index.html#http_websocket_session>`__
link in a web browser.

Loading
-------

To load the library, load the ``loader.lgt`` file:

::

   | ?- logtalk_load(http_websocket_session(loader)).

Testing
-------

To test this library, load the ``tester.lgt`` file:

::

   | ?- logtalk_load(http_websocket_session(tester)).

Current scope
-------------

The current implementation provides:

- ``initial_state/1`` and ``is_state/1`` for working with session state
  terms.
- ``read_message/4`` for stateful message reads that preserve pending
  fragmented data across interleaved control messages while tracking
  close-handshake state.
- ``read_message/5`` for stateful message reads plus automatic
  close-handshake replies.
- ``read_message/6`` for stateful message reads plus automatic
  close-handshake replies and optional auto-pong and maximum payload
  length policies.
- ``write_message/2-3`` as stateless convenience wrappers for role-aware
  writes.
- ``write_message/4-5`` for role-aware writes that also update the
  session state, including close-handshake transitions.

Role-aware objects
------------------

The parameterized object
``http_websocket_session(Role, TextRepresentation)`` accepts:

- ``Role`` equal to ``client`` or ``server``
- ``TextRepresentation`` equal to ``atom``, ``chars``, or ``codes``

The library also provides two convenience objects using atom text:

- ``http_websocket_client_session``
- ``http_websocket_server_session``

Client sessions expect unmasked inbound frames and mask all outgoing
frames. Server sessions expect masked inbound frames and leave outgoing
frames unmasked.

Stateful reads
--------------

The ``read_message/4`` predicate threads an explicit session state term:

::

   read_message(Stream, State0, State, Message)

When a fragmented text or binary message is in progress and a control
frame is received before the final continuation frame, the control frame
is returned as a normalized ``message(Type, Payload)`` term and the
pending fragmented data is kept in ``State`` for the next call.

Close-handshake state is tracked in the returned state. Open states keep
the compact form ``session_state(Pending)``. Once a close message has
been sent or received, the state uses
``session_state(Pending, CloseStatus)`` where ``CloseStatus`` is one of:

- ``close_sent(Payload)``
- ``close_received(Payload)``
- ``closed(SentPayload, ReceivedPayload)``

Automatic control handling
--------------------------

The ``read_message/5`` predicate automatically writes a matching close
reply when it reads a close message and the session state shows that no
close message has yet been sent.

The ``read_message/6`` predicate adds the options:

- ``auto_pong(on)`` or ``auto_pong(off)``
- ``max_payload_length(Bytes)``

When ``auto_pong(on)`` is used, incoming ping messages are still
returned to the caller but a matching pong message is written
automatically on the output stream. When ``max_payload_length(Bytes)``
is used, inbound frames whose declared payload length is greater than
``Bytes`` are rejected before allocating payload storage.

Outgoing fragmentation
----------------------

The ``write_message/3`` predicate accepts the option:

- ``fragment_size(Size)``

For ``text`` and ``binary`` messages, this splits the payload into
frames of at most ``Size`` bytes. The first frame uses the original
opcode and continuation frames use the ``continuation`` opcode. Control
messages remain single final frames regardless of the option.

Current workflow
----------------

- Complete the opening handshake with ``http_client::open_websocket/4``
  or ``http_socket_transport::serve_websocket_once/5``.
- Use the ``http_websocket_messages`` layer when you only need stateless
  message normalization and simple reassembly.
- Use the ``http_websocket_session`` layer when you need stateful reads
  across interleaved control messages, close-state tracking, automatic
  close replies, optional auto-pong behavior, or role-aware outgoing
  fragmentation and masking.
- Use the ``http_websocket_service`` library when a callback object
  should own the connection lifecycle through higher-level session loops
  with optional keepalive, idle-timeout, and registry-backed broadcast
  policies.

Current limitations
-------------------

- Fragmentation is controlled only by fixed payload chunk size.
- Reserved-bit extension negotiation and extension semantics remain
  delegated to lower layers.
