use alloc::format;
use core::time::Duration;
use std::time::Instant;
use liminal::protocol::Frame;
use liminal_protocol::wire::ParticipantFrame;
use super::{Connection, FrameStream, IO_TIMEOUT, ParticipantPumpDiagnostics, participant};
use crate::SdkError;
impl<S: FrameStream> Connection<S> {
pub(super) const fn consume_pump_fence(&mut self, frame: &Frame) -> bool {
if matches!(frame, Frame::Pong { .. }) && self.pump_fences_pending > 0 {
self.pump_fences_pending -= 1;
true
} else {
false
}
}
pub(in crate::remote) const fn pump_diagnostics(&self) -> ParticipantPumpDiagnostics {
self.pump_diagnostics
}
pub(in crate::remote) fn try_receive_participant(
&mut self,
) -> Result<Option<ParticipantFrame>, SdkError> {
self.pump_diagnostics.pumps_run = self.pump_diagnostics.pumps_run.saturating_add(1);
if let Some(frame) = self.receive_optional_within(Duration::ZERO)? {
return participant::response_frame(frame).map(Some);
}
let pending =
self.pump_fences_pending
.checked_add(1)
.ok_or_else(|| SdkError::Protocol {
description: "participant pump fence count exhausted".into(),
})?;
let started = Instant::now();
self.send(&Frame::Ping { flags: 0 })?;
self.pump_fences_pending = pending;
let result = self.poll_within(started, IO_TIMEOUT, true);
let restore =
self.stream
.set_read_deadline(IO_TIMEOUT)
.map_err(|error| SdkError::Connection {
description: format!(
"failed to restore read timeout after pump fence: {error}"
),
});
let frame = result?;
restore?;
match frame {
Some(frame) => participant::response_frame(frame).map(Some),
None if self.pump_fences_pending == 0 => {
self.receive_optional_within(Duration::ZERO)?
.map(participant::response_frame)
.transpose()
}
None => Err(SdkError::Connection {
description: format!(
"participant pump liveness fence was unanswered after {:.3}s",
started.elapsed().as_secs_f64()
),
}),
}
}
}