mirror of https://github.com/Trivernis/bromine.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
155 lines
4.9 KiB
Rust
155 lines
4.9 KiB
Rust
use crate::context::Context;
|
|
use crate::error::{Error, Result};
|
|
use crate::event::{Event, EventType};
|
|
use crate::ipc::stream_emitter::emit_metadata::EmitMetadata;
|
|
use crate::ipc::stream_emitter::emit_metadata_with_response::remove_reply_listener;
|
|
use crate::payload::IntoPayload;
|
|
use crate::poll_unwrap;
|
|
use futures_core::Stream;
|
|
use std::future::Future;
|
|
use std::pin::Pin;
|
|
use std::task::Poll;
|
|
use std::time::Duration;
|
|
use futures_core::future::BoxFuture;
|
|
use tokio::sync::mpsc::Receiver;
|
|
|
|
/// A metadata object returned after waiting for a reply to an event
|
|
/// This object needs to be awaited for to get the actual reply
|
|
pub struct EmitMetadataWithResponseStream<P: IntoPayload> {
|
|
pub(crate) timeout: Option<Duration>,
|
|
pub(crate) fut: Option<BoxFuture<'static, Result<ResponseStream>>>,
|
|
pub(crate) emit_metadata: Option<EmitMetadata<P>>,
|
|
}
|
|
|
|
type StreamFutureResult = Result<(Option<Event>, Context, Receiver<Event>)>;
|
|
|
|
/// An asynchronous stream one can read all responses to a specific event from.
|
|
pub struct ResponseStream {
|
|
event_id: u64,
|
|
ctx: Option<Context>,
|
|
receiver: Option<Receiver<Event>>,
|
|
timeout: Duration,
|
|
fut: Option<BoxFuture<'static, StreamFutureResult>>,
|
|
}
|
|
|
|
impl ResponseStream {
|
|
pub(crate) fn new(
|
|
event_id: u64,
|
|
timeout: Duration,
|
|
ctx: Context,
|
|
receiver: Receiver<Event>,
|
|
) -> Self {
|
|
Self {
|
|
event_id,
|
|
ctx: Some(ctx),
|
|
receiver: Some(receiver),
|
|
timeout,
|
|
fut: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<P: IntoPayload> Unpin for EmitMetadataWithResponseStream<P> {}
|
|
|
|
impl<P: IntoPayload> EmitMetadataWithResponseStream<P> {
|
|
/// Sets a timeout for awaiting replies to this emitted event
|
|
#[inline]
|
|
pub fn with_timeout(mut self, timeout: Duration) -> Self {
|
|
self.timeout = Some(timeout);
|
|
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<P: IntoPayload + Send + Sync + 'static> Future for EmitMetadataWithResponseStream<P> {
|
|
type Output = Result<ResponseStream>;
|
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
|
|
if self.fut.is_none() {
|
|
let mut emit_metadata = poll_unwrap!(self.emit_metadata.take());
|
|
let ctx = poll_unwrap!(emit_metadata
|
|
.event_metadata
|
|
.as_ref()
|
|
.and_then(|m| m.ctx.clone()));
|
|
let timeout = self
|
|
.timeout
|
|
.take()
|
|
.unwrap_or(ctx.default_reply_timeout);
|
|
|
|
let event_id = match poll_unwrap!(emit_metadata.event_metadata.as_mut()).get_event() {
|
|
Ok(e) => e.id(),
|
|
Err(e) => {
|
|
return Poll::Ready(Err(e));
|
|
}
|
|
};
|
|
|
|
self.fut = Some(Box::pin(async move {
|
|
let tx = ctx.register_reply_listener(event_id).await?;
|
|
emit_metadata.await?;
|
|
|
|
Ok(ResponseStream::new(event_id, timeout, ctx, tx))
|
|
}))
|
|
}
|
|
self.fut.as_mut().unwrap().as_mut().poll(cx)
|
|
}
|
|
}
|
|
|
|
impl Unpin for ResponseStream {}
|
|
|
|
impl Stream for ResponseStream {
|
|
type Item = Result<Event>;
|
|
|
|
fn poll_next(
|
|
mut self: Pin<&mut Self>,
|
|
cx: &mut std::task::Context<'_>,
|
|
) -> Poll<Option<Self::Item>> {
|
|
if self.fut.is_none() {
|
|
if self.ctx.is_none() || self.receiver.is_none() {
|
|
return Poll::Ready(None);
|
|
}
|
|
let ctx = self.ctx.take().unwrap();
|
|
let mut receiver = self.receiver.take().unwrap();
|
|
let timeout = self.timeout;
|
|
let event_id = self.event_id;
|
|
|
|
self.fut = Some(Box::pin(async move {
|
|
let event: Option<Event> = tokio::select! {
|
|
tx_result = receiver.recv() => {
|
|
Ok(tx_result)
|
|
}
|
|
_ = tokio::time::sleep(timeout) => {
|
|
Err(Error::Timeout)
|
|
}
|
|
}?;
|
|
|
|
if event.is_none() || event.as_ref().unwrap().event_type() == EventType::End {
|
|
remove_reply_listener(&ctx, event_id).await;
|
|
}
|
|
|
|
Ok((event, ctx, receiver))
|
|
}));
|
|
}
|
|
|
|
match self.fut.as_mut().unwrap().as_mut().poll(cx) {
|
|
Poll::Ready(r) => match r {
|
|
Ok((event, ctx, tx)) => {
|
|
self.fut = None;
|
|
|
|
if let Some(event) = event {
|
|
if event.event_type() != EventType::End {
|
|
self.ctx = Some(ctx);
|
|
self.receiver = Some(tx);
|
|
}
|
|
|
|
Poll::Ready(Some(Ok(event)))
|
|
} else {
|
|
Poll::Ready(None)
|
|
}
|
|
}
|
|
Err(e) => Poll::Ready(Some(Err(e))),
|
|
},
|
|
Poll::Pending => Poll::Pending,
|
|
}
|
|
}
|
|
}
|