use std::marker::PhantomData;
use std::sync::Arc;
use std::time::Duration;
use dashmap::DashMap;
use serde::Serialize;
use tokio_util::sync::CancellationToken;
use crate::streaming::frame::{SendError, StreamFrame};
use crate::streaming::handle::StreamAnchorHandle;
use crate::streaming::sender::{
StreamSenderCancelInfo, cached_detached, cached_dropped, cached_heartbeat,
};
use super::anchor::MpscAnchorEntry;
use super::types::SenderId;
#[derive(Clone)]
pub(crate) enum SenderChannel {
Local(flume::Sender<(u64, Vec<u8>)>),
Remote(flume::Sender<Vec<u8>>),
}
pub struct MpscStreamSender<T> {
sender_id: SenderId,
channel: SenderChannel,
handle: StreamAnchorHandle,
heartbeat_cancel: CancellationToken,
sent_terminal: bool,
mpsc_registry: Arc<DashMap<u64, MpscAnchorEntry>>,
cancel_token: CancellationToken,
sender_stream_id: u64,
sender_registry: Arc<crate::streaming::control::SenderRegistry>,
poison_tx: flume::Sender<()>,
_phantom: PhantomData<T>,
}
impl<T> std::fmt::Debug for MpscStreamSender<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("MpscStreamSender")
.field("sender_id", &self.sender_id)
.field("handle", &self.handle)
.field("sent_terminal", &self.sent_terminal)
.finish_non_exhaustive()
}
}
impl<T: Serialize> MpscStreamSender<T> {
pub(crate) fn new(
sender_id: SenderId,
channel: SenderChannel,
handle: StreamAnchorHandle,
mpsc_registry: Arc<DashMap<u64, MpscAnchorEntry>>,
cancel: StreamSenderCancelInfo,
heartbeat_interval: Duration,
) -> Self {
let StreamSenderCancelInfo {
cancel_token,
sender_stream_id,
sender_registry,
poison_tx,
} = cancel;
let heartbeat_cancel = CancellationToken::new();
let hb_cancel = heartbeat_cancel.clone();
let hb_channel = channel.clone();
let hb_sender_id = sender_id.0;
tokio::spawn(async move {
let mut interval = tokio::time::interval(heartbeat_interval);
interval.tick().await; loop {
tokio::select! {
_ = hb_cancel.cancelled() => break,
_ = interval.tick() => {
let bytes = cached_heartbeat().clone();
match &hb_channel {
SenderChannel::Local(tx) => {
let _ = tx.try_send((hb_sender_id, bytes));
}
SenderChannel::Remote(tx) => {
let _ = tx.try_send(bytes);
}
}
}
}
}
});
Self {
sender_id,
channel,
handle,
heartbeat_cancel,
sent_terminal: false,
mpsc_registry,
cancel_token,
sender_stream_id,
sender_registry,
poison_tx,
_phantom: PhantomData,
}
}
pub fn sender_id(&self) -> SenderId {
self.sender_id
}
pub fn cancellation_token(&self) -> CancellationToken {
self.cancel_token.clone()
}
pub async fn send(&self, item: T) -> Result<(), SendError> {
if self.poison_tx.is_disconnected() {
return Err(SendError::ChannelClosed);
}
let bytes = rmp_serde::to_vec(&StreamFrame::Item(item))
.map_err(|e| SendError::SerializationError(e.to_string()))?;
match &self.channel {
SenderChannel::Local(tx) => tx
.send_async((self.sender_id.0, bytes))
.await
.map_err(|_| SendError::ChannelClosed),
SenderChannel::Remote(tx) => tx
.send_async(bytes)
.await
.map_err(|_| SendError::ChannelClosed),
}
}
pub async fn send_err(&self, msg: impl ToString) -> Result<(), SendError> {
if self.poison_tx.is_disconnected() {
return Err(SendError::ChannelClosed);
}
let bytes = rmp_serde::to_vec(&StreamFrame::<()>::SenderError(msg.to_string()))
.expect("SenderError serializes infallibly");
match &self.channel {
SenderChannel::Local(tx) => tx
.send_async((self.sender_id.0, bytes))
.await
.map_err(|_| SendError::ChannelClosed),
SenderChannel::Remote(tx) => tx
.send_async(bytes)
.await
.map_err(|_| SendError::ChannelClosed),
}
}
pub async fn detach(mut self) -> Result<StreamAnchorHandle, SendError> {
self.heartbeat_cancel.cancel();
self.sent_terminal = true;
let bytes = cached_detached().clone();
let result = match &self.channel {
SenderChannel::Local(tx) => tx
.send_async((self.sender_id.0, bytes))
.await
.map_err(|_| SendError::ChannelClosed),
SenderChannel::Remote(tx) => tx
.send_async(bytes)
.await
.map_err(|_| SendError::ChannelClosed),
};
let (_, local_id) = self.handle.unpack();
if let Some(slot) = crate::streaming::mpsc::anchor::remove_sender_slot(
&self.mpsc_registry,
local_id,
self.sender_id.0,
) && let Some(pt) = slot.pump_token
{
pt.cancel();
}
self.sender_registry.senders.remove(&self.sender_stream_id);
result?;
Ok(self.handle)
}
}
impl<T> Drop for MpscStreamSender<T> {
fn drop(&mut self) {
self.sender_registry.senders.remove(&self.sender_stream_id);
if !self.sent_terminal {
self.heartbeat_cancel.cancel();
let bytes = cached_dropped().clone();
match &self.channel {
SenderChannel::Local(tx) => {
let _ = tx.send((self.sender_id.0, bytes));
}
SenderChannel::Remote(tx) => {
let _ = tx.try_send(bytes);
}
}
let (_, local_id) = self.handle.unpack();
if let Some(slot) = crate::streaming::mpsc::anchor::remove_sender_slot(
&self.mpsc_registry,
local_id,
self.sender_id.0,
) && let Some(pt) = slot.pump_token
{
pt.cancel();
}
}
}
}