bgpkit_parser/parser/
mod.rs1use std::io::Read;
5
6#[macro_use]
7pub mod utils;
8pub mod bgp;
9pub mod bmp;
10pub mod filter;
11pub mod iters;
12pub mod mrt;
13pub mod rpki;
14
15#[cfg(feature = "rislive")]
16pub mod rislive;
17
18pub(crate) use self::utils::*;
19
20use crate::models::MrtRecord;
21pub use mrt::mrt_elem::Elementor;
22#[cfg(feature = "oneio")]
23use oneio::{get_cache_reader, get_reader};
24
25pub use crate::error::{ParserError, ParserErrorWithBytes};
26pub use bmp::{parse_bmp_msg, parse_openbmp_header, parse_openbmp_msg};
27pub use filter::*;
28pub use iters::*;
29pub use mrt::*;
30
31#[cfg(feature = "rislive")]
32pub use rislive::parse_ris_live_message;
33
34pub struct BgpkitParser<R> {
35 reader: R,
36 core_dump: bool,
37 filters: Vec<Filter>,
38 options: ParserOptions,
39}
40
41pub(crate) struct ParserOptions {
42 show_warnings: bool,
43}
44impl Default for ParserOptions {
45 fn default() -> Self {
46 ParserOptions {
47 show_warnings: true,
48 }
49 }
50}
51
52#[cfg(feature = "oneio")]
53impl BgpkitParser<Box<dyn Read + Send>> {
54 pub fn new(path: &str) -> Result<Self, ParserErrorWithBytes> {
56 let reader = get_reader(path)?;
57 Ok(BgpkitParser {
58 reader,
59 core_dump: false,
60 filters: vec![],
61 options: ParserOptions::default(),
62 })
63 }
64
65 pub fn new_cached(path: &str, cache_dir: &str) -> Result<Self, ParserErrorWithBytes> {
71 let file_name = path.rsplit('/').next().unwrap().to_string();
72 let new_file_name = format!(
73 "cache-{}",
74 add_suffix_to_filename(file_name.as_str(), crc32(path).as_str())
75 );
76 let reader = get_cache_reader(path, cache_dir, Some(new_file_name), false)?;
77 Ok(BgpkitParser {
78 reader,
79 core_dump: false,
80 filters: vec![],
81 options: ParserOptions::default(),
82 })
83 }
84}
85
86#[cfg(feature = "oneio")]
87fn add_suffix_to_filename(filename: &str, suffix: &str) -> String {
88 let mut parts: Vec<&str> = filename.split('.').collect(); if parts.len() > 1 {
90 let last_part = parts.pop().unwrap(); let new_last_part = format!("{suffix}.{last_part}"); parts.push(&new_last_part); parts.join(".") } else {
95 format!("{filename}.{suffix}")
97 }
98}
99
100impl<R: Read> BgpkitParser<R> {
101 pub fn from_reader(reader: R) -> Self {
103 BgpkitParser {
104 reader,
105 core_dump: false,
106 filters: vec![],
107 options: ParserOptions::default(),
108 }
109 }
110
111 pub fn next_record(&mut self) -> Result<MrtRecord, ParserErrorWithBytes> {
113 parse_mrt_record(&mut self.reader)
114 }
115}
116
117impl<R> BgpkitParser<R> {
118 pub fn enable_core_dump(self) -> Self {
119 BgpkitParser {
120 reader: self.reader,
121 core_dump: true,
122 filters: self.filters,
123 options: self.options,
124 }
125 }
126
127 pub fn disable_warnings(self) -> Self {
128 let mut options = self.options;
129 options.show_warnings = false;
130 BgpkitParser {
131 reader: self.reader,
132 core_dump: self.core_dump,
133 filters: self.filters,
134 options,
135 }
136 }
137
138 pub fn add_filter(
139 self,
140 filter_type: &str,
141 filter_value: &str,
142 ) -> Result<Self, ParserErrorWithBytes> {
143 let mut filters = self.filters;
144 filters.push(Filter::new(filter_type, filter_value)?);
145 Ok(BgpkitParser {
146 reader: self.reader,
147 core_dump: self.core_dump,
148 filters,
149 options: self.options,
150 })
151 }
152}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test_new_with_reader() {
160 let reader = oneio::get_reader("http://archive.routeviews.org/route-views.ny/bgpdata/2023.02/UPDATES/updates.20230215.0630.bz2").unwrap();
162 assert_eq!(
163 12683,
164 BgpkitParser::from_reader(reader).into_elem_iter().count()
165 );
166
167 let reader = oneio::get_reader("https://spaces.bgpkit.org/parser/update-example").unwrap();
169 assert_eq!(
170 8160,
171 BgpkitParser::from_reader(reader).into_elem_iter().count()
172 );
173 }
174
175 #[test]
176 fn test_new_cached_with_reader() {
177 let url = "https://spaces.bgpkit.org/parser/update-example.gz";
178 let parser = BgpkitParser::new_cached(url, "/tmp/bgpkit-parser-tests")
179 .unwrap()
180 .enable_core_dump()
181 .disable_warnings();
182 let count = parser.into_elem_iter().count();
183 assert_eq!(8160, count);
184 let parser = BgpkitParser::new_cached(url, "/tmp/bgpkit-parser-tests").unwrap();
185 let count = parser.into_elem_iter().count();
186 assert_eq!(8160, count);
187 }
188
189 #[test]
190 fn test_add_suffix_to_filename() {
191 let filename = "example.txt";
193 let suffix = "suffix";
194 let result = add_suffix_to_filename(filename, suffix);
195 assert_eq!(result, "example.suffix.txt");
196
197 let filename = "example.tar.gz";
199 let suffix = "suffix";
200 let result = add_suffix_to_filename(filename, suffix);
201 assert_eq!(result, "example.tar.suffix.gz");
202
203 let filename = "example";
205 let suffix = "suffix";
206 let result = add_suffix_to_filename(filename, suffix);
207 assert_eq!(result, "example.suffix");
208
209 let filename = "";
211 let suffix = "suffix";
212 let result = add_suffix_to_filename(filename, suffix);
213 assert_eq!(result, ".suffix");
214
215 let filename = "example.txt";
217 let suffix = "";
218 let result = add_suffix_to_filename(filename, suffix);
219 assert_eq!(result, "example..txt");
220 }
221}