hyperion/instance/device/
file.rs

1use async_trait::async_trait;
2use chrono::Utc;
3use std::{fmt::Write, time};
4use tokio::{fs::File, io::AsyncWriteExt};
5
6use crate::models;
7
8use super::{common::*, DeviceError};
9
10pub type FileDevice = Rewriter<FileDeviceImpl>;
11
12pub struct FileDeviceImpl {
13    leds: Vec<models::Color>,
14    print_timestamp: bool,
15    file_handle: File,
16    last_write_time: time::Instant,
17    str_buf: String,
18}
19
20#[async_trait]
21impl WritingDevice for FileDeviceImpl {
22    type Config = models::File;
23
24    fn new(config: &Self::Config) -> Result<Self, DeviceError> {
25        let file_handle = std::fs::OpenOptions::new()
26            .create(true)
27            .append(true)
28            .open(&config.output)?;
29
30        Ok(Self {
31            leds: vec![Default::default(); config.hardware_led_count as _],
32            print_timestamp: config.print_time_stamp,
33            file_handle: File::from_std(file_handle),
34            last_write_time: time::Instant::now(),
35            str_buf: String::new(),
36        })
37    }
38
39    async fn set_let_data(
40        &mut self,
41        _config: &Self::Config,
42        led_data: &[models::Color],
43    ) -> Result<(), DeviceError> {
44        self.leds.copy_from_slice(led_data);
45        Ok(())
46    }
47
48    async fn write(&mut self) -> Result<(), DeviceError> {
49        self.str_buf.clear();
50
51        if self.print_timestamp {
52            // Prepend timestamp
53            let now = Utc::now();
54            let elapsed_time_ms = self.last_write_time.elapsed().as_millis();
55            self.last_write_time = time::Instant::now();
56
57            write!(self.str_buf, "{} | +{}", now, elapsed_time_ms)?;
58        }
59
60        write!(self.str_buf, " [")?;
61        for led in &self.leds {
62            write!(self.str_buf, "{{{},{},{}}}", led.red, led.green, led.blue)?;
63        }
64        writeln!(self.str_buf, "]")?;
65
66        self.file_handle.write_all(self.str_buf.as_bytes()).await?;
67        self.file_handle.flush().await?;
68
69        Ok(())
70    }
71}