diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 0d59fd3..154216d 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -42,7 +42,8 @@ "terminal.integrated.defaultProfile.linux": "zsh" }, "extensions": [ - "mhutchie.git-graph" + "mhutchie.git-graph", + "Gruntfuggly.todo-tree" ] } }, diff --git a/doc/duck.ai_2025-06-05_04-03-23.md b/doc/duck.ai_2025-06-05_04-03-23.md deleted file mode 100644 index 0403195..0000000 --- a/doc/duck.ai_2025-06-05_04-03-23.md +++ /dev/null @@ -1,87 +0,0 @@ -Diese Konversation wurde mit Duck.ai (https://duck.ai) unter Verwendung des o3-mini-Modells von OpenAI generiert. KI-Chats zeigen möglicherweise falsche oder anstößige Informationen an (weitere Informationen siehe https://duckduckgo.com/duckai/privacy-terms). - -==================== - -Benutzereingabe 1 von 2 - 5.6.2025, 02:27:36: -in Rust, what can I use to display multiple progress bars in the terminal? - -o3-mini: -You can use the indicatif crate, which provides a MultiProgress type that lets you manage and display multiple progress bars concurrently in a terminal. - -Below is a simple example of how to use indicatif’s MultiProgress to display multiple progress bars: - -```rust -use indicatif::{MultiProgress, ProgressBar, ProgressStyle}; -use std::{thread, time::Duration}; - -fn main() { - // Create a MultiProgress container. - let m = MultiProgress::new(); - - // Create several progress bars. - let pb1 = m.add(ProgressBar::new(100)); - pb1.set_style( - ProgressStyle::default_bar() - .template("{msg} {bar:40.cyan/blue} {pos:>3}/{len:3}") - .expect("Failed to set progress bar style"), - ); - pb1.set_message("Downloading"); - - let pb2 = m.add(ProgressBar::new(50)); - pb2.set_style( - ProgressStyle::default_bar() - .template("{msg} {bar:40.green/black} {pos:>3}/{len:3}") - .expect("Failed to set progress bar style"), - ); - pb2.set_message("Processing"); - - // Optionally, spawn threads to update the progress bars concurrently. - let h1 = std::thread::spawn(move || { - for i in 0..=100 { - pb1.set_position(i); - thread::sleep(Duration::from_millis(50)); - } - pb1.finish_with_message("Download complete"); - }); - - let h2 = std::thread::spawn(move || { - for i in 0..=50 { - pb2.set_position(i); - thread::sleep(Duration::from_millis(100)); - } - pb2.finish_with_message("Processing complete"); - }); - - // Wait for threads to complete. MultiProgress takes care of rendering. - h1.join().expect("Thread 1 panicked"); - h2.join().expect("Thread 2 panicked"); - - // You may also iterate on the multi-progress which blocks until all bars finish: - // m.join().unwrap(); -} -``` - -### Steps Explained - -1. **MultiProgress Container**: - Create a `MultiProgress` instance which is used to manage multiple progress bars. - -2. **Progress Bars**: - Create individual progress bars using `MultiProgress::add()`. You can customize each progress bar with a message, style, and length. - -3. **Concurrent Updates**: - The example spawns two threads – one for each progress bar. Each thread updates its progress bar independently using `set_position()` and finishes the progress bar with `finish_with_message()`. - -4. **Thread Joining**: - Ensure the main thread waits for the worker threads to complete to prevent the program from exiting prematurely. - -### Installation - -Make sure to add indicatif to your Cargo.toml: - -```toml -[dependencies] -indicatif = "0.17" # or the latest version available on crates.io -``` - -This crate provides many options for customizing and using progress bars in a concurrent and effective manner. The documentation is available at [indicatif on docs.rs](https://docs.rs/indicatif) for further details and advanced usage. diff --git a/src/appstate.rs b/src/appstate.rs index 9038d0b..0b9dfc8 100644 --- a/src/appstate.rs +++ b/src/appstate.rs @@ -41,6 +41,18 @@ impl FileState { FileState::U(uploading) => uploading.file_name(), } } + + fn start_upload( + self, + http: &ureq::Agent, + alias: &Alias, + share: &Share, + ) -> io::Result { + match self { + FileState::C(checked) => checked.start_upload(http, alias, share), + FileState::U(uploading) => Ok(uploading), + } + } } impl AppState { @@ -110,12 +122,10 @@ impl AppState { http: &ureq::Agent, chunk_size: usize, ) -> Result, UploadError> { - let uploading = match self.files.pop_front() { - Some(FileState::C(checked)) => checked - .start_upload(http, &self.alias, &self.share) - .unwrap(), - Some(FileState::U(uploading)) => uploading, - None => return Ok(None), + let uploading = if let Some(state) = self.files.pop_front() { + state.start_upload(http, &self.alias, &self.share).unwrap() // HACK unwrap + } else { + return Ok(None); }; debug!("{uploading} chunk {chunk_size}"); @@ -156,7 +166,7 @@ impl AppState { debug!("Finished {:?}!", path.display()); bar.finish(); self.progress = None; - self.share.notify(http, &self.alias).unwrap(); + self.share.notify(http, &self.alias).unwrap(); // HACK unwrap Ok(self.files.front().map(drop)) } diff --git a/src/main.rs b/src/main.rs index 7c36d60..7e17e70 100644 --- a/src/main.rs +++ b/src/main.rs @@ -59,7 +59,7 @@ fn main() { match AppState::from_args(&args, &agent) { Ok(state) => { - state.save().unwrap(); + state.save().unwrap(); // HACK unwrap state } Err(e) => { @@ -98,13 +98,13 @@ fn main() { Err(e) => error!("error: {e:?}"), Ok(None) => { info!("all uploads done"); - state.clear().unwrap(); + state.clear().unwrap(); // HACK unwrap break; } _ => (), } - state.save().unwrap(); + state.save().unwrap(); // HACK unwrap stop.load(Ordering::SeqCst).then(|| exit(0)); } } diff --git a/src/sharry/file/checked.rs b/src/sharry/file/checked.rs index db9542c..77e6548 100644 --- a/src/sharry/file/checked.rs +++ b/src/sharry/file/checked.rs @@ -1,7 +1,6 @@ use std::{ ffi::OsStr, - fs, - io::{self, ErrorKind}, + fs, io, path::{Path, PathBuf}, }; @@ -25,14 +24,17 @@ impl FileChecked { }) } else { Err(io::Error::new( - ErrorKind::InvalidInput, + io::ErrorKind::InvalidInput, "Not a regular file", )) } } pub fn file_name(&self) -> &str { - self.path.file_name().unwrap().to_str().unwrap() + self.path + .file_name() + .and_then(OsStr::to_str) + .expect("bad file name") } pub fn start_upload( @@ -46,13 +48,9 @@ impl FileChecked { let res = { let endpoint = alias.get_endpoint(format!("alias/upload/{}/files/tus", share.id)); - let name = (self.path.file_name().and_then(OsStr::to_str)) - .ok_or_else(|| io::Error::new(ErrorKind::NotFound, "bad file name"))? - .to_string(); - (http.post(endpoint)) .sharry_header(alias) - .header("Sharry-File-Name", &name) + .header("Sharry-File-Name", self.file_name()) .header("Upload-Length", size) .send_empty() .map_err(io::Error::other)? diff --git a/src/sharry/file/uploading.rs b/src/sharry/file/uploading.rs index 297196a..048ece4 100644 --- a/src/sharry/file/uploading.rs +++ b/src/sharry/file/uploading.rs @@ -1,6 +1,7 @@ use std::{ + ffi::OsStr, fmt::{Debug, Display}, - fs::File, + fs, io::{self, Read, Seek, SeekFrom}, path::PathBuf, }; @@ -58,7 +59,7 @@ impl FileUploading { fn read_chunk(&self, chunk_size: usize) -> io::Result> { let offset = u64::try_from(self.offset).map_err(io::Error::other)?; - let mut f = File::open(&self.path)?; + let mut f = fs::File::open(&self.path)?; f.seek(SeekFrom::Start(offset))?; let mut bytes = vec![0; chunk_size]; @@ -69,7 +70,10 @@ impl FileUploading { } pub fn file_name(&self) -> &str { - self.path.file_name().unwrap().to_str().unwrap() + self.path + .file_name() + .and_then(OsStr::to_str) + .expect("bad file name") } pub fn offset(&self) -> T