use chrono::{DateTime, Utc};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[non_exhaustive]
pub enum Stage {
Collect,
Correlate,
Classify,
}
impl Stage {
pub fn label(self) -> &'static str {
match self {
Self::Collect => "Collect",
Self::Correlate => "Correlate",
Self::Classify => "Classify",
}
}
pub fn all() -> [Stage; 3] {
[Self::Collect, Self::Correlate, Self::Classify]
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum Outcome {
Completed,
Failed {
reason: String,
},
Skipped {
reason: String,
},
}
impl Outcome {
pub fn label(&self) -> &'static str {
match self {
Self::Completed => "ok",
Self::Failed { .. } => "failed",
Self::Skipped { .. } => "skipped",
}
}
pub fn reason(&self) -> Option<&str> {
match self {
Self::Completed => None,
Self::Failed { reason } | Self::Skipped { reason } => Some(reason.as_str()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ProgressEvent {
pub stage: Stage,
pub target: String,
pub done: u64,
pub total: Option<u64>,
pub outcome: Option<Outcome>,
pub detail: Option<String>,
pub at: DateTime<Utc>,
}
impl ProgressEvent {
fn new(stage: Stage, target: impl Into<String>) -> Self {
Self {
stage,
target: target.into(),
done: 0,
total: None,
outcome: None,
detail: None,
at: Utc::now(),
}
}
pub fn started(stage: Stage, target: impl Into<String>, total: Option<u64>) -> Self {
Self {
total,
..Self::new(stage, target)
}
}
pub fn advanced(
stage: Stage,
target: impl Into<String>,
done: u64,
total: Option<u64>,
) -> Self {
Self {
done,
total,
..Self::new(stage, target)
}
}
pub fn completed(stage: Stage, target: impl Into<String>, done: u64) -> Self {
Self {
done,
total: Some(done),
outcome: Some(Outcome::Completed),
..Self::new(stage, target)
}
}
pub fn failed(stage: Stage, target: impl Into<String>, reason: impl Into<String>) -> Self {
let reason = reason.into();
Self {
detail: Some(reason.clone()),
outcome: Some(Outcome::Failed { reason }),
..Self::new(stage, target)
}
}
pub fn skipped(stage: Stage, target: impl Into<String>, reason: impl Into<String>) -> Self {
let reason = reason.into();
Self {
detail: Some(reason.clone()),
outcome: Some(Outcome::Skipped { reason }),
..Self::new(stage, target)
}
}
#[must_use]
pub fn with_detail(mut self, detail: impl Into<String>) -> Self {
self.detail = Some(detail.into());
self
}
pub fn is_terminal(&self) -> bool {
self.outcome.is_some()
}
}