diff --git a/cli/file_fetcher.rs b/cli/file_fetcher.rs index f714a18ca7..8738e4f486 100644 --- a/cli/file_fetcher.rs +++ b/cli/file_fetcher.rs @@ -1,15 +1,17 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. use crate::args::CacheSetting; +use crate::auth_tokens::AuthToken; use crate::auth_tokens::AuthTokens; use crate::cache::HttpCache; use crate::colors; +use crate::http_util; use crate::http_util::resolve_redirect_from_response; use crate::http_util::CacheSemantics; -use crate::http_util::FetchOnceArgs; -use crate::http_util::FetchOnceResult; +use crate::http_util::HeadersMap; use crate::http_util::HttpClient; use crate::util::progress_bar::ProgressBar; +use crate::util::progress_bar::UpdateGuard; use crate::util::text_encoding; use data_url::DataUrl; @@ -21,6 +23,7 @@ use deno_core::error::AnyError; use deno_core::futures; use deno_core::futures::future::FutureExt; use deno_core::parking_lot::Mutex; +use deno_core::url::Url; use deno_core::ModuleSpecifier; use deno_runtime::deno_fetch::reqwest::header::HeaderValue; use deno_runtime::deno_fetch::reqwest::header::ACCEPT; @@ -470,6 +473,7 @@ impl FileFetcher { maybe_accept: maybe_accept.clone(), maybe_etag, maybe_auth_token, + maybe_progress_guard: maybe_progress_guard.as_ref(), }, ) .await? @@ -637,14 +641,30 @@ impl FileFetcher { } } +#[derive(Debug, Eq, PartialEq)] +enum FetchOnceResult { + Code(Vec, HeadersMap), + NotModified, + Redirect(Url, HeadersMap), +} + +#[derive(Debug)] +struct FetchOnceArgs<'a> { + pub url: Url, + pub maybe_accept: Option, + pub maybe_etag: Option, + pub maybe_auth_token: Option, + pub maybe_progress_guard: Option<&'a UpdateGuard>, +} + /// Asynchronously fetches the given HTTP URL one pass only. /// If no redirect is present and no error occurs, /// yields Code(ResultPayload). /// If redirect occurs, does not follow and /// yields Redirect(url). -async fn fetch_once( +async fn fetch_once<'a>( http_client: &HttpClient, - args: FetchOnceArgs, + args: FetchOnceArgs<'a>, ) -> Result { let mut request = http_client.get_no_redirect(args.url.clone()); @@ -710,7 +730,11 @@ async fn fetch_once( return Err(err); } - let body = response.bytes().await?.to_vec(); + let body = http_util::get_response_body_with_progress( + response, + args.maybe_progress_guard, + ) + .await?; Ok(FetchOnceResult::Code(body, result_headers)) } @@ -1760,6 +1784,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1787,6 +1812,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1815,6 +1841,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1837,6 +1864,7 @@ mod tests { maybe_accept: None, maybe_etag: Some("33a64df551425fcc55e".to_string()), maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1857,6 +1885,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1887,6 +1916,7 @@ mod tests { maybe_accept: Some("application/json".to_string()), maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1913,6 +1943,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1953,6 +1984,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -1990,6 +2022,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2025,6 +2058,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2066,6 +2100,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2110,6 +2145,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2133,6 +2169,7 @@ mod tests { maybe_accept: None, maybe_etag: Some("33a64df551425fcc55e".to_string()), maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2170,6 +2207,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; @@ -2200,6 +2238,7 @@ mod tests { maybe_accept: None, maybe_etag: None, maybe_auth_token: None, + maybe_progress_guard: None, }, ) .await; diff --git a/cli/http_util.rs b/cli/http_util.rs index 966ba693ec..e7fbcd1f31 100644 --- a/cli/http_util.rs +++ b/cli/http_util.rs @@ -1,5 +1,4 @@ // Copyright 2018-2022 the Deno authors. All rights reserved. MIT license. -use crate::auth_tokens::AuthToken; use crate::util::progress_bar::UpdateGuard; use crate::version::get_user_agent; @@ -218,21 +217,6 @@ impl CacheSemantics { } } -#[derive(Debug, Eq, PartialEq)] -pub enum FetchOnceResult { - Code(Vec, HeadersMap), - NotModified, - Redirect(Url, HeadersMap), -} - -#[derive(Debug)] -pub struct FetchOnceArgs { - pub url: Url, - pub maybe_accept: Option, - pub maybe_etag: Option, - pub maybe_auth_token: Option, -} - #[derive(Debug, Clone)] pub struct HttpClient(reqwest::Client); @@ -312,24 +296,9 @@ impl HttpClient { ); } - if let Some(progress_guard) = progress_guard { - if let Some(total_size) = response.content_length() { - progress_guard.set_total_size(total_size); - let mut current_size = 0; - let mut data = Vec::with_capacity(total_size as usize); - let mut stream = response.bytes_stream(); - while let Some(item) = stream.next().await { - let bytes = item?; - current_size += bytes.len() as u64; - progress_guard.set_position(current_size); - data.extend(bytes.into_iter()); - } - return Ok(Some(data)); - } - } - - let bytes = response.bytes().await?; - Ok(Some(bytes.into())) + get_response_body_with_progress(response, progress_guard) + .await + .map(Some) } async fn get_redirected_response( @@ -358,6 +327,29 @@ impl HttpClient { } } +pub async fn get_response_body_with_progress( + response: reqwest::Response, + progress_guard: Option<&UpdateGuard>, +) -> Result, AnyError> { + if let Some(progress_guard) = progress_guard { + if let Some(total_size) = response.content_length() { + progress_guard.set_total_size(total_size); + let mut current_size = 0; + let mut data = Vec::with_capacity(total_size as usize); + let mut stream = response.bytes_stream(); + while let Some(item) = stream.next().await { + let bytes = item?; + current_size += bytes.len() as u64; + progress_guard.set_position(current_size); + data.extend(bytes.into_iter()); + } + return Ok(data); + } + } + let bytes = response.bytes().await?; + Ok(bytes.into()) +} + #[cfg(test)] mod test { use super::*; diff --git a/cli/main.rs b/cli/main.rs index ecff408d7c..462e9e0a45 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -260,6 +260,10 @@ pub fn main() { util::windows::ensure_stdio_open(); #[cfg(windows)] colors::enable_ansi(); // For Windows 10 + deno_runtime::permissions::set_prompt_callbacks( + Box::new(util::draw_thread::DrawThread::hide), + Box::new(util::draw_thread::DrawThread::show), + ); let args: Vec = env::args().collect(); diff --git a/cli/util/draw_thread.rs b/cli/util/draw_thread.rs index b069a14b7c..49c45312c0 100644 --- a/cli/util/draw_thread.rs +++ b/cli/util/draw_thread.rs @@ -30,7 +30,6 @@ impl Drop for DrawThreadGuard { #[derive(Debug, Clone)] struct InternalEntry { - priority: u8, id: u16, renderer: Arc, } @@ -69,6 +68,13 @@ static INTERNAL_STATE: Lazy>> = Lazy::new(|| { })) }); +static IS_TTY_WITH_CONSOLE_SIZE: Lazy = Lazy::new(|| { + atty::is(atty::Stream::Stderr) + && console_size() + .map(|s| s.cols > 0 && s.rows > 0) + .unwrap_or(false) +}); + /// The draw thread is responsible for rendering multiple active /// `DrawThreadRenderer`s to stderr. It is global because the /// concept of stderr in the process is also a global concept. @@ -78,31 +84,17 @@ pub struct DrawThread; impl DrawThread { /// Is using a draw thread supported. pub fn is_supported() -> bool { - atty::is(atty::Stream::Stderr) - && log::log_enabled!(log::Level::Info) - && console_size() - .map(|s| s.cols > 0 && s.rows > 0) - .unwrap_or(false) + // don't put the log level in the lazy because the + // log level may change as the application runs + log::log_enabled!(log::Level::Info) && *IS_TTY_WITH_CONSOLE_SIZE } - /// Adds a renderer to the draw thread with a given priority. - /// Renderers are sorted by priority with higher priority - /// entries appearing at the bottom of the screen. - pub fn add_entry( - priority: u8, - renderer: Arc, - ) -> DrawThreadGuard { + /// Adds a renderer to the draw thread. + pub fn add_entry(renderer: Arc) -> DrawThreadGuard { let internal_state = &*INTERNAL_STATE; let mut internal_state = internal_state.lock(); let id = internal_state.next_entry_id; - internal_state.entries.push(InternalEntry { - id, - priority, - renderer, - }); - internal_state - .entries - .sort_by(|a, b| a.priority.cmp(&b.priority)); + internal_state.entries.push(InternalEntry { id, renderer }); if internal_state.next_entry_id == u16::MAX { internal_state.next_entry_id = 0; @@ -116,16 +108,15 @@ impl DrawThread { } /// Hides the draw thread. - #[allow(dead_code)] pub fn hide() { let internal_state = &*INTERNAL_STATE; let mut internal_state = internal_state.lock(); internal_state.hide = true; + Self::clear_and_stop_draw_thread(&mut internal_state); } /// Shows the draw thread if it was previously hidden. - #[allow(dead_code)] pub fn show() { let internal_state = &*INTERNAL_STATE; let mut internal_state = internal_state.lock(); @@ -159,7 +150,11 @@ impl DrawThread { } fn maybe_start_draw_thread(internal_state: &mut InternalState) { - if internal_state.has_draw_thread || internal_state.hide { + if internal_state.has_draw_thread + || internal_state.hide + || internal_state.entries.is_empty() + || !DrawThread::is_supported() + { return; } @@ -168,7 +163,7 @@ impl DrawThread { let drawer_id = internal_state.drawer_id; tokio::task::spawn_blocking(move || { - let mut previous_size = console_size().unwrap(); + let mut previous_size = console_size(); loop { let mut delay_ms = 120; { @@ -182,6 +177,10 @@ impl DrawThread { internal_state.entries.clone() }; + // this should always be set, but have the code handle + // it not being for some reason + let size = console_size(); + // Call into the renderers outside the lock to prevent a potential // deadlock between our internal state lock and the renderers // internal state lock. @@ -194,13 +193,12 @@ impl DrawThread { // which attempts to acquire the other thread's Render's internal // lock causing a deadlock let mut text = String::new(); - let size = console_size().unwrap(); if size != previous_size { // means the user is actively resizing the console... // wait a little bit until they stop resizing previous_size = size; delay_ms = 200; - } else { + } else if let Some(size) = size { let mut should_new_line_next = false; for entry in entries { let new_text = entry.renderer.render(&size); @@ -210,23 +208,23 @@ impl DrawThread { should_new_line_next = !new_text.is_empty(); text.push_str(&new_text); } - } - // now reacquire the lock, ensure we should still be drawing, then - // output the text - { - let internal_state = &*INTERNAL_STATE; - let mut internal_state = internal_state.lock(); - if internal_state.should_exit_draw_thread(drawer_id) { - break; + // now reacquire the lock, ensure we should still be drawing, then + // output the text + { + let internal_state = &*INTERNAL_STATE; + let mut internal_state = internal_state.lock(); + if internal_state.should_exit_draw_thread(drawer_id) { + break; + } + internal_state.static_text.eprint_with_size( + &text, + console_static_text::ConsoleSize { + cols: Some(size.cols as u16), + rows: Some(size.rows as u16), + }, + ); } - internal_state.static_text.eprint_with_size( - &text, - console_static_text::ConsoleSize { - cols: Some(size.cols as u16), - rows: Some(size.rows as u16), - }, - ); } } diff --git a/cli/util/progress_bar/mod.rs b/cli/util/progress_bar/mod.rs index 8651e2d209..a20ac43c94 100644 --- a/cli/util/progress_bar/mod.rs +++ b/cli/util/progress_bar/mod.rs @@ -23,6 +23,7 @@ mod renderer; // Inspired by Indicatif, but this custom implementation allows // for more control over what's going on under the hood. +#[derive(Debug)] pub struct UpdateGuard { maybe_entry: Option, } @@ -183,7 +184,7 @@ impl ProgressBarInner { { internal_state.start_time = SystemTime::now(); internal_state.draw_thread_guard = - Some(DrawThread::add_entry(0, Arc::new(self.clone()))); + Some(DrawThread::add_entry(Arc::new(self.clone()))); } } } diff --git a/runtime/permissions/prompter.rs b/runtime/permissions/prompter.rs index d231f73448..93c321107c 100644 --- a/runtime/permissions/prompter.rs +++ b/runtime/permissions/prompter.rs @@ -38,11 +38,11 @@ pub fn permission_prompt( } pub fn set_prompt_callbacks( - before_callback: Option, - after_callback: Option, + before_callback: PromptCallback, + after_callback: PromptCallback, ) { - *MAYBE_BEFORE_PROMPT_CALLBACK.lock() = before_callback; - *MAYBE_AFTER_PROMPT_CALLBACK.lock() = after_callback; + *MAYBE_BEFORE_PROMPT_CALLBACK.lock() = Some(before_callback); + *MAYBE_AFTER_PROMPT_CALLBACK.lock() = Some(after_callback); } pub type PromptCallback = Box;