use crate::common::IpFamily;
use chrono::{Datelike, Local, Timelike};
use ipnet::IpNet;
use std::{
collections::BTreeSet,
error::Error,
fs::{self, OpenOptions},
io::Write,
path::Path,
};
pub fn write_ip_lists_to_files(
country_code: &str,
ipv4_list: &BTreeSet<IpNet>,
ipv6_list: &BTreeSet<IpNet>,
mode: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let ipv4_file = format!("IPv4_{}.txt", country_code);
let ipv6_file = format!("IPv6_{}.txt", country_code);
write_single_ip_list(&ipv4_file, ipv4_list, mode)?;
write_single_ip_list(&ipv6_file, ipv6_list, mode)?;
Ok(())
}
fn write_single_ip_list<P: AsRef<Path>>(
path: P,
nets: &BTreeSet<IpNet>,
mode: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let now = Local::now();
let formatted_header = format!(
"# {}/{}/{} {}:{}\n",
now.year(),
now.month(),
now.day(),
now.hour(),
now.minute()
);
let lines: Vec<String> = nets.iter().map(|net| net.to_string()).collect();
let content = format!("{}{}\n", formatted_header, lines.join("\n"));
match mode {
"append" => {
let mut file = OpenOptions::new().create(true).append(true).open(&path)?;
file.write_all(content.as_bytes())?;
println!("[output] Appended IP list to: {}", path.as_ref().display());
}
_ => {
fs::write(&path, &content)?;
println!(
"[output] Wrote (overwrite) IP list to: {}",
path.as_ref().display()
);
}
}
Ok(())
}
pub fn write_as_ip_list_to_file(
as_number: &str,
family: IpFamily,
ipnets: &BTreeSet<IpNet>,
mode: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
let now = Local::now().format("%Y-%m-%d %H:%M").to_string();
let file_name = format!("AS_{}_{}.txt", as_number, family.as_str());
let header = format!("# Execution Date and Time: {}\n", now);
let body = ipnets
.iter()
.map(IpNet::to_string)
.collect::<Vec<_>>()
.join("\n");
let content = format!("{}{}\n", header, body);
match mode {
"append" => {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&file_name)?;
file.write_all(content.as_bytes())?;
println!("[output] Appended IP list to: {}", file_name);
}
_ => {
fs::write(&file_name, content)?;
println!("[output] Wrote (overwrite) IP list to: {}", file_name);
}
}
Ok(())
}
pub fn write_overlap_to_file(
country_code: &str,
as_number: &str,
overlaps: &BTreeSet<IpNet>,
mode: &str,
) -> Result<(), Box<dyn Error + Send + Sync>> {
if overlaps.is_empty() {
println!(
"[overlap] No overlap found for country={} and AS={}",
country_code, as_number
);
return Ok(());
}
let filename = format!("overlap_{}_{}.txt", country_code, as_number);
let now_str = Local::now().format("%Y-%m-%d %H:%M").to_string();
let header = format!(
"# Overlap between Country={} and AS={} at {}\n",
country_code, as_number, now_str
);
let body = overlaps
.iter()
.map(|net| net.to_string())
.collect::<Vec<_>>()
.join("\n");
let content = format!("{}\n{}\n", header, body);
match mode {
"append" => {
let mut file = OpenOptions::new()
.create(true)
.append(true)
.open(&filename)?;
file.write_all(content.as_bytes())?;
println!("[overlap] Appended overlaps to: {}", filename);
}
_ => {
fs::write(&filename, content)?;
println!("[overlap] Wrote overlaps to: {}", filename);
}
}
Ok(())
}