mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 21:21:32 +00:00
krata: rework into daemon / controller structure
This commit is contained in:
@ -4,71 +4,73 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::Result;
|
||||
use futures::future::join_all;
|
||||
use krata::{
|
||||
control::{ConsoleStreamUpdate, StreamUpdate},
|
||||
stream::StreamContext,
|
||||
};
|
||||
use log::debug;
|
||||
use std::process::exit;
|
||||
use termion::raw::IntoRawMode;
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncReadExt, AsyncWriteExt},
|
||||
select,
|
||||
};
|
||||
|
||||
pub struct XenConsole {
|
||||
xen_read_handle: File,
|
||||
xen_write_handle: File,
|
||||
stream: StreamContext,
|
||||
}
|
||||
|
||||
impl XenConsole {
|
||||
pub async fn new(tty: &str) -> Result<XenConsole> {
|
||||
let xen_read_handle = File::options().read(true).write(false).open(tty).await?;
|
||||
let xen_write_handle = File::options().read(false).write(true).open(tty).await?;
|
||||
Ok(XenConsole {
|
||||
xen_read_handle,
|
||||
xen_write_handle,
|
||||
})
|
||||
pub async fn new(stream: StreamContext) -> Result<XenConsole> {
|
||||
Ok(XenConsole { stream })
|
||||
}
|
||||
|
||||
pub async fn attach(self) -> Result<()> {
|
||||
let stdin = stdin();
|
||||
let stdin = unsafe { File::from_raw_fd(stdin().as_raw_fd()) };
|
||||
let terminal = stdout().into_raw_mode()?;
|
||||
let stdout = unsafe { File::from_raw_fd(terminal.as_raw_fd()) };
|
||||
let reader_task = tokio::task::spawn(async move {
|
||||
if let Err(error) = XenConsole::copy_stdout(stdout, self.xen_read_handle).await {
|
||||
debug!("failed to copy console output: {}", error);
|
||||
}
|
||||
});
|
||||
let writer_task = tokio::task::spawn(async move {
|
||||
if let Err(error) = XenConsole::intercept_stdin(
|
||||
unsafe { File::from_raw_fd(stdin.as_raw_fd()) },
|
||||
self.xen_write_handle,
|
||||
)
|
||||
.await
|
||||
{
|
||||
debug!("failed to intercept stdin: {}", error);
|
||||
}
|
||||
});
|
||||
|
||||
join_all(vec![reader_task, writer_task]).await;
|
||||
if let Err(error) = XenConsole::process(stdin, stdout, self.stream).await {
|
||||
debug!("failed to process console stream: {}", error);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn copy_stdout(mut stdout: File, mut console: File) -> Result<()> {
|
||||
let mut buffer = vec![0u8; 256];
|
||||
loop {
|
||||
let size = console.read(&mut buffer).await?;
|
||||
stdout.write_all(&buffer[0..size]).await?;
|
||||
stdout.flush().await?;
|
||||
}
|
||||
}
|
||||
|
||||
async fn intercept_stdin(mut stdin: File, mut console: File) -> Result<()> {
|
||||
async fn process(mut stdin: File, mut stdout: File, mut stream: StreamContext) -> Result<()> {
|
||||
let mut buffer = vec![0u8; 60];
|
||||
loop {
|
||||
let size = stdin.read(&mut buffer).await?;
|
||||
if size == 1 && buffer[0] == 0x1d {
|
||||
exit(0);
|
||||
}
|
||||
console.write_all(&buffer[0..size]).await?;
|
||||
select! {
|
||||
x = stream.receiver.recv() => match x {
|
||||
Some(StreamUpdate::ConsoleStream(update)) => {
|
||||
stdout.write_all(&update.data).await?;
|
||||
stdout.flush().await?;
|
||||
},
|
||||
|
||||
None => {
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
x = stdin.read(&mut buffer) => match x {
|
||||
Ok(size) => {
|
||||
if size == 1 && buffer[0] == 0x1d {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
let data = buffer[0..size].to_vec();
|
||||
stream.send(StreamUpdate::ConsoleStream(ConsoleStreamUpdate {
|
||||
data,
|
||||
})).await?;
|
||||
},
|
||||
|
||||
Err(error) => {
|
||||
return Err(error.into());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user