1use crate::common::OutputFormat;
2use crate::error::AppError;
3use crate::output::write_ip_lists_to_files;
4use ipnet::IpNet;
5use std::collections::{BTreeSet, HashMap};
6use std::sync::Arc;
7use tokio::task::JoinHandle;
8use crate::common::debug_log;
9
10pub async fn process_all_country_codes(
12 country_codes: &[String],
13 rir_texts: &[String],
14 output_format: OutputFormat,
15) -> Result<(), AppError> {
16 let rir_texts_owned = rir_texts.to_owned();
18 let country_map = tokio::task::spawn_blocking(move || {
19 crate::parse::parse_all_country_codes(&rir_texts_owned)
20 })
21 .await??;
22 let country_map_arc = Arc::new(country_map);
23
24 let mut tasks: Vec<JoinHandle<Result<(), AppError>>> = Vec::new();
26 for code in country_codes {
27 let code_cloned = code.clone();
28 let map_cloned = Arc::clone(&country_map_arc);
29 tasks.push(tokio::spawn(async move {
30 crate::process::process_country_code_from_map(&code_cloned, &map_cloned, output_format)
31 .await
32 }));
33 }
34
35 for handle in tasks {
37 handle.await??;
38 }
39 Ok(())
40}
41
42pub fn parse_and_collect_ips(
49 country_code: &str,
50 rir_texts: &[String],
51) -> Result<(BTreeSet<IpNet>, BTreeSet<IpNet>), AppError> {
52 let cc_upper = country_code.to_ascii_uppercase();
54 let map = crate::parse::parse_all_country_codes(rir_texts)?;
55 let (v4_vec, v6_vec) = map.get(&cc_upper).cloned().unwrap_or_default();
56 let v4_set: BTreeSet<IpNet> = v4_vec.into_iter().collect();
57 let v6_set: BTreeSet<IpNet> = v6_vec.into_iter().collect();
58 Ok((v4_set, v6_set))
59}
60
61pub async fn process_country_code_from_map(
62 country_code: &str,
63 country_map: &HashMap<String, (Vec<IpNet>, Vec<IpNet>)>,
64 output_format: OutputFormat,
65) -> Result<(), AppError> {
66 let upper = country_code.to_ascii_uppercase();
67 let (v4_vec, v6_vec) = match country_map.get(&upper) {
68 Some(tup) => tup,
69 None => {
70 debug_log(format!("No IPs found for country code: {}", upper));
71 return Ok(());
72 }
73 };
74
75 let (ipv4_set, ipv6_set) = tokio::task::block_in_place(|| {
77 let v4_set = IpNet::aggregate(&v4_vec).into_iter().collect();
78 let v6_set = IpNet::aggregate(&v6_vec).into_iter().collect();
79 (v4_set, v6_set)
80 });
81
82 write_ip_lists_to_files(&upper, &ipv4_set, &ipv6_set, output_format).await
83}