#![allow(non_snake_case)]
use crate::core::RiResult;
use crate::queue::{RiQueue, RiQueueConsumer, RiQueueMessage, RiQueueProducer, RiQueueStats};
use async_trait::async_trait;
use std::collections::{HashMap, VecDeque};
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::path::Path;
use std::sync::Arc;
use tokio::sync::{Mutex, RwLock};
use tokio::task::spawn_blocking;
struct MemoryQueueState {
messages: VecDeque<RiQueueMessage>,
consumers: HashMap<String, VecDeque<RiQueueMessage>>,
}
impl MemoryQueueState {
fn new() -> Self {
Self {
messages: VecDeque::new(),
consumers: HashMap::new(),
}
}
}
pub struct RiMemoryQueue {
name: String,
state: Arc<RwLock<MemoryQueueState>>,
persistence_path: Option<String>,
}
#[allow(dead_code)]
impl RiMemoryQueue {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
state: Arc::new(RwLock::new(MemoryQueueState::new())),
persistence_path: None,
}
}
pub fn with_persistence(name: &str, persistence_path: &str) -> Self {
let queue = Self {
name: name.to_string(),
state: Arc::new(RwLock::new(MemoryQueueState::new())),
persistence_path: Some(persistence_path.to_string()),
};
if let Err(e) = queue.load_messages() {
log::warn!("Failed to load persisted messages for queue '{name}': {e}");
}
queue
}
fn load_messages(&self) -> RiResult<()> {
if let Some(path) = &self.persistence_path {
if Path::new(path).exists() {
let mut file = File::open(path)?;
const MAX_PERSISTENCE_FILE_SIZE: u64 = 100 * 1024 * 1024; let metadata = file.metadata()?;
if metadata.len() > MAX_PERSISTENCE_FILE_SIZE {
log::warn!(
"[Ri.MemoryQueue] Persistence file too large: {} bytes (max {} bytes)",
metadata.len(), MAX_PERSISTENCE_FILE_SIZE
);
return Err(crate::core::RiError::Other(format!(
"Persistence file too large: {} bytes (max {} bytes)",
metadata.len(), MAX_PERSISTENCE_FILE_SIZE
)));
}
let mut content = String::new();
file.read_to_string(&mut content)?;
if !content.is_empty() {
let messages: VecDeque<RiQueueMessage> = serde_json::from_str(&content)
.map_err(|e| {
log::warn!("[Ri.MemoryQueue] Failed to deserialize messages: {}", e);
crate::core::RiError::Other(format!("Failed to deserialize messages: {}", e))
})?;
const MAX_MESSAGES: usize = 100000;
let messages: VecDeque<RiQueueMessage> = messages.into_iter().take(MAX_MESSAGES).collect();
let mut state = self.state.blocking_write();
state.messages = messages;
}
}
}
Ok(())
}
fn save_messages(&self) -> RiResult<()> {
if let Some(path) = &self.persistence_path {
let state = self.state.blocking_read();
let content = serde_json::to_string(&state.messages)?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path)?;
file.write_all(content.as_bytes())?;
}
Ok(())
}
}
#[async_trait]
impl RiQueue for RiMemoryQueue {
async fn create_producer(&self) -> RiResult<Box<dyn RiQueueProducer>> {
Ok(Box::new(MemoryQueueProducer {
state: self.state.clone(),
persistence_path: self.persistence_path.clone(),
}))
}
async fn create_consumer(
&self,
consumer_group: &str,
) -> RiResult<Box<dyn RiQueueConsumer>> {
Ok(Box::new(MemoryQueueConsumer {
state: self.state.clone(),
consumer_group: consumer_group.to_string(),
paused: Arc::new(Mutex::new(false)),
persistence_path: self.persistence_path.clone(),
}))
}
async fn get_stats(&self) -> RiResult<RiQueueStats> {
let state = self.state.read().await;
Ok(RiQueueStats {
queue_name: self.name.clone(),
message_count: state.messages.len() as u64,
consumer_count: state.consumers.len() as u32,
producer_count: 1,
processed_messages: 0,
failed_messages: 0,
avg_processing_time_ms: 0.0,
total_bytes_sent: 0,
total_bytes_received: 0,
last_message_time: 0,
})
}
async fn purge(&self) -> RiResult<()> {
let mut state = self.state.write().await;
state.messages.clear();
state.consumers.clear();
if let Some(path) = &self.persistence_path {
let path_clone = path.clone();
spawn_blocking(move || {
if Path::new(&path_clone).exists() {
if let Err(e) = std::fs::remove_file(&path_clone) {
log::warn!("Failed to remove persistence file '{path_clone}': {e}");
}
}
})
.await
.map_err(|e| {
log::error!("Failed to execute persistence file removal: {e}");
crate::core::RiError::Other(format!("Failed to clear persistence: {e}"))
})?;
}
Ok(())
}
async fn delete(&self) -> RiResult<()> {
self.purge().await
}
}
struct MemoryQueueProducer {
state: Arc<RwLock<MemoryQueueState>>,
persistence_path: Option<String>,
}
#[async_trait]
impl RiQueueProducer for MemoryQueueProducer {
async fn send(&self, message: RiQueueMessage) -> RiResult<()> {
let mut state = self.state.write().await;
state.messages.push_back(message);
if let Some(path) = &self.persistence_path {
let messages_clone = state.messages.clone();
let path_clone = path.clone();
let _ = spawn_blocking(move || {
let content = serde_json::to_string(&messages_clone)
.map_err(|e| {
log::error!("Failed to serialize messages for persistence: {e}");
crate::core::RiError::Serde(format!("Serialization failed: {e}"))
})?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path_clone)
.map_err(|e| {
log::error!("Failed to open persistence file: {e}");
crate::core::RiError::Io(format!("File open failed: {e}"))
})?;
file.write_all(content.as_bytes())
.map_err(|e| {
log::error!("Failed to write persistence file: {e}");
crate::core::RiError::Io(format!("File write failed: {e}"))
})?;
Ok::<(), crate::core::RiError>(())
})
.await
.map_err(|e| {
log::error!("Failed to execute persistence task: {e}");
crate::core::RiError::Other(format!("Persistence task failed: {e}"))
});
}
Ok(())
}
async fn send_batch(&self, messages: Vec<RiQueueMessage>) -> RiResult<()> {
let mut state = self.state.write().await;
for message in messages {
state.messages.push_back(message);
}
if let Some(path) = &self.persistence_path {
let messages_clone = state.messages.clone();
let path_clone = path.clone();
let _ = spawn_blocking(move || {
let content = serde_json::to_string(&messages_clone)
.map_err(|e| {
log::error!("Failed to serialize messages for persistence: {e}");
crate::core::RiError::Serde(format!("Serialization failed: {e}"))
})?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path_clone)
.map_err(|e| {
log::error!("Failed to open persistence file: {e}");
crate::core::RiError::Io(format!("File open failed: {e}"))
})?;
file.write_all(content.as_bytes())
.map_err(|e| {
log::error!("Failed to write persistence file: {e}");
crate::core::RiError::Io(format!("File write failed: {e}"))
})?;
Ok::<(), crate::core::RiError>(())
})
.await
.map_err(|e| {
log::error!("Failed to execute persistence task: {e}");
crate::core::RiError::Other(format!("Persistence task failed: {e}"))
});
}
Ok(())
}
}
struct MemoryQueueConsumer {
state: Arc<RwLock<MemoryQueueState>>,
consumer_group: String,
paused: Arc<Mutex<bool>>,
persistence_path: Option<String>,
}
#[async_trait]
impl RiQueueConsumer for MemoryQueueConsumer {
async fn receive(&self) -> RiResult<Option<RiQueueMessage>> {
let paused = *self.paused.lock().await;
if paused {
return Ok(None);
}
let mut state = self.state.write().await;
if let Some(consumer_queue) = state.consumers.get_mut(&self.consumer_group) {
if let Some(message) = consumer_queue.pop_front() {
return Ok(Some(message));
}
}
if let Some(message) = state.messages.pop_front() {
let mut consumer_queue = VecDeque::new();
consumer_queue.push_back(message.clone());
state
.consumers
.insert(self.consumer_group.clone(), consumer_queue);
if let Some(path) = &self.persistence_path {
let messages_clone = state.messages.clone();
let path_clone = path.clone();
let _ = spawn_blocking(move || {
let content = serde_json::to_string(&messages_clone)
.map_err(|e| {
log::error!("Failed to serialize messages for persistence: {e}");
crate::core::RiError::Serde(format!("Serialization failed: {e}"))
})?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path_clone)
.map_err(|e| {
log::error!("Failed to open persistence file: {e}");
crate::core::RiError::Io(format!("File open failed: {e}"))
})?;
file.write_all(content.as_bytes())
.map_err(|e| {
log::error!("Failed to write persistence file: {e}");
crate::core::RiError::Io(format!("File write failed: {e}"))
})?;
Ok::<(), crate::core::RiError>(())
})
.await
.map_err(|e| {
log::error!("Failed to execute persistence task: {e}");
crate::core::RiError::Other(format!("Persistence task failed: {e}"))
});
}
Ok(Some(message))
} else {
Ok(None)
}
}
async fn ack(&self, _message_id: &str) -> RiResult<()> {
Ok(())
}
async fn nack(&self, message_id: &str) -> RiResult<()> {
let mut state = self.state.write().await;
if let Some(consumer_queue) = state.consumers.get_mut(&self.consumer_group) {
let mut message_to_requeue: Option<RiQueueMessage> = None;
let mut index = 0;
for (i, message) in consumer_queue.iter().enumerate() {
if message.id == message_id {
message_to_requeue = Some(message.clone());
index = i;
break;
}
}
if let Some(mut message) = message_to_requeue {
consumer_queue.remove(index);
message.increment_retry();
state.messages.push_back(message);
if let Some(path) = &self.persistence_path {
let messages_clone = state.messages.clone();
let path_clone = path.clone();
let _ = spawn_blocking(move || {
let content = serde_json::to_string(&messages_clone)
.map_err(|e| {
log::error!("Failed to serialize messages for persistence: {e}");
crate::core::RiError::Serde(format!("Serialization failed: {e}"))
})?;
let mut file = OpenOptions::new()
.write(true)
.create(true)
.truncate(true)
.open(path_clone)
.map_err(|e| {
log::error!("Failed to open persistence file: {e}");
crate::core::RiError::Io(format!("File open failed: {e}"))
})?;
file.write_all(content.as_bytes())
.map_err(|e| {
log::error!("Failed to write persistence file: {e}");
crate::core::RiError::Io(format!("File write failed: {e}"))
})?;
Ok::<(), crate::core::RiError>(())
})
.await
.map_err(|e| {
log::error!("Failed to execute persistence task: {e}");
crate::core::RiError::Other(format!("Persistence task failed: {e}"))
});
}
}
}
Ok(())
}
async fn pause(&self) -> RiResult<()> {
let mut paused = self.paused.lock().await;
*paused = true;
Ok(())
}
async fn resume(&self) -> RiResult<()> {
let mut paused = self.paused.lock().await;
*paused = false;
Ok(())
}
}