feat: is_loading use HashSet<Uuid>

each set loading function uses a unique uuid, so that the loading animation will always be played, previously would stop on any remove_loading call
This commit is contained in:
Jack Wills
2022-09-07 14:33:03 +00:00
parent 34275b0220
commit 66583e1b03
4 changed files with 38 additions and 31 deletions
+1
View File
@@ -23,6 +23,7 @@ tokio = {version = "1.21", features=["full"]}
tracing = "0.1" tracing = "0.1"
tracing-subscriber = "0.3" tracing-subscriber = "0.3"
tui = "0.19" tui = "0.19"
uuid = {version = "1.1", features = ["v4", "fast-rng"]}
[dev-dependencies] [dev-dependencies]
+7 -2
View File
@@ -8,8 +8,13 @@ FROM alpine:latest AS runtime
COPY ./target/x86_64-unknown-linux-musl/release/oxker /usr/local/bin COPY ./target/x86_64-unknown-linux-musl/release/oxker /usr/local/bin
COPY ./containerised/start_oxker.sh ./ COPY ./containerised/start_oxker.sh ./
# Run the application ## Run the application
ENTRYPOINT [ "./start_oxker.sh"] ENTRYPOINT [ "./start_oxker.sh"]
# One liner to build musl program, build docker image, then execute the image ## One liner to build musl program, build docker image, then execute the image
# cargo build --release --target x86_64-unknown-linux-musl && docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev # cargo build --release --target x86_64-unknown-linux-musl && docker build -t oxker_dev -f containerised/Dockerfile_dev . && docker run --rm -it --volume /var/run/docker.sock:/var/run/docker.sock:ro oxker_dev
## Buildx command to build musl version for all three platforms, should probably be executed in create_release
# docker buildx create --use
# docker buildx build --platform linux/arm/v6,linux/arm64,linux/amd64 -t oxker_dev_all -o type=tar,dest=/tmp/oxker_dev_all.tar -f containerised/Dockerfile .
+19 -17
View File
@@ -5,6 +5,7 @@ use bollard::{
}; };
use futures_util::StreamExt; use futures_util::StreamExt;
use parking_lot::Mutex; use parking_lot::Mutex;
use uuid::Uuid;
use std::{ use std::{
collections::HashMap, collections::HashMap,
sync::{ sync::{
@@ -295,25 +296,26 @@ impl DockerData {
} }
/// Animate the loading icon /// Animate the loading icon
async fn loading_spin(&mut self) -> JoinHandle<()> { async fn loading_spin(&mut self, loading_uuid: Uuid) -> JoinHandle<()> {
let gui_state = Arc::clone(&self.gui_state); let gui_state = Arc::clone(&self.gui_state);
tokio::spawn(async move { tokio::spawn(async move {
loop { loop {
tokio::time::sleep(std::time::Duration::from_millis(100)).await; tokio::time::sleep(std::time::Duration::from_millis(100)).await;
gui_state.lock().next_loading(); gui_state.lock().next_loading(loading_uuid);
} }
}) })
} }
/// Stop the loading_spin function, and reset gui loading status /// Stop the loading_spin function, and reset gui loading status
fn stop_loading_spin(&mut self, handle: &JoinHandle<()>) { fn stop_loading_spin(&mut self, handle: &JoinHandle<()>, loading_uuid: Uuid) {
handle.abort(); handle.abort();
self.gui_state.lock().reset_loading(); self.gui_state.lock().remove_loading(loading_uuid);
} }
// Initialize docker container data, before any messages are received // Initialize docker container data, before any messages are received
async fn initialise_container_data(&mut self) { async fn initialise_container_data(&mut self) {
let loading_spin = self.loading_spin().await; let loading_uuid = Uuid::new_v4();
let loading_spin = self.loading_spin(loading_uuid).await;
let all_ids = self.update_all_containers().await; let all_ids = self.update_all_containers().await;
self.update_all_container_stats(&all_ids).await; self.update_all_container_stats(&all_ids).await;
@@ -331,7 +333,7 @@ impl DockerData {
self.initialised = self.app_data.lock().initialised(&all_ids); self.initialised = self.app_data.lock().initialised(&all_ids);
} }
self.app_data.lock().init = true; self.app_data.lock().init = true;
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
} }
/// Handle incoming messages, container controls & all container information update /// Handle incoming messages, container controls & all container information update
@@ -339,27 +341,28 @@ impl DockerData {
while let Some(message) = self.receiver.recv().await { while let Some(message) = self.receiver.recv().await {
let docker = Arc::clone(&self.docker); let docker = Arc::clone(&self.docker);
let app_data = Arc::clone(&self.app_data); let app_data = Arc::clone(&self.app_data);
let loading_uuid = Uuid::new_v4();
match message { match message {
DockerMessage::Pause(id) => { DockerMessage::Pause(id) => {
let loading_spin = self.loading_spin().await; let loading_spin = self.loading_spin(loading_uuid).await;
if docker.pause_container(&id).await.is_err() { if docker.pause_container(&id).await.is_err() {
app_data app_data
.lock() .lock()
.set_error(AppError::DockerCommand(DockerControls::Pause)); .set_error(AppError::DockerCommand(DockerControls::Pause));
}; };
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
} }
DockerMessage::Restart(id) => { DockerMessage::Restart(id) => {
let loading_spin = self.loading_spin().await; let loading_spin = self.loading_spin(loading_uuid).await;
if docker.restart_container(&id, None).await.is_err() { if docker.restart_container(&id, None).await.is_err() {
app_data app_data
.lock() .lock()
.set_error(AppError::DockerCommand(DockerControls::Restart)); .set_error(AppError::DockerCommand(DockerControls::Restart));
}; };
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
} }
DockerMessage::Start(id) => { DockerMessage::Start(id) => {
let loading_spin = self.loading_spin().await; let loading_spin = self.loading_spin(loading_uuid).await;
if docker if docker
.start_container(&id, None::<StartContainerOptions<String>>) .start_container(&id, None::<StartContainerOptions<String>>)
.await .await
@@ -369,20 +372,19 @@ impl DockerData {
.lock() .lock()
.set_error(AppError::DockerCommand(DockerControls::Start)); .set_error(AppError::DockerCommand(DockerControls::Start));
}; };
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
} }
DockerMessage::Stop(id) => { DockerMessage::Stop(id) => {
let loading_spin = self.loading_spin().await; let loading_spin = self.loading_spin(loading_uuid).await;
if docker.stop_container(&id, None).await.is_err() { if docker.stop_container(&id, None).await.is_err() {
app_data app_data
.lock() .lock()
.set_error(AppError::DockerCommand(DockerControls::Stop)); .set_error(AppError::DockerCommand(DockerControls::Stop));
}; };
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
} }
DockerMessage::Unpause(id) => { DockerMessage::Unpause(id) => {
// gen uuid, leading_spin(uuid) let loading_spin = self.loading_spin(loading_uuid).await;
let loading_spin = self.loading_spin().await;
if docker.unpause_container(&id).await.is_err() { if docker.unpause_container(&id).await.is_err() {
app_data app_data
.lock() .lock()
@@ -390,7 +392,7 @@ impl DockerData {
}; };
// loading sping take uuid to remove // loading sping take uuid to remove
// stop_loading_sping(uuid) // stop_loading_sping(uuid)
self.stop_loading_spin(&loading_spin); self.stop_loading_spin(&loading_spin, loading_uuid);
self.update_everything().await; self.update_everything().await;
} }
DockerMessage::Update => self.update_everything().await, DockerMessage::Update => self.update_everything().await,
+9 -10
View File
@@ -1,5 +1,6 @@
use std::{collections::HashMap, fmt}; use std::{collections::{HashMap, HashSet}, fmt};
use tui::layout::{Constraint, Rect}; use tui::layout::{Constraint, Rect};
use uuid::Uuid;
use crate::app_data::Header; use crate::app_data::Header;
@@ -174,9 +175,7 @@ pub struct GuiState {
panel_map: HashMap<SelectablePanel, Rect>, panel_map: HashMap<SelectablePanel, Rect>,
heading_map: HashMap<Header, Rect>, heading_map: HashMap<Header, Rect>,
loading_icon: Loading, loading_icon: Loading,
// Should be a vec, each time loading add a new to the vec, and reset remove from vec is_loading: HashSet<Uuid>,
// for for if is_loading just check if vec is empty or not
is_loading: bool,
pub selected_panel: SelectablePanel, pub selected_panel: SelectablePanel,
pub show_help: bool, pub show_help: bool,
pub info_box_text: Option<String>, pub info_box_text: Option<String>,
@@ -190,7 +189,7 @@ impl GuiState {
loading_icon: Loading::One, loading_icon: Loading::One,
selected_panel: SelectablePanel::Containers, selected_panel: SelectablePanel::Containers,
show_help: false, show_help: false,
is_loading: false, is_loading: HashSet::new(),
info_box_text: None, info_box_text: None,
} }
} }
@@ -250,14 +249,14 @@ impl GuiState {
} }
/// Advance loading animation /// Advance loading animation
pub fn next_loading(&mut self) { pub fn next_loading(&mut self, uuid: Uuid) {
self.loading_icon = self.loading_icon.next(); self.loading_icon = self.loading_icon.next();
self.is_loading = true; self.is_loading.insert(uuid);
} }
/// if is_loading, return loading animation frame, else single space /// if is_loading, return loading animation frame, else single space
pub fn get_loading(&mut self) -> String { pub fn get_loading(&mut self) -> String {
if self.is_loading { if !self.is_loading.is_empty() {
self.loading_icon.to_string() self.loading_icon.to_string()
} else { } else {
String::from(" ") String::from(" ")
@@ -265,8 +264,8 @@ impl GuiState {
} }
/// set is_loading to false, but keep animation frame at same state /// set is_loading to false, but keep animation frame at same state
pub fn reset_loading(&mut self) { pub fn remove_loading(&mut self, uuid: Uuid) {
self.is_loading = false; self.is_loading.remove(&uuid);
} }
/// Set info box content /// Set info box content