gbserver/gb-messaging/src/rabbitmq.rs

188 lines
5 KiB
Rust
Raw Normal View History

2024-12-22 20:56:52 -03:00
use gb_core::{Result, Error};
use lapin::{
options::*,
types::FieldTable,
Connection, ConnectionProperties,
2024-12-23 00:20:59 -03:00
Channel,
BasicProperties,
2024-12-22 20:56:52 -03:00
};
use serde::{de::DeserializeOwned, Serialize};
use std::sync::Arc;
use tokio::sync::Mutex;
use tracing::{instrument, error};
2024-12-23 00:20:59 -03:00
use futures::StreamExt;
2024-12-22 20:56:52 -03:00
pub struct RabbitMQ {
2024-12-23 00:20:59 -03:00
connection: Arc<Connection>,
2024-12-22 20:56:52 -03:00
channel: Arc<Mutex<Channel>>,
}
2024-12-23 00:20:59 -03:00
impl Clone for RabbitMQ {
fn clone(&self) -> Self {
Self {
connection: self.connection.clone(),
channel: self.channel.clone(),
}
}
}
2024-12-22 20:56:52 -03:00
impl RabbitMQ {
pub async fn new(url: &str) -> Result<Self> {
let connection = Connection::connect(
url,
ConnectionProperties::default(),
)
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("RabbitMQ connection error: {}", e)))?;
2024-12-22 20:56:52 -03:00
let channel = connection.create_channel()
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("RabbitMQ channel error: {}", e)))?;
2024-12-22 20:56:52 -03:00
Ok(Self {
2024-12-23 00:20:59 -03:00
connection: Arc::new(connection),
2024-12-22 20:56:52 -03:00
channel: Arc::new(Mutex::new(channel)),
})
}
#[instrument(skip(self, message))]
pub async fn publish<T: Serialize>(
&self,
exchange: &str,
routing_key: &str,
message: &T,
) -> Result<()> {
let payload = serde_json::to_string(message)
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("Serialization error: {}", e)))?;
2024-12-22 20:56:52 -03:00
let channel = self.channel.lock().await;
channel.basic_publish(
exchange,
routing_key,
BasicPublishOptions::default(),
payload.as_bytes(),
BasicProperties::default(),
)
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("RabbitMQ publish error: {}", e)))?;
2024-12-22 20:56:52 -03:00
Ok(())
}
#[instrument(skip(self, handler))]
pub async fn subscribe<T, F, Fut>(
&self,
queue: &str,
handler: F,
) -> Result<()>
where
T: DeserializeOwned,
F: Fn(T) -> Fut,
Fut: std::future::Future<Output = Result<()>>,
{
let channel = self.channel.lock().await;
channel.queue_declare(
queue,
QueueDeclareOptions::default(),
FieldTable::default(),
)
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("RabbitMQ queue declare error: {}", e)))?;
2024-12-22 20:56:52 -03:00
let mut consumer = channel.basic_consume(
queue,
"consumer",
BasicConsumeOptions::default(),
FieldTable::default(),
)
.await
2024-12-23 00:20:59 -03:00
.map_err(|e| Error::internal(format!("RabbitMQ consume error: {}", e)))?;
2024-12-22 20:56:52 -03:00
while let Some(delivery) = consumer.next().await {
match delivery {
Ok(delivery) => {
if let Ok(payload) = String::from_utf8(delivery.data.clone()) {
match serde_json::from_str::<T>(&payload) {
Ok(value) => {
if let Err(e) = handler(value).await {
error!("Handler error: {}", e);
}
}
Err(e) => error!("Deserialization error: {}", e),
}
}
delivery.ack(BasicAckOptions::default())
.await
.map_err(|e| error!("Ack error: {}", e)).ok();
}
Err(e) => error!("Consumer error: {}", e),
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::*;
use serde::{Deserialize, Serialize};
use uuid::Uuid;
2024-12-23 00:20:59 -03:00
use std::time::Duration;
2024-12-22 20:56:52 -03:00
2024-12-23 00:20:59 -03:00
#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)]
2024-12-22 20:56:52 -03:00
struct TestMessage {
id: Uuid,
content: String,
}
#[fixture]
async fn rabbitmq() -> RabbitMQ {
RabbitMQ::new("amqp://localhost:5672")
.await
.unwrap()
}
#[fixture]
fn test_message() -> TestMessage {
TestMessage {
id: Uuid::new_v4(),
content: "test message".to_string(),
}
}
#[rstest]
#[tokio::test]
async fn test_publish_subscribe(
rabbitmq: RabbitMQ,
test_message: TestMessage,
) {
2024-12-23 00:20:59 -03:00
let queue = "test_queue";
let routing_key = "test_routing_key";
2024-12-22 20:56:52 -03:00
let rabbitmq_clone = rabbitmq.clone();
let test_message_clone = test_message.clone();
2024-12-23 00:20:59 -03:00
2024-12-22 20:56:52 -03:00
let handle = tokio::spawn(async move {
let handler = |msg: TestMessage| async move {
assert_eq!(msg, test_message_clone);
Ok(())
};
2024-12-23 00:20:59 -03:00
2024-12-22 20:56:52 -03:00
rabbitmq_clone.subscribe(queue, handler).await.unwrap();
});
tokio::time::sleep(Duration::from_millis(100)).await;
rabbitmq.publish("", routing_key, &test_message)
.await
.unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
2024-12-23 00:20:59 -03:00
2024-12-22 20:56:52 -03:00
handle.abort();
}
2024-12-23 00:20:59 -03:00
}