1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use async_trait::async_trait;
use chrono::Utc;
use std::{fmt::Write, time};
use tokio::{fs::File, io::AsyncWriteExt};

use crate::models;

use super::{common::*, DeviceError};

pub type FileDevice = Rewriter<FileDeviceImpl>;

pub struct FileDeviceImpl {
    leds: Vec<models::Color>,
    print_timestamp: bool,
    file_handle: File,
    last_write_time: time::Instant,
    str_buf: String,
}

#[async_trait]
impl WritingDevice for FileDeviceImpl {
    type Config = models::File;

    fn new(config: &Self::Config) -> Result<Self, DeviceError> {
        let file_handle = std::fs::OpenOptions::new()
            .write(true)
            .create(true)
            .append(true)
            .open(&config.output)?;

        Ok(Self {
            leds: vec![Default::default(); config.hardware_led_count as _],
            print_timestamp: config.print_time_stamp,
            file_handle: File::from_std(file_handle),
            last_write_time: time::Instant::now(),
            str_buf: String::new(),
        })
    }

    async fn set_let_data(
        &mut self,
        _config: &Self::Config,
        led_data: &[models::Color],
    ) -> Result<(), DeviceError> {
        self.leds.copy_from_slice(led_data);
        Ok(())
    }

    async fn write(&mut self) -> Result<(), DeviceError> {
        self.str_buf.clear();

        if self.print_timestamp {
            // Prepend timestamp
            let now = Utc::now();
            let elapsed_time_ms = self.last_write_time.elapsed().as_millis();
            self.last_write_time = time::Instant::now();

            write!(self.str_buf, "{} | +{}", now, elapsed_time_ms)?;
        }

        write!(self.str_buf, " [")?;
        for led in &self.leds {
            write!(self.str_buf, "{{{},{},{}}}", led.red, led.green, led.blue)?;
        }
        writeln!(self.str_buf, "]")?;

        self.file_handle.write_all(self.str_buf.as_bytes()).await?;
        self.file_handle.flush().await?;

        Ok(())
    }
}