init commit

This commit is contained in:
Jack Wills
2022-04-25 02:44:39 +00:00
commit 5101f60aaa
28 changed files with 3289 additions and 0 deletions
+7
View File
@@ -0,0 +1,7 @@
use crossterm::event::{KeyCode, MouseEvent};
#[derive(Debug, Clone)]
pub enum InputMessages {
ButtonPress(KeyCode),
MouseEvent(MouseEvent),
}
+262
View File
@@ -0,0 +1,262 @@
use std::sync::{
atomic::{AtomicBool, Ordering},
Arc,
};
use bollard::{container::StartContainerOptions, Docker};
use crossterm::event::{KeyCode, MouseButton, MouseEvent, MouseEventKind};
use parking_lot::Mutex;
use tokio::sync::broadcast::Receiver;
use tui::layout::Rect;
mod message;
use crate::{
app_data::{AppData, DockerControls},
app_error::AppError,
ui::{GuiState, SelectablePanel},
};
pub use message::InputMessages;
/// Handle all input events
#[derive(Debug)]
pub struct InputHandler {
app_data: Arc<Mutex<AppData>>,
docker: Arc<Docker>,
gui_state: Arc<Mutex<GuiState>>,
is_running: Arc<AtomicBool>,
rec: Receiver<InputMessages>,
}
impl InputHandler {
/// Initialize self, and running the message handling loop
pub async fn init(
app_data: Arc<Mutex<AppData>>,
rec: Receiver<InputMessages>,
docker: Arc<Docker>,
gui_state: Arc<Mutex<GuiState>>,
is_running: Arc<AtomicBool>,
) {
let mut inner = Self {
app_data,
docker,
gui_state,
is_running,
rec,
};
inner.start().await;
}
/// check for incoming messages
async fn start(&mut self) {
while let Ok(message) = self.rec.recv().await {
match message {
InputMessages::ButtonPress(key_code) => self.button_press(key_code).await,
InputMessages::MouseEvent(mouse_event) => {
let show_error = self.app_data.lock().show_error;
let show_info = self.gui_state.lock().show_help;
if !show_error && !show_info {
self.mouse_press(mouse_event);
}
}
}
if !self.is_running.load(Ordering::SeqCst) {
break;
}
}
}
/// Handle any keyboard button events
async fn button_press(&mut self, key_code: KeyCode) {
let show_error = self.app_data.lock().show_error;
let show_info = self.gui_state.lock().show_help;
if show_error {
match key_code {
KeyCode::Char('q') => {
self.is_running.store(false, Ordering::SeqCst);
}
KeyCode::Char('c') => {
self.app_data.lock().show_error = false;
self.app_data.lock().remove_error();
}
_ => (),
}
} else if show_info {
match key_code {
KeyCode::Char('q') => {
self.is_running.store(false, Ordering::SeqCst);
}
KeyCode::Char('h') => {
self.gui_state.lock().show_help = false;
}
_ => (),
}
} else {
match key_code {
KeyCode::Char('q') => {
self.is_running.store(false, Ordering::SeqCst);
}
KeyCode::Char('h') => {
self.gui_state.lock().show_help = true;
}
KeyCode::Tab => self.gui_state.lock().next_panel(),
KeyCode::BackTab => self.gui_state.lock().previous_panel(),
KeyCode::Home => {
let mut locked_data = self.app_data.lock();
match self.gui_state.lock().selected_panel {
SelectablePanel::Containers => locked_data.containers.start(),
SelectablePanel::Logs => locked_data.log_start(),
SelectablePanel::Commands => locked_data.docker_command_start(),
}
}
KeyCode::End => {
let mut locked_data = self.app_data.lock();
match self.gui_state.lock().selected_panel {
SelectablePanel::Containers => locked_data.containers.end(),
SelectablePanel::Logs => locked_data.log_end(),
SelectablePanel::Commands => locked_data.docker_command_end(),
}
}
KeyCode::Up => self.previous(),
KeyCode::PageUp => {
for _ in 0..=6 {
self.previous()
}
}
KeyCode::Down => self.next(),
KeyCode::PageDown => {
for _ in 0..=6 {
self.next()
}
}
KeyCode::Enter => {
// Does is matter though?
// This isn't great, just means you can't send docker commands before full initialization of the program
// could change to to if loading = true, although at the moment don't have a loading bool
let panel = self.gui_state.lock().selected_panel;
if panel == SelectablePanel::Commands {
let command = self.app_data.lock().get_docker_command();
if command.is_some() {
let id = self.app_data.lock().get_selected_container_id();
let app_data = Arc::clone(&self.app_data);
let docker = Arc::clone(&self.docker);
if id.is_some() {
let id = id.unwrap();
match command.unwrap() {
DockerControls::Pause => {
tokio::spawn(async move {
docker.pause_container(&id).await.unwrap_or_else(
|_| {
app_data.lock().set_error(
AppError::DockerCommand(
DockerControls::Pause,
),
)
},
);
});
}
DockerControls::Unpause => {
tokio::spawn(async move {
docker.unpause_container(&id).await.unwrap_or_else(
|_| {
app_data.lock().set_error(
AppError::DockerCommand(
DockerControls::Unpause,
),
)
},
);
});
}
DockerControls::Start => {
tokio::spawn(async move {
docker
.start_container(
&id,
None::<StartContainerOptions<String>>,
)
.await
.unwrap_or_else(|_| {
app_data.lock().set_error(
AppError::DockerCommand(
DockerControls::Start,
),
)
});
});
}
DockerControls::Stop => {
tokio::spawn(async move {
docker.stop_container(&id, None).await.unwrap_or_else(
|_| {
app_data.lock().set_error(
AppError::DockerCommand(
DockerControls::Stop,
),
)
},
);
});
}
DockerControls::Restart => {
tokio::spawn(async move {
docker
.restart_container(&id, None)
.await
.unwrap_or_else(|_| {
app_data.lock().set_error(
AppError::DockerCommand(
DockerControls::Restart,
),
)
});
});
}
}
}
}
}
}
_ => (),
}
}
}
/// Handle mouse button events
fn mouse_press(&mut self, mouse_event: MouseEvent) {
match mouse_event.kind {
MouseEventKind::ScrollUp => self.previous(),
MouseEventKind::ScrollDown => self.next(),
MouseEventKind::Down(MouseButton::Left) => {
self.gui_state.lock().rect_insersects(Rect::new(
mouse_event.column,
mouse_event.row,
1,
1,
));
}
_ => (),
}
}
/// Change state of selected container
fn next(&mut self) {
let mut locked_data = self.app_data.lock();
match self.gui_state.lock().selected_panel {
SelectablePanel::Containers => locked_data.containers.next(),
SelectablePanel::Logs => locked_data.log_next(),
SelectablePanel::Commands => locked_data.docker_command_next(),
};
}
/// Change state of selected container
fn previous(&mut self) {
let mut locked_data = self.app_data.lock();
match self.gui_state.lock().selected_panel {
SelectablePanel::Containers => locked_data.containers.previous(),
SelectablePanel::Logs => locked_data.log_previous(),
SelectablePanel::Commands => locked_data.docker_command_previous(),
}
}
}