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}