diff --git a/CHANGELOG.md b/CHANGELOG.md index 01572cb..85ab2f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +## [0.2.25] - 2024-06-07 + +- improve follow [this](https://users.rust-lang.org/t/i-just-wrote-the-hardest-code-in-my-life-any-improvements/112596) + ## [0.2.24] - 2024-06-06 - fix: batch pull SIGINT hint missed diff --git a/Cargo.lock b/Cargo.lock index cc23b27..6c145d8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,7 +367,7 @@ checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" [[package]] name = "fav" -version = "0.2.24" +version = "0.2.25" dependencies = [ "fav_cli", "tokio", @@ -377,7 +377,7 @@ dependencies = [ [[package]] name = "fav_cli" -version = "0.2.24" +version = "0.2.25" dependencies = [ "chrono", "clap", @@ -425,7 +425,7 @@ dependencies = [ [[package]] name = "fav_utils" -version = "0.0.8" +version = "0.0.9" dependencies = [ "fav_core", "futures", diff --git a/Cargo.toml b/Cargo.toml index 2a46152..b9725f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ resolver = "2" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [workspace.package] -version = "0.2.24" +version = "0.2.25" authors = ["Louis <836250617@qq.com>"] description = "Back up your favorite online resources with CLI." license = "MIT" @@ -16,8 +16,8 @@ documentation = "" [workspace.dependencies] fav_core = { path = "fav_core", version = "0.1.0" } fav_derive = { path = "fav_derive", version = "0.0.1" } -fav_utils = { path = "fav_utils", version = "0.0.8" } -fav_cli = { path = "fav_cli", version = "0.2.24" } +fav_utils = { path = "fav_utils", version = "0.0.9" } +fav_cli = { path = "fav_cli", version = "0.2.25" } [profile.release] lto = "fat" diff --git a/fav_core/src/local.rs b/fav_core/src/local.rs index 8da5f7c..b6bb3e3 100644 --- a/fav_core/src/local.rs +++ b/fav_core/src/local.rs @@ -70,11 +70,11 @@ pub trait SaveLocal: Net { &self, res: &mut R, urls: Vec, - f: F, + cancelled: F, ) -> impl Future> where R: Res, - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send; } diff --git a/fav_core/src/test_utils/impls.rs b/fav_core/src/test_utils/impls.rs index a302e4c..225edd4 100644 --- a/fav_core/src/test_utils/impls.rs +++ b/fav_core/src/test_utils/impls.rs @@ -43,7 +43,7 @@ impl ResOps for App { async fn fetch_res(&self, _: &mut Self::Res, _: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { @@ -52,7 +52,7 @@ impl ResOps for App { async fn pull_res(&self, _: &mut Self::Res, _: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { @@ -65,7 +65,7 @@ impl SetOps for App { async fn fetch_set(&self, _: &mut Self::Set, _: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { diff --git a/fav_utils/Cargo.toml b/fav_utils/Cargo.toml index 9f680a0..e184647 100644 --- a/fav_utils/Cargo.toml +++ b/fav_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fav_utils" -version = "0.0.8" +version = "0.0.9" authors.workspace = true description = "Fav's utils crate; A collection of utilities and data structures for the fav project" license.workspace = true diff --git a/fav_utils/src/bili/local.rs b/fav_utils/src/bili/local.rs index 50ab99a..3e56c47 100644 --- a/fav_utils/src/bili/local.rs +++ b/fav_utils/src/bili/local.rs @@ -4,7 +4,6 @@ use core::future::Future; use fav_core::prelude::*; use reqwest::header::CONTENT_LENGTH; use std::io::{BufWriter, Write as _}; -use tracing::error; impl PathInfo for Bili { #[cfg(test)] @@ -29,7 +28,7 @@ impl SaveLocal for Bili { ) -> FavCoreResult<()> where R: Res, - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { @@ -54,59 +53,45 @@ impl SaveLocal for Bili { let mut file_a = BufWriter::new(tempfile::NamedTempFile::new()?); let mut finish_v = false; let mut finish_a = false; - let mut failed_reason = None; - loop { - tokio::select! { - chunk = resp_v.chunk(), if !finish_v => { - match chunk { - Ok(Some(chunk)) => { - pb.inc(chunk.len() as u64); - file_v.write_all(&chunk).unwrap(); - } - Ok(None) => finish_v = true, - Err(e) => { - error!("Failed to download video: {}", res.id()); - failed_reason = Some(e); - } - } - }, - chunk = resp_a.chunk(), if !finish_a => { - match chunk { - Ok(Some(chunk)) => { - pb.inc(chunk.len() as u64); - file_a.write_all(&chunk).unwrap(); - } - Ok(None) => finish_a = true, - Err(e) => { - error!("Failed to download video: {}", res.id()); - failed_reason = Some(e); - } - } - }, - _ = async {}, if finish_v && finish_a => { - file_v.flush().unwrap(); - file_a.flush().unwrap(); - pb.finish(); - merge( - title, - &id, - file_v.into_inner().unwrap().path().to_str().unwrap(), - file_a.into_inner().unwrap().path().to_str().unwrap(), - ) - .await?; - res.on_status(StatusFlags::SAVED); - return Ok(()) - }, - _ = async {}, if failed_reason.is_some() => { - file_v.into_inner().unwrap().close()?; - file_a.into_inner().unwrap().close()?; - return Err(failed_reason.unwrap().into()); - }, - _ = f() => { - file_v.into_inner().unwrap().close()?; - file_a.into_inner().unwrap().close()?; - return Err(FavCoreError::Cancel) + tokio::select! { + res = async { + while let Some(chunk) = resp_v.chunk().await? { + pb.inc(chunk.len() as u64); + file_v.write_all(&chunk)?; } + finish_v = true; + Ok(()) + }, if !finish_v => { + res + }, + res = async { + while let Some(chunk) = resp_a.chunk().await? { + pb.inc(chunk.len() as u64); + file_a.write_all(&chunk)?; + } + finish_a = true; + Ok(()) + }, if !finish_a => { + res + }, + _ = async {}, if finish_v && finish_a => { + file_v.flush().unwrap(); + file_a.flush().unwrap(); + pb.finish(); + merge( + title, + &id, + file_v.into_inner().unwrap().path().to_str().unwrap(), + file_a.into_inner().unwrap().path().to_str().unwrap(), + ) + .await?; + res.on_status(StatusFlags::SAVED); + Ok(()) + }, + _ = f() => { + file_v.into_inner().unwrap().close()?; + file_a.into_inner().unwrap().close()?; + Err(FavCoreError::Cancel) } } } diff --git a/fav_utils/src/bili/ops.rs b/fav_utils/src/bili/ops.rs index 9877a7b..640782f 100644 --- a/fav_utils/src/bili/ops.rs +++ b/fav_utils/src/bili/ops.rs @@ -7,7 +7,7 @@ use futures::StreamExt; use reqwest::Response; use std::collections::HashMap; use tokio::time::{sleep, Duration}; -use tracing::{error, info}; +use tracing::info; use url::Url; const POLL_INTERVAL: u64 = 3; @@ -65,9 +65,9 @@ impl SetsOps for Bili { impl SetOps for Bili { type Set = BiliSet; - async fn fetch_set(&self, set: &mut Self::Set, f: F) -> FavCoreResult<()> + async fn fetch_set(&self, set: &mut Self::Set, cancelled: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { @@ -80,21 +80,22 @@ impl SetOps for Bili { let params = vec![id.clone(), pn, "20".to_string()]; self.request_proto::(ApiKind::FetchSet, params, "/data") }) - .buffer_unordered(10); - loop { - tokio::select! { - res = stream.next() => { + .buffer_unordered(8); + tokio::select! { + res = async { + while let Some(res) = stream.next().await { match res { - Some(Ok(res)) => *set |= res.with_res_status_on(StatusFlags::FAV), - Some(Err(e)) => error!("{}", e), - None => break + Ok(res) => *set |= res.with_res_status_on(StatusFlags::FAV), + Err(e) => return Err(e), } } - _ = f() => return Err(FavCoreError::Cancel) + info!("Fetch set<{}> successfully.", id); + Ok(()) + } => { + res } + _ = cancelled() => Err(FavCoreError::Cancel) } - info!("Fetch set<{}> successfully.", id); - Ok(()) } } @@ -103,30 +104,30 @@ impl ResOps for Bili { async fn fetch_res(&self, resource: &mut Self::Res, f: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, { let params = vec![resource.bvid.clone()]; tokio::select! { res = self.request_proto::(ApiKind::FetchRes, params, "/data") => { - match res { - Ok(res) => *resource |= res, - Err(e) if matches!(e, FavCoreError::NetworkError(_)) => Err(e)?, - _ => resource.on_status(StatusFlags::EXPIRED), - } - resource.on_status(StatusFlags::FETCHED); - }, + match res { + Ok(res) => *resource |= res, + Err(FavCoreError::NetworkError(e)) => Err(e)?, + _ => resource.on_status(StatusFlags::EXPIRED), + } + resource.on_status(StatusFlags::FETCHED); + Ok(()) + }, _ = f() => { - return Err(FavCoreError::Cancel); + Err(FavCoreError::Cancel) } } - Ok(()) } async fn pull_res(&self, resource: &mut Self::Res, f: F) -> FavCoreResult<()> where - F: Fn() -> Fut + Send, + F: FnOnce() -> Fut + Send, Fut: Future + Send, Any: Send, {