reimplement with fred
This commit is contained in:
@ -25,7 +25,7 @@ opentelemetry = { version = "0.21", optional = true }
|
||||
opentelemetry_sdk = { version = "0.21", optional = true }
|
||||
opentelemetry-stdout = { version = "0.2", features = ["trace"], optional = true }
|
||||
|
||||
redis = { version = "0.25", features = ["tokio-comp"] }
|
||||
fred = { version = "9", features = ["subscriber-client"] }
|
||||
sea-orm = { version = "0", features = [ "sqlx-sqlite", "runtime-tokio-rustls", "macros", "mock", "with-chrono", "with-json", "with-uuid" ] }
|
||||
|
||||
tera = "1"
|
||||
|
@ -1,3 +1,4 @@
|
||||
pub mod grpc;
|
||||
mod redisexchange;
|
||||
pub mod websocket;
|
||||
|
||||
pub mod grpc;
|
||||
pub mod websockets;
|
||||
|
@ -1,13 +1,12 @@
|
||||
use std::{pin::Pin, sync::Arc};
|
||||
use std::pin::Pin;
|
||||
|
||||
use fred::prelude::*;
|
||||
|
||||
use futures::stream::*;
|
||||
use signaling::{signaling_server::*, SignalingMessage};
|
||||
use tonic::Status;
|
||||
|
||||
use tokio::sync::{
|
||||
mpsc::{Receiver, Sender},
|
||||
Mutex,
|
||||
};
|
||||
use tokio::sync::mpsc::{Receiver, Sender};
|
||||
|
||||
/// A wrapper around [`tokio::sync::mpsc::Receiver`] that implements [`Stream`].
|
||||
///
|
||||
@ -74,7 +73,7 @@ impl<T> From<Receiver<T>> for ReceiverStream<T> {
|
||||
}
|
||||
|
||||
pub struct SignalingService {
|
||||
pub redis: redis::Client,
|
||||
pub redis: fred::types::RedisConfig,
|
||||
}
|
||||
|
||||
impl SignalingService {
|
||||
@ -105,8 +104,8 @@ impl SignalingService {
|
||||
async fn handle_with_redis_exchange(
|
||||
stream: tonic::Streaming<SignalingMessage>,
|
||||
tx: Sender<Result<SignalingMessage, Status>>,
|
||||
redis: redis::aio::MultiplexedConnection,
|
||||
pubsub: Arc<Mutex<redis::aio::PubSub>>,
|
||||
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);
|
||||
@ -135,18 +134,19 @@ impl Signaling for SignalingService {
|
||||
let in_stream = request.into_inner();
|
||||
let (tx, rx) = tokio::sync::mpsc::channel(128);
|
||||
|
||||
let redis = self.redis.get_multiplexed_tokio_connection().await.unwrap();
|
||||
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 = match self.redis.get_async_pubsub().await {
|
||||
Ok(pubsub) => pubsub,
|
||||
Err(err) => return Err(Status::unknown(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,
|
||||
Arc::new(Mutex::new(pubsub)),
|
||||
in_stream, tx, redis, pubsub,
|
||||
));
|
||||
|
||||
let output_stream = ReceiverStream::new(rx);
|
||||
|
@ -1,6 +1,6 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use redis::AsyncCommands;
|
||||
use fred::prelude::*;
|
||||
|
||||
use signaling::{IceCandidate, SdpMessage, SignalingMessage};
|
||||
use tokio::sync::{
|
||||
@ -8,8 +8,6 @@ use tokio::sync::{
|
||||
Mutex,
|
||||
};
|
||||
|
||||
use futures::StreamExt;
|
||||
|
||||
enum RedisChannel {
|
||||
DiscoverRequest,
|
||||
DiscoverResponse(String),
|
||||
@ -58,8 +56,8 @@ impl TryFrom<&str> for RedisChannel {
|
||||
pub async fn send_message_to_peers(
|
||||
mut messages_to_peers: Receiver<SignalingMessage>,
|
||||
messages_from_peers: Sender<SignalingMessage>,
|
||||
mut redis: redis::aio::MultiplexedConnection,
|
||||
pubsub: Arc<Mutex<redis::aio::PubSub>>,
|
||||
redis: fred::clients::RedisClient,
|
||||
pubsub: fred::clients::SubscriberClient,
|
||||
) {
|
||||
let mut name = String::default();
|
||||
|
||||
@ -88,8 +86,8 @@ pub async fn send_message_to_peers(
|
||||
));
|
||||
}
|
||||
signaling::signaling_message::Message::DiscoverRequest(()) => {
|
||||
let peers = match redis
|
||||
.publish::<_, _, u64>(format!("chatchat:{room}:discover"), name.clone())
|
||||
let peers: usize = match redis
|
||||
.publish(format!("chatchat:{room}:discover"), name.clone())
|
||||
.await
|
||||
{
|
||||
Ok(peers) => peers,
|
||||
@ -98,15 +96,12 @@ pub async fn send_message_to_peers(
|
||||
break;
|
||||
}
|
||||
};
|
||||
tracing::info!(peers, room, sender = name, "broadcasting discover")
|
||||
tracing::info!(peers, room, sender = name, "broadcasting discover");
|
||||
}
|
||||
signaling::signaling_message::Message::DiscoverResponse(()) => {
|
||||
let receiver = message.receiver.unwrap();
|
||||
let peers = match redis
|
||||
.publish::<_, _, u64>(
|
||||
format!("chatchat:{room}:discover:{receiver}"),
|
||||
name.clone(),
|
||||
)
|
||||
let peers: usize = match redis
|
||||
.publish(format!("chatchat:{room}:discover:{receiver}"), name.clone())
|
||||
.await
|
||||
{
|
||||
Ok(peers) => peers,
|
||||
@ -120,8 +115,8 @@ pub async fn send_message_to_peers(
|
||||
signaling::signaling_message::Message::SessionOffer(sdp) => {
|
||||
let msg = serde_json::to_string(&sdp).unwrap();
|
||||
let receiver = message.receiver.unwrap();
|
||||
let peers = match redis
|
||||
.publish::<_, _, u64>(format!("chatchat:{room}:offer:{receiver}"), msg)
|
||||
let peers: usize = match redis
|
||||
.publish(format!("chatchat:{room}:offer:{receiver}"), msg)
|
||||
.await
|
||||
{
|
||||
Ok(peers) => peers,
|
||||
@ -136,8 +131,8 @@ pub async fn send_message_to_peers(
|
||||
signaling::signaling_message::Message::SessionAnswer(sdp) => {
|
||||
let msg = serde_json::to_string(&sdp).unwrap();
|
||||
let receiver = message.receiver.unwrap();
|
||||
let peers = match redis
|
||||
.publish::<_, _, u64>(format!("chatchat:{room}:answer:{receiver}"), msg)
|
||||
let peers: usize = match redis
|
||||
.publish(format!("chatchat:{room}:answer:{receiver}"), msg)
|
||||
.await
|
||||
{
|
||||
Ok(peers) => peers,
|
||||
@ -151,8 +146,8 @@ pub async fn send_message_to_peers(
|
||||
signaling::signaling_message::Message::IceCandidate(candidate) => {
|
||||
let msg = serde_json::to_string(&candidate).unwrap();
|
||||
let receiver = message.receiver.unwrap();
|
||||
let peers = match redis
|
||||
.publish::<_, _, u64>(format!("chatchat:{room}:icecandidate:{receiver}"), msg)
|
||||
let peers: usize = match redis
|
||||
.publish(format!("chatchat:{room}:icecandidate:{receiver}"), msg)
|
||||
.await
|
||||
{
|
||||
Ok(peers) => peers,
|
||||
@ -166,17 +161,17 @@ pub async fn send_message_to_peers(
|
||||
}
|
||||
}
|
||||
tracing::debug!(name, "stopped send to peer");
|
||||
let _ = closing_tx.send(()).await;
|
||||
let _ = closing_tx.send(String::from("websocket exited")).await;
|
||||
}
|
||||
pub async fn receive_message_from_peers(
|
||||
name: String,
|
||||
room: String,
|
||||
tx: Sender<SignalingMessage>,
|
||||
pubsub: Arc<Mutex<redis::aio::PubSub>>,
|
||||
closing_rx: Arc<Mutex<Receiver<()>>>,
|
||||
pubsub: fred::clients::SubscriberClient,
|
||||
closing_rx: Arc<Mutex<Receiver<String>>>,
|
||||
) {
|
||||
let mut closing_rx = closing_rx.lock().await;
|
||||
let mut pubsub = pubsub.lock().await;
|
||||
// let mut pubsub = pubsub.lock().await;
|
||||
|
||||
let discover_request_channel = format!(
|
||||
"chatchat:{room}:{}",
|
||||
@ -199,25 +194,19 @@ pub async fn receive_message_from_peers(
|
||||
RedisChannel::SessionIceCandidate(name.clone()).to_string()
|
||||
);
|
||||
|
||||
tracing::trace!(room, name, channels=?[
|
||||
&discover_request_channel,
|
||||
&discover_response_channel,
|
||||
&session_offer_channel,
|
||||
&session_answer_channel,
|
||||
&session_ice_channel,
|
||||
], "subscribed");
|
||||
pubsub
|
||||
.subscribe(&[
|
||||
discover_request_channel,
|
||||
discover_response_channel,
|
||||
session_offer_channel,
|
||||
session_answer_channel,
|
||||
session_ice_channel,
|
||||
])
|
||||
.await
|
||||
.unwrap();
|
||||
let channels = [
|
||||
&discover_request_channel,
|
||||
&discover_response_channel,
|
||||
&session_offer_channel,
|
||||
&session_answer_channel,
|
||||
&session_ice_channel,
|
||||
];
|
||||
|
||||
let mut messages = pubsub.on_message();
|
||||
pubsub.subscribe(&channels).await.unwrap();
|
||||
tracing::info!(?channels, "subscribed");
|
||||
|
||||
// let mut messages = pubsub.on_message();
|
||||
let mut messages = pubsub.message_rx();
|
||||
|
||||
tracing::info!(room, name = name.clone(), "connection ready");
|
||||
let _ = tx
|
||||
@ -231,34 +220,41 @@ pub async fn receive_message_from_peers(
|
||||
|
||||
loop {
|
||||
tokio::select! {
|
||||
_ = closing_rx.recv() => {
|
||||
message = closing_rx.recv() => {
|
||||
tracing::warn!(message, "exit due to closing rx");
|
||||
break;
|
||||
},
|
||||
maybe_message = messages.next() => {
|
||||
let message = if let Some(message) = maybe_message {
|
||||
message
|
||||
} else {
|
||||
break;
|
||||
maybe_message = messages.recv() => {
|
||||
let message = match maybe_message {
|
||||
Ok(message) => message,
|
||||
Err(error) => {
|
||||
tracing::warn!(?error, "failed to recv message from redis");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
let channel = match message
|
||||
.get_channel_name()
|
||||
.channel.to_string()
|
||||
.strip_prefix(&format!("chatchat:{}:", room.clone()))
|
||||
{
|
||||
Some(channel) => channel,
|
||||
Some(channel) => channel.to_string(),
|
||||
_ => continue,
|
||||
};
|
||||
let channel = match RedisChannel::try_from(channel) {
|
||||
let channel = match RedisChannel::try_from(channel.as_str()) {
|
||||
Ok(channel) => channel,
|
||||
Err(unrecognized) => {
|
||||
tracing::warn!(unrecognized, "unrecognized");
|
||||
continue;
|
||||
}
|
||||
};
|
||||
let payload: String = match message.get_payload() {
|
||||
Ok(msg) => msg,
|
||||
_ => continue,
|
||||
let msg_kind = message.value.kind();
|
||||
let payload = if let fred::types::RedisValue::String(ref s) = message.value {
|
||||
s.to_string()
|
||||
} else {
|
||||
tracing::warn!(?msg_kind, "message is not string");
|
||||
continue;
|
||||
};
|
||||
|
||||
match channel {
|
||||
RedisChannel::DiscoverRequest => {
|
||||
if payload == name {
|
||||
|
@ -1,14 +1,15 @@
|
||||
use axum::{extract::State, response::IntoResponse};
|
||||
use fred::prelude::*;
|
||||
|
||||
use crate::{signaling::redisexchange, types::AppState};
|
||||
use axum::extract::ws::Message;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{Mutex, RwLock};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
pub async fn handle_message_from_frontend(
|
||||
mut ws: axum::extract::ws::WebSocket,
|
||||
redis: redis::aio::MultiplexedConnection,
|
||||
pubsub: Arc<Mutex<redis::aio::PubSub>>,
|
||||
redis: fred::clients::RedisClient,
|
||||
pubsub: fred::clients::SubscriberClient,
|
||||
) {
|
||||
let (peer_tx, mut peer_rx) = tokio::sync::mpsc::channel(128);
|
||||
let (browser_tx, browser_rx) = tokio::sync::mpsc::channel(128);
|
||||
@ -55,7 +56,6 @@ pub async fn handle_message_from_frontend(
|
||||
}
|
||||
}
|
||||
}
|
||||
// browser_rx.close();
|
||||
}
|
||||
|
||||
pub async fn handle_ws_upgrade(
|
||||
@ -63,17 +63,17 @@ pub async fn handle_ws_upgrade(
|
||||
State(state): State<Arc<RwLock<AppState>>>,
|
||||
) -> Result<impl IntoResponse, String> {
|
||||
let state = state.read().await;
|
||||
let redis: redis::aio::MultiplexedConnection =
|
||||
match state.redis.get_multiplexed_tokio_connection().await {
|
||||
Ok(redis) => redis,
|
||||
Err(err) => return Err(err.to_string()),
|
||||
};
|
||||
|
||||
let pubsub = match state.clone().redis.get_async_pubsub().await {
|
||||
Ok(pubsub) => pubsub,
|
||||
Err(err) => return Err(err.to_string()),
|
||||
};
|
||||
let builder = fred::types::Builder::from_config(state.redis.clone());
|
||||
let redis = builder.build().unwrap();
|
||||
if let Err(err) = redis.init().await {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
|
||||
Ok(upgrade
|
||||
.on_upgrade(|ws| handle_message_from_frontend(ws, redis, Arc::new(Mutex::new(pubsub)))))
|
||||
let pubsub = builder.build_subscriber_client().unwrap();
|
||||
if let Err(err) = pubsub.init().await {
|
||||
return Err(err.to_string());
|
||||
}
|
||||
|
||||
Ok(upgrade.on_upgrade(|ws| handle_message_from_frontend(ws, redis, pubsub)))
|
||||
}
|
@ -8,5 +8,5 @@ pub struct PageContext {
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub templates: tera::Tera,
|
||||
pub redis: redis::Client,
|
||||
pub redis: fred::types::RedisConfig,
|
||||
}
|
||||
|
@ -57,13 +57,14 @@ pub struct Config {
|
||||
impl Default for Config {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
redis_addr: String::from("redis://127.0.0.1")
|
||||
redis_addr: String::from("redis://127.0.0.1"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn make_service(config: Option<Config>) -> Result<IntoMakeService<Router<()>>, Box<dyn std::error::Error>> {
|
||||
pub fn make_service(
|
||||
config: Option<Config>,
|
||||
) -> Result<IntoMakeService<Router<()>>, Box<dyn std::error::Error>> {
|
||||
let config = config.unwrap_or_default();
|
||||
let templates = load_templates()?;
|
||||
|
||||
@ -72,7 +73,7 @@ pub fn make_service(config: Option<Config>) -> Result<IntoMakeService<Router<()>
|
||||
#[cfg(feature = "serve-static")]
|
||||
let router = router.route_service("/static/*path", staticfiles::StaticFiles::strip("/static/"));
|
||||
|
||||
let redis = redis::Client::open(config.redis_addr)?;
|
||||
let redis = fred::types::RedisConfig::from_url(&config.redis_addr)?;
|
||||
|
||||
let grpc_service = tonic_web::enable(signaling::signaling_server::SignalingServer::new(
|
||||
GrpcSignalingService {
|
||||
@ -87,7 +88,7 @@ pub fn make_service(config: Option<Config>) -> Result<IntoMakeService<Router<()>
|
||||
"/signaling.Signaling/*rpc",
|
||||
axum::routing::any_service(grpc_service.clone()),
|
||||
)
|
||||
.route("/ws", get(crate::signaling::websocket::handle_ws_upgrade))
|
||||
.route("/ws", get(crate::signaling::websockets::handle_ws_upgrade))
|
||||
.with_state(Arc::new(RwLock::new(crate::types::AppState {
|
||||
templates: templates,
|
||||
redis,
|
||||
|
Reference in New Issue
Block a user