use std::sync::{Arc, Mutex, MutexGuard, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, 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) fn lock<T: ?Sized>(mutex: &Mutex<T>) -> MutexGuard<'_, T> {
mutex.lock().unwrap_or_else(PoisonError::into_inner)
}
pub(crate) fn read_lock<T: ?Sized>(rwlock: &RwLock<T>) -> RwLockReadGuard<'_, T> {
rwlock.read().unwrap_or_else(PoisonError::into_inner)
}
pub(crate) fn write_lock<T: ?Sized>(rwlock: &RwLock<T>) -> RwLockWriteGuard<'_, T> {
rwlock.write().unwrap_or_else(PoisonError::into_inner)
}
#[cfg(test)]
pub(crate) fn poison_with<G>(acquire: impl FnOnce() -> G + Send) {
std::thread::scope(|scope| {
let _ = scope
.spawn(|| {
let _guard = acquire();
panic!("poison the lock");
})
.join();
});
}
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;