.. index:: single: http_websocket_service(HTTPTransport,Role,TextRepresentation)
.. _http_websocket_service/3:

.. rst-class:: right

**object**

``http_websocket_service(HTTPTransport,Role,TextRepresentation)``
=================================================================

* ``HTTPTransport`` - The object implementing ``http_transport_protocol``.
* ``Role`` - Peer role for masking policy. Possible values are ``client`` and ``server``.
* ``TextRepresentation`` - Text representation to be used for text messages and close reasons. Possible values are ``atom`` (default), ``chars``, and ``codes``.


Callback-driven WebSocket session loops over upgraded WebSocket connections provided by a selected ``http_transport_protocol`` implementation, including automatic close-handshake orchestration, optional auto-pong, keepalive, and idle-timeout policies.

| **Availability:** 
|    ``logtalk_load(http_websocket_service(loader))``

| **Author:** Paulo Moura
| **Version:** 1:0:0
| **Date:** 2026-07-09

| **Compilation flags:**
|    ``static, context_switching_calls, threaded``


| **Extends:**
|    ``public`` :ref:`http_websocket_session(Role,TextRepresentation) <http_websocket_session/2>`
| **Uses:**
|    :ref:`http_websocket_service_loop_options <http_websocket_service_loop_options/0>`
|    :ref:`http_websocket_service_registry <http_websocket_service_registry/0>`
|    :ref:`list <list/0>`
|    :ref:`os <os/0>`
|    :ref:`user <user/0>`

| **Remarks:**

   - Option precedence: When the same loop option is given multiple times, the first occurrence is used.
   - Timed policies: Keepalive and idle-timeout deadlines are tracked using wall-clock time, making the loop robust to scheduling jitter and slow reads.

| **Inherited public predicates:**
|     :ref:`http_websocket_session/2::initial_state/1`  :ref:`http_websocket_messages/1::is_message/1`  :ref:`http_websocket_session/2::is_state/1`  :ref:`http_websocket_messages/1::message/3`  :ref:`http_websocket_messages/1::payload/2`  :ref:`http_websocket_messages/1::read_message/2`  :ref:`http_websocket_session/2::read_message/4`  :ref:`http_websocket_session/2::read_message/5`  :ref:`http_websocket_session/2::read_message/6`  :ref:`http_websocket_messages/1::type/2`  :ref:`http_websocket_session/2::write_message/2`  :ref:`http_websocket_session/2::write_message/3`  :ref:`http_websocket_session/2::write_message/4`  :ref:`http_websocket_session/2::write_message/5`  

.. contents::
   :local:
   :backlinks: top

Public predicates
-----------------

.. index:: run_session/3
.. _http_websocket_service/3::run_session/3:

``run_session/3``
^^^^^^^^^^^^^^^^^

Runs a higher-level session loop on an upgraded WebSocket connection produced by the selected transport parameterization until the close handshake completes or the peer closes the stream, then closes the upgraded connection automatically.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``run_session(Connection,Handler,State)``
| **Mode and number of proofs:**
|    ``run_session(+compound,+object_identifier,-compound)`` - ``one_or_error``

| **Exceptions:**
|    ``Connection`` is a variable:
|        ``instantiation_error``
|    ``Connection`` is not a valid upgraded WebSocket connection handle:
|        ``domain_error(http_socket_transport_connection,Connection)``
|    ``Handler`` is a variable:
|        ``instantiation_error``
|    ``Handler`` is not a valid WebSocket service handler:
|        ``domain_error(http_websocket_service_handler,Handler)``
|    The session role parameter is neither ``client`` nor ``server``:
|        ``domain_error(http_websocket_session_role,_Role_)``
|    The inbound frame/message sequence violates RFC 6455 session rules:
|        ``domain_error(http_websocket_session_sequence,Frame)``
|    The inbound frame violates the current peer masking policy:
|        ``domain_error(http_websocket_session_masking,Frame)``
|    The inbound frame uses unsupported extensions:
|        ``domain_error(http_websocket_session_extensions,Frame)``
|    The inbound frame is invalid:
|        ``domain_error(http_websocket_frame,Frame)``
|    The inbound message text is invalid:
|        ``domain_error(http_websocket_message_text,Payload)``
|    ``Handler`` returns a variable reply list:
|        ``instantiation_error``
|    ``Handler`` returns a non-list reply list:
|        ``type_error(list,Replies)``
|    ``Handler`` returns an invalid reply:
|        ``domain_error(http_websocket_service_handler_reply,Reply)``

