diff --git a/src/core/status.rs b/src/core/status.rs index 86dc11f..7ea0c0f 100644 --- a/src/core/status.rs +++ b/src/core/status.rs @@ -3,31 +3,46 @@ use crate::Result; static STATUS_MAX_RETRY: u32 = 0b100; static STATUS_OK: u32 = 0b111; -/// 用来表示下载的状态,不想写太多列了,所以仅使用一个 u32 表示 -/// 从低位开始,固定每三位表示一种数据的状态 +/// 用来表示下载的状态,不想写太多列了,所以仅使用一个 u32 表示。 +/// 从低位开始,固定每三位表示一种数据的状态,从 0b000 开始,每失败一次加一,最多 0b100(即重试 4 次), +/// 如果成功,将对应的三位设置为 0b111。 +/// 当所有任务都成功或者由于尝试次数过多失败,为 status 最高位打上标记 1,将来不再继续尝试。 pub struct Status(u32); impl Status { - pub fn new(status: u32) -> Self { + /// 如果 status 整体大于等于 1 << 31,则表示任务已经被处理过,不再需要重试。 + /// 数据库可以使用 status < Status::handled() 来筛选需要处理的内容。 + pub fn handled() -> u32 { + 1 << 31 + } + + fn new(status: u32) -> Self { Self(status) } - pub fn should_run(&self) -> [bool; 3] { - let mut result = [false; 3]; - for (i, res) in result.iter_mut().enumerate() { - *res = self.check_continue(i); - } - result + /// 从低到高检查状态,如果该位置的任务应该继续尝试执行,则返回 true,否则返回 false + fn should_run(&self, size: usize) -> Vec { + assert!(size < 10, "u32 can only store 10 status"); + (0..size).map(|x| self.check_continue(x)).collect() } - pub fn update_status(&mut self, result: &[Result<()>]) { - assert!(result.len() == 3, "result length must be 3"); - for (i, res) in result.iter().enumerate().take(3) { + /// 一般仅需要被内部调用 + fn set_flag(&mut self, handled: bool) { + if handled { + self.0 |= 1 << 31; + } else { + self.0 &= !(1 << 31); + } + } + + fn update_status(&mut self, result: &[Result<()>]) { + assert!(result.len() < 10, "u32 can only store 10 status"); + for (i, res) in result.iter().enumerate() { self.set_result(res, i); } - if self.should_run().iter().all(|x| !x) { + if self.should_run(result.len()).iter().all(|x| !x) { // 所有任务都成功或者由于尝试次数过多失败,为 status 最高位打上标记,将来不再重试 - self.0 |= 1 << 31; + self.set_flag(true) } } @@ -60,3 +75,51 @@ impl From for u32 { status.0 } } + +/// 从前到后分别表示:视频封面、分页下载、视频信息 +pub struct VideoStatus(Status); + +impl VideoStatus { + pub fn new(status: u32) -> Self { + Self(Status::new(status)) + } + + pub fn should_run(&self) -> Vec { + self.0.should_run(3) + } + + pub fn update_status(&mut self, result: &[Result<()>]) { + assert!(result.len() == 3, "VideoStatus should have 3 status"); + self.0.update_status(result) + } +} + +impl From for u32 { + fn from(status: VideoStatus) -> Self { + status.0.into() + } +} + +/// 从前到后分别表示:视频封面、视频内容、视频信息 +pub struct PageStatus(Status); + +impl PageStatus { + pub fn new(status: u32) -> Self { + Self(Status::new(status)) + } + + pub fn should_run(&self) -> Vec { + self.0.should_run(3) + } + + pub fn update_status(&mut self, result: &[Result<()>]) { + assert!(result.len() == 3, "PageStatus should have 3 status"); + self.0.update_status(result) + } +} + +impl From for u32 { + fn from(status: PageStatus) -> Self { + status.0.into() + } +}