| Did you know ... | Search Documentation: |
| Pack logtalk -- logtalk-3.101.0/docs/handbook/_sources/libraries/http_websocket_service.rst.txt |
.. _library_http_websocket_service:
http_websocket_service
This library provides higher-level callback-driven WebSocket session
loops on top of the http_websocket_session state-machine library and
upgraded WebSocket connections provided by a selected
http_transport_protocol implementation. It adds connection lifecycle
ownership, optional auto-pong, keepalive, and idle-timeout policies,
client- and server-side conveniences that collapse the opening handshake
and the session loop into a single call, and a registry-backed broadcast
helper for multi-session servers.
By default, the convenience objects use the http_socket_transport
transport. The parametric
http_websocket_service(_HTTPSocket_, _Role_, _TextRepresentation_),
http_websocket_client_service(_HTTPSocket_), and
http_websocket_server_service(_HTTPSocket_) objects can also use
alternative http_transport_protocol implementations such as
http_process_transport.
This library can be used with backend Prolog systems that support
unbound integer arithmetic and the sockets library: ECLiPSe, SICStus
Prolog, SWI-Prolog, Trealla Prolog, and XVM. On backends that don't
support threads, only a subset of the library is usable; see the
"Backends without thread support" section below for the details.
Open the `../../apis/library_index.html#http_websocket_service <../../apis/library_index.html#http_websocket_service>`__ link in a web browser.
To load the library, load the loader.lgt file:
::
| ?- logtalk_load(http_websocket_service(loader)).
To test this library, load the tester.lgt file:
::
| ?- logtalk_load(http_websocket_service(tester)).
The current implementation provides:
run_session/3-4 for higher-level callback-driven loops over
upgraded WebSocket connection handles produced by the selected
transport parameterization that keep reading until the close handshake
completes or the peer closes the stream and then close the upgraded
connection automatically, with optional auto-pong, keepalive,
idle-timeout, and maximum payload length policies.open/4-5 in the http_websocket_client_service object as a
client-side convenience that combines
http_client::open_websocket/4, optional initial outbound messages,
and the higher-level session loop. The accepted URL schemes depend on
the selected transport parameterization, e.g. ws:// for
http_socket_transport and both ws:// and wss:// for
http_process_transport.serve_once/6-7 in the http_websocket_server_service object as
a server-side convenience that combines the selected transport
parameterization serve_websocket_once/5 predicate with the
higher-level session loop.serve_until_shutdown/5-6 and request_shutdown/1 in the
http_websocket_server_service object for registry-backed
multi-session servers with queued broadcast delivery.http_websocket_service_registry object for managing active
sessions and queued outbound messages.
The run_session/3-4 predicates accept an upgraded WebSocket
connection handle produced by the selected transport parameterization
together with a handler object that implements the
http_websocket_service_handler_protocol protocol:
::
handle(Message, Replies)
For each received normalized message, the handler returns a list of normalized reply messages to write before the next read. The loop:
closed(SentPayload, ReceivedPayload) or the peer closes the
stream, andauto_pong(on) or auto_pong(off)keepalive_interval(Seconds)idle_timeout(Seconds)max_payload_length(Bytes)
When keepalive_interval(Seconds) is used, the loop sends empty ping
messages after Seconds of inbound silence. When
idle_timeout(Seconds) is used, the loop sends
message(close, status(1001, idle_timeout)) after Seconds of
inbound silence and then waits one more idle interval for the peer close
reply. These timed options require backend thread support. The keepalive
and idle-timeout policies are tracked using absolute wall-clock
deadlines, making the loop robust to scheduling jitter and slow reads.
A small server-side session handler can look like:
::
:- object(chat_session_handler,
implements(http_websocket_service_handler_protocol)).
handle(message(text, ping), [message(text, pong)]) :-
!.
handle(message(text, Text), [message(text, Text)]) :-
!.
handle(message(close, _Payload), []) :-
!.
handle(_Message, []).
:- end_object.
After a successful opening handshake returns an upgraded Connection
handle, run the loop with either:
::
| ?- http_websocket_server_service::run_session(Connection, chat_session_handler, FinalState).
or:
::
| ?- http_websocket_server_service::run_session(Connection, chat_session_handler, FinalState, [auto_pong(on)]).
or with timed loop policies:
::
| ?- http_websocket_server_service::run_session(Connection, chat_session_handler, FinalState, [auto_pong(on), keepalive_interval(30), idle_timeout(120)]).
The run_session/3-4 predicates take ownership of the upgraded
connection, so no explicit transport close_connection/1 call is
needed afterwards.
For a client that wants to collapse the opening handshake and the
callback loop into a single call, the http_websocket_client_service
object provides:
::
open(URL, SessionHandler, Response, FinalState)
or:
::
open(URL, SessionHandler, Response, FinalState, [protocols([chat]), initial_messages([message(text, hello)]), auto_pong(on)])
The accepted WebSocket URL schemes depend on the selected transport
parameterization. For example, the default
http_websocket_client_service object uses http_socket_transport
and therefore accepts ws:// URLs, while
http_websocket_client_service(http_process_transport) also accepts
wss:// URLs.
The initial_messages(Messages) option writes the given list of
normalized outbound messages immediately after the handshake and before
the first session read. The open/4-5 predicates also accept the
keepalive_interval/1, idle_timeout/1, and
max_payload_length/1 session-loop options. They take ownership of
the upgraded connection and close it automatically when the session loop
finishes.
For a server that wants to collapse the opening handshake and the
callback loop into a single call, the http_websocket_server_service
object provides:
::
serve_once(Listener, HandshakeHandler, SessionHandler, Response, FinalState, ClientInfo)
or:
::
serve_once(Listener, HandshakeHandler, SessionHandler, Response, FinalState, ClientInfo, [auto_pong(on)])
These predicates accept one incoming socket connection, serve one valid opening handshake via the given HTTP handler, run the session loop via the given session handler, and then close the upgraded connection automatically. They also accept the keepalive_interval/1, idle_timeout/1, and max_payload_length/1 session-loop options.
For server-side helpers, the Listener must come from the same
selected transport parameterization as the service object, e.g.
http_websocket_server_service(http_process_transport) must be paired
with a listener opened by http_process_transport::open_listener/4.
For multi-session servers that need queued outbound delivery and
broadcast, the http_websocket_server_service object also provides:
::
serve_until_shutdown(Listener, HandshakeHandler, SessionHandler, Registry, Control)
or:
::
serve_until_shutdown(Listener, HandshakeHandler, SessionHandler, Registry, Control, [auto_pong(on), keepalive_interval(30), idle_timeout(120)])
This helper accepts opening handshakes until:
http_websocket_server_service::request_shutdown(Control) is
called, orRegistry and
handled in its own session worker. The registry queues outbound messages
so that each worker only writes to its own connection.
When used with serve_until_shutdown/5-6, the session handler may
still return plain normalized reply messages, but it may also return
these action wrappers:
reply(Message)broadcast(Message)broadcast_others(Message)
For example, a simple chat-style broadcast handler can look like:
::
:- object(chat_broadcast_handler,
implements(http_websocket_service_handler_protocol)).
handle(message(text, Text), [broadcast_others(message(text, Text))]) :-
!.
handle(message(close, _Payload), []) :-
!.
handle(_Message, []).
:- end_object.
The http_websocket_service_registry object provides the registry
handle and queue-management predicates used by this helper. The
registry-backed server helper requires backend thread support.
The library loads on any backend that supports the sockets library
and unbounded integer arithmetic, but the available functionality
depends on whether the backend supports threads.
Available without thread support:
run_session/3-4, http_websocket_client_service::open/4-5,
and http_websocket_server_service::serve_once/6-7 predicates when
called without the keepalive_interval/1 and idle_timeout/1
options. In this case, the session loop reads from the connection
using plain blocking reads and no background reader is required.http_websocket_service_registry data predicates (open/1,
close/1, register/2, unregister/2, send/3,
broadcast/2, broadcast_except/3, and take_pending/3),
which are plain database operations.
Requiring thread support:
existence_error(http_websocket_service,timing) exception before
reading or writing any frames.serve_until_shutdown/5-6 and request_shutdown/1
predicates, which run each accepted session in its own worker thread.
On backends without thread support, these predicates throw a
existence_error(http_websocket_server_service,registry) exception.
In all cases, unsupported usage fails fast with a existence_error/2 exceptions at validation time instead of hanging or silently misbehaving.
http_websocket_session library directly when you need
stateful reads, close-state tracking, or role-aware writes on binary
streams that you manage yourself.run_session/3-4 and let the service
layer close it when the close handshake completes.http_websocket_client_service::open/4-5 and let
the service layer handle the opening handshake, any configured initial
outbound messages, and the final connection close.wss:// URLs, use the
a TLS-capable parameterization such as http_process_transport.http_websocket_server_service::serve_once/6-7.http_process_transport, use the matching parametric service object
and open the listener with that same transport parameterization.http_websocket_service_registry::open/1 and call
http_websocket_server_service::serve_until_shutdown/5-6.run_session/3-4 and serve_once/6-7 helpers are
synchronous, single-connection callback loops.serve_until_shutdown/5-6 helper are not
available and throw existence_error/2 exceptions; see the
"Backends without thread support" section above.