use std::collections::HashMap;
use std::fs::File;
use std::io::{BufWriter, Write};
use flowscope::extract::{FiveTuple, FiveTupleKey};
use flowscope::extractor::FlowExtractor;
use flowscope::nprint::{NPrintConfig, NPrintMatrix};
use flowscope::pcap::PcapFlowSource;
use flowscope::{AsPacketView, PacketView};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let path = std::env::args()
.nth(1)
.unwrap_or_else(|| "tests/data/mixed_short.pcap".to_string());
let extractor = FiveTuple::bidirectional();
let cfg = NPrintConfig::default();
let mut matrices: HashMap<FiveTupleKey, NPrintMatrix> = HashMap::new();
let mut total_packets = 0u64;
for view in PcapFlowSource::open(&path)?.views() {
let view = view?;
total_packets += 1;
let pv: PacketView<'_> = view.as_packet_view();
let Some(extracted) = extractor.extract(pv) else {
continue;
};
let key = extracted.key;
let entry = matrices
.entry(key)
.or_insert_with(|| NPrintMatrix::new(cfg));
let pv2: PacketView<'_> = view.as_packet_view();
entry.push_view(&pv2);
}
let mut written = 0u64;
let mut total_rows = 0u64;
for (flow_idx, (key, matrix)) in matrices.iter().enumerate() {
if matrix.is_empty() {
continue;
}
let filename = format!("nprint_{}.csv", flow_idx + 1);
let f = File::create(&filename)?;
let mut w = BufWriter::new(f);
for row in matrix.rows() {
let line = row
.bits
.iter()
.map(|b| b.as_raw().to_string())
.collect::<Vec<_>>()
.join(",");
writeln!(w, "{line}")?;
}
w.flush()?;
total_rows += matrix.len() as u64;
written += 1;
eprintln!(
"[nprint] wrote {filename:<24} {:>4} rows flow {:?}:{} ↔ {:?}:{}",
matrix.len(),
key.a.ip(),
key.a.port(),
key.b.ip(),
key.b.port(),
);
}
eprintln!(
"\n--- nprint export ---\n {total_packets} packet(s) processed\n \
{written} flow file(s) written\n {total_rows} total row(s)"
);
Ok(())
}