using System;
using ZB.MOM.WW.MxGateway.Contracts;
using ZB.MOM.WW.MxGateway.Worker.Bootstrap;
namespace ZB.MOM.WW.MxGateway.Worker.Ipc;
/// Configuration options for the worker frame protocol.
public sealed class WorkerFrameProtocolOptions
{
/// Default maximum message size in bytes (16 MB).
public const int DefaultMaxMessageBytes = 16 * 1024 * 1024;
///
/// Upper ceiling the worker will accept for a gateway-negotiated frame maximum
/// (GatewayHello.max_frame_bytes). Matches the gateway's own configuration ceiling
/// so a nonsensical negotiated value is rejected at the handshake rather than driving an absurd
/// per-frame allocation. 256 MiB.
///
public const int MaxNegotiableFrameBytes = 256 * 1024 * 1024;
/// Initializes a new instance of the WorkerFrameProtocolOptions class from WorkerOptions.
/// Worker initialization options.
public WorkerFrameProtocolOptions(WorkerOptions options)
: this(
options?.SessionId ?? throw new ArgumentNullException(nameof(options)),
options.ProtocolVersion,
options.Nonce,
DefaultMaxMessageBytes)
{
}
/// Initializes a new instance of the WorkerFrameProtocolOptions class with default max message bytes.
/// Identifier of the session.
/// Protocol version.
/// Nonce for startup validation.
public WorkerFrameProtocolOptions(
string sessionId,
uint protocolVersion,
string nonce)
: this(
sessionId,
protocolVersion,
nonce,
DefaultMaxMessageBytes)
{
}
/// Initializes a new instance of the WorkerFrameProtocolOptions class with all parameters.
/// Identifier of the session.
/// Protocol version.
/// Nonce for startup validation.
/// Maximum message size in bytes.
public WorkerFrameProtocolOptions(
string sessionId,
uint protocolVersion,
string nonce,
int maxMessageBytes)
{
if (string.IsNullOrWhiteSpace(sessionId))
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.InvalidConfiguration,
"Worker frame protocol requires a session id.");
}
if (protocolVersion == 0)
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.InvalidConfiguration,
"Worker frame protocol requires a non-zero protocol version.");
}
if (protocolVersion != GatewayContractInfo.WorkerProtocolVersion)
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.ProtocolVersionMismatch,
$"Worker frame protocol version {protocolVersion} is not supported.");
}
if (string.IsNullOrWhiteSpace(nonce))
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.InvalidConfiguration,
"Worker frame protocol requires a nonce.");
}
if (maxMessageBytes <= 0)
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.InvalidConfiguration,
"Worker frame protocol max message size must be greater than zero.");
}
SessionId = sessionId;
ProtocolVersion = protocolVersion;
Nonce = nonce;
MaxMessageBytes = maxMessageBytes;
}
/// Gets the session ID for the worker protocol.
public string SessionId { get; }
/// Gets the protocol version.
public uint ProtocolVersion { get; }
/// Gets the nonce for startup validation.
public string Nonce { get; }
///
/// Gets the maximum worker-frame message size in bytes. Initialized from the constructor and
/// then adopted once from the gateway-negotiated value during the startup handshake
/// (GatewayHello.max_frame_bytes) via ,
/// before the message loop starts. Not mutated afterwards, so the single-threaded handshake write
/// is safe for the reader/writer that share this instance.
///
public int MaxMessageBytes { get; private set; }
///
/// Adopts the gateway-negotiated frame maximum conveyed in GatewayHello.max_frame_bytes.
/// A value of 0 (an older gateway that never set the field) is ignored and the
/// constructor default is kept. A value above is rejected.
///
/// The gateway-negotiated maximum, or 0 for "keep default".
internal void AdoptNegotiatedMaxMessageBytes(uint negotiatedMaxFrameBytes)
{
if (negotiatedMaxFrameBytes == 0)
{
return;
}
if (negotiatedMaxFrameBytes > MaxNegotiableFrameBytes)
{
throw new WorkerFrameProtocolException(
WorkerFrameProtocolErrorCode.InvalidConfiguration,
$"GatewayHello negotiated frame maximum {negotiatedMaxFrameBytes} exceeds the worker ceiling "
+ $"of {MaxNegotiableFrameBytes} bytes.");
}
MaxMessageBytes = (int)negotiatedMaxFrameBytes;
}
}