use std::{
collections::VecDeque,
marker::PhantomData,
pin::Pin,
sync::Arc,
task::{Context, Poll},
};
use futures::Sink;
use serde::Serialize;
use crate::{codec::CodecType, error::Error};
pub struct Publisher<T, C: CodecType> {
client: Arc<async_nats::Client>,
subject: String,
buffer: VecDeque<Vec<u8>>,
_marker: PhantomData<(T, C)>,
}
impl<T, C: CodecType> Publisher<T, C> {
pub(crate) fn new(client: Arc<async_nats::Client>, subject: String) -> Self {
Self {
client,
subject,
buffer: VecDeque::new(),
_marker: PhantomData,
}
}
pub fn subject(&self) -> &str {
&self.subject
}
pub fn client(&self) -> &async_nats::Client {
&self.client
}
}
impl<T: Serialize, C: CodecType> Publisher<T, C> {
pub async fn publish(&self, message: &T) -> crate::error::Result<()> {
let data = C::encode(message)?;
self.client
.publish(self.subject.clone(), data.into())
.await?;
Ok(())
}
}
impl<T, C: CodecType> Clone for Publisher<T, C> {
fn clone(&self) -> Self {
Self {
client: self.client.clone(),
subject: self.subject.clone(),
buffer: VecDeque::new(),
_marker: PhantomData,
}
}
}
impl<T: Serialize + Unpin, C: CodecType + Unpin> Sink<T> for Publisher<T, C> {
type Error = Error;
fn poll_ready(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn start_send(self: Pin<&mut Self>, item: T) -> Result<(), Self::Error> {
let data = C::encode(&item)?;
let this = self.get_mut();
this.buffer.push_back(data);
Ok(())
}
fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
let this = self.get_mut();
while let Some(data) = this.buffer.pop_front() {
let client = this.client.clone();
let subject = this.subject.clone();
tokio::spawn(async move {
let _ = client.publish(subject, data.into()).await;
});
}
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
self.poll_flush(cx)
}
}