| **Remarks:**

    - Handler protocol: The handler object must conform to the ``http_websocket_service_handler_protocol`` protocol and return a list of normalized reply messages for each received message.
    - Connection ownership: This predicate takes ownership of the upgraded connection and closes it before succeeding or rethrowing any exception.


------------

.. index:: run_session/4
.. _http_websocket_service/3::run_session/4:

``run_session/4``
^^^^^^^^^^^^^^^^^

Runs a higher-level session loop on an upgraded WebSocket connection produced by the selected transport parameterization using the given loop options, then closes the upgraded connection automatically.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``run_session(Connection,Handler,State,Options)``
| **Mode and number of proofs:**
|    ``run_session(+compound,+object_identifier,-compound,+list)`` - ``one_or_error``

| **Exceptions:**
|    ``Connection`` is a variable:
|        ``instantiation_error``
|    ``Connection`` is not a valid upgraded WebSocket connection handle:
|        ``domain_error(http_socket_transport_connection,Connection)``
|    ``Handler`` is a variable:
|        ``instantiation_error``
|    ``Handler`` is not a valid WebSocket service handler:
|        ``domain_error(http_websocket_service_handler,Handler)``
|    ``Options`` is a variable or a partial list:
|        ``instantiation_error``
|    ``Options`` is neither a variable nor a list:
|        ``type_error(list,Options)``
|    An element ``Option`` of the list ``Options`` is neither a variable nor a compound term:
|        ``type_error(compound,Option)``
|    An element ``Option`` of the list ``Options`` is a compound term but not a valid option:
|        ``domain_error(option,Option)``
|    ``Options`` contains an invalid WebSocket service loop option:
|        ``domain_error(http_websocket_service_option,Option)``
|    Timed session-loop options are not available on this backend:
|        ``existence_error(http_websocket_service,timing)``
|    The session role parameter is neither ``client`` nor ``server``:
|        ``domain_error(http_websocket_session_role,_Role_)``
|    The inbound frame/message sequence violates RFC 6455 session rules:
|        ``domain_error(http_websocket_session_sequence,Frame)``
|    The inbound frame violates the current peer masking policy:
|        ``domain_error(http_websocket_session_masking,Frame)``
|    The inbound frame uses unsupported extensions:
|        ``domain_error(http_websocket_session_extensions,Frame)``
|    The inbound frame is invalid:
|        ``domain_error(http_websocket_frame,Frame)``
|    The inbound message text is invalid:
|        ``domain_error(http_websocket_message_text,Payload)``
|    ``Handler`` returns a variable reply list:
|        ``instantiation_error``
|    ``Handler`` returns a non-list reply list:
|        ``type_error(list,Replies)``
|    ``Handler`` returns an invalid reply:
|        ``domain_error(http_websocket_service_handler_reply,Reply)``

| **Remarks:**

    - Option ``auto_pong(on)``: Automatically writes pong replies while still forwarding ping messages to the handler.
    - Option ``auto_pong(off)``: Disables automatic pong replies. This is the default.
    - Option ``keepalive_interval(Seconds)``: When no inbound message is received for the given positive number of seconds, writes an empty ping message and continues the loop. This option requires backend thread support.
    - Option ``idle_timeout(Seconds)``: When no inbound message is received for the given positive number of seconds, writes ``message(close, status(1001, idle_timeout))`` and waits up to one additional idle-timeout interval for the peer to complete the close handshake before stopping. This option requires backend thread support.
    - Option ``max_payload_length(Bytes)``: Rejects inbound frames whose declared payload length is greater than ``Bytes`` before allocating payload storage. Oversized frames are treated as ``1009`` close errors in the session loop. Use a non-negative integer.


------------

Protected predicates
--------------------

.. index:: run_session_connection/5
.. _http_websocket_service/3::run_session_connection/5:

