use flowscope::PacketView;
use crate::protocol::FlowKey;
pub(crate) trait FlowByteAccumulator: Send {
fn feed(&mut self, view: &PacketView<'_>);
fn flush(&mut self, key: &FlowKey);
}
#[cfg(feature = "nprint")]
pub(crate) type NprintHandler = Box<dyn FnMut(&FlowKey, &flowscope::nprint::NPrintMatrix) + Send>;
#[cfg(feature = "nprint")]
pub(crate) struct NprintAccumulator {
config: flowscope::nprint::NPrintConfig,
extractor: flowscope::extract::FiveTuple,
flows: rustc_hash::FxHashMap<FlowKey, flowscope::nprint::NPrintMatrix>,
handlers: Vec<NprintHandler>,
max_flows: usize,
skipped_flows: u64,
}
#[cfg(feature = "nprint")]
impl NprintAccumulator {
pub(crate) fn new(
config: flowscope::nprint::NPrintConfig,
max_flows: usize,
handlers: Vec<NprintHandler>,
) -> Self {
Self {
config,
extractor: flowscope::extract::FiveTuple::bidirectional(),
flows: rustc_hash::FxHashMap::default(),
handlers,
max_flows,
skipped_flows: 0,
}
}
}
#[cfg(feature = "nprint")]
impl FlowByteAccumulator for NprintAccumulator {
fn feed(&mut self, view: &PacketView<'_>) {
use flowscope::FlowExtractor;
let Some(extracted) = self.extractor.extract(*view) else {
return;
};
if let Some(matrix) = self.flows.get_mut(&extracted.key) {
matrix.push_view(view);
} else if self.flows.len() < self.max_flows {
let mut matrix = flowscope::nprint::NPrintMatrix::new(self.config);
matrix.push_view(view);
self.flows.insert(extracted.key, matrix);
} else {
self.skipped_flows = self.skipped_flows.saturating_add(1);
}
}
fn flush(&mut self, key: &FlowKey) {
if let Some(matrix) = self.flows.remove(key) {
for handler in self.handlers.iter_mut() {
handler(key, &matrix);
}
}
}
}