1use chrono::{
7 DateTime,
8 Utc
9};
10
11use std::path::Path;
12use std::fs::{
13 File,
14 OpenOptions
15};
16use std::io::Write;
17
18use crate::frame::CRFrame;
19use crate::serialization::CRSerializeable;
20
21pub static HUMAN_TIMESTAMP_FORMAT : &str = "%y%m%d_%H%M%S%Z";
23
24pub fn get_runfilename(run : u32, subrun : u64, rb_id : Option<u8>, timestamp : Option<String>) -> String {
37 let ts : String;
38 match timestamp {
39 Some(_ts) => {
40 ts = _ts;
41 }
42 None => {
43 ts = get_utc_timestamp();
44 }
45 }
46 let fname : String;
47 match rb_id {
48 None => {
49 fname = format!("Run{run}_{subrun}.{ts}.gaps");
50 }
51 Some(rbid) => {
52 fname = format!("Run{run}_{subrun}.{ts}.RB{rbid:02}.gaps");
53 }
54 }
55 fname
56}
57
58pub fn get_utc_timestamp() -> String {
60 let now: DateTime<Utc> = Utc::now();
61 let timestamp_str = now.format(HUMAN_TIMESTAMP_FORMAT).to_string();
63 timestamp_str
64}
65
66pub struct CRWriter {
72
73 pub file : File,
74 pub file_path : String,
76 pub pkts_per_file : usize,
81 pub mbytes_per_file : usize,
85 pub file_name : String,
86 pub run_id : u32,
87 file_id : usize,
88 n_packets : usize,
91 file_nbytes_wr : usize,
94 pub file_timestamp : Option<String>,
98}
99
100impl CRWriter {
101
102 pub fn new(mut file_path : String, run_id : u32, subrun_id : Option<u64>, timestamp : Option<String>) -> Self {
114 let file : File;
116 let file_name : String;
117 if !file_path.ends_with("/") {
118 file_path += "/";
119 }
120 let filename : String;
121 if let Some(subrun) = subrun_id {
122 filename = format!("{}{}", file_path, get_runfilename(run_id, subrun, None, timestamp));
123 } else {
124 filename = format!("{}{}", file_path, get_runfilename(run_id, 0, None, timestamp));
125 }
126 let path = Path::new(&filename);
127 println!("Writing to file {filename}");
128 file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
129 file_name = filename;
130 Self {
131 file,
132 file_path : file_path,
133 pkts_per_file : 0,
134 mbytes_per_file : 420,
135 run_id : run_id,
136 file_nbytes_wr : 0,
137 file_id : 1,
138 n_packets : 0,
139 file_name : file_name,
140 file_timestamp : None,
141 }
142 }
143
144 pub fn get_file(&self, timestamp : Option<String>) -> File {
145 let file : File;
146 let filename = format!("{}{}", self.file_path, get_runfilename(self.run_id, self.file_id as u64, None, timestamp));
147 let path = Path::new(&filename);
149 info!("Writing to file {filename}");
150 file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
151 file
152 }
153
154 pub fn add_frame(&mut self, frame : &CRFrame) {
158 let buffer = frame.serialize();
159 self.file_nbytes_wr += buffer.len();
160 match self.file.write_all(buffer.as_slice()) {
161 Err(err) => error!("Writing to file to path {} failed! {}", self.file_path, err),
162 Ok(_) => ()
163 }
164 self.n_packets += 1;
165 let mut newfile = false;
166 if self.pkts_per_file != 0 {
167 if self.n_packets == self.pkts_per_file {
168 newfile = true;
169 self.n_packets = 0;
170 }
171 } else if self.mbytes_per_file != 0 {
172 if self.file_nbytes_wr >= self.mbytes_per_file * 1_048_576 {
174 newfile = true;
175 self.file_nbytes_wr = 0;
176 }
177 }
178 if newfile {
179 match self.file.sync_all() {
181 Err(err) => {
182 error!("Unable to sync file to disc! {err}");
183 },
184 Ok(_) => ()
185 }
186 self.file = self.get_file(self.file_timestamp.clone());
187 self.file_id += 1;
188 }
194 debug!("CRFrame written!");
195 }
196}
197
198impl Default for CRWriter {
199 fn default() -> Self {
200 CRWriter::new(String::from(""),0,None, None)
201 }
202}
203