pcap_processor/commands/
unique.rs1use crate::cli::{SortOrder, UniqueArgs};
2use crate::error::Result;
3use crate::output::{OutputData, ValueEntry, format_output};
4use crate::tshark::{TsharkConfig, TsharkRunner, TsharkValidator};
5use std::collections::HashMap;
6
7pub fn run_unique(args: UniqueArgs, tshark_path: Option<std::path::PathBuf>) -> Result<()> {
8 let config = TsharkConfig::detect(tshark_path)?;
9 let runner = TsharkRunner::new(config);
10 let mut validator = TsharkValidator::new(&runner);
11
12 validator.validate_field(&args.field)?;
14
15 if let Some(ref filter) = args.filter {
17 validator.validate_filter(filter)?;
18 }
19
20 let files = validator.expand_files(&args.files)?;
22
23 let mut value_counts: HashMap<String, usize> = HashMap::new();
25
26 for file in &files {
27 let values = runner.extract_field_values(
28 file,
29 &args.field,
30 args.filter.as_deref(),
31 args.no_resolve,
32 )?;
33
34 for value in values {
35 *value_counts.entry(value).or_insert(0) += 1;
36 }
37 }
38
39 let mut entries: Vec<ValueEntry> = value_counts
41 .into_iter()
42 .map(|(value, count)| ValueEntry { value, count })
43 .collect();
44
45 match args.sort {
47 SortOrder::Value => {
48 entries.sort_by(|a, b| a.value.cmp(&b.value));
49 }
50 SortOrder::Count => {
51 entries.sort_by(|a, b| b.count.cmp(&a.count).then(a.value.cmp(&b.value)));
52 }
53 }
54
55 let data = OutputData {
57 field: args.field,
58 total_unique: entries.len(),
59 values: entries,
60 };
61
62 let output = format_output(&data, args.format, args.count)?;
64 print!("{}", output);
65
66 Ok(())
67}