///|
/// Settings sent by `IDENTIFY` when a connection is opened.
pub struct ConnectionOptions {
client_id : String
hostname : String
heartbeat_interval : Int
output_buffer_size : Int
output_buffer_timeout : Int
message_timeout : Int
sample_rate : Int
tls_v1 : Bool
feature_negotiation : Bool
} derive(Debug)
///|
pub extend ConnectionOptions with @moonbitlang/core/debug.Debug::{to_repr}
///|
/// Creates conservative settings compatible with NSQ 1.x brokers.
pub fn ConnectionOptions::new(
client_id? : String = "moon-nsq",
hostname? : String = "moonbit",
heartbeat_interval? : Int = 30_000,
output_buffer_size? : Int = 16_384,
output_buffer_timeout? : Int = 250,
message_timeout? : Int = 60_000,
sample_rate? : Int = 0,
tls_v1? : Bool = false,
feature_negotiation? : Bool = false,
) -> ConnectionOptions raise ProtocolError {
let options = {
client_id,
hostname,
heartbeat_interval,
output_buffer_size,
output_buffer_timeout,
message_timeout,
sample_rate,
tls_v1,
feature_negotiation,
}
options.validate()
options
}
///|
/// Checks ranges before any bytes are sent to a broker.
pub fn ConnectionOptions::validate(
self : ConnectionOptions,
) -> Unit raise ProtocolError {
if self.client_id.length() == 0 || self.client_id.length() > 64 {
raise InvalidOption("client_id must contain 1 to 64 characters")
}
if self.hostname.length() == 0 || self.hostname.length() > 255 {
raise InvalidOption("hostname must contain 1 to 255 characters")
}
if self.heartbeat_interval < 1_000 || self.heartbeat_interval > 3_600_000 {
raise InvalidOption("heartbeat_interval must be between 1000 and 3600000ms")
}
if self.output_buffer_size < 0 || self.output_buffer_size > 65_536 {
raise InvalidOption("output_buffer_size must be between 0 and 65536")
}
if self.output_buffer_timeout < 1 || self.output_buffer_timeout > 60_000 {
raise InvalidOption("output_buffer_timeout must be between 1 and 60000ms")
}
if self.message_timeout < 1_000 || self.message_timeout > 3_600_000 {
raise InvalidOption("message_timeout must be between 1000 and 3600000ms")
}
if self.sample_rate < 0 || self.sample_rate > 100 {
raise InvalidOption("sample_rate must be between 0 and 100")
}
if self.tls_v1 && !self.feature_negotiation {
raise InvalidOption("TLS requires feature negotiation")
}
}
///|
/// Consumer-local settings that do not alter broker topology.
pub struct ConsumerOptions {
max_in_flight : Int
requeue_delay : Int
max_attempts : Int
touch_interval : Int
} derive(Debug)
///|
pub extend ConsumerOptions with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub fn ConsumerOptions::new(
max_in_flight? : Int = 1,
requeue_delay? : Int = 0,
max_attempts? : Int = 5,
touch_interval? : Int = 30_000,
) -> ConsumerOptions raise ProtocolError {
let options = { max_in_flight, requeue_delay, max_attempts, touch_interval, }
options.validate()
options
}
///|
pub fn ConsumerOptions::validate(
self : ConsumerOptions,
) -> Unit raise ProtocolError {
if self.max_in_flight < 1 || self.max_in_flight > 2_500 {
raise InvalidOption("max_in_flight must be between 1 and 2500")
}
if self.requeue_delay < 0 || self.requeue_delay > 3_600_000 {
raise InvalidOption("requeue_delay must be between 0 and 3600000ms")
}
if self.max_attempts < 1 || self.max_attempts > 65_535 {
raise InvalidOption("max_attempts must be between 1 and 65535")
}
if self.touch_interval < 1_000 || self.touch_interval > 3_600_000 {
raise InvalidOption("touch_interval must be between 1000 and 3600000ms")
}
}
///|
/// A bounded exponential delay policy used after disconnected sessions.
pub struct BackoffOptions {
initial_delay : Int
max_delay : Int
multiplier : Int
} derive(Debug)
///|
pub extend BackoffOptions with @moonbitlang/core/debug.Debug::{to_repr}
///|
pub fn BackoffOptions::new(
initial_delay? : Int = 100,
max_delay? : Int = 30_000,
multiplier? : Int = 2,
) -> BackoffOptions raise ProtocolError {
let options = { initial_delay, max_delay, multiplier, }
if options.initial_delay < 1 || options.max_delay < options.initial_delay {
raise InvalidOption("backoff delays must be positive and ordered")
}
if options.multiplier < 1 || options.multiplier > 16 {
raise InvalidOption("backoff multiplier must be between 1 and 16")
}
options
}
///|
/// Returns the capped delay for a zero-based reconnect attempt.
pub fn BackoffOptions::delay_for(self : BackoffOptions, attempt : Int) -> Int {
if attempt <= 0 {
return self.initial_delay
}
let mut delay = self.initial_delay
for _ in 0..= self.max_delay {
return self.max_delay
}
if delay > self.max_delay / self.multiplier {
return self.max_delay
}
delay = delay * self.multiplier
}
delay
}