1use clap::Parser;
2use serde::{Deserialize, Serialize};
3use std::net::Ipv6Addr;
4use std::path::PathBuf;
5
6use crate::commands::Command;
7use crate::commands::common::AddressPredicate;
8use crate::data::{DataRow, DataStreamInfo, DataStreamResult, stream_from_iter};
9
10#[derive(Parser, Serialize, Deserialize)]
11pub struct ViewCommand {
12 #[arg(value_name = "FILE")]
14 pub file: PathBuf,
15 #[arg(short = 'f', long, value_name = "FIELD")]
17 pub field: Option<String>,
18 #[arg(long, value_enum)]
20 pub include: Vec<AddressPredicate>,
21 #[arg(long, value_enum)]
23 pub exclude: Vec<AddressPredicate>,
24 #[arg(short = 'u', long)]
26 pub unique: bool,
27 #[arg(long)]
29 pub tui: bool,
30}
31
32impl Command for ViewCommand {
33 async fn run(&self) -> Result<(), String> {
34 let addresses = self.load_and_filter_addresses().await?;
36
37 let data_rows: Vec<DataRow> = addresses
39 .into_iter()
40 .map(|addr| DataRow::new().with_column("address", addr.to_string()))
41 .collect();
42
43 let headers = vec!["address".to_string()];
44 let info = DataStreamInfo::new(headers)
45 .with_total_rows(data_rows.len())
46 .with_description(format!("Viewing {} addresses from file", data_rows.len()));
47
48 let stream = stream_from_iter(data_rows);
49 Ok(())
50 }
51}
52
53impl ViewCommand {
54 pub fn new(
55 file: PathBuf,
56 field: Option<String>,
57 include: Vec<AddressPredicate>,
58 exclude: Vec<AddressPredicate>,
59 unique: bool,
60 tui: bool,
61 ) -> Self {
62 Self {
63 file,
64 field,
65 include,
66 exclude,
67 unique,
68 tui,
69 }
70 }
71
72 async fn load_and_filter_addresses(&self) -> Result<Vec<Ipv6Addr>, String> {
73 let content = tokio::fs::read_to_string(&self.file)
75 .await
76 .map_err(|e| format!("Failed to read file: {}", e))?;
77
78 let mut addresses = Vec::new();
79 for line in content.lines() {
80 let line = line.trim();
81 if line.is_empty() {
82 continue;
83 }
84
85 let addr_str = if let Some(field) = &self.field {
87 let parts: Vec<&str> = line.split(',').collect();
89 if parts.len() > 0 {
90 parts[0] } else {
92 line
93 }
94 } else {
95 line
96 };
97
98 if let Ok(addr) = addr_str.parse::<Ipv6Addr>() {
99 addresses.push(addr);
100 }
101 }
102
103 let filtered_addresses = self.apply_predicates(addresses)?;
105
106 let final_addresses = if self.unique {
108 let mut unique_set = std::collections::HashSet::new();
109 filtered_addresses
110 .into_iter()
111 .filter(|addr| unique_set.insert(*addr))
112 .collect()
113 } else {
114 filtered_addresses
115 };
116
117 Ok(final_addresses)
118 }
119
120 fn apply_predicates(&self, addresses: Vec<Ipv6Addr>) -> Result<Vec<Ipv6Addr>, String> {
121 let all_predicates = analyze::analysis::predicates::get_all_predicates();
122
123 Ok(addresses
124 .into_iter()
125 .filter(|addr| {
126 if !self.include.is_empty() {
128 let include_match = self.include.iter().any(|predicate| {
129 let filter_name = predicate.to_filter_name();
130 if let Some((_, predicate_fn)) =
131 all_predicates.iter().find(|(name, _)| name == &filter_name)
132 {
133 predicate_fn(*addr)
134 } else {
135 false
136 }
137 });
138 if !include_match {
139 return false;
140 }
141 }
142
143 for predicate in &self.exclude {
145 let filter_name = predicate.to_filter_name();
146 if let Some((_, predicate_fn)) =
147 all_predicates.iter().find(|(name, _)| name == &filter_name)
148 {
149 if predicate_fn(*addr) {
150 return false;
151 }
152 }
153 }
154
155 true
156 })
157 .collect())
158 }
159}