1use crate::common::{IpFamily, OutputFormat};
2use crate::error::AppError;
3use crate::output_common::{make_header, sanitize_identifier, write_list_nft, write_list_txt};
4use chrono::Local;
5use ipnet::IpNet;
6use std::collections::BTreeSet;
7use crate::common::debug_log;
8
9pub async fn write_ip_lists_to_files(
12 country_code: &str,
13 ipv4_list: &BTreeSet<IpNet>,
14 ipv6_list: &BTreeSet<IpNet>,
15 format_enum: OutputFormat,
16) -> Result<(), AppError> {
17 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
18 let safe_code = sanitize_identifier(&country_code.to_uppercase());
19
20 match format_enum {
21 OutputFormat::Txt => {
22 let ipv4_file = format!("IPv4_{}.txt", safe_code);
24 let header_v4 = make_header(&now_str, &safe_code, "N/A");
25 write_list_txt(&ipv4_file, ipv4_list, &header_v4).await?;
26
27 let ipv6_file = format!("IPv6_{}.txt", safe_code);
29 let header_v6 = make_header(&now_str, &safe_code, "N/A");
30 write_list_txt(&ipv6_file, ipv6_list, &header_v6).await?;
31 }
32 OutputFormat::Nft => {
33 let ipv4_file = format!("IPv4_{}.nft", safe_code);
35 let header_v4 = make_header(&now_str, &safe_code, "N/A");
36 write_list_nft(&ipv4_file, ipv4_list, &header_v4).await?;
37
38 let ipv6_file = format!("IPv6_{}.nft", safe_code);
40 let header_v6 = make_header(&now_str, &safe_code, "N/A");
41 write_list_nft(&ipv6_file, ipv6_list, &header_v6).await?;
42 }
43 }
44 Ok(())
45}
46
47pub async fn write_as_ip_list_to_file(
50 as_number: &str,
51 family: IpFamily,
52 ipnets: &BTreeSet<IpNet>,
53 format_enum: OutputFormat,
54) -> Result<(), AppError> {
55 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
56 let safe_as = sanitize_identifier(as_number);
57 let header = make_header(&now_str, "N/A", &safe_as);
58
59 match format_enum {
60 OutputFormat::Txt => {
61 let file_name = format!("AS_{}_{}.txt", safe_as, family.as_str());
62 write_list_txt(&file_name, ipnets, &header).await?;
63 debug_log(format!("Wrote TXT for AS_{} {}", safe_as, family.as_str()));
64 }
65 OutputFormat::Nft => {
66 let file_name = format!("AS_{}_{}.nft", safe_as, family.as_str());
67 write_list_nft(&file_name, ipnets, &header).await?;
68 debug_log(format!("Wrote NFT for AS_{} {}", safe_as, family.as_str()));
69 }
70 }
71 Ok(())
72}
73
74pub async fn write_overlap_to_file(
76 country_code: &str,
77 as_number: &str,
78 overlaps: &BTreeSet<IpNet>,
79 format_enum: OutputFormat,
80) -> Result<(), AppError> {
81 use chrono::Local;
82 let safe_cc = sanitize_identifier(country_code);
83 let safe_as = sanitize_identifier(as_number);
84
85 let overlaps_v4: BTreeSet<IpNet> = overlaps
86 .iter()
87 .cloned()
88 .filter(|net| matches!(net, IpNet::V4(_)))
89 .collect();
90
91 let overlaps_v6: BTreeSet<IpNet> = overlaps
92 .iter()
93 .cloned()
94 .filter(|net| matches!(net, IpNet::V6(_)))
95 .collect();
96
97 if overlaps_v4.is_empty() && overlaps_v6.is_empty() {
98 debug_log(format!(
99 "No overlap found for country={} and AS={}",
100 country_code, as_number
101 ));
102 return Ok(());
103 }
104
105 match format_enum {
106 OutputFormat::Txt => {
107 if !overlaps_v4.is_empty() {
108 let filename_v4 = format!("overlap_{}_{}_IPv4.txt", safe_cc, safe_as);
109 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
110 let header_v4 = make_header(&now_str, &safe_cc, &safe_as);
111 write_list_txt(&filename_v4, &overlaps_v4, &header_v4).await?;
112 }
113 if !overlaps_v6.is_empty() {
114 let filename_v6 = format!("overlap_{}_{}_IPv6.txt", safe_cc, safe_as);
115 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
116 let header_v6 = make_header(&now_str, &safe_cc, &safe_as);
117 write_list_txt(&filename_v6, &overlaps_v6, &header_v6).await?;
118 }
119 }
120 OutputFormat::Nft => {
121 if !overlaps_v4.is_empty() {
122 let filename_v4 = format!("overlap_{}_{}_IPv4.nft", safe_cc, safe_as);
123 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
124 let header_v4 = make_header(&now_str, &safe_cc, &safe_as);
125 write_list_nft(&filename_v4, &overlaps_v4, &header_v4).await?;
126 }
127 if !overlaps_v6.is_empty() {
128 let filename_v6 = format!("overlap_{}_{}_IPv6.nft", safe_cc, safe_as);
129 let now_str = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
130 let header_v6 = make_header(&now_str, &safe_cc, &safe_as);
131 write_list_nft(&filename_v6, &overlaps_v6, &header_v6).await?;
132 }
133 }
134 }
135
136 Ok(())
137}