web_terminal/
terminal.rs

1use std::{
2    fs::File,
3    io::{
4        BufReader, 
5        Read, 
6        Write
7    },
8    os::{
9        fd::RawFd,
10        unix::io::FromRawFd
11    },
12    sync::Arc
13};
14use futures::{
15    SinkExt,
16    stream::SplitSink
17};
18use tokio::sync::{Mutex, MutexGuard};
19use warp::ws::{ Message, WebSocket };
20
21/// Struct for Terminal Instance
22#[derive(Debug)]
23pub struct Terminal;
24impl Terminal{
25
26    /// Reads the output of the executed commands then send the output to the websocket client.
27    pub fn reader(master_raw_fd: RawFd, wx_tx_state_reader: Arc<Mutex<SplitSink<WebSocket, Message>>>) -> tokio::task::JoinHandle<()> {                              
28        tokio::spawn(async move {
29            let mut buf: BufReader<File> = BufReader::new( unsafe {  File::from_raw_fd(master_raw_fd) });    
30            let mut output_buffer: Vec<u8> = vec![0;1024];
31            let mut output_all: Vec<u8> = Vec::new();
32            loop {
33                if let Ok(b) = buf.read(&mut output_buffer) {
34                    if b > 0 {
35                        for &byte in &output_buffer {
36                            if byte != 0 {
37                                output_all.push(byte);
38                            }
39                        }                        
40                        let mut ws_tx: MutexGuard<SplitSink<WebSocket, Message>> = wx_tx_state_reader.lock().await;
41                        match ws_tx.send(Message::binary(output_all)).await {
42                            Ok(_) => {
43                                output_all = Vec::new();
44                                output_buffer = vec![0;1024];
45                                drop(ws_tx);
46                            },
47                            Err(error) => {
48                                eprintln!("UNABLE_TO_SEND_MESSAGE: {:?}",error);
49                                drop(ws_tx);
50                                break;
51                            }
52                        }
53                    }
54                }
55                else{                    
56                    tokio::time::sleep(std::time::Duration::from_millis(100)).await;
57                }
58            }
59        })
60    }
61
62    ///Write the command in the master file descriptor issued by the forkpty.
63    pub fn writer(f: &mut File, command: &[u8]) -> Result<bool,std::io::Error> { 
64        if let Err(error) = f.write_all(command) {
65            return Err(error);
66        }
67        if let Err(error) = f.flush() {
68            return Err(error);
69        }
70        Ok(true)
71    }
72}