libmactime2/
lib.rs

1use anyhow::{Result};
2use chrono::offset::TimeZone;
3use chrono::{LocalResult, NaiveDateTime};
4use chrono_tz::Tz;
5
6pub mod bodyfile;
7pub mod error;
8pub mod filter;
9mod output;
10//use derive_builder::Builder;
11pub use error::*;
12mod stream;
13
14pub use crate::bodyfile::*;
15use crate::stream::*;
16use clap::clap_derive::ValueEnum;
17pub use filter::*;
18use output::*;
19mod cli;
20pub use cli::Cli;
21
22#[derive(ValueEnum, Clone)]
23pub enum InputFormat {
24    BODYFILE,
25
26    #[cfg(feature = "elastic")]
27    JSON,
28}
29
30#[derive(ValueEnum, Clone)]
31pub enum OutputFormat {
32    CSV,
33    TXT,
34    JSON,
35
36    #[cfg(feature = "elastic")]
37    ELASTIC,
38}
39
40//#[derive(Builder)]
41pub struct Mactime2Application {
42    format: OutputFormat,
43    bodyfile: Option<String>,
44    src_zone: Tz,
45    dst_zone: Tz,
46    strict_mode: bool,
47}
48
49impl Mactime2Application {
50
51    fn create_sorter(&self, decoder: &mut BodyfileDecoder) -> Box<dyn Sorter<Result<(), MactimeError>>> {
52        let options = RunOptions {
53            strict_mode: self.strict_mode,
54            src_zone: self.src_zone,
55        };
56
57        if matches!(self.format, OutputFormat::JSON) {
58            Box::new(JsonSorter::with_receiver(decoder.get_receiver(), options))
59        } else {
60            let mut sorter = BodyfileSorter::default().with_receiver(decoder.get_receiver(), options);
61
62            sorter = sorter.with_output(match self.format {
63                OutputFormat::CSV => Box::new(CsvOutput::new(self.src_zone, self.dst_zone)),
64                OutputFormat::TXT => Box::new(TxtOutput::new(self.src_zone, self.dst_zone)),
65                _ => panic!("invalid execution path"),
66            });
67            Box::new(sorter)
68        }
69    }
70
71    pub fn run(&self) -> Result<()> {
72        let options = RunOptions {
73            strict_mode: self.strict_mode,
74            src_zone: self.src_zone,
75        };
76
77        let mut reader = <BodyfileReader as StreamReader<String, ()>>::from(&self.bodyfile)?;
78        let mut decoder = BodyfileDecoder::with_receiver(reader.get_receiver(), options);
79        let mut sorter = self.create_sorter(&mut decoder);
80        sorter.run();
81
82        let _ = reader.join();
83        let _ = decoder.join();
84        sorter.join().unwrap()?;
85        Ok(())
86    }
87
88    pub fn format_date(unix_ts: i64, src_zone: &Tz, dst_zone: &Tz) -> String {
89        if unix_ts >= 0 {
90            let src_timestamp =
91                match src_zone.from_local_datetime(&NaiveDateTime::from_timestamp_opt(unix_ts, 0).unwrap()) {
92                    LocalResult::None => {
93                        return "INVALID DATETIME".to_owned();
94                    }
95                    LocalResult::Single(t) => t,
96                    LocalResult::Ambiguous(t1, _t2) => t1,
97                };
98            let dst_timestamp = src_timestamp.with_timezone(dst_zone);
99            dst_timestamp.to_rfc3339()
100        } else {
101            "0000-00-00T00:00:00+00:00".to_owned()
102        }
103    }
104}
105
106impl From<Cli> for Mactime2Application {
107    fn from(cli: Cli) -> Self {
108        let format = match cli.output_format {
109            Some(f) => f,
110            None => {
111                if cli.csv_format {
112                    OutputFormat::CSV
113                } else if cli.json_format {
114                    OutputFormat::JSON
115                } else {
116                    OutputFormat::TXT
117                }
118            }
119        };
120
121        Self {
122            format,
123            bodyfile: Some(cli.input_file),
124            src_zone: cli
125                .src_zone
126                .map(|tz| tz.parse().unwrap())
127                .unwrap_or(Tz::UTC),
128            dst_zone: cli
129                .dst_zone
130                .map(|tz| tz.parse().unwrap())
131                .unwrap_or(Tz::UTC),
132            strict_mode: cli.strict_mode,
133        }
134    }
135}
136
137impl Default for Mactime2Application {
138    fn default() -> Self {
139        Self {
140            format: OutputFormat::CSV,
141            bodyfile: None,
142            src_zone: Tz::UTC,
143            dst_zone: Tz::UTC,
144            strict_mode: false,
145        }
146    }
147}