use std::path::Path;
use crate::driver::SlotMessage;
use crate::event::{EndReason, FlowSide, FlowStats};
use crate::extract::{FiveTuple, FiveTupleKey};
use crate::extractor::L4Proto;
use crate::pcap::PcapFlowSource;
use crate::session::SessionEvent;
use crate::{DatagramParser, Result, SessionParser, Timestamp};
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Pulse<K, M> {
Started {
key: K,
ts: Timestamp,
},
Message(SlotMessage<M, K>),
ParserClosed {
key: K,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
},
ParserSideStopped {
key: K,
side: FlowSide,
reason: EndReason,
detail: Option<String>,
ts: Timestamp,
},
Ended {
key: K,
reason: EndReason,
stats: FlowStats,
l4: Option<L4Proto>,
},
Tick {
key: K,
stats: FlowStats,
ts: Timestamp,
},
}
fn pulse_from_event<K, M>(ev: SessionEvent<K, M>) -> Option<Pulse<K, M>> {
match ev {
SessionEvent::Started { key, ts, .. } => Some(Pulse::Started { key, ts }),
SessionEvent::Application {
key,
side,
orientation,
message,
ts,
..
} => Some(Pulse::Message(SlotMessage::new(
key,
side,
orientation,
message,
ts,
))),
SessionEvent::ParserClosed {
key,
reason,
detail,
ts,
..
} => Some(Pulse::ParserClosed {
key,
reason,
detail,
ts,
}),
SessionEvent::ParserSideStopped {
key,
side,
reason,
detail,
ts,
..
} => Some(Pulse::ParserSideStopped {
key,
side,
reason,
detail,
ts,
}),
SessionEvent::Closed {
key,
reason,
stats,
l4,
..
} => Some(Pulse::Ended {
key,
reason,
stats,
l4,
}),
SessionEvent::Tick { key, stats, ts } => Some(Pulse::Tick { key, stats, ts }),
SessionEvent::FlowAnomaly { .. } | SessionEvent::TrackerAnomaly { .. } => None,
}
}
pub fn session_pulses<P>(
path: impl AsRef<Path>,
) -> Result<impl Iterator<Item = Pulse<FiveTupleKey, P::Message>>>
where
P: SessionParser + Default + Clone + Send + Sync + 'static,
{
let source = PcapFlowSource::open(path)?;
Ok(source
.sessions(FiveTuple::bidirectional(), P::default())
.filter_map(Result::ok)
.filter_map(pulse_from_event))
}
pub fn datagram_pulses<P>(
path: impl AsRef<Path>,
) -> Result<impl Iterator<Item = Pulse<FiveTupleKey, P::Message>>>
where
P: DatagramParser + Default + Clone + Send + Sync + 'static,
{
let source = PcapFlowSource::open(path)?;
Ok(source
.datagrams(FiveTuple::bidirectional(), P::default())
.filter_map(Result::ok)
.filter_map(pulse_from_event))
}