use std::io::{BufRead, BufReader, Read};
use crate::{BgpkitCommonsError, Result};
pub const RIR_DELEGATED_STATS_URLS: &[&str] = &[
"https://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest",
"https://ftp.ripe.net/pub/stats/ripencc/delegated-ripencc-latest",
"https://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest",
"https://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest",
"https://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest",
];
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DelegatedRecord {
pub registry: String,
pub country: String,
pub record_type: String,
pub start: String,
pub value: String,
pub date: String,
pub status: String,
pub extensions: Vec<String>,
}
pub fn parse_reader<R: Read>(reader: R) -> impl Iterator<Item = Result<DelegatedRecord>> {
BufReader::new(reader)
.lines()
.filter_map(|line| match line {
Err(error) => Some(Err(error.into())),
Ok(line) => {
let line = line.trim();
if line.is_empty() || line.starts_with('#') {
return None;
}
Some(parse_line(line))
}
})
}
fn parse_line(line: &str) -> Result<DelegatedRecord> {
let fields = line.split('|').collect::<Vec<_>>();
if fields.len() < 7 {
return Err(BgpkitCommonsError::invalid_format(
"delegated statistics record",
line,
"expected at least 7 pipe-delimited fields",
));
}
Ok(DelegatedRecord {
registry: fields[0].to_string(),
country: fields[1].to_string(),
record_type: fields[2].to_string(),
start: fields[3].to_string(),
value: fields[4].to_string(),
date: fields[5].to_string(),
status: fields[6].to_string(),
extensions: fields[7..]
.iter()
.map(|value| (*value).to_string())
.collect(),
})
}
pub fn fetch(url: &str) -> Result<Box<dyn Read>> {
Ok(oneio::get_reader(url)?)
}