use std::sync::{Arc, Weak};
use std::time::Duration;
use log::info;
use crate::client::ids::WireId;
use crate::errors::Error;
use crate::messages::{unknown_message_type_notice, IncomingMessages, Notice, ResponseMessage, MESSAGE_ID_LEN};
use crate::subscriptions::common::RoutedItem;
pub(crate) trait NoticeSink: Send + Sync {
fn deliver(&self, notice: Notice);
}
pub(crate) fn log_orphan(id: WireId, item: &RoutedItem) {
match item {
RoutedItem::Notice(n) => info!("no recipient for notice (id={id}): {n}"),
RoutedItem::Error(e) => info!("no recipient for error (id={id}): {e}"),
RoutedItem::Response(_) => {}
}
}
pub(crate) fn report_unroutable_frame(message: &ResponseMessage, notice_sink: &dyn NoticeSink) {
if message.message_type() == IncomingMessages::NotValid {
notice_sink.deliver(unknown_message_type_notice(message));
} 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 = MESSAGE_ID_LEN;
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)
}
#[derive(Clone, Debug, Default)]
pub(crate) struct Lease(Arc<()>);
impl Lease {
pub(crate) fn new() -> Self {
Self::default()
}
pub(crate) fn downgrade(&self) -> LeaseRef {
LeaseRef(Arc::downgrade(&self.0))
}
}
#[derive(Clone, Debug)]
pub(crate) struct LeaseRef(Weak<()>);
impl LeaseRef {
pub(crate) fn is_live(&self) -> bool {
self.0.strong_count() > 0
}
pub(crate) fn is(&self, other: &LeaseRef) -> bool {
Weak::ptr_eq(&self.0, &other.0)
}
}
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;