libnsave/
search_ti.rs

1use crate::{common::*, configure::*, mmapbuf::*, timeindex::LinkRecord};
2use bincode::deserialize_from;
3use chrono::{Datelike, Duration, Local, NaiveDateTime, Timelike};
4use std::{
5    cell::RefCell,
6    fs::{File, OpenOptions},
7    path::PathBuf,
8};
9
10#[derive(Debug)]
11pub struct SearchTi {
12    configure: &'static Configure,
13    pub current_date: RefCell<NaiveDateTime>,
14    pub end_date: NaiveDateTime,
15    dir_id: u64,
16    reader: RefCell<Option<MmapBufReader>>,
17}
18
19impl SearchTi {
20    pub fn new(
21        configure: &'static Configure,
22        start_date: NaiveDateTime,
23        end_date: Option<NaiveDateTime>,
24        dir_id: u64,
25    ) -> Self {
26        let now = Local::now().naive_local();
27        let mut e_date = if let Some(time) = end_date { time } else { now };
28        if e_date >= now {
29            e_date = now - Duration::try_minutes(1).unwrap();
30        }
31
32        SearchTi {
33            configure,
34            current_date: RefCell::new(start_date),
35            end_date: e_date,
36            dir_id,
37            reader: RefCell::new(None),
38        }
39    }
40
41    fn next_ti_in_dir(&self) -> Option<(LinkRecord, NaiveDateTime)> {
42        if self.reader.borrow().is_none() && !self.next_dir() {
43            return None;
44        }
45
46        let mut binding = self.reader.borrow_mut();
47        let reader = binding.as_mut().unwrap();
48        if let Ok(ti) = deserialize_from::<_, LinkRecord>(reader) {
49            Some((ti, *self.current_date.borrow()))
50        } else {
51            None
52        }
53    }
54
55    pub fn next_ti(&self) -> Option<(LinkRecord, NaiveDateTime)> {
56        let ti = self.next_ti_in_dir();
57        if ti.is_some() {
58            return ti;
59        }
60
61        if self.next_dir() {
62            self.next_ti_in_dir()
63        } else {
64            None
65        }
66    }
67
68    fn next_dir(&self) -> bool {
69        let mut search_date = *self.current_date.borrow();
70        while search_date <= self.end_date {
71            if let Ok((ti_file, _ti_file_path)) =
72                date2ti_file(self.configure, search_date, self.dir_id)
73            {
74                *self.current_date.borrow_mut() = search_date;
75                *self.reader.borrow_mut() = Some(MmapBufReader::new(ti_file));
76                return true;
77            }
78            search_date += Duration::try_minutes(1).unwrap();
79        }
80        false
81    }
82}
83
84pub fn date2ti_file(
85    configure: &'static Configure,
86    date: NaiveDateTime,
87    dir: u64,
88) -> Result<(File, PathBuf), StoreError> {
89    let mut path = PathBuf::new();
90    path.push(configure.store_path.clone());
91    path.push(format!("{:03}", dir));
92    path.push(format!("{:04}", date.year()));
93    path.push(format!("{:02}", date.month()));
94    path.push(format!("{:02}", date.day()));
95    path.push(format!("{:02}", date.hour()));
96    path.push(format!("{:02}", date.minute()));
97    path.push("timeindex.ti");
98
99    match OpenOptions::new()
100        .read(true)
101        .write(true)
102        .create(false)
103        .truncate(false)
104        .open(&path)
105    {
106        Ok(file) => Ok((file, path)),
107        Err(e) => Err(StoreError::CliError(format!("open file error: {}", e))),
108    }
109}