use std::time::Duration;
use log::{error, info, warn};
use crate::connection::common::NoticeSink;
use crate::errors::Error;
use crate::messages::{
ConnectivityStatus, IncomingMessages, Notice, ResponseMessage, CONNECTIVITY_RESTORED_DATA_LOST_CODE, CONNECTIVITY_RESTORED_DATA_MAINTAINED_CODE,
UNKNOWN_MESSAGE_TYPE_CODE,
};
use crate::subscriptions::common::RoutedItem;
fn is_benign_connectivity_notice(notice: &Notice) -> bool {
notice.connectivity_status() == Some(ConnectivityStatus::Ok) || notice.code == CONNECTIVITY_RESTORED_DATA_MAINTAINED_CODE
}
pub(crate) fn log_unrouted_notice(notice: &Notice) {
if is_benign_connectivity_notice(notice) {
info!("connectivity: {notice}");
} else if notice.code == CONNECTIVITY_RESTORED_DATA_LOST_CODE || notice.is_warning() {
warn!("warning: {notice}");
} else {
error!("error: {notice}");
}
}
pub(crate) fn log_orphan(request_id: i32, item: &RoutedItem) {
match item {
RoutedItem::Notice(n) => info!("no recipient for notice (id={request_id}): {n}"),
RoutedItem::Error(e) => info!("no recipient for error (id={request_id}): {e}"),
RoutedItem::Response(_) => {}
}
}
pub(crate) fn report_unroutable_frame(message: &ResponseMessage, notice_sink: &dyn NoticeSink) {
if message.message_type() == IncomingMessages::NotValid {
warn!("unroutable frame: message id maps to no known type — the stream may be desynchronized: {message:?}");
notice_sink.deliver(Notice::synthesized(
UNKNOWN_MESSAGE_TYPE_CODE,
format!(
"received a frame with message id {}, which maps to no known type; the stream may be desynchronized",
message.message_id()
),
));
} else {
info!("no recipient found for: {message:?}");
}
}
pub(crate) const MAX_RECONNECT_ATTEMPTS: u32 = 20;
pub(crate) const MAX_FRAME_LENGTH: usize = 0x00FF_FFFF;
pub(crate) const MIN_FRAME_LENGTH: usize = 4;
pub(crate) fn validate_frame_length(length: usize) -> Result<usize, Error> {
if length > MAX_FRAME_LENGTH {
return Err(Error::InvalidFrame(format!(
"frame length {length} exceeds maximum {MAX_FRAME_LENGTH}; the stream is desynchronized"
)));
}
if length < MIN_FRAME_LENGTH {
return Err(Error::InvalidFrame(format!(
"frame length {length} is shorter than the {MIN_FRAME_LENGTH}-byte message id; the stream is desynchronized"
)));
}
Ok(length)
}
pub(crate) struct FibonacciBackoff {
previous: u64,
current: u64,
max: u64,
}
impl FibonacciBackoff {
pub(crate) fn new(max: u64) -> Self {
FibonacciBackoff {
previous: 0,
current: 1.min(max),
max,
}
}
pub(crate) fn next_delay(&mut self) -> Duration {
if self.current < self.max {
let next = self.previous.saturating_add(self.current).min(self.max);
self.previous = self.current;
self.current = next;
}
Duration::from_secs(self.current)
}
}
#[cfg(test)]
#[path = "common_tests.rs"]
mod tests;