use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use serde_json::Value;
use std::collections::HashMap;
use std::path::PathBuf;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeliveryPayload {
pub result: DeliveryResult,
pub destination: String,
pub delivery_method: DeliveryMethod,
pub bytes_processed: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub items_delivered: Option<u64>,
pub processed_at: DateTime<Utc>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::serde_support::present_json"
)]
pub middleware_context: Option<Value>,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum DeliveryMethod {
HttpPost { url: String },
HttpPut { url: String },
S3Upload { bucket: String, key: String },
DatabaseInsert { table: String },
QueuePublish { queue_name: String },
FileWrite { path: PathBuf },
Noop, Custom(String), }
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "result", rename_all = "snake_case")]
pub enum DeliveryResult {
Buffered {},
Success {
#[serde(skip_serializing_if = "Option::is_none")]
confirmation: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
response_headers: Option<HashMap<String, String>>,
},
Failed {
error_type: String,
error_message: String,
},
Partial {
successful_count: u64,
failed_count: u64,
error_summary: String,
#[serde(skip_serializing_if = "Option::is_none")]
failed_items: Option<Vec<String>>,
},
}
impl DeliveryPayload {
pub fn success(method: DeliveryMethod, bytes_processed: Option<u64>) -> Self {
Self {
result: DeliveryResult::Success {
confirmation: None,
response_headers: None,
},
destination: String::new(),
delivery_method: method,
bytes_processed,
items_delivered: None,
processed_at: Utc::now(),
middleware_context: None,
}
}
pub fn buffered(method: DeliveryMethod, bytes_processed: Option<u64>) -> Self {
Self {
result: DeliveryResult::Buffered {},
destination: String::new(),
delivery_method: method,
bytes_processed,
items_delivered: None,
processed_at: Utc::now(),
middleware_context: None,
}
}
pub fn failed(
method: DeliveryMethod,
error_type: impl Into<String>,
error_msg: impl Into<String>,
) -> Self {
Self {
result: DeliveryResult::Failed {
error_type: error_type.into(),
error_message: error_msg.into(),
},
destination: String::new(),
delivery_method: method,
bytes_processed: None,
items_delivered: None,
processed_at: Utc::now(),
middleware_context: None,
}
}
pub fn partial(
method: DeliveryMethod,
ok: u64,
bad: u64,
summary: impl Into<String>,
failed_items: Option<Vec<String>>,
) -> Self {
Self {
result: DeliveryResult::Partial {
successful_count: ok,
failed_count: bad,
error_summary: summary.into(),
failed_items,
},
destination: String::new(),
delivery_method: method,
bytes_processed: None,
items_delivered: None,
processed_at: Utc::now(),
middleware_context: None,
}
}
pub fn http_post_success(
url: impl Into<String>,
bytes: Option<u64>,
headers: Option<HashMap<String, String>>,
confirmation: Option<String>,
) -> Self {
let url: String = url.into();
Self {
destination: String::new(),
delivery_method: DeliveryMethod::HttpPost { url },
bytes_processed: bytes,
result: DeliveryResult::Success {
confirmation,
response_headers: headers,
},
items_delivered: None,
processed_at: Utc::now(),
middleware_context: None,
}
}
}
impl DeliveryPayload {
pub fn with_middleware_context(mut self, context: Value) -> Self {
self.middleware_context = Some(context);
self
}
pub fn with_bytes_processed(mut self, bytes: u64) -> Self {
self.bytes_processed = Some(bytes);
self
}
pub fn with_items(mut self, items: u64) -> Self {
self.items_delivered = Some(items);
self
}
}