Make the native download progress screen show how many files are left.

This commit is contained in:
Dustin Carlino 2021-04-20 19:05:58 -07:00
parent 3b9a7cfa1f
commit 38f5da4f80
4 changed files with 72 additions and 28 deletions

View File

@ -9,7 +9,8 @@ use crate::sandbox::gameplay::GameplayMode;
use crate::sandbox::SandboxMode;
pub fn import(ctx: &mut EventCtx) -> Transition {
let (_, progress_rx) = futures_channel::mpsc::channel(1);
let (_, outer_progress_rx) = futures_channel::mpsc::channel(1);
let (_, inner_progress_rx) = futures_channel::mpsc::channel(1);
Transition::Push(FutureLoader::<App, Option<String>>::new(
ctx,
Box::pin(async {
@ -21,7 +22,8 @@ pub fn import(ctx: &mut EventCtx) -> Transition {
Box::new(move |_: &App| result);
Ok(wrap)
}),
progress_rx,
outer_progress_rx,
inner_progress_rx,
"Waiting for a file to be chosen",
Box::new(|ctx, app, maybe_path| {
if let Ok(Some(path)) = maybe_path {

View File

@ -476,11 +476,13 @@ impl State<App> for SandboxLoader {
continue;
}
gameplay::LoadScenario::Future(future) => {
let (_, progress_rx) = futures_channel::mpsc::channel(1);
let (_, outer_progress_rx) = futures_channel::mpsc::channel(1);
let (_, inner_progress_rx) = futures_channel::mpsc::channel(1);
return Transition::Push(FutureLoader::<App, Scenario>::new(
ctx,
Box::pin(future),
progress_rx,
outer_progress_rx,
inner_progress_rx,
"Loading Scenario",
Box::new(|_, _, scenario| {
// TODO show error/retry alert?

View File

@ -429,8 +429,11 @@ where
panel: Panel,
receiver: oneshot::Receiver<Result<Box<dyn Send + FnOnce(&A) -> T>>>,
on_load: Option<Box<dyn FnOnce(&mut EventCtx, &mut A, Result<T>) -> Transition<A>>>,
progress_receiver: Option<mpsc::Receiver<String>>,
last_progress: String,
// These're just two different types of progress updates that callers can provide
outer_progress_receiver: Option<mpsc::Receiver<String>>,
inner_progress_receiver: Option<mpsc::Receiver<String>>,
last_outer_progress: String,
last_inner_progress: String,
// If Runtime is dropped, any active tasks will be canceled, so we retain it here even
// though we never access it. It might make more sense for Runtime to live on App if we're
@ -449,7 +452,8 @@ where
pub fn new(
ctx: &mut EventCtx,
future: Pin<Box<dyn Future<Output = Result<Box<dyn Send + FnOnce(&A) -> T>>>>>,
progress_receiver: mpsc::Receiver<String>,
outer_progress_receiver: mpsc::Receiver<String>,
inner_progress_receiver: mpsc::Receiver<String>,
loading_title: &str,
on_load: Box<dyn FnOnce(&mut EventCtx, &mut A, Result<T>) -> Transition<A>>,
) -> Box<dyn State<A>> {
@ -463,8 +467,10 @@ where
panel: ctx.make_loading_screen(Text::from(loading_title)),
receiver,
on_load: Some(on_load),
progress_receiver: Some(progress_receiver),
last_progress: String::new(),
outer_progress_receiver: Some(outer_progress_receiver),
inner_progress_receiver: Some(inner_progress_receiver),
last_outer_progress: String::new(),
last_inner_progress: String::new(),
})
}
@ -472,7 +478,8 @@ where
pub fn new(
ctx: &mut EventCtx,
future: Pin<Box<dyn Send + Future<Output = Result<Box<dyn Send + FnOnce(&A) -> T>>>>>,
progress_receiver: mpsc::Receiver<String>,
outer_progress_receiver: mpsc::Receiver<String>,
inner_progress_receiver: mpsc::Receiver<String>,
loading_title: &str,
on_load: Box<dyn FnOnce(&mut EventCtx, &mut A, Result<T>) -> Transition<A>>,
) -> Box<dyn State<A>> {
@ -489,8 +496,10 @@ where
receiver,
on_load: Some(on_load),
runtime,
progress_receiver: Some(progress_receiver),
last_progress: String::new(),
outer_progress_receiver: Some(outer_progress_receiver),
inner_progress_receiver: Some(inner_progress_receiver),
last_outer_progress: String::new(),
last_inner_progress: String::new(),
})
}
}
@ -508,15 +517,32 @@ where
return on_load(ctx, app, Err(anyhow!("channel canceled")));
}
Ok(None) => {
if let Some(ref mut rx) = self.progress_receiver {
if let Some(ref mut rx) = self.outer_progress_receiver {
// Read all of the progress that's happened
loop {
match rx.try_next() {
Ok(Some(msg)) => {
self.last_progress = msg;
self.last_outer_progress = msg;
}
Ok(None) => {
self.progress_receiver = None;
self.outer_progress_receiver = None;
break;
}
Err(_) => {
// No messages
break;
}
}
}
}
if let Some(ref mut rx) = self.inner_progress_receiver {
loop {
match rx.try_next() {
Ok(Some(msg)) => {
self.last_inner_progress = msg;
}
Ok(None) => {
self.inner_progress_receiver = None;
break;
}
Err(_) => {
@ -533,7 +559,8 @@ where
"Time spent: {}",
Duration::realtime_elapsed(self.started)
)),
Line(&self.last_progress),
Line(&self.last_outer_progress),
Line(&self.last_inner_progress),
]));
// Until the response is received, just ask winit to regularly call event(), so we

View File

@ -40,10 +40,10 @@ fn prettyprint_bytes(bytes: u64) -> String {
}
let kb = (bytes as f64) / 1024.0;
if kb < 1024.0 {
return format!("{} kb", kb as usize);
return format!("{} KB", kb as usize);
}
let mb = kb / 1024.0;
format!("{} mb", mb as usize)
format!("{} MB", mb as usize)
}
/// Prompt to download a missing city. On either success or failure (maybe the player choosing to
@ -70,16 +70,19 @@ pub fn prompt_to_download_missing_data<A: AppLike + 'static>(
}
let cities = vec![map_name.to_data_pack_name()];
let (progress_tx, progress_rx) = futures_channel::mpsc::channel(1000);
let (outer_progress_tx, outer_progress_rx) = futures_channel::mpsc::channel(1000);
let (inner_progress_tx, inner_progress_rx) = futures_channel::mpsc::channel(1000);
Transition::Replace(FutureLoader::<A, Vec<String>>::new(
ctx,
Box::pin(async {
let result = download_cities(cities, progress_tx).await;
let result =
download_cities(cities, outer_progress_tx, inner_progress_tx).await;
let wrap: Box<dyn Send + FnOnce(&A) -> Vec<String>> =
Box::new(move |_: &A| result);
Ok(wrap)
}),
progress_rx,
outer_progress_rx,
inner_progress_rx,
"Downloading missing files",
Box::new(|ctx, _, maybe_messages| {
let messages = match maybe_messages {
@ -97,7 +100,11 @@ pub fn prompt_to_download_missing_data<A: AppLike + 'static>(
))
}
async fn download_cities(cities: Vec<String>, mut progress: mpsc::Sender<String>) -> Vec<String> {
async fn download_cities(
cities: Vec<String>,
mut outer_progress: mpsc::Sender<String>,
mut inner_progress: mpsc::Sender<String>,
) -> Vec<String> {
let mut data_packs = DataPacks {
runtime: BTreeSet::new(),
input: BTreeSet::new(),
@ -117,24 +124,30 @@ async fn download_cities(cities: Vec<String>, mut progress: mpsc::Sender<String>
let num_files = manifest.entries.len();
let mut messages = Vec::new();
let mut files_so_far = 0;
for (path, entry) in manifest.entries {
files_so_far += 1;
let local_path = abstio::path(path.strip_prefix("data/").unwrap());
let url = format!(
"http://abstreet.s3-website.us-east-2.amazonaws.com/{}/{}.gz",
version, path
);
// TODO How can we have two streams, and have this logging be the "outer" one? And show x /
// y files or something.
info!(
"Downloading {} ({})",
if let Err(err) = outer_progress.try_send(format!(
"Downloading file {}/{}: {} ({})",
files_so_far,
num_files,
url,
prettyprint_bytes(entry.compressed_size_bytes)
);
)) {
warn!("Couldn't send progress: {}", err);
}
match abstio::download_bytes(&url, &mut progress)
match abstio::download_bytes(&url, &mut inner_progress)
.await
.and_then(|bytes| {
// TODO Instead of holding everything in memory like this, we could also try to
// stream the gunzipping and output writing
info!("Decompressing {}", path);
std::fs::create_dir_all(std::path::Path::new(&local_path).parent().unwrap())
.unwrap();