gbserver/gb-messaging/src/redis_pubsub.rs

124 lines
3.4 KiB
Rust
Raw Normal View History

2024-12-22 20:56:52 -03:00
use gb_core::{Result, Error};
2024-12-26 10:09:39 -03:00
use redis::{Client, AsyncCommands};
2024-12-24 21:13:47 -03:00
use serde::Serialize;
2024-12-22 20:56:52 -03:00
use std::sync::Arc;
2024-12-23 00:20:59 -03:00
use tracing::instrument;
2024-12-24 21:13:47 -03:00
use futures_util::StreamExt;
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
#[derive(Clone)]
2024-12-22 20:56:52 -03:00
pub struct RedisPubSub {
2024-12-23 00:20:59 -03:00
client: Arc<Client>,
}
2024-12-24 21:13:47 -03:00
impl RedisPubSub {
pub fn new(client: Arc<Client>) -> Self {
Self { client }
2024-12-23 00:20:59 -03:00
}
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
#[instrument(skip(self, payload), err)]
pub async fn publish<T: Serialize>(&self, channel: &str, payload: &T) -> Result<()> {
let mut conn = self.client
.get_async_connection()
.await
.map_err(|e| Error::internal(e.to_string()))?;
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
let serialized = serde_json::to_string(payload)
.map_err(|e| Error::internal(e.to_string()))?;
conn.publish::<_, _, i32>(channel, serialized)
2024-12-22 20:56:52 -03:00
.await
2024-12-24 21:13:47 -03:00
.map_err(|e| Error::internal(e.to_string()))?;
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
Ok(())
2024-12-22 20:56:52 -03:00
}
2024-12-24 21:13:47 -03:00
#[instrument(skip(self, handler), err)]
pub async fn subscribe<F>(&self, channels: &[&str], mut handler: F) -> Result<()>
2024-12-22 20:56:52 -03:00
where
2024-12-24 21:13:47 -03:00
F: FnMut(String, String) + Send + 'static,
2024-12-22 20:56:52 -03:00
{
2024-12-24 21:13:47 -03:00
let mut pubsub = self.client
.get_async_connection()
2024-12-22 20:56:52 -03:00
.await
2024-12-24 21:13:47 -03:00
.map_err(|e| Error::internal(e.to_string()))?
.into_pubsub();
for channel in channels {
pubsub.subscribe(*channel)
.await
.map_err(|e| Error::internal(e.to_string()))?;
}
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
let mut stream = pubsub.on_message();
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
while let Some(msg) = stream.next().await {
let channel = msg.get_channel_name().to_string();
let payload: String = msg.get_payload()
.map_err(|e| Error::internal(e.to_string()))?;
handler(channel, payload);
}
2024-12-22 20:56:52 -03:00
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
2024-12-24 21:13:47 -03:00
use redis::Client;
2024-12-22 20:56:52 -03:00
use serde::{Deserialize, Serialize};
use uuid::Uuid;
2024-12-24 21:13:47 -03:00
use tokio::sync::mpsc;
2024-12-23 00:20:59 -03:00
use std::time::Duration;
2024-12-22 20:56:52 -03:00
2024-12-24 21:13:47 -03:00
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
2024-12-22 20:56:52 -03:00
struct TestMessage {
id: Uuid,
content: String,
}
2024-12-24 21:13:47 -03:00
async fn setup() -> (RedisPubSub, TestMessage) {
let client = Arc::new(Client::open("redis://127.0.0.1/").unwrap());
let redis_pubsub = RedisPubSub::new(client);
let test_message = TestMessage {
2024-12-22 20:56:52 -03:00
id: Uuid::new_v4(),
content: "test message".to_string(),
2024-12-24 21:13:47 -03:00
};
(redis_pubsub, test_message)
2024-12-22 20:56:52 -03:00
}
#[tokio::test]
2024-12-24 21:13:47 -03:00
async fn test_publish_subscribe() {
let (redis_pubsub, test_message) = setup().await;
let channel = "test_channel";
let (tx, mut rx) = mpsc::channel(1);
2024-12-22 20:56:52 -03:00
let pubsub_clone = redis_pubsub.clone();
2024-12-26 10:09:39 -03:00
2024-12-24 21:13:47 -03:00
tokio::spawn(async move {
let handler = move |_channel: String, payload: String| {
let received: TestMessage = serde_json::from_str(&payload).unwrap();
tx.try_send(received).unwrap();
2024-12-22 20:56:52 -03:00
};
pubsub_clone.subscribe(&[channel], handler).await.unwrap();
});
2024-12-24 21:13:47 -03:00
// Give the subscriber time to connect
2024-12-22 20:56:52 -03:00
tokio::time::sleep(Duration::from_millis(100)).await;
2024-12-24 21:13:47 -03:00
redis_pubsub.publish(channel, &test_message).await.unwrap();
let received = tokio::time::timeout(Duration::from_secs(1), rx.recv())
2024-12-22 20:56:52 -03:00
.await
2024-12-24 21:13:47 -03:00
.unwrap()
2024-12-22 20:56:52 -03:00
.unwrap();
2024-12-24 21:13:47 -03:00
assert_eq!(received, test_message);
2024-12-22 20:56:52 -03:00
}
}