``run_session_connection/5``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Protected helper that runs the callback-driven session loop on an upgraded WebSocket connection starting from the given session state and using the given loop options. Connection ownership is handled by the caller.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``run_session_connection(Connection,HandlerDescriptor,State,UpdatedState,Options)``
| **Mode and number of proofs:**
|    ``run_session_connection(+compound,+compound,+compound,-compound,+list)`` - ``one_or_error``

| **Exceptions:**
|    ``Connection`` is a variable:
|        ``instantiation_error``
|    ``Connection`` is not a valid upgraded WebSocket connection handle:
|        ``domain_error(http_socket_transport_connection,Connection)``
|    ``HandlerDescriptor`` is not a valid WebSocket service handler descriptor:
|        ``domain_error(http_websocket_service_handler,HandlerDescriptor)``
|    The handler in ``HandlerDescriptor`` is a variable:
|        ``instantiation_error``
|    The handler in ``HandlerDescriptor`` is not a valid WebSocket service handler:
|        ``domain_error(http_websocket_service_handler,Handler)``
|    ``State`` is a variable:
|        ``instantiation_error``
|    ``State`` is not a valid WebSocket session state:
|        ``domain_error(http_websocket_session_state,State)``
|    ``Options`` is a variable or a partial list:
|        ``instantiation_error``
|    ``Options`` is neither a variable nor a list:
|        ``type_error(list,Options)``
|    An element ``Option`` of the list ``Options`` is neither a variable nor a compound term:
|        ``type_error(compound,Option)``
|    An element ``Option`` of the list ``Options`` is a compound term but not a valid option:
|        ``domain_error(option,Option)``
|    ``Options`` contains an invalid WebSocket service loop option:
|        ``domain_error(http_websocket_service_option,Option)``
|    Timed session-loop options are not available on this backend:
|        ``existence_error(http_websocket_service,timing)``
|    The session role parameter is neither ``client`` nor ``server``:
|        ``domain_error(http_websocket_session_role,_Role_)``
|    The inbound frame/message sequence violates RFC 6455 session rules:
|        ``domain_error(http_websocket_session_sequence,Frame)``
|    The inbound frame violates the current peer masking policy:
|        ``domain_error(http_websocket_session_masking,Frame)``
|    The inbound frame uses unsupported extensions:
|        ``domain_error(http_websocket_session_extensions,Frame)``
|    The inbound frame is invalid:
|        ``domain_error(http_websocket_frame,Frame)``
|    The inbound message text is invalid:
|        ``domain_error(http_websocket_message_text,Payload)``
|    The handler returns a variable reply or action list:
|        ``instantiation_error``
|    The handler returns a non-list reply list:
|        ``type_error(list,Replies)``
|    The handler returns a non-list action list:
|        ``type_error(list,Actions)``
|    The handler returns an invalid reply:
|        ``domain_error(http_websocket_service_handler_reply,Reply)``
|    The handler returns an invalid registry action:
|        ``domain_error(http_websocket_service_handler_action,Action)``
|    The registry in ``HandlerDescriptor`` is not an open WebSocket service registry handle:
|        ``domain_error(http_websocket_service_registry,Registry)``
|    The session in ``HandlerDescriptor`` is not a valid WebSocket service registry session handle:
|        ``domain_error(http_websocket_service_registry_session,Session)``
|    The session in ``HandlerDescriptor`` is not registered in the registry:
|        ``existence_error(http_websocket_service_registry_session,websocket_session(RegistryId,SessionId))``


------------

.. index:: validate_non_negative_integer_option/4
.. _http_websocket_service/3::validate_non_negative_integer_option/4:

``validate_non_negative_integer_option/4``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Validates a non-negative integer option value for the given domain and option name.

| **Compilation flags:**
|    ``static``

| **Template:**
|    ``validate_non_negative_integer_option(Domain,Name,Value,ValidatedValue)``
| **Mode and number of proofs:**
|    ``validate_non_negative_integer_option(+atom,+atom,@term,-integer)`` - ``one_or_error``

| **Exceptions:**
|    ``Value`` is not a non-negative integer option value for the given domain and option name:
|        ``domain_error(Domain,Option)``


------------

Private predicates
------------------

(no local declarations; see entity ancestors if any)

Operators
---------

(none)

