Skip to main content

veloxity_core/log/
drain.rs

1use crate::{
2    comm::messages::messages::StatustextMsg,
3    events::{COMM_RESPONSE_QUEUE_CAPACITY, CommResponse},
4    log::Logger,
5    ports::EventEmitPort,
6};
7
8const MAX_LOGS_PER_DRAIN: usize = 1;
9
10pub struct LogDrainCtx<'a> {
11    pub responses: EventEmitPort<'a, CommResponse, COMM_RESPONSE_QUEUE_CAPACITY>,
12    pub connected: bool,
13}
14
15pub fn drain_logs_to_comm_responses(mut ctx: LogDrainCtx<'_>) -> usize {
16    if !ctx.connected {
17        return 0;
18    }
19
20    let mut drained = 0;
21
22    while drained < MAX_LOGS_PER_DRAIN {
23        let Some(entry) = Logger::pop() else {
24            break;
25        };
26
27        let mut text = [0u8; 50];
28        let bytes = entry.message.as_str().as_bytes();
29        let len = bytes.len().min(text.len());
30        text[..len].copy_from_slice(&bytes[..len]);
31
32        if ctx
33            .responses
34            .emit(CommResponse::Statustext(StatustextMsg {
35                severity: entry.severity,
36                text,
37            }))
38            .is_err()
39        {
40            break;
41        }
42
43        drained += 1;
44    }
45
46    drained
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use crate::{
53        comm::messages::enums::Severity,
54        events::{COMM_RESPONSE_QUEUE_CAPACITY, EventQueue},
55        log_info, log_warn,
56    };
57
58    #[test]
59    fn drain_logs_queues_statustext_responses() {
60        while Logger::pop().is_some() {}
61
62        log_info!("hello");
63        log_warn!("world");
64
65        let mut responses = EventQueue::<CommResponse, COMM_RESPONSE_QUEUE_CAPACITY>::new();
66        let drained = drain_logs_to_comm_responses(LogDrainCtx {
67            responses: EventEmitPort::new(&mut responses),
68            connected: true,
69        });
70
71        assert_eq!(drained, 1);
72        match responses.pop().unwrap() {
73            CommResponse::Statustext(msg) => {
74                assert!(matches!(msg.severity, Severity::Info));
75                assert_eq!(&msg.text[..5], b"hello");
76            }
77            _ => panic!("expected statustext response"),
78        }
79
80        let drained = drain_logs_to_comm_responses(LogDrainCtx {
81            responses: EventEmitPort::new(&mut responses),
82            connected: true,
83        });
84
85        assert_eq!(drained, 1);
86        match responses.pop().unwrap() {
87            CommResponse::Statustext(msg) => {
88                assert!(matches!(msg.severity, Severity::Warning));
89                assert_eq!(&msg.text[..5], b"world");
90            }
91            _ => panic!("expected statustext response"),
92        }
93    }
94
95    #[test]
96    fn drain_logs_waits_for_companion_connection() {
97        while Logger::pop().is_some() {}
98
99        log_info!("buffered");
100
101        let mut responses = EventQueue::<CommResponse, COMM_RESPONSE_QUEUE_CAPACITY>::new();
102        let drained = drain_logs_to_comm_responses(LogDrainCtx {
103            responses: EventEmitPort::new(&mut responses),
104            connected: false,
105        });
106
107        assert_eq!(drained, 0);
108        assert!(responses.is_empty());
109
110        let drained = drain_logs_to_comm_responses(LogDrainCtx {
111            responses: EventEmitPort::new(&mut responses),
112            connected: true,
113        });
114
115        assert_eq!(drained, 1);
116    }
117}