detached_shell/
pty_buffer.rs

1use std::collections::VecDeque;
2use std::sync::{Arc, Mutex};
3
4/// Circular buffer for PTY output
5/// Stores output generated while no client is attached
6pub struct PtyBuffer {
7    buffer: Arc<Mutex<VecDeque<Vec<u8>>>>,
8    max_size: usize,
9    total_bytes: Arc<Mutex<usize>>,
10}
11
12impl PtyBuffer {
13    pub fn new(max_size: usize) -> Self {
14        PtyBuffer {
15            buffer: Arc::new(Mutex::new(VecDeque::new())),
16            max_size,
17            total_bytes: Arc::new(Mutex::new(0)),
18        }
19    }
20
21    pub fn push(&self, data: &[u8]) {
22        let mut buffer = self.buffer.lock().unwrap();
23        let mut total = self.total_bytes.lock().unwrap();
24
25        buffer.push_back(data.to_vec());
26        *total += data.len();
27
28        // Remove old data if we exceed max size
29        while *total > self.max_size && !buffer.is_empty() {
30            if let Some(old_data) = buffer.pop_front() {
31                *total -= old_data.len();
32            }
33        }
34    }
35
36    pub fn drain_to(&self, output: &mut Vec<u8>) {
37        let mut buffer = self.buffer.lock().unwrap();
38        let mut total = self.total_bytes.lock().unwrap();
39
40        while let Some(data) = buffer.pop_front() {
41            output.extend_from_slice(&data);
42        }
43
44        *total = 0;
45    }
46
47    pub fn is_empty(&self) -> bool {
48        self.buffer.lock().unwrap().is_empty()
49    }
50
51    pub fn clone_handle(&self) -> Self {
52        PtyBuffer {
53            buffer: Arc::clone(&self.buffer),
54            max_size: self.max_size,
55            total_bytes: Arc::clone(&self.total_bytes),
56        }
57    }
58}