#[cfg(feature = "pg")]
use crate::BackendPool;
#[cfg(feature = "pg")]
use kevy_embedded::Store;
mod admin;
mod lifecycle;
pub mod suppression;
pub use admin::*;
pub use lifecycle::*;
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum QueueStatus {
Pending,
InFlight,
Delivered,
Failed,
Bounced,
}
impl QueueStatus {
pub fn as_str(&self) -> &'static str {
match self {
Self::Pending => "pending",
Self::InFlight => "inflight",
Self::Delivered => "delivered",
Self::Failed => "failed",
Self::Bounced => "bounced",
}
}
pub fn parse(s: &str) -> Option<Self> {
match s {
"pending" => Some(Self::Pending),
"inflight" => Some(Self::InFlight),
"delivered" => Some(Self::Delivered),
"failed" => Some(Self::Failed),
"bounced" => Some(Self::Bounced),
_ => None,
}
}
}
#[derive(Debug, Clone)]
pub struct QueuedMessage {
pub id: i64,
pub sender: String,
pub recipient: String,
pub domain: String,
pub message_data: Vec<u8>,
pub status: QueueStatus,
pub attempts: u32,
pub max_attempts: u32,
pub next_retry: i64,
pub last_error: Option<String>,
pub message_id: Option<String>,
pub created_at: i64,
pub updated_at: i64,
pub is_forwarded: bool,
}
#[cfg(feature = "pg")]
pub async fn enqueue(
pool: &BackendPool,
sender: &str,
recipient: &str,
domain: &str,
message_data: &[u8],
message_id: Option<&str>,
now: i64,
) -> Result<i64, sqlx::Error> {
enqueue_ex(
pool,
sender,
recipient,
domain,
message_data,
message_id,
now,
false,
)
.await
}
#[allow(clippy::too_many_arguments)]
#[cfg(feature = "pg")]
pub async fn enqueue_ex(
pool: &BackendPool,
sender: &str,
recipient: &str,
domain: &str,
message_data: &[u8],
message_id: Option<&str>,
now: i64,
is_forwarded: bool,
) -> Result<i64, sqlx::Error> {
let row: (i64,) = sqlx::query_as(
"INSERT INTO outbound_queue (sender, recipient, domain, message_data, status, next_retry, message_id, created_at, updated_at, is_forwarded)
VALUES ($1, $2, $3, $4, 'pending', $5, $6, $5, $5, $7)
RETURNING id",
)
.bind(sender)
.bind(recipient)
.bind(domain)
.bind(message_data)
.bind(now)
.bind(message_id)
.bind(is_forwarded)
.fetch_one(pool)
.await?;
Ok(row.0)
}
#[cfg(feature = "pg")]
pub fn notify(kevy: &Store) {
let _ = kevy.publish(b"queue:notify", b"1");
}
#[allow(clippy::too_many_arguments)]
#[cfg(feature = "pg")]
pub async fn enqueue_scheduled(
pool: &BackendPool,
sender: &str,
recipient: &str,
domain: &str,
message_data: &[u8],
message_id: Option<&str>,
created_at: i64,
scheduled_at: i64,
) -> Result<i64, sqlx::Error> {
let row: (i64,) = sqlx::query_as(
"INSERT INTO outbound_queue (sender, recipient, domain, message_data, status, next_retry, message_id, created_at, updated_at, is_forwarded)
VALUES ($1, $2, $3, $4, 'pending', $5, $6, $7, $7, false)
RETURNING id",
)
.bind(sender)
.bind(recipient)
.bind(domain)
.bind(message_data)
.bind(scheduled_at)
.bind(message_id)
.bind(created_at)
.fetch_one(pool)
.await?;
Ok(row.0)
}