1
0

Misc improvements and fixes (#109)

* now utilizing tracing better

* better tracing

* fix mac vs pc oppositional env var issue

* modified loading package

* added droppable loadingbarid that sends completion message

* loading bar

* regressed bug on mac

* fixed non-updated loading bar on playground

* Loading bar improvements

---------

Co-authored-by: Jai A <jaiagr+gpg@pm.me>
This commit is contained in:
Wyatt Verchere
2023-05-08 12:14:08 -07:00
committed by GitHub
parent c79d5c32a6
commit 65c1942037
33 changed files with 726 additions and 294 deletions

View File

@@ -1,9 +1,11 @@
use super::LoadingBarId;
use crate::event::{
EventError, LoadingBar, LoadingBarType, ProcessPayloadType,
ProfilePayloadType,
};
use futures::prelude::*;
use std::path::PathBuf;
use tracing::warn;
#[cfg(feature = "tauri")]
use crate::event::{
@@ -13,6 +15,9 @@ use crate::event::{
use tauri::Manager;
use uuid::Uuid;
#[cfg(feature = "cli")]
const CLI_PROGRESS_BAR_TOTAL: u64 = 1000;
/*
Events are a way we can communciate with the Tauri frontend from the Rust backend.
We include a feature flag for Tauri, so that we can compile this code without Tauri.
@@ -45,18 +50,34 @@ pub async fn init_loading(
bar_type: LoadingBarType,
total: f64,
title: &str,
) -> crate::Result<Uuid> {
) -> crate::Result<LoadingBarId> {
let event_state = crate::EventState::get().await?;
let key = Uuid::new_v4();
let key = LoadingBarId(Uuid::new_v4());
event_state.loading_bars.write().await.insert(
key,
key.0,
LoadingBar {
loading_bar_id: key,
loading_bar_uuid: key.0,
message: title.to_string(),
total,
current: 0.0,
bar_type,
#[cfg(feature = "cli")]
cli_progress_bar: {
let pb = indicatif::ProgressBar::new(CLI_PROGRESS_BAR_TOTAL);
pb.set_position(0);
pb.set_style(
indicatif::ProgressStyle::default_bar()
.template(
"{spinner:.green} [{elapsed_precise}] [{bar:.lime/green}] {pos}/{len} {msg}",
).unwrap()
.progress_chars("#>-"),
);
//pb.set_message(title);
pb
},
},
);
// attempt an initial loading_emit event to the frontend
@@ -65,13 +86,13 @@ pub async fn init_loading(
}
pub async fn init_or_edit_loading(
id: Option<Uuid>,
id: Option<LoadingBarId>,
bar_type: LoadingBarType,
total: f64,
title: &str,
) -> crate::Result<Uuid> {
) -> crate::Result<LoadingBarId> {
if let Some(id) = id {
edit_loading(id, bar_type, total, title).await?;
edit_loading(&id, bar_type, total, title).await?;
Ok(id)
} else {
@@ -80,21 +101,27 @@ pub async fn init_or_edit_loading(
}
// Edits a loading bar's type
// This also resets the bar's current progress to 0
pub async fn edit_loading(
id: Uuid,
id: &LoadingBarId,
bar_type: LoadingBarType,
total: f64,
title: &str,
) -> crate::Result<()> {
let event_state = crate::EventState::get().await?;
if let Some(bar) = event_state.loading_bars.write().await.get_mut(&id) {
if let Some(bar) = event_state.loading_bars.write().await.get_mut(&id.0) {
bar.bar_type = bar_type;
bar.total = total;
bar.message = title.to_string();
bar.current = 0.0;
#[cfg(feature = "cli")]
{
bar.cli_progress_bar.reset(); // indicatif::ProgressBar::new(CLI_PROGRESS_BAR_TOTAL as u64);
}
};
emit_loading(&id, 0.0, None).await?;
emit_loading(id, 0.0, None).await?;
Ok(())
}
@@ -104,18 +131,19 @@ pub async fn edit_loading(
// message is the message to display on the loading bar- if None, use the loading bar's default one
// By convention, fraction is the fraction of the progress bar that is filled
#[allow(unused_variables)]
#[tracing::instrument(level = "debug")]
pub async fn emit_loading(
key: &Uuid,
key: &LoadingBarId,
increment_frac: f64,
message: Option<&str>,
) -> crate::Result<()> {
let event_state = crate::EventState::get().await?;
let mut loading_bar = event_state.loading_bars.write().await;
let loading_bar = match loading_bar.get_mut(key) {
let loading_bar = match loading_bar.get_mut(&key.0) {
Some(f) => f,
None => {
return Err(EventError::NoLoadingBar(*key).into());
return Err(EventError::NoLoadingBar(key.0).into());
}
};
@@ -128,6 +156,22 @@ pub async fn emit_loading(
} else {
Some(display_frac)
};
// Emit event to indicatif progress bar
#[cfg(feature = "cli")]
{
loading_bar.cli_progress_bar.set_message(
message
.map(|x| x.to_string())
.unwrap_or(loading_bar.message.clone()),
);
loading_bar.cli_progress_bar.set_position(
((loading_bar.current / loading_bar.total)
* CLI_PROGRESS_BAR_TOTAL as f64)
.round() as u64,
);
}
// Emit event to tauri
#[cfg(feature = "tauri")]
event_state
@@ -138,7 +182,7 @@ pub async fn emit_loading(
fraction: display_frac,
message: message.unwrap_or(&loading_bar.message).to_string(),
event: loading_bar.bar_type.clone(),
loader_uuid: loading_bar.loading_bar_id,
loader_uuid: loading_bar.loading_bar_uuid,
},
)
.map_err(EventError::from)?;
@@ -162,6 +206,7 @@ pub async fn emit_warning(message: &str) -> crate::Result<()> {
)
.map_err(EventError::from)?;
}
warn!("{}", message);
Ok(())
}
@@ -235,7 +280,6 @@ macro_rules! count {
() => (0usize);
( $x:tt $($xs:tt)* ) => (1usize + $crate::count!($($xs)*));
}
#[cfg(feature = "tauri")]
#[macro_export]
macro_rules! loading_join {
($key:expr, $total:expr, $message:expr; $($task:expr $(,)?)+) => {
@@ -272,24 +316,16 @@ macro_rules! loading_join {
};
}
#[cfg(not(feature = "tauri"))]
#[macro_export]
macro_rules! loading_join {
($start:expr, $end:expr, $message:expr; $($future:expr $(,)?)+) => {{
tokio::try_join!($($future),+)
}};
}
// A drop in replacement to try_for_each_concurrent that emits loading events as it goes
// Key is the key to use for which loading bar- a LoadingBarId. If None, does nothing
// Total is the total amount of progress that the loading bar should take up by all futures in this (will be split evenly amongst them).
// If message is Some(t) you will overwrite this loading bar's message with a custom one
// num_futs is the number of futures that will be run, which is needed as we allow Iterator to be passed in, which doesn't have a size
#[cfg(feature = "tauri")]
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
stream: I,
limit: Option<usize>,
key: Option<&Uuid>,
key: Option<&LoadingBarId>,
total: f64,
num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
message: Option<&str>,
@@ -316,31 +352,3 @@ where
})
.await
}
#[cfg(not(feature = "tauri"))]
pub async fn loading_try_for_each_concurrent<I, F, Fut, T>(
stream: I,
limit: Option<usize>,
_key: Option<&Uuid>,
_total: f64,
_num_futs: usize, // num is in here as we allow Iterator to be passed in, which doesn't have a size
_message: Option<&str>,
f: F,
) -> crate::Result<()>
where
I: futures::TryStreamExt<Error = crate::Error> + TryStream<Ok = T>,
F: FnMut(T) -> Fut + Send,
Fut: Future<Output = crate::Result<()>> + Send,
T: Send,
{
let mut f = f;
stream
.try_for_each_concurrent(limit, |item| {
let f = f(item);
async move {
f.await?;
Ok(())
}
})
.await
}

View File

@@ -48,11 +48,18 @@ impl EventState {
Ok(EVENT_STATE.get().ok_or(EventError::NotInitialized)?.clone())
}
// Values provided should not be used directly, as they are clones and are not guaranteed to be up-to-date
pub async fn list_progress_bars() -> crate::Result<HashMap<Uuid, LoadingBar>>
{
let value = Self::get().await?;
let read = value.loading_bars.read().await;
Ok(read.clone())
let mut display_list: HashMap<Uuid, LoadingBar> = HashMap::new();
for (uuid, loading_bar) in read.iter() {
display_list.insert(*uuid, loading_bar.clone());
}
Ok(display_list)
}
// Initialization requires no app handle in non-tauri mode, so we can just use the same function
@@ -64,16 +71,84 @@ impl EventState {
#[derive(Serialize, Debug, Clone)]
pub struct LoadingBar {
pub loading_bar_id: Uuid,
// loading_bar_uuid not be used directly by external functions as it may not reflect the current state of the loading bar/hashmap
pub loading_bar_uuid: Uuid,
pub message: String,
pub total: f64,
pub current: f64,
pub bar_type: LoadingBarType,
#[cfg(feature = "cli")]
#[serde(skip)]
pub cli_progress_bar: indicatif::ProgressBar,
}
#[derive(Serialize, Debug)]
pub struct LoadingBarId(Uuid);
// When Loading bar id is dropped, we should remove it from the hashmap
impl Drop for LoadingBarId {
fn drop(&mut self) {
let loader_uuid = self.0;
let _event = LoadingBarType::StateInit;
let _message = "finished".to_string();
tokio::spawn(async move {
if let Ok(event_state) = crate::EventState::get().await {
{
let mut bars = event_state.loading_bars.write().await;
bars.remove(&loader_uuid);
}
}
});
}
}
// When Loading bar is dropped, should attempt to throw out one last event to indicate that the loading bar is done
#[cfg(feature = "tauri")]
impl Drop for LoadingBar {
fn drop(&mut self) {
let loader_uuid = self.loading_bar_uuid;
let event = self.bar_type.clone();
let fraction = self.current / self.total;
let cli_progress_bar = self.cli_progress_bar.clone();
tokio::spawn(async move {
#[cfg(feature = "tauri")]
{
use tauri::Manager;
if let Ok(event_state) = crate::EventState::get().await {
let _ = event_state.app.emit_all(
"loading",
LoadingPayload {
fraction: None,
message: "Completed".to_string(),
event,
loader_uuid,
},
);
tracing::debug!(
"Exited at {fraction} for loading bar: {:?}",
loader_uuid
);
}
}
// Emit event to indicatif progress bar arc
#[cfg(feature = "cli")]
{
cli_progress_bar.finish();
}
});
}
}
#[derive(Serialize, Deserialize, Clone, Debug, Hash, PartialEq, Eq)]
#[serde(tag = "type")]
#[serde(rename_all = "snake_case")]
pub enum LoadingBarType {
StateInit,
PackFileDownload {
pack_name: Option<String>,
pack_version: String,
},
PackDownload {
pack_name: String,
pack_id: Option<String>,
@@ -124,6 +199,7 @@ pub struct ProfilePayload {
pub event: ProfilePayloadType,
}
#[derive(Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum ProfilePayloadType {
Created,
Added, // also triggered when Created