postfix-log-parser 0.2.0

高性能模块化Postfix日志解析器,经3.2GB生产数据验证,SMTPD事件100%准确率
Documentation
//! Local本地投递模块
//!
//! 处理Postfix local投递代理的事件,包括本地邮箱投递、外部命令执行和配置警告

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// 本地投递组件事件
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LocalEvent {
    ConfigurationWarning(ConfigurationWarning),
    LocalDelivery(LocalDelivery),
    ExternalDelivery(ExternalDelivery),
}

/// 本地投递配置警告
///
/// 记录本地投递组件的配置问题和警告信息
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ConfigurationWarning {
    /// 警告发生时间戳(UTC时间)
    pub timestamp: DateTime<Utc>,

    /// 警告类型分类
    /// 按照问题的性质进行分类,如NIS域、别名、权限等
    pub warning_type: WarningType,

    /// 警告消息内容
    /// 具体的警告描述信息
    pub message: String,

    /// 附加详细信息
    /// 包含与警告相关的额外上下文信息
    pub details: HashMap<String, String>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum WarningType {
    NisDomainNotSet,
    RequiredAliasNotFound,
    FilePermission,
    Configuration,
    Other,
}

/// 本地投递事件
///
/// 记录邮件到本地邮箱的投递过程和结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalDelivery {
    /// 投递发生时间戳(UTC时间)
    pub timestamp: DateTime<Utc>,

    /// 队列ID(邮件在系统中的唯一标识符)
    pub queue_id: String,

    /// 最终收件人地址
    /// 经过别名解析后的实际投递地址
    pub recipient: String,

    /// 原始收件人地址(如果有别名转换)
    /// 邮件最初的目标地址,在别名解析前
    pub original_recipient: Option<String>,

    /// 中继信息
    /// 通常为"local"表示本地投递
    pub relay: String,

    /// 总投递延迟时间(秒)
    /// 从邮件接收到投递完成的总时间
    pub delay: f64,

    /// 延迟时间细分(各阶段用时)
    /// 详细的时间分解,包含队列等待、处理等各阶段
    pub delays: Vec<f64>,

    /// 投递状态码(DSN格式)
    /// 符合RFC 3463标准的状态码
    pub dsn: String,

    /// 投递状态结果
    pub status: DeliveryStatus,

    /// 投递方法类型
    pub delivery_method: DeliveryMethod,

    /// 邮件大小(字节数,可选)
    pub size: Option<u64>,

    /// 收件人数量(可选)
    pub nrcpt: Option<u32>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DeliveryStatus {
    Sent,
    Bounced,
    Deferred,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
pub enum DeliveryMethod {
    Mailbox,
    Discarded,
    Forwarded,
    Piped,
    File,
}

/// 外部投递事件
///
/// 记录通过外部命令或文件进行的邮件投递
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExternalDelivery {
    /// 投递发生时间戳(UTC时间)
    pub timestamp: DateTime<Utc>,

    /// 队列ID(邮件在系统中的唯一标识符)
    pub queue_id: String,

    /// 收件人地址
    pub recipient: String,

    /// 原始收件人地址(如果有转换)
    /// 在别名或转发规则应用前的原始地址
    pub original_recipient: Option<String>,

    /// 执行的外部命令(如果适用)
    /// 用于投递邮件的外部程序或脚本
    pub command: Option<String>,

    /// 投递的文件路径(如果适用)
    /// 邮件投递到的文件系统路径
    pub file_path: Option<String>,

    /// 投递状态结果
    pub status: DeliveryStatus,

    /// 投递延迟时间(秒)
    /// 从开始投递到完成的耗时
    pub delay: f64,

    /// 附加详细信息
    /// 包含投递过程中的额外信息和元数据
    pub details: HashMap<String, String>,
}

impl LocalEvent {
    pub fn timestamp(&self) -> DateTime<Utc> {
        match self {
            LocalEvent::ConfigurationWarning(event) => event.timestamp,
            LocalEvent::LocalDelivery(event) => event.timestamp,
            LocalEvent::ExternalDelivery(event) => event.timestamp,
        }
    }

    pub fn event_type(&self) -> &'static str {
        match self {
            LocalEvent::ConfigurationWarning(_) => "configuration_warning",
            LocalEvent::LocalDelivery(_) => "local_delivery",
            LocalEvent::ExternalDelivery(_) => "external_delivery",
        }
    }
}

impl WarningType {
    pub fn as_str(&self) -> &'static str {
        match self {
            WarningType::NisDomainNotSet => "nis_domain_not_set",
            WarningType::RequiredAliasNotFound => "required_alias_not_found",
            WarningType::FilePermission => "file_permission",
            WarningType::Configuration => "configuration",
            WarningType::Other => "other",
        }
    }
}

impl DeliveryStatus {
    pub fn as_str(&self) -> &'static str {
        match self {
            DeliveryStatus::Sent => "sent",
            DeliveryStatus::Bounced => "bounced",
            DeliveryStatus::Deferred => "deferred",
        }
    }
}

impl DeliveryMethod {
    pub fn as_str(&self) -> &'static str {
        match self {
            DeliveryMethod::Mailbox => "mailbox",
            DeliveryMethod::Discarded => "discarded",
            DeliveryMethod::Forwarded => "forwarded",
            DeliveryMethod::Piped => "piped",
            DeliveryMethod::File => "file",
        }
    }
}