C++ STREAM Session Per-Language Interface¶
C++ per-language interface table of contents · Session Actor Dispatch
1. Public Session Surface¶
The public session interface doesn't expose transport control record and connection identity.
enum class stream_codec_t : std::uint8_t {
raw = 0,
json = 1,
message_pack = 2,
protobuf = 3
};
enum class stream_session_error_t {
internal = 0,
transport_error = 1
};
enum class stream_close_reason_t : std::uint8_t {
client_close = 1,
idle_timeout = 2,
heartbeat_timeout = 3,
server_drain = 4,
protocol_error = 5,
transport_error = 6
};
class stream_compression_codec_t {
public:
virtual ~stream_compression_codec_t() = default;
virtual zlink::framework::message_t compress(
const zlink::framework::message_t &payload) const = 0;
virtual zlink::framework::message_t decompress(
const zlink::framework::message_t &payload,
std::size_t max_decompressed_size) const = 0;
};
std::shared_ptr<const stream_compression_codec_t>
lz4_stream_compression_codec();
class stream_error_t {
public:
stream_error_t() = default;
stream_error_t(
stream_session_error_t error,
std::string message);
stream_session_error_t error() const noexcept;
std::string_view message() const noexcept;
};
struct session_message_context_t {
std::string packet_name;
message_metadata_t metadata;
bool can_reply;
};
class stream_t {
public:
stream_t();
~stream_t();
stream_t(stream_t &&) noexcept;
stream_t &operator=(stream_t &&) noexcept;
stream_t(const stream_t &) = default;
stream_t &operator=(const stream_t &) = default;
std::string session_id() const;
std::optional<zlink::routing_id_t> routing_id() const;
std::optional<std::string> local_address() const;
std::optional<std::string> remote_address() const;
session_actor_manager_t &actors();
task_t<void> close();
stream_send_call_t write_packet(
const zlink::framework::message_t &payload);
stream_write_call_t reply_packet(
const zlink::framework::message_t &payload);
};
class packet_stream_session_t {
public:
virtual ~packet_stream_session_t() = default;
virtual task_t<void> on_connected(stream_t &stream) = 0;
virtual task_t<void> on_disconnected(stream_t &stream) = 0;
virtual task_t<void> on_actor_binding_replaced(
stream_t &stream,
std::string actor_id);
virtual task_t<void> on_error(
stream_t &stream,
const stream_error_t &error) = 0;
virtual task_t<void> on_packet(
stream_t &stream,
const session_message_context_t &context,
const zlink::framework::message_t &payload);
};
class stream_builder_t {
public:
stream_builder_t();
~stream_builder_t();
stream_builder_t(stream_builder_t &&) noexcept;
stream_builder_t &operator=(stream_builder_t &&) noexcept;
stream_builder_t(const stream_builder_t &) = default;
stream_builder_t &operator=(const stream_builder_t &) = default;
stream_builder_t &bind(std::string endpoint);
stream_builder_t &bind(std::uint16_t port = 0);
stream_builder_t &set_bind_host(std::string host);
stream_builder_t &set_advertise_host(std::string host);
stream_builder_t ®ister_session(std::string session_name);
stream_snapshot_t snapshot() const;
};
struct stream_snapshot_t {
std::string name;
std::string bind_endpoint;
std::string packet_session_name;
std::string tls_certificate_file;
std::string tls_private_key_file;
bool tls_require_client_certificate;
std::int64_t max_message_size = 64 * 1024;
};
class stream_compression_options_builder_t {
public:
stream_compression_options_builder_t &use_default();
stream_compression_options_builder_t &use_lz4();
stream_compression_options_builder_t &use(
std::shared_ptr<const stream_compression_codec_t> codec);
stream_compression_options_builder_t &disable();
};
struct stream_socket_config_t {
std::int64_t max_message_size = 64 * 1024;
};
class stream_node_options_builder_t {
public:
stream_node_options_builder_t &bind(std::string endpoint);
stream_node_options_builder_t &bind(std::uint16_t port = 0);
stream_node_options_builder_t &set_bind_host(std::string host);
stream_node_options_builder_t &set_advertise_host(std::string host);
stream_node_options_builder_t &set_tls_server(
std::string certificate_file,
std::string private_key_file,
bool require_client_certificate = false);
stream_socket_config_t &configure_socket() noexcept;
stream_node_options_builder_t &enable_actor_dispatch();
stream_node_options_builder_t ®ister_session(std::string session_name);
template <typename TSession>
requires std::derived_from<TSession, packet_stream_session_t>
stream_node_options_builder_t ®ister_session();
};
configure_socket().max_message_size is the StreamNode's Core STREAM
inbound ceiling. It defaults to 64 KiB; a complete message is measured
as header bytes plus payload bytes, excluding the 6-byte prefix. The
ceiling applies only to messages received from client to server, not to
messages sent from server to client. 0 means that Framework adds no
separate ceiling, while a positive value is finite. A negative value is a
startup configuration error. When a client message exceeds the ceiling,
Core rejects it with EMSGSIZE and the server closes that connection. The
server callback receives no partial message. A raw client observes the
connection close and doesn't receive a wire error code.
stream_error_t only exposes a provider-neutral error kind and
description. The native transport error code is runtime-internal
diagnostic information and isn't included in the public contract.
on_actor_binding_replaced(...) is an optional callback run once on the previous session when
the same Actor is bound to a new session. The application may call write_packet(...) to notify
the client, but does not call close(). The framework closes the connection 100 ms after the
callback reaches a successful or failed terminal; an empty outbound queue does not shorten this delay. The
new bind does not wait for this callback or close.
| Implementation difference | Current state |
|---|---|
| Session Actor binding replacement | None. The C++ runtime implements commands 36/38 codec conformance, the one-way command 51, this callback, and the non-blocking 100 ms close timer. |
After bind, relay/request relay and notify_disconnected() use a
per-Actor stored route and don't look up Location Store for every
message. On physical disconnect, the Framework performs an automatic
all-settled notification across every current binding and runs the
Spot callback at most once per binding identity.
notify_disconnected() is a logical notification while the connection
is kept, and waits until the callback terminal. session_actor_t::ref() const noexcept returns const actor_ref_t &.
Session–Actor binding §8.2 owns relocation route updates for a bound Session.
The Actor-interworking member of bound_session_t,
session_actor_t, and session_actor_manager_t is owned by the
Actor interface. The metadata/compression/
async() member of stream_send_call_t and stream_write_call_t
keeps the same admission contract as the call family in
Channel messaging.
STREAM application callback, send/reply, and compression extension use
zlink::framework::message_t, not the binding message. Framework's
codec registry converts a typed payload and this message boundary.
After the Framework-internal recv loop reads a raw part and completes
queue admission, it runs the packet callback. The packet callback
receives session_message_context_t, which carries the packet name
and immutable metadata. Whether reply is possible is provided by that
Session specialization's can_reply. Connection close and operation
cancellation are handled through stream_t lifecycle and each call's
completion, and cancellation state isn't added to the universal
message_context_t. stream_t's optional routing ID and local/remote
address are a session identity snapshot the handshake confirmed, kept
through packet dispatch.
The Session callback accesses that session's Actor binding manager
through the received stream_t's actors(). Since Actor dispatch uses
global ActorId lookup and an actor_ref_t bind, a target
MeshName or local Actor overload isn't registered. Without Object role
client/server and Location Store, startup fails with
not_configured.
A handshake failure is only recorded to runtime monitoring before the
session is created, and isn't delivered to on_error(...).
The wire value is a contract. stream_close_reason_t's 1-6 are the
same values as the session-closing payload in
Stream Connector §4.6.
Don't cast the enum to an integer and use it as the wire value —
the codec converts it explicitly.