2024-05-30 01:55:13 +08:00

158 lines
4.7 KiB
Rust

use std::pin::Pin;
use fred::prelude::*;
use futures::stream::*;
use signaling::{signaling_server::*, SignalingMessage};
use tonic::Status;
use tokio::sync::mpsc::{Receiver, Sender};
/// A wrapper around [`tokio::sync::mpsc::Receiver`] that implements [`Stream`].
///
/// [`tokio::sync::mpsc::Receiver`]: struct@tokio::sync::mpsc::Receiver
/// [`Stream`]: trait@crate::Stream
#[derive(Debug)]
pub struct ReceiverStream<T> {
inner: Receiver<T>,
}
impl<T> ReceiverStream<T> {
/// Create a new `ReceiverStream`.
pub fn new(recv: Receiver<T>) -> Self {
Self { inner: recv }
}
/// Get back the inner `Receiver`.
pub fn into_inner(self) -> Receiver<T> {
self.inner
}
/// Closes the receiving half of a channel without dropping it.
///
/// This prevents any further messages from being sent on the channel while
/// still enabling the receiver to drain messages that are buffered. Any
/// outstanding [`Permit`] values will still be able to send messages.
///
/// To guarantee no messages are dropped, after calling `close()`, you must
/// receive all items from the stream until `None` is returned.
///
/// [`Permit`]: struct@tokio::sync::mpsc::Permit
pub fn close(&mut self) {
self.inner.close();
}
}
impl<T> Stream for ReceiverStream<T> {
type Item = T;
fn poll_next(
mut self: Pin<&mut Self>,
cx: &mut futures::task::Context<'_>,
) -> futures::task::Poll<Option<Self::Item>> {
self.inner.poll_recv(cx)
}
}
impl<T> AsRef<Receiver<T>> for ReceiverStream<T> {
fn as_ref(&self) -> &Receiver<T> {
&self.inner
}
}
impl<T> AsMut<Receiver<T>> for ReceiverStream<T> {
fn as_mut(&mut self) -> &mut Receiver<T> {
&mut self.inner
}
}
impl<T> From<Receiver<T>> for ReceiverStream<T> {
fn from(recv: Receiver<T>) -> Self {
Self::new(recv)
}
}
pub struct SignalingService {
pub redis: fred::types::RedisConfig,
}
impl SignalingService {
async fn copy_from_tonic_stream_to_sender(
mut stream: tonic::Streaming<SignalingMessage>,
stream_tx: Sender<SignalingMessage>,
) -> Result<(), tonic::Status> {
while let Some(message_or_error) = stream.next().await {
match message_or_error {
Ok(message) => {
let _ = stream_tx.send(message).await;
}
Err(status) => return Err(status),
}
}
Ok(())
}
async fn copy_from_receiver_to_sender(
mut stream_rx: Receiver<SignalingMessage>,
stream: tokio::sync::mpsc::Sender<Result<SignalingMessage, tonic::Status>>,
) -> Result<(), tonic::Status> {
while let Some(msg) = stream_rx.recv().await {
let _ = stream.send(Ok(msg)).await;
}
Ok(())
}
async fn handle_with_redis_exchange(
stream: tonic::Streaming<SignalingMessage>,
tx: Sender<Result<SignalingMessage, Status>>,
redis: fred::clients::RedisClient,
pubsub: fred::clients::SubscriberClient,
) {
let (stream_tx, stream_rx) = tokio::sync::mpsc::channel(128);
let (result_tx, result_rx) = tokio::sync::mpsc::channel(128);
tokio::spawn(SignalingService::copy_from_tonic_stream_to_sender(
stream, stream_tx,
));
tokio::spawn(SignalingService::copy_from_receiver_to_sender(
result_rx, tx,
));
super::redisexchange::send_message_to_peers(stream_rx, result_tx, redis, pubsub).await;
tracing::debug!("stream terminated");
}
}
#[tonic::async_trait]
impl Signaling for SignalingService {
type BiuStream =
Pin<Box<dyn Stream<Item = Result<signaling::SignalingMessage, tonic::Status>> + Send>>;
async fn biu(
&self,
request: tonic::Request<tonic::Streaming<signaling::SignalingMessage>>,
) -> Result<tonic::Response<Self::BiuStream>, Status> {
let in_stream = request.into_inner();
let (tx, rx) = tokio::sync::mpsc::channel(128);
let builder = fred::types::Builder::from_config(self.redis.clone());
let redis = builder.build().unwrap();
if let Err(err) = redis.init().await {
return Err(Status::internal(err.to_string()));
}
let pubsub = builder.build_subscriber_client().unwrap();
if let Err(err) = pubsub.init().await {
return Err(Status::internal(err.to_string()));
}
tokio::spawn(SignalingService::handle_with_redis_exchange(
in_stream, tx, redis, pubsub,
));
let output_stream = ReceiverStream::new(rx);
Ok(tonic::Response::new(
Box::pin(output_stream) as Self::BiuStream
))
}
}