use std::io::Read;
#[macro_use]
pub mod utils;
pub mod bgp;
pub mod bmp;
pub mod filter;
pub mod iters;
pub mod mrt;
#[cfg(feature = "rislive")]
pub mod rislive;
pub(crate) use self::utils::*;
use crate::models::MrtRecord;
pub use mrt::mrt_elem::Elementor;
use oneio::{get_cache_reader, get_reader};
pub use crate::error::{ParserError, ParserErrorWithBytes};
pub use bmp::{parse_bmp_msg, parse_openbmp_header, parse_openbmp_msg};
pub use filter::*;
pub use iters::*;
pub use mrt::*;
#[cfg(feature = "rislive")]
pub use rislive::parse_ris_live_message;
pub struct BgpkitParser<R> {
reader: R,
core_dump: bool,
filters: Vec<Filter>,
options: ParserOptions,
}
pub(crate) struct ParserOptions {
show_warnings: bool,
}
impl Default for ParserOptions {
fn default() -> Self {
ParserOptions {
show_warnings: true,
}
}
}
impl BgpkitParser<Box<dyn Read + Send>> {
pub fn new(path: &str) -> Result<Self, ParserErrorWithBytes> {
let reader = get_reader(path)?;
Ok(BgpkitParser {
reader,
core_dump: false,
filters: vec![],
options: ParserOptions::default(),
})
}
pub fn new_cached(path: &str, cache_dir: &str) -> Result<Self, ParserErrorWithBytes> {
let file_name = path.rsplit('/').next().unwrap().to_string();
let new_file_name = format!(
"cache-{}",
add_suffix_to_filename(file_name.as_str(), crc32(path).as_str())
);
let reader = get_cache_reader(path, cache_dir, Some(new_file_name), false)?;
Ok(BgpkitParser {
reader,
core_dump: false,
filters: vec![],
options: ParserOptions::default(),
})
}
}
fn add_suffix_to_filename(filename: &str, suffix: &str) -> String {
let mut parts: Vec<&str> = filename.split('.').collect(); if parts.len() > 1 {
let last_part = parts.pop().unwrap(); let new_last_part = format!("{}.{}", suffix, last_part); parts.push(&new_last_part); parts.join(".") } else {
format!("{}.{}", filename, suffix)
}
}
impl<R: Read> BgpkitParser<R> {
pub fn from_reader(reader: R) -> Self {
BgpkitParser {
reader,
core_dump: false,
filters: vec![],
options: ParserOptions::default(),
}
}
pub fn next_record(&mut self) -> Result<MrtRecord, ParserErrorWithBytes> {
parse_mrt_record(&mut self.reader)
}
}
impl<R> BgpkitParser<R> {
pub fn enable_core_dump(self) -> Self {
BgpkitParser {
reader: self.reader,
core_dump: true,
filters: self.filters,
options: self.options,
}
}
pub fn disable_warnings(self) -> Self {
let mut options = self.options;
options.show_warnings = false;
BgpkitParser {
reader: self.reader,
core_dump: self.core_dump,
filters: self.filters,
options,
}
}
pub fn add_filter(
self,
filter_type: &str,
filter_value: &str,
) -> Result<Self, ParserErrorWithBytes> {
let mut filters = self.filters;
filters.push(Filter::new(filter_type, filter_value)?);
Ok(BgpkitParser {
reader: self.reader,
core_dump: self.core_dump,
filters,
options: self.options,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_new_with_reader() {
let reader = oneio::get_reader("http://archive.routeviews.org/route-views.ny/bgpdata/2023.02/UPDATES/updates.20230215.0630.bz2").unwrap();
assert_eq!(
12683,
BgpkitParser::from_reader(reader).into_elem_iter().count()
);
let reader = oneio::get_reader("https://spaces.bgpkit.org/parser/update-example").unwrap();
assert_eq!(
8160,
BgpkitParser::from_reader(reader).into_elem_iter().count()
);
}
#[test]
fn test_new_cahced_with_reader() {
let url = "https://spaces.bgpkit.org/parser/update-example.gz";
let parser = BgpkitParser::new_cached(url, "/tmp/bgpkit-parser-tests")
.unwrap()
.enable_core_dump()
.disable_warnings();
let count = parser.into_elem_iter().count();
assert_eq!(8160, count);
let parser = BgpkitParser::new_cached(url, "/tmp/bgpkit-parser-tests").unwrap();
let count = parser.into_elem_iter().count();
assert_eq!(8160, count);
}
}