tramex_tools/interface/interface_file/
file_handler.rs1use crate::data::{AdditionalInfos, Data, Trace};
4use crate::errors::ErrorCode;
5use crate::errors::TramexError;
6use crate::interface::interface_types::InterfaceTrait;
7use crate::interface::layer::Layers;
8use crate::interface::parse_config::{FileMetadata, Technology};
9use crate::tramex_error;
10use std::path::PathBuf;
11use super::file_index::FileIndex;
14use super::utils_file::parse_one_block;
15
16const BATCH_SIZE: usize = 100;
18
19#[derive(Debug, Clone)]
20pub struct File {
22 pub file_path: PathBuf,
24
25 pub file_content: Vec<String>,
27
28 pub full_read: bool,
30
31 nb_read: usize,
33
34 index_line: usize,
36
37 pub available: bool,
39
40 pub index: Option<FileIndex>,
42
43 pub current_log_index: usize,
48}
49
50impl Default for File {
51 fn default() -> Self {
52 Self {
53 file_path: PathBuf::from(""),
54 file_content: vec![],
55 full_read: false,
56 nb_read: BATCH_SIZE,
57 index_line: 0,
58 available: true,
59 index: None,
60 current_log_index: 0,
62 }
63 }
64}
65
66impl InterfaceTrait for File {
67 fn get_more_data(&mut self, _layer_list: Layers, data: &mut Data) -> Result<(), Vec<TramexError>> {
68 if self.full_read {
69 return Ok(());
70 }
71
72 if self.index.is_none() && data.events.is_empty() {
74 data.metadata = FileMetadata::parse_from_lines(&self.file_content);
75
76 log::info!("Building file index...");
78 match FileIndex::build_from_lines(&self.file_content) {
79 Ok(index) => {
80 log::info!("File index built: {} logs found", index.total_count);
81 self.index = Some(index);
82 }
83 Err(e) => {
84 log::error!("Failed to build file index: {}", e.message);
85 return Err(vec![e]);
86 }
87 }
88 }
89
90 let (mut traces, err_processed) = self.process();
92
93 if data.metadata.technology == Technology::Unknown {
95 for trace in &traces {
96 if let AdditionalInfos::RRCInfos(infos) = &trace.additional_infos {
97 if infos.canal.ends_with("-NR") {
98 data.metadata.technology = Technology::NR;
99 } else {
100 data.metadata.technology = Technology::LTE;
101 }
102 break; }
104 }
105 }
106
107 data.events.append(&mut traces);
108 if !err_processed.is_empty() {
109 let filtered: Vec<TramexError> = err_processed
110 .iter()
111 .filter(|tmx_err| !matches!(tmx_err.get_code(), ErrorCode::EndOfFile))
112 .filter(|tmx_err| !matches!(tmx_err.get_code(), ErrorCode::ParsingLayerNotImplemented))
113 .cloned()
114 .collect();
115 if !filtered.is_empty() {
117 return Err(filtered);
118 }
119 }
120 Ok(())
121 }
122
123 fn close(&mut self) -> Result<(), TramexError> {
124 Ok(())
125 }
126
127 fn supports_preloading(&self) -> bool {
128 true
129 }
130
131 fn get_total_event_count(&self) -> Option<usize> {
132 self.index.as_ref().map(|idx| idx.total_count)
133 }
134
135 fn is_fully_read(&self) -> bool {
136 self.full_read
137 }
138}
139
140impl File {
141 pub fn new(file_path: PathBuf, file_content: String) -> Self {
143 Self {
144 file_path,
145 file_content: file_content.lines().map(|x| x.to_string()).collect(),
146 full_read: false,
147 nb_read: BATCH_SIZE,
148 index_line: 0,
149 available: true,
150 index: None,
151 current_log_index: 0,
153 }
154 }
155
156 pub fn new_file_content(file_path: PathBuf, file_content: String) -> Self {
158 Self {
159 file_path,
160 file_content: file_content.lines().map(|x| x.to_string()).collect(),
161 full_read: false,
162 nb_read: BATCH_SIZE,
163 index_line: 0,
164 available: true,
165 index: None,
166 current_log_index: 0,
168 }
169 }
170
171 pub fn change_nb_read(&mut self, toread: usize) {
173 self.nb_read = toread;
174 }
175
176 pub fn process(&mut self) -> (Vec<Trace>, Vec<TramexError>) {
178 let (vec_trace, opt_err) = File::process_string(&self.file_content, self.nb_read, &mut self.index_line);
179 for one_error in &opt_err {
180 if matches!(one_error.get_code(), ErrorCode::EndOfFile) {
181 self.full_read = true;
182 }
183 }
184 (vec_trace, opt_err)
185 }
186 pub fn process_string(lines: &[String], nb_to_read: usize, ix: &mut usize) -> (Vec<Trace>, Vec<TramexError>) {
188 let mut traces = vec![];
189 let mut errors = vec![];
190 for _ in 0..nb_to_read {
191 if *ix >= lines.len() {
192 errors.push(tramex_error!("End of file".to_string(), ErrorCode::EndOfFile));
193 break;
194 }
195 match parse_one_block(&lines[*ix..], ix) {
196 Ok(trace) => {
197 traces.push(trace);
198 }
199 Err(err) => {
200 log::error!("{}", err.message);
201 errors.push(err);
202 }
203 };
204 }
205 (traces, errors)
206 }
207}