use super::{private, GetRawSocket, Period, RawSocket};
use crate::error::Error;
use Period::*;
use serde::{Deserialize, Serialize};
use std::{sync::MutexGuard, time::Duration};
fn set_heartbeat(
raw_socket: &RawSocket,
maybe: Option<Heartbeat>,
mut mutex: MutexGuard<Option<Heartbeat>>,
) -> Result<(), Error> {
if *mutex == maybe {
return Ok(());
}
if let Some(heartbeat) = &maybe {
raw_socket.set_heartbeat_interval(heartbeat.interval)?;
if let Finite(timeout) = heartbeat.timeout {
raw_socket.set_heartbeat_timeout(timeout)?;
}
if let Finite(ttl) = heartbeat.ttl {
raw_socket.set_heartbeat_timeout(ttl)?;
}
} else {
raw_socket.set_heartbeat_interval(Duration::from_millis(0))?;
raw_socket.set_heartbeat_timeout(Duration::from_millis(0))?;
raw_socket.set_heartbeat_ttl(Duration::from_millis(0))?;
}
*mutex = maybe;
Ok(())
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct Heartbeat {
#[serde(with = "humantime_serde")]
pub(crate) interval: Duration,
pub(crate) timeout: Period,
pub(crate) ttl: Period,
}
impl Heartbeat {
pub fn new<D>(interval: D) -> Self
where
D: Into<Duration>,
{
Self {
interval: interval.into(),
timeout: Infinite,
ttl: Infinite,
}
}
pub fn interval(&self) -> Duration {
self.interval
}
pub fn add_timeout<D>(mut self, timeout: D) -> Self
where
D: Into<Duration>,
{
self.timeout = Finite(timeout.into());
self
}
pub fn timeout(&self) -> Period {
self.timeout
}
pub fn add_ttl<D>(mut self, ttl: D) -> Self
where
D: Into<Duration>,
{
self.ttl = Finite(ttl.into());
self
}
pub fn ttl(&self) -> Period {
self.ttl
}
}
impl<'a> From<&'a Heartbeat> for Heartbeat {
fn from(hb: &'a Heartbeat) -> Self {
hb.to_owned()
}
}
pub trait Heartbeating: GetRawSocket {
fn heartbeat(&self) -> Option<Heartbeat> {
self.raw_socket().heartbeat().lock().unwrap().to_owned()
}
fn set_heartbeat(&self, maybe: Option<Heartbeat>) -> Result<(), Error> {
let raw_socket = self.raw_socket();
let mutex = raw_socket.heartbeat().lock().unwrap();
set_heartbeat(raw_socket, maybe, mutex)
}
}
#[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
#[doc(hidden)]
pub struct HeartbeatingConfig {
pub(crate) heartbeat: Option<Heartbeat>,
}
impl HeartbeatingConfig {
pub(crate) fn apply<S: Heartbeating>(
&self,
socket: &S,
) -> Result<(), Error> {
socket.set_heartbeat(self.heartbeat.clone())
}
}
#[doc(hidden)]
pub trait GetHeartbeatingConfig: private::Sealed {
fn heartbeat_config(&self) -> &HeartbeatingConfig;
fn heartbeat_config_mut(&mut self) -> &mut HeartbeatingConfig;
}
impl GetHeartbeatingConfig for HeartbeatingConfig {
fn heartbeat_config(&self) -> &HeartbeatingConfig {
self
}
fn heartbeat_config_mut(&mut self) -> &mut HeartbeatingConfig {
self
}
}
pub trait ConfigureHeartbeating: GetHeartbeatingConfig {
fn heartbeat(&self) -> Option<&Heartbeat> {
self.heartbeat_config().heartbeat.as_ref()
}
fn set_heartbeat(&mut self, maybe: Option<Heartbeat>) {
self.heartbeat_config_mut().heartbeat = maybe;
}
}
impl ConfigureHeartbeating for HeartbeatingConfig {}
pub trait BuildHeartbeating: GetHeartbeatingConfig + Sized {
fn heartbeat<H>(&mut self, heartbeat: H) -> &mut Self
where
H: Into<Heartbeat>,
{
self.heartbeat_config_mut()
.set_heartbeat(Some(heartbeat.into()));
self
}
}