use std::time::Instant;
use serde::Serialize;
use crate::NodeId;
#[derive(Debug, Clone, Serialize)]
pub struct Trace {
pub flow_id: String,
pub flow_version: u64,
pub steps: Vec<TraceStep>,
pub outcome: FlowOutcome,
#[serde(skip_serializing_if = "Option::is_none")]
pub error: Option<String>,
#[serde(skip)]
started: Instant,
}
impl Trace {
pub fn new(flow_id: &str, flow_version: u64) -> Self {
Trace {
flow_id: flow_id.to_string(),
flow_version,
steps: Vec::new(),
outcome: FlowOutcome::Defect, error: None,
started: Instant::now(),
}
}
pub(crate) fn push(&mut self, node: &NodeId, kind: &'static str, detail: StepDetail) {
let at_ms = self.started.elapsed().as_millis() as u64;
self.steps.push(TraceStep {
node: node.clone(),
kind,
at_ms,
detail,
});
}
pub fn is_clean(&self) -> bool {
!matches!(self.outcome, FlowOutcome::Aborted | FlowOutcome::Defect)
}
}
#[derive(Debug, Clone, PartialEq, Serialize)]
pub struct TraceStep {
pub node: NodeId,
pub kind: &'static str,
pub at_ms: u64,
pub detail: StepDetail,
}
#[derive(Debug, Clone, PartialEq, Serialize)]
#[serde(tag = "detail", rename_all = "snake_case")]
pub enum StepDetail {
Spoke,
Hours { open: bool },
MenuChoice { digit: String },
MenuNoInput,
MenuInvalid,
Ring { answered: bool },
MessageRecorded { secs: u32 },
Transferred { target: String },
HungUp,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum FlowOutcome {
Answered,
MessageLeft,
Transferred,
HungUp,
Aborted,
Defect,
}