gondola_core/io/caraspace/
writer.rs

1// This file is part of gaps-online-software and published 
2// under the GPLv3 license
3
4use crate::prelude::*;
5
6/// Write CRFrames to disk.
7///
8/// Operates sequentially, frames can 
9/// be added one at a time, then will
10/// be synced to disk.
11#[cfg_attr(feature="pybindings", pyclass)]
12pub struct CRWriter {
13
14  pub file            : File,
15  /// location to store the file
16  pub file_path       : String,
17  /// The maximum number of packets 
18  /// for a single file. Ater this 
19  /// number is reached, a new 
20  /// file is started.
21  pub pkts_per_file   : usize,
22  /// The maximum number of (Mega)bytes
23  /// per file. After this a new file 
24  /// is started
25  pub mbytes_per_file : usize,
26  pub file_name       : String,
27  pub run_id          : u32,
28  file_id             : usize,
29  /// internal packet counter, number of 
30  /// packets which went through the writer
31  n_packets           : usize,
32  /// internal counter for bytes written in 
33  /// this file
34  file_nbytes_wr      : usize,
35  /// it can also take a timestamp, in case we 
36  /// don't want to use the current time when the 
37  /// file is written
38  pub file_timestamp  : Option<String>,
39}
40
41impl CRWriter {
42
43  /// Instantiate a new PacketWriter 
44  ///
45  /// # Arguments
46  ///
47  /// * file_path       : Path to store the file under
48  /// * run_id          : Run ID for this file (will be written in filename)
49  /// * subrun_id       : Sub-Run ID for this file (will be written in filename. 
50  ///                     If None, a generic "0" will be used
51  /// * timestamp       : The writer will add an automatic timestamp to the current file
52  ///                     based on the current time. This option allows to overwrite 
53  ///                     that behaviour
54  pub fn new(mut file_path : String, run_id : u32, subrun_id : Option<u64>, timestamp : Option<String>) -> Self {
55    //let filename = file_prefix.clone() + "_0.tof.gaps";
56    let file : File;
57    let file_name : String;
58    if !file_path.ends_with("/") {
59      file_path += "/";
60    }
61    let filename : String;
62    if let Some(subrun) = subrun_id {
63      filename = format!("{}{}", file_path, get_runfilename(run_id, subrun, None, timestamp));
64    } else {
65      filename = format!("{}{}", file_path, get_runfilename(run_id, 0, None, timestamp));
66    }
67    let path     = Path::new(&filename); 
68    println!("Writing to file {filename}");
69    file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
70    file_name = filename;
71    Self {
72      file,
73      file_path        : file_path,
74      pkts_per_file    : 0,
75      mbytes_per_file  : 420,
76      run_id           : run_id,
77      file_nbytes_wr   : 0,    
78      file_id          : 1,
79      n_packets        : 0,
80      file_name        : file_name,
81      file_timestamp   : None,
82    }
83  }
84
85  pub fn get_file(&self, timestamp : Option<String>) -> File { 
86    let file : File;
87    let filename = format!("{}{}", self.file_path, get_runfilename(self.run_id, self.file_id as u64, None, timestamp));
88    //let filename = self.file_path.clone() + &get_runfilename(runid,self.file_id as u64, None);
89    let path     = Path::new(&filename); 
90    info!("Writing to file {filename}");
91    file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
92    file
93  }
94
95  /// Induce serialization to disk for a CRFrame
96  ///
97  ///
98  pub fn add_frame(&mut self, frame : &CRFrame) {
99    let buffer = frame.to_bytestream();
100    self.file_nbytes_wr += buffer.len();
101    match self.file.write_all(buffer.as_slice()) {
102      Err(err) => error!("Writing to file to path {} failed! {}", self.file_path, err),
103      Ok(_)    => ()
104    }
105    self.n_packets += 1;
106    let mut newfile = false;
107    if self.pkts_per_file != 0 {
108      if self.n_packets == self.pkts_per_file {
109        newfile = true;
110        self.n_packets = 0;
111      }
112    } else if self.mbytes_per_file != 0 {
113      // multiply by mebibyte
114      if self.file_nbytes_wr >= self.mbytes_per_file * 1_048_576 {
115        newfile = true;
116        self.file_nbytes_wr = 0;
117      }
118    }
119    if newfile {
120        //let filename = self.file_prefix.clone() + "_" + &self.file_id.to_string() + ".tof.gaps";
121        match self.file.sync_all() {
122          Err(err) => {
123            error!("Unable to sync file to disc! {err}");
124          },
125          Ok(_) => ()
126        }
127        self.file = self.get_file(self.file_timestamp.clone());
128        self.file_id += 1;
129        //let path  = Path::new(&filename);
130        //println!("==> [TOFPACKETWRITER] Will start a new file {}", path.display());
131        //self.file = OpenOptions::new().create(true).append(true).open(path).expect("Unable to open file {filename}");
132        //self.n_packets = 0;
133        //self.file_id += 1;
134      }
135  debug!("CRFrame written!");
136  }
137}
138
139impl Default for CRWriter {
140  fn default() -> Self {
141    CRWriter::new(String::from(""),0,None, None)
142  }
143}
144
145impl fmt::Display for CRWriter {
146  fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
147    let mut repr = String::from("<CRWriter:");
148    repr += &(format!("\n  path: {}", self.file_path)); 
149    repr += ">";
150    write!(f, "{}", repr)
151  }
152}
153
154#[cfg(feature="pybindings")]
155#[pymethods]
156impl CRWriter {
157  
158  #[new]
159  #[pyo3(signature = (filename, run_id, subrun_id = None, timestamp = None))]
160  fn new_py(filename : String, run_id : u32, subrun_id : Option<u64>, timestamp : Option<String>) -> Self {
161    Self::new(filename, run_id, subrun_id, timestamp)
162  }
163 
164  fn set_mbytes_per_file(&mut self, fsize : usize) {
165    self.mbytes_per_file = fsize;
166  }
167
168  fn set_file_timestamp(&mut self, timestamp : String) {
169    self.file_timestamp = Some(timestamp);
170  }
171  
172  #[pyo3(name="add_frame")]
173  fn add_frame_py(&mut self, frame : CRFrame) {
174    self.add_frame(&frame);  
175  }
176}
177
178#[cfg(feature="pybindings")]
179pythonize_display!(CRWriter);
180