sse-format

This commit is contained in:
2023-10-19 17:43:00 +03:00
parent 8473694757
commit 5cf79bf531
5 changed files with 106 additions and 66 deletions

View File

@@ -5,6 +5,7 @@ use futures::StreamExt;
use redis::{AsyncCommands, Client};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use uuid::Uuid;
use std::collections::HashMap;
use std::env;
use std::sync::{Arc, Mutex};
@@ -21,14 +22,20 @@ struct AppState {
#[derive(Serialize, Deserialize, Clone, Debug)]
struct RedisMessageData {
payload: HashMap<String, Value>,
kind: String,
action: String
}
#[derive(Serialize, Deserialize, Clone, Debug)]
pub struct SSEMessageData {
payload: HashMap<String, Value>,
action: String,
entity: String
}
async fn connect_handler(
req: HttpRequest,
state: web::Data<AppState>,
) -> Result<HttpResponse, actix_web::Error> {
let handler_id: u64 = rand::random();
let token = match req.headers().get("Authorization") {
Some(val) => val.to_str().unwrap_or("").split(" ").last().unwrap_or(""),
@@ -71,13 +78,13 @@ async fn connect_handler(
let handle = tokio::spawn(async move {
let conn = state_clone.redis.get_async_connection().await.unwrap();
let mut pubsub = conn.into_pubsub();
let followers_channel = format!("followers:{}", listener_id);
let followers_channel = format!("follower:{}", listener_id);
pubsub.subscribe(followers_channel.clone()).await.unwrap();
println!("'{}' subscribed", followers_channel);
pubsub.subscribe("new_shout").await.unwrap();
println!("'new_shout' subscribed");
pubsub.subscribe("new_reaction").await.unwrap();
println!("'new_reaction' subscribed");
println!("'{}' pubsub subscribed", followers_channel);
pubsub.subscribe("shout").await.unwrap();
println!("'shout' pubsub subscribed");
pubsub.subscribe("reaction").await.unwrap();
println!("'reaction' pubsub subscribed");
for chat_id in &chats {
let channel_name = format!("chat:{}", chat_id);
@@ -86,23 +93,27 @@ async fn connect_handler(
}
while let Some(msg) = pubsub.on_message().next().await {
let message_str: String = msg.get_payload().unwrap();
let message_data: RedisMessageData = serde_json::from_str(&message_str).unwrap();
let message_author = message_data.payload.get("author")
.and_then(Value::as_i64) // Convert Value to i64
.unwrap_or(-1) as i32; // Convert i64 to i32
if (msg.get_channel_name().starts_with("chat:") && message_author != listener_id)
|| msg.get_channel_name().starts_with("followers:")
|| data::is_fitting(
let redis_message_str: String = msg.get_payload().unwrap();
let redis_message_data: RedisMessageData = serde_json::from_str(&redis_message_str).unwrap();
let prepared_message_data = SSEMessageData {
payload: redis_message_data.payload,
action: redis_message_data.action,
entity: msg.get_channel_name()
.to_owned()
.split(":")
.next()
.unwrap_or("")
.to_string()
};
if data::is_fitting(
listener_id,
message_data.kind.to_string(),
message_data.payload,
prepared_message_data.clone(),
)
.await
.is_ok()
{
let send_result = tx.send(message_str.clone());
let prepared_message_str = serde_json::to_string(&prepared_message_data).unwrap();
let send_result = tx.send(prepared_message_str.clone());
if send_result.is_err() {
// remove author from online list
let _ = con
@@ -114,7 +125,7 @@ async fn connect_handler(
});
break;
} else {
println!("[handler {}] message handled {}", handler_id, message_str);
println!("[handler] message handled {}", prepared_message_str);
}
};
}
@@ -125,16 +136,28 @@ async fn connect_handler(
.unwrap()
.insert(format!("{}", listener_id.clone()), handle);
let server_event_stream = futures::stream::unfold(rx, |mut rx| async {
let result = rx.recv().await;
match result {
Ok(server_event) => {
let formatted_server_event = format!("data: {}\n\n", server_event);
Some((Ok::<_, actix_web::Error>(Bytes::from(formatted_server_event)), rx))
},
Err(_) => None,
}
});
let server_event_stream = futures::stream::unfold(rx, |mut rx| async {
let result = rx.recv().await;
match result {
Ok(server_event) => {
let message_data: SSEMessageData = serde_json::from_str(&server_event).unwrap();
let event_entity = message_data.entity; // Assuming 'entity' field represents the entity type
let event_action = message_data.action; // 'action' field represents the operation type
let event_id = format!("{}", Uuid::new_v4()); // Generate a random UUID as the event ID
let formatted_server_event = format!(
"id: {}\nevent: {}\ndata: {{\"action\": \"{}\", \"payload\": {}}}\n\n",
event_id,
event_entity,
event_action,
server_event
);
Some((Ok::<_, actix_web::Error>(Bytes::from(formatted_server_event)), rx))
},
Err(_) => None,
}
});
Ok(HttpResponse::Ok()
.append_header(("content-type", "text/event-stream"))