Merge branch 'refactor/docker' into dev
This commit is contained in:
@@ -333,7 +333,7 @@ impl fmt::Display for State {
|
||||
|
||||
/// Items for the container control list
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DockerControls {
|
||||
pub enum DockerCommand {
|
||||
Pause,
|
||||
Restart,
|
||||
Start,
|
||||
@@ -342,7 +342,7 @@ pub enum DockerControls {
|
||||
Delete,
|
||||
}
|
||||
|
||||
impl DockerControls {
|
||||
impl DockerCommand {
|
||||
pub const fn get_color(self) -> Color {
|
||||
match self {
|
||||
Self::Pause => Color::Yellow,
|
||||
@@ -366,7 +366,7 @@ impl DockerControls {
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DockerControls {
|
||||
impl fmt::Display for DockerCommand {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let disp = match self {
|
||||
Self::Pause => "pause",
|
||||
@@ -577,7 +577,7 @@ impl Logs {
|
||||
pub struct ContainerItem {
|
||||
pub cpu_stats: VecDeque<CpuStats>,
|
||||
pub created: u64,
|
||||
pub docker_controls: StatefulList<DockerControls>,
|
||||
pub docker_controls: StatefulList<DockerCommand>,
|
||||
pub id: ContainerId,
|
||||
pub image: ContainerImage,
|
||||
pub is_oxker: bool,
|
||||
@@ -620,7 +620,7 @@ impl ContainerItem {
|
||||
state: State,
|
||||
status: ContainerStatus,
|
||||
) -> Self {
|
||||
let mut docker_controls = StatefulList::new(DockerControls::gen_vec(state));
|
||||
let mut docker_controls = StatefulList::new(DockerCommand::gen_vec(state));
|
||||
docker_controls.start();
|
||||
|
||||
Self {
|
||||
|
||||
+28
-29
@@ -535,7 +535,7 @@ impl AppData {
|
||||
|
||||
/// Get the current selected docker command
|
||||
/// So know which command to execute
|
||||
pub fn selected_docker_controls(&self) -> Option<DockerControls> {
|
||||
pub fn selected_docker_controls(&self) -> Option<DockerCommand> {
|
||||
self.get_selected_container().and_then(|i| {
|
||||
i.docker_controls.state.selected().and_then(|x| {
|
||||
i.docker_controls
|
||||
@@ -574,15 +574,14 @@ impl AppData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get mutable Option of the currently selected container DockerControls state
|
||||
/// Get mutable Option of the currently selected container DockerCommand state
|
||||
pub fn get_control_state(&mut self) -> Option<&mut ListState> {
|
||||
self.get_mut_selected_container()
|
||||
.map(|i| &mut i.docker_controls.state)
|
||||
}
|
||||
|
||||
/// Get mutable Option of the currently selected container DockerControls items
|
||||
/// TODO command or control, need a uniform name across the application
|
||||
pub fn get_control_items(&mut self) -> Option<&mut Vec<DockerControls>> {
|
||||
/// Get mutable Option of the currently selected container DockerConmand items
|
||||
pub fn get_control_items(&mut self) -> Option<&mut Vec<DockerCommand>> {
|
||||
self.get_mut_selected_container()
|
||||
.map(|i| &mut i.docker_controls.items)
|
||||
}
|
||||
@@ -855,7 +854,7 @@ impl AppData {
|
||||
item.status = status;
|
||||
};
|
||||
if item.state != state {
|
||||
item.docker_controls.items = DockerControls::gen_vec(state);
|
||||
item.docker_controls.items = DockerCommand::gen_vec(state);
|
||||
// Update the list state, needs to be None if the gen_vec returns an empty vec
|
||||
match state {
|
||||
State::Removing | State::Restarting | State::Unknown => {
|
||||
@@ -1526,7 +1525,7 @@ mod tests {
|
||||
app_data.docker_controls_start();
|
||||
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Pause));
|
||||
assert_eq!(result, Some(DockerCommand::Pause));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1539,7 +1538,7 @@ mod tests {
|
||||
app_data.docker_controls_next();
|
||||
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Restart));
|
||||
assert_eq!(result, Some(DockerCommand::Restart));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1551,12 +1550,12 @@ mod tests {
|
||||
app_data.docker_controls_end();
|
||||
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Delete));
|
||||
assert_eq!(result, Some(DockerCommand::Delete));
|
||||
|
||||
// Next has no effect when at end
|
||||
app_data.docker_controls_next();
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Delete));
|
||||
assert_eq!(result, Some(DockerCommand::Delete));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1569,19 +1568,19 @@ mod tests {
|
||||
app_data.docker_controls_previous();
|
||||
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Stop));
|
||||
assert_eq!(result, Some(DockerCommand::Stop));
|
||||
|
||||
// previous has no effect when at start
|
||||
app_data.docker_controls_start();
|
||||
app_data.docker_controls_previous();
|
||||
let result = app_data.selected_docker_controls();
|
||||
assert_eq!(result, Some(DockerControls::Pause));
|
||||
assert_eq!(result, Some(DockerCommand::Pause));
|
||||
}
|
||||
|
||||
#[test]
|
||||
/// DockerCommands get correct controls dependant on container state
|
||||
fn test_app_data_get_control_items() {
|
||||
let test_state = |state: State, expected: &mut Vec<DockerControls>| {
|
||||
let test_state = |state: State, expected: &mut Vec<DockerCommand>| {
|
||||
let gen_item_state = |state: State| {
|
||||
ContainerItem::new(
|
||||
1,
|
||||
@@ -1605,42 +1604,42 @@ mod tests {
|
||||
test_state(
|
||||
State::Dead,
|
||||
&mut vec![
|
||||
DockerControls::Start,
|
||||
DockerControls::Restart,
|
||||
DockerControls::Delete,
|
||||
DockerCommand::Start,
|
||||
DockerCommand::Restart,
|
||||
DockerCommand::Delete,
|
||||
],
|
||||
);
|
||||
test_state(
|
||||
State::Exited,
|
||||
&mut vec![
|
||||
DockerControls::Start,
|
||||
DockerControls::Restart,
|
||||
DockerControls::Delete,
|
||||
DockerCommand::Start,
|
||||
DockerCommand::Restart,
|
||||
DockerCommand::Delete,
|
||||
],
|
||||
);
|
||||
test_state(
|
||||
State::Paused,
|
||||
&mut vec![
|
||||
DockerControls::Resume,
|
||||
DockerControls::Stop,
|
||||
DockerControls::Delete,
|
||||
DockerCommand::Resume,
|
||||
DockerCommand::Stop,
|
||||
DockerCommand::Delete,
|
||||
],
|
||||
);
|
||||
test_state(State::Removing, &mut vec![DockerControls::Delete]);
|
||||
test_state(State::Removing, &mut vec![DockerCommand::Delete]);
|
||||
test_state(
|
||||
State::Restarting,
|
||||
&mut vec![DockerControls::Stop, DockerControls::Delete],
|
||||
&mut vec![DockerCommand::Stop, DockerCommand::Delete],
|
||||
);
|
||||
test_state(
|
||||
State::Running(RunningState::Healthy),
|
||||
&mut vec![
|
||||
DockerControls::Pause,
|
||||
DockerControls::Restart,
|
||||
DockerControls::Stop,
|
||||
DockerControls::Delete,
|
||||
DockerCommand::Pause,
|
||||
DockerCommand::Restart,
|
||||
DockerCommand::Stop,
|
||||
DockerCommand::Delete,
|
||||
],
|
||||
);
|
||||
test_state(State::Unknown, &mut vec![DockerControls::Delete]);
|
||||
test_state(State::Unknown, &mut vec![DockerCommand::Delete]);
|
||||
}
|
||||
|
||||
// ****** //
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
use crate::app_data::DockerControls;
|
||||
use crate::app_data::DockerCommand;
|
||||
use std::fmt;
|
||||
|
||||
/// app errors to set in global state
|
||||
#[allow(unused)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AppError {
|
||||
DockerCommand(DockerControls),
|
||||
DockerCommand(DockerCommand),
|
||||
DockerExec,
|
||||
DockerLogs,
|
||||
DockerConnect,
|
||||
|
||||
@@ -1,19 +1,21 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::app_data::ContainerId;
|
||||
use crate::app_data::{ContainerId, DockerCommand};
|
||||
use bollard::Docker;
|
||||
use tokio::sync::oneshot::Sender;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DockerMessage {
|
||||
ConfirmDelete(ContainerId),
|
||||
Delete(ContainerId),
|
||||
Control((DockerCommand, ContainerId)),
|
||||
|
||||
// Delete(ContainerId),
|
||||
Exec(Sender<Arc<Docker>>),
|
||||
Pause(ContainerId),
|
||||
// Pause(ContainerId),
|
||||
Quit,
|
||||
Restart(ContainerId),
|
||||
Start(ContainerId),
|
||||
Stop(ContainerId),
|
||||
Resume(ContainerId),
|
||||
// Restart(ContainerId),
|
||||
// Start(ContainerId),
|
||||
// Stop(ContainerId),
|
||||
// Resume(ContainerId),
|
||||
Update,
|
||||
}
|
||||
|
||||
+35
-74
@@ -22,7 +22,7 @@ use tokio::{
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
app_data::{AppData, ContainerId, ContainerStatus, DockerControls, State},
|
||||
app_data::{AppData, ContainerId, ContainerStatus, DockerCommand, State},
|
||||
app_error::AppError,
|
||||
parse_args::CliArgs,
|
||||
ui::{GuiState, Status},
|
||||
@@ -340,7 +340,7 @@ impl DockerData {
|
||||
/// Set the global error as the docker error, and set gui_state to error
|
||||
fn set_error(
|
||||
app_data: &Arc<Mutex<AppData>>,
|
||||
error: DockerControls,
|
||||
error: DockerCommand,
|
||||
gui_state: &Arc<Mutex<GuiState>>,
|
||||
) {
|
||||
app_data
|
||||
@@ -348,78 +348,19 @@ impl DockerData {
|
||||
.set_error(AppError::DockerCommand(error), gui_state, Status::Error);
|
||||
}
|
||||
|
||||
/// Handle incoming messages, container controls & all container information update
|
||||
/// Spawn Docker commands off into own thread
|
||||
#[allow(clippy::too_many_lines)]
|
||||
async fn message_handler(&mut self) {
|
||||
while let Some(message) = self.receiver.recv().await {
|
||||
let docker = Arc::clone(&self.docker);
|
||||
let gui_state = Arc::clone(&self.gui_state);
|
||||
let app_data = Arc::clone(&self.app_data);
|
||||
/// Execute docker comamnds (start, stop etc) on it's own tokio thread
|
||||
async fn execute_command(&mut self, control: DockerCommand, id: ContainerId) {
|
||||
let (app_data, docker, gui_state) = (
|
||||
Arc::clone(&self.app_data),
|
||||
Arc::clone(&self.docker),
|
||||
Arc::clone(&self.gui_state),
|
||||
);
|
||||
tokio::spawn(async move {
|
||||
let uuid = Uuid::new_v4();
|
||||
// TODO need to refactor these
|
||||
match message {
|
||||
DockerMessage::Exec(docker_tx) => {
|
||||
docker_tx.send(Arc::clone(&self.docker)).ok();
|
||||
}
|
||||
DockerMessage::Pause(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker.pause_container(id.get()).await.is_err() {
|
||||
Self::set_error(&app_data, DockerControls::Pause, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
}
|
||||
DockerMessage::Restart(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker.restart_container(id.get(), None).await.is_err() {
|
||||
Self::set_error(&app_data, DockerControls::Restart, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
}
|
||||
DockerMessage::Start(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker
|
||||
.start_container(id.get(), None::<StartContainerOptions<String>>)
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
Self::set_error(&app_data, DockerControls::Start, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
}
|
||||
DockerMessage::Stop(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker.stop_container(id.get(), None).await.is_err() {
|
||||
Self::set_error(&app_data, DockerControls::Stop, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
}
|
||||
DockerMessage::Resume(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker.unpause_container(id.get()).await.is_err() {
|
||||
Self::set_error(&app_data, DockerControls::Resume, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
}
|
||||
DockerMessage::Delete(id) => {
|
||||
tokio::spawn(async move {
|
||||
GuiState::start_loading_animation(&gui_state, uuid);
|
||||
if docker
|
||||
if match control {
|
||||
DockerCommand::Delete => {
|
||||
docker
|
||||
.remove_container(
|
||||
id.get(),
|
||||
Some(RemoveContainerOptions {
|
||||
@@ -429,18 +370,38 @@ impl DockerData {
|
||||
}),
|
||||
)
|
||||
.await
|
||||
}
|
||||
DockerCommand::Pause => docker.pause_container(id.get()).await,
|
||||
DockerCommand::Restart => docker.restart_container(id.get(), None).await,
|
||||
DockerCommand::Resume => docker.unpause_container(id.get()).await,
|
||||
DockerCommand::Start => {
|
||||
docker
|
||||
.start_container(id.get(), None::<StartContainerOptions<String>>)
|
||||
.await
|
||||
}
|
||||
DockerCommand::Stop => docker.stop_container(id.get(), None).await,
|
||||
}
|
||||
.is_err()
|
||||
{
|
||||
Self::set_error(&app_data, DockerControls::Stop, &gui_state);
|
||||
Self::set_error(&app_data, control, &gui_state);
|
||||
}
|
||||
gui_state.lock().stop_loading_animation(uuid);
|
||||
});
|
||||
self.update_everything().await;
|
||||
self.gui_state.lock().set_delete_container(None);
|
||||
}
|
||||
|
||||
/// Handle incoming messages, container controls & all container information update
|
||||
/// Spawn Docker commands off into own thread
|
||||
async fn message_handler(&mut self) {
|
||||
while let Some(message) = self.receiver.recv().await {
|
||||
match message {
|
||||
DockerMessage::ConfirmDelete(id) => {
|
||||
self.gui_state.lock().set_delete_container(Some(id));
|
||||
}
|
||||
DockerMessage::Control((command, id)) => self.execute_command(command, id).await,
|
||||
DockerMessage::Exec(docker_tx) => {
|
||||
docker_tx.send(Arc::clone(&self.docker)).ok();
|
||||
}
|
||||
DockerMessage::Update => self.update_everything().await,
|
||||
DockerMessage::Quit => {
|
||||
self.spawns
|
||||
|
||||
+12
-18
@@ -22,7 +22,7 @@ use uuid::Uuid;
|
||||
|
||||
mod message;
|
||||
use crate::{
|
||||
app_data::{AppData, DockerControls, Header},
|
||||
app_data::{AppData, DockerCommand, Header},
|
||||
app_error::AppError,
|
||||
docker_data::DockerMessage,
|
||||
exec::{tty_readable, ExecMode},
|
||||
@@ -112,7 +112,10 @@ impl InputHandler {
|
||||
async fn confirm_delete(&self) {
|
||||
let id = self.gui_state.lock().get_delete_container();
|
||||
if let Some(id) = id {
|
||||
self.docker_tx.send(DockerMessage::Delete(id)).await.ok();
|
||||
self.docker_tx
|
||||
.send(DockerMessage::Control((DockerCommand::Delete, id)))
|
||||
.await
|
||||
.ok();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,26 +284,17 @@ impl InputHandler {
|
||||
let option_id = self.app_data.lock().get_selected_container_id();
|
||||
if let Some(id) = option_id {
|
||||
match command {
|
||||
DockerControls::Delete => self
|
||||
DockerCommand::Delete => self
|
||||
.docker_tx
|
||||
.send(DockerMessage::ConfirmDelete(id))
|
||||
.await
|
||||
.ok(),
|
||||
DockerControls::Pause => {
|
||||
self.docker_tx.send(DockerMessage::Pause(id)).await.ok()
|
||||
}
|
||||
DockerControls::Resume => {
|
||||
self.docker_tx.send(DockerMessage::Resume(id)).await.ok()
|
||||
}
|
||||
DockerControls::Start => {
|
||||
self.docker_tx.send(DockerMessage::Start(id)).await.ok()
|
||||
}
|
||||
DockerControls::Stop => {
|
||||
self.docker_tx.send(DockerMessage::Stop(id)).await.ok()
|
||||
}
|
||||
DockerControls::Restart => {
|
||||
self.docker_tx.send(DockerMessage::Restart(id)).await.ok()
|
||||
}
|
||||
|
||||
_ => self
|
||||
.docker_tx
|
||||
.send(DockerMessage::Control((command, id)))
|
||||
.await
|
||||
.ok(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user