digdigdig3_station/storage/
rotation.rs1use std::fs::{create_dir_all, File, OpenOptions};
6use std::io::{BufWriter, Write};
7use std::path::PathBuf;
8
9use byteorder::{LittleEndian, WriteBytesExt};
10use chrono::{NaiveDate, Utc};
11
12pub fn read_file_range(
15 path: &std::path::Path,
16 from_ms: i64,
17 to_ms: i64,
18) -> std::io::Result<Vec<(i64, Vec<u8>)>> {
19 use byteorder::ReadBytesExt;
20 use std::io::{BufReader, Read};
21
22 let file = File::open(path)?;
23 let mut reader = BufReader::new(file);
24 let mut out = Vec::new();
25
26 loop {
27 let ts = match reader.read_i64::<LittleEndian>() {
28 Ok(v) => v,
29 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
30 Err(e) => return Err(e),
31 };
32 let len = match reader.read_u32::<LittleEndian>() {
33 Ok(v) => v as usize,
34 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
35 Err(e) => return Err(e),
36 };
37 let mut payload = vec![0u8; len];
38 match reader.read_exact(&mut payload) {
39 Ok(()) => {
40 if ts >= from_ms && ts <= to_ms {
41 out.push((ts, payload));
42 }
43 }
44 Err(e) if e.kind() == std::io::ErrorKind::UnexpectedEof => break,
45 Err(e) => return Err(e),
46 }
47 }
48 Ok(out)
49}
50
51pub struct RotatingWriter {
53 dir: PathBuf,
54 current_day: NaiveDate,
55 writer: BufWriter<File>,
56}
57
58impl RotatingWriter {
59 pub fn new(dir: impl Into<PathBuf>) -> std::io::Result<Self> {
61 let dir = dir.into();
62 create_dir_all(&dir)?;
63 let today = Utc::now().date_naive();
64 let path = dir.join(format!("{}.bin", today.format("%Y-%m-%d")));
65 let file = OpenOptions::new()
66 .create(true)
67 .append(true)
68 .open(&path)?;
69 Ok(Self {
70 dir,
71 current_day: today,
72 writer: BufWriter::new(file),
73 })
74 }
75
76 pub fn append(&mut self, ts_ms: i64, payload: &[u8]) -> std::io::Result<()> {
78 let today = Utc::now().date_naive();
79 if today != self.current_day {
80 self.rotate(today)?;
81 }
82 self.writer.write_i64::<LittleEndian>(ts_ms)?;
83 self.writer.write_u32::<LittleEndian>(payload.len() as u32)?;
84 self.writer.write_all(payload)?;
85 Ok(())
86 }
87
88 pub fn flush(&mut self) -> std::io::Result<()> {
90 self.writer.flush()
91 }
92
93 fn rotate(&mut self, new_day: NaiveDate) -> std::io::Result<()> {
94 self.writer.flush()?;
95 let path = self.dir.join(format!("{}.bin", new_day.format("%Y-%m-%d")));
96 let file = OpenOptions::new()
97 .create(true)
98 .append(true)
99 .open(&path)?;
100 self.writer = BufWriter::new(file);
101 self.current_day = new_day;
102 Ok(())
103 }
104
105 pub fn rotate_to(&mut self, day: NaiveDate) -> std::io::Result<()> {
107 self.rotate(day)
108 }
109
110 pub fn current_day(&self) -> NaiveDate {
112 self.current_day
113 }
114}