use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
#[cfg(feature = "polygon")]
use std::time::Duration;
use futures::stream::Stream;
use tokio::sync::{broadcast, mpsc};
use super::source::{ReconnectConfig, StreamCommand, StreamSource, run_stream_loop};
use super::subscription::Subscription;
const COMMAND_CAPACITY: usize = 32;
#[cfg(feature = "polygon")]
pub(crate) const RECONNECT_BACKOFF: Duration = Duration::from_secs(3);
pub(crate) struct SourceStream<T>
where
T: Clone + Send + 'static,
{
inner: Subscription<T, StreamCommand>,
}
impl<T> SourceStream<T>
where
T: Clone + Send + 'static,
{
pub(crate) fn start(
source: Arc<dyn StreamSource<T>>,
symbols: Vec<String>,
reconnect: ReconnectConfig,
capacity: usize,
) -> Self {
Self::spawn(capacity, move |broadcast_tx, command_rx| async move {
let _ = run_stream_loop(source, symbols, broadcast_tx, command_rx, reconnect).await;
})
}
pub(crate) fn spawn<F, Fut>(capacity: usize, run: F) -> Self
where
F: FnOnce(broadcast::Sender<T>, mpsc::Receiver<StreamCommand>) -> Fut,
Fut: Future<Output = ()> + Send + 'static,
{
SourceStream {
inner: Subscription::start(capacity, COMMAND_CAPACITY, run),
}
}
pub(crate) fn resubscribe(&self) -> Self {
SourceStream {
inner: self.inner.resubscribe(),
}
}
pub(crate) async fn add<S, I>(&self, symbols: I)
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
let symbols: Vec<String> = symbols.into_iter().map(Into::into).collect();
self.inner.send(StreamCommand::Subscribe(symbols)).await;
}
pub(crate) async fn remove<S, I>(&self, symbols: I)
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
let symbols: Vec<String> = symbols.into_iter().map(Into::into).collect();
self.inner.send(StreamCommand::Unsubscribe(symbols)).await;
}
pub(crate) async fn close(&self) {
self.inner.send(StreamCommand::Close).await;
}
}
impl<T> Stream for SourceStream<T>
where
T: Clone + Send + 'static,
{
type Item = T;
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Pin::new(&mut self.inner).poll_next(cx)
}
}
#[cfg(any(feature = "polygon", feature = "fred"))]
macro_rules! stream_handle {
(
$(#[$attr:meta])*
$name:ident($item:ty);
add: $add:ident = $add_doc:literal,
remove: $remove:ident = $remove_doc:literal,
) => {
$(#[$attr])*
pub struct $name {
inner: $crate::streaming::handle::SourceStream<$item>,
}
impl $name {
pub fn resubscribe(&self) -> Self {
Self {
inner: self.inner.resubscribe(),
}
}
#[doc = $add_doc]
pub async fn $add<S, I>(&self, symbols: I)
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.inner.add(symbols).await;
}
#[doc = $remove_doc]
pub async fn $remove<S, I>(&self, symbols: I)
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.inner.remove(symbols).await;
}
pub async fn close(&self) {
self.inner.close().await;
}
}
impl ::futures::stream::Stream for $name {
type Item = $item;
fn poll_next(
mut self: ::std::pin::Pin<&mut Self>,
cx: &mut ::std::task::Context<'_>,
) -> ::std::task::Poll<Option<Self::Item>> {
::futures::stream::Stream::poll_next(
::std::pin::Pin::new(&mut self.inner),
cx,
)
}
}
};
}
#[cfg(feature = "polygon")]
macro_rules! stream_builder {
($builder:ident, $field:ident = $doc:literal) => {
impl $builder {
#[doc = $doc]
pub fn $field<S, I>(mut self, symbols: I) -> Self
where
S: Into<String>,
I: IntoIterator<Item = S>,
{
self.$field.extend(symbols.into_iter().map(Into::into));
self
}
pub fn retry(mut self, delay: ::std::time::Duration) -> Self {
self.retry_delay = delay;
self
}
pub fn max_reconnect_attempts(mut self, max: u32) -> Self {
self.max_reconnect_attempts = Some(max);
self
}
}
impl Default for $builder {
fn default() -> Self {
Self::new()
}
}
};
}
#[cfg(feature = "polygon")]
pub(crate) use stream_builder;
#[cfg(any(feature = "polygon", feature = "fred"))]
pub(crate) use stream_handle;