From f121a04f1bc38370ff666550db1e688c57c49a99 Mon Sep 17 00:00:00 2001 From: n08i40k Date: Thu, 2 Oct 2025 07:55:07 +0400 Subject: [PATCH] refactor: refactor providers code --- Cargo.lock | 3 +- Cargo.toml | 2 +- .../provider-engels-polytechnic/Cargo.toml | 6 +- .../provider-engels-polytechnic/src/lib.rs | 8 +- .../src/parser/error.rs | 38 ++++ .../src/parser/mod.rs | 212 +++++++----------- .../src/parser/worksheet.rs | 31 ++- .../src/updater/error.rs | 33 +++ .../src/{updater.rs => updater/mod.rs} | 106 ++------- .../src/xls_downloader.rs | 4 +- 10 files changed, 206 insertions(+), 237 deletions(-) create mode 100644 providers/provider-engels-polytechnic/src/parser/error.rs create mode 100644 providers/provider-engels-polytechnic/src/updater/error.rs rename providers/provider-engels-polytechnic/src/{updater.rs => updater/mod.rs} (66%) diff --git a/Cargo.lock b/Cargo.lock index c1ac31f..f062066 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3094,7 +3094,7 @@ dependencies = [ [[package]] name = "provider-engels-polytechnic" -version = "0.2.2" +version = "0.2.3" dependencies = [ "async-trait", "base", @@ -3106,7 +3106,6 @@ dependencies = [ "regex", "reqwest", "sentry", - "serde", "strsim", "tokio", "tokio-util", diff --git a/Cargo.toml b/Cargo.toml index 1a79e75..46f3af0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ members = ["actix-macros", "actix-test", "providers"] [package] name = "schedule-parser-rusted" -version = "1.3.0" +version = "1.3.1" edition = "2024" publish = false diff --git a/providers/provider-engels-polytechnic/Cargo.toml b/providers/provider-engels-polytechnic/Cargo.toml index 6736cc3..152a4ab 100644 --- a/providers/provider-engels-polytechnic/Cargo.toml +++ b/providers/provider-engels-polytechnic/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "provider-engels-polytechnic" -version = "0.2.2" +version = "0.2.3" edition = "2024" [features] @@ -14,9 +14,7 @@ tokio-util = "0.7.16" chrono = { version = "0.4.41", features = ["serde"] } -serde = { version = "1.0.219", features = ["derive"] } - -derive_more = { version = "2.0.1", features = ["error", "display"] } +derive_more = { version = "2.0.1", features = ["error", "display", "from"] } utoipa = { version = "5.4.0", features = ["macros", "chrono"] } diff --git a/providers/provider-engels-polytechnic/src/lib.rs b/providers/provider-engels-polytechnic/src/lib.rs index 8b7e9bf..e4eecbf 100644 --- a/providers/provider-engels-polytechnic/src/lib.rs +++ b/providers/provider-engels-polytechnic/src/lib.rs @@ -1,4 +1,4 @@ -use crate::updater::Updater; +pub use crate::updater::{UpdateSource, Updater}; use async_trait::async_trait; use base::{ScheduleProvider, ScheduleSnapshot}; use std::ops::DerefMut; @@ -8,8 +8,6 @@ use tokio::sync::RwLock; use tokio::time::interval; use tokio_util::sync::CancellationToken; -pub use crate::updater::UpdateSource; - mod parser; mod updater; mod xls_downloader; @@ -27,7 +25,7 @@ pub struct EngelsPolytechnicProvider { impl EngelsPolytechnicProvider { pub async fn get( update_source: UpdateSource, - ) -> Result, crate::updater::error::Error> { + ) -> Result, crate::updater::Error> { let (updater, snapshot) = Updater::new(update_source).await?; Ok(Arc::new(Wrapper { @@ -65,7 +63,7 @@ impl ScheduleProvider for Wrapper { this.snapshot = Arc::new(snapshot); }, - Err(updater::error::Error::QueryUrlFailed(updater::error::QueryUrlError::UriFetchFailed)) => {}, + Err(updater::Error::EmptyUri) => {}, Err(err) => { sentry::capture_error(&err); diff --git a/providers/provider-engels-polytechnic/src/parser/error.rs b/providers/provider-engels-polytechnic/src/parser/error.rs new file mode 100644 index 0000000..0635bd9 --- /dev/null +++ b/providers/provider-engels-polytechnic/src/parser/error.rs @@ -0,0 +1,38 @@ +use derive_more::{Display, Error, From}; +use crate::parser::worksheet::CellPos; + +#[derive(Clone, Debug, Display, Error)] +#[display("'{data}' at {pos}")] +pub struct ErrorCell { + pub pos: CellPos, + pub data: String, +} + +impl ErrorCell { + pub fn new(row: u32, column: u32, data: &str) -> Self { + Self { + pos: CellPos { row, column }, + data: data.to_string(), + } + } +} + +#[derive(Debug, Display, Error, From)] +pub enum Error { + #[from] + BadXls(calamine::XlsError), + + #[display("No work sheets found.")] + NoWorkSheets, + + #[display("There is no data on work sheet boundaries.")] + UnknownWorkSheetRange, + + #[display("Failed to read lesson start and end from {_0}.")] + NoLessonBoundaries(ErrorCell), + + #[display("No start and end times matching the lesson (at {_0}) was found.")] + LessonTimeNotFound(CellPos), +} + +pub type Result = core::result::Result; diff --git a/providers/provider-engels-polytechnic/src/parser/mod.rs b/providers/provider-engels-polytechnic/src/parser/mod.rs index 6bcb1b5..0ac915f 100644 --- a/providers/provider-engels-polytechnic/src/parser/mod.rs +++ b/providers/provider-engels-polytechnic/src/parser/mod.rs @@ -1,6 +1,7 @@ +pub use self::error::{Error, Result}; use crate::or_continue; -use crate::parser::error::{Error, ErrorCell, ErrorCellPos}; -use crate::parser::worksheet::WorkSheet; +use crate::parser::error::ErrorCell; +use crate::parser::worksheet::{CellPos, CellRange, WorkSheet}; use crate::parser::LessonParseResult::{Lessons, Street}; use base::LessonType::Break; use base::{ @@ -13,82 +14,12 @@ use std::collections::HashMap; use std::io::Cursor; use std::sync::LazyLock; +mod error; mod macros; mod worksheet; -pub mod error { - use derive_more::{Display, Error}; - use serde::{Serialize, Serializer}; - use std::sync::Arc; - use utoipa::ToSchema; - - #[derive(Clone, Debug, Display, Error, ToSchema)] - #[display("row {row}, column {column}")] - pub struct ErrorCellPos { - pub row: u32, - pub column: u32, - } - - #[derive(Clone, Debug, Display, Error, ToSchema)] - #[display("'{data}' at {pos}")] - pub struct ErrorCell { - pub pos: ErrorCellPos, - pub data: String, - } - - impl ErrorCell { - pub fn new(row: u32, column: u32, data: String) -> Self { - Self { - pos: ErrorCellPos { row, column }, - data, - } - } - } - - #[derive(Clone, Debug, Display, Error, ToSchema)] - pub enum Error { - /// Errors related to reading XLS file. - #[display("{_0:?}: Failed to read XLS file.")] - #[schema(value_type = String)] - BadXLS(Arc), - - /// Not a single sheet was found. - #[display("No work sheets found.")] - NoWorkSheets, - - /// There are no data on the boundaries of the sheet. - #[display("There is no data on work sheet boundaries.")] - UnknownWorkSheetRange, - - /// Failed to read the beginning and end of the lesson from the cell - #[display("Failed to read lesson start and end from {_0}.")] - LessonBoundaries(ErrorCell), - - /// Not found the beginning and the end corresponding to the lesson. - #[display("No start and end times matching the lesson (at {_0}) was found.")] - LessonTimeNotFound(ErrorCellPos), - } - - impl Serialize for Error { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - match self { - Error::BadXLS(_) => serializer.serialize_str("BAD_XLS"), - Error::NoWorkSheets => serializer.serialize_str("NO_WORK_SHEETS"), - Error::UnknownWorkSheetRange => { - serializer.serialize_str("UNKNOWN_WORK_SHEET_RANGE") - } - Error::LessonBoundaries(_) => serializer.serialize_str("GLOBAL_TIME"), - Error::LessonTimeNotFound(_) => serializer.serialize_str("LESSON_TIME_NOT_FOUND"), - } - } - } -} - /// Data cell storing the group name. -pub struct GroupCellInfo { +pub struct GroupMarkup { /// Column index. pub column: u32, @@ -97,7 +28,7 @@ pub struct GroupCellInfo { } /// Data cell storing the line. -pub struct DayCellInfo { +pub struct DayMarkup { /// Line index. pub row: u32, @@ -111,8 +42,13 @@ pub struct DayCellInfo { pub date: DateTime, } +pub struct WorkSheetMarkup { + days: Box<[DayMarkup]>, + groups: Box<[GroupMarkup]>, +} + /// Data on the time of lessons from the second column of the schedule. -pub struct BoundariesCellInfo { +pub struct BoundariesData { /// Temporary segment of the lesson. pub time_range: LessonBoundaries, @@ -123,23 +59,26 @@ pub struct BoundariesCellInfo { pub default_index: Option, /// The frame of the cell. - pub xls_range: ((u32, u32), (u32, u32)), + pub range: CellRange, } + /// Obtaining a "skeleton" schedule from the working sheet. -fn parse_skeleton( - worksheet: &WorkSheet, -) -> Result<(Vec, Vec), crate::parser::error::Error> { - let mut groups: Vec = Vec::new(); - let mut days: Vec<(u32, String, Option>)> = Vec::new(); +fn parse_markup(worksheet: &WorkSheet) -> Result { + struct PartialDayMarkup { + row: u32, + name: String, + date: Option>, + } - let worksheet_start = worksheet - .start() - .ok_or(error::Error::UnknownWorkSheetRange)?; - let worksheet_end = worksheet.end().ok_or(error::Error::UnknownWorkSheetRange)?; + let mut groups: Vec = Vec::new(); + let mut days: Vec = Vec::new(); - let mut row = worksheet_start.0; + let (start_row, start_col) = worksheet.start().ok_or(Error::UnknownWorkSheetRange)?; + let (end_row, end_col) = worksheet.end().ok_or(Error::UnknownWorkSheetRange)?; - while row < worksheet_end.0 { + let mut row = start_row; + + while row < end_row { row += 1; let day_full_name = or_continue!(worksheet.get_string_from_cell(row, 0)); @@ -149,8 +88,8 @@ fn parse_skeleton( // переход на предыдущую строку row -= 1; - for column in (worksheet_start.1 + 2)..=worksheet_end.1 { - groups.push(GroupCellInfo { + for column in (start_col + 2)..=end_col { + groups.push(GroupMarkup { column, name: or_continue!(worksheet.get_string_from_cell(row, column)) .replace(" ", ""), @@ -183,37 +122,44 @@ fn parse_skeleton( (name, date) }; - days.push((row, day_name, day_date)); + days.push(PartialDayMarkup { + row, + name: day_name, + date: day_date, + }); } // fix unparsable day dates let days_max = days.len().min(5); for i in 0..days_max { - if days[i].2.is_none() && days[i + 1].2.is_some() { - days[i].2 = Some(days[i + 1].2.unwrap() - Duration::days(1)); + if days[i].date.is_none() && days[i + 1].date.is_some() { + days[i].date = Some(days[i + 1].date.unwrap() - Duration::days(1)); } } for i in 0..days_max { let i = days_max - i; - if days[i - 1].2.is_none() && days[i].2.is_some() { - days[i - 1].2 = Some(days[i].2.unwrap() - Duration::days(1)); + if days[i - 1].date.is_none() && days[i].date.is_some() { + days[i - 1].date = Some(days[i].date.unwrap() - Duration::days(1)); } } let days = days .into_iter() - .map(|day| DayCellInfo { - row: day.0, + .map(|day| DayMarkup { + row: day.row, column: 0, - name: day.1, - date: day.2.unwrap(), + name: day.name, + date: day.date.unwrap(), }) .collect(); - Ok((days, groups)) + Ok(WorkSheetMarkup { + days, + groups: groups.into_boxed_slice(), + }) } /// The result of obtaining a lesson from the cell. @@ -258,11 +204,11 @@ fn guess_lesson_type(text: &str) -> Option { fn parse_lesson( worksheet: &WorkSheet, day: &Day, - day_boundaries: &[BoundariesCellInfo], - lesson_boundaries: &BoundariesCellInfo, + day_boundaries: &[BoundariesData], + lesson_boundaries: &BoundariesData, group_column: u32, -) -> Result { - let row = lesson_boundaries.xls_range.0.0; +) -> Result { + let row = lesson_boundaries.range.start.row; let name = { let cell_data = match worksheet.get_string_from_cell(row, group_column) { @@ -285,15 +231,12 @@ fn parse_lesson( let (default_range, lesson_time) = { let end_time_arr = day_boundaries .iter() - .filter(|time| time.xls_range.1.0 == cell_range.1.0) - .collect::>(); + .filter(|time| time.range.end.row == cell_range.end.row) + .collect::>(); let end_time = end_time_arr .first() - .ok_or(error::Error::LessonTimeNotFound(ErrorCellPos { - row, - column: group_column, - }))?; + .ok_or(Error::LessonTimeNotFound(CellPos::new(row, group_column)))?; let range: Option<[u8; 2]> = if lesson_boundaries.default_index.is_some() { let default = lesson_boundaries.default_index.unwrap() as u8; @@ -307,8 +250,8 @@ fn parse_lesson( end: end_time.time_range.end, }; - Ok((range, time)) - }?; + (range, time) + }; let ParsedLessonName { name, @@ -319,7 +262,7 @@ fn parse_lesson( { let cabinets: Vec = parse_cabinets( worksheet, - (cell_range.0.0, cell_range.1.0), + (cell_range.start.row, cell_range.end.row), group_column + 1, ); @@ -421,7 +364,7 @@ struct ParsedLessonName { //noinspection GrazieInspection /// Getting the "pure" name of the lesson and list of teachers from the text of the lesson cell. -fn parse_name_and_subgroups(text: &str) -> Result { +fn parse_name_and_subgroups(text: &str) -> Result { // Части названия пары: // 1. Само название. // 2. Список преподавателей и подгрупп. @@ -486,9 +429,7 @@ fn parse_name_and_subgroups(text: &str) -> Result { } }; - let subgroup_index = capture - .get(2) - .and_then(|m| Some(m.as_str().parse::().unwrap())); + let subgroup_index = capture.get(2).map(|m| m.as_str().parse::().unwrap()); let subgroup = Some(LessonSubGroup { cabinet: None, @@ -530,7 +471,7 @@ fn parse_name_and_subgroups(text: &str) -> Result { let lesson_type = if let Some(extra) = extra && extra.len() > 4 { - let result = guess_lesson_type(&extra); + let result = guess_lesson_type(extra); if result.is_none() { #[cfg(not(debug_assertions))] @@ -597,8 +538,8 @@ fn parse_day_boundaries( date: DateTime, row_range: (u32, u32), column: u32, -) -> Result, crate::parser::error::Error> { - let mut day_times: Vec = Vec::new(); +) -> Result> { + let mut day_times: Vec = Vec::new(); for row in row_range.0..row_range.1 { let time_cell = if let Some(str) = worksheet.get_string_from_cell(row, column) { @@ -608,7 +549,7 @@ fn parse_day_boundaries( }; let lesson_time = parse_lesson_boundaries_cell(&time_cell, date).ok_or( - error::Error::LessonBoundaries(ErrorCell::new(row, column, time_cell.clone())), + Error::NoLessonBoundaries(ErrorCell::new(row, column, &time_cell)), )?; // type @@ -633,11 +574,11 @@ fn parse_day_boundaries( None }; - day_times.push(BoundariesCellInfo { + day_times.push(BoundariesData { time_range: lesson_time, lesson_type, default_index, - xls_range: worksheet.get_merge_from_start(row, column), + range: worksheet.get_merge_from_start(row, column), }); } @@ -652,9 +593,9 @@ fn parse_day_boundaries( /// * `week_markup`: markup of the current week. fn parse_week_boundaries( worksheet: &WorkSheet, - week_markup: &[DayCellInfo], -) -> Result>, crate::parser::error::Error> { - let mut result: Vec> = Vec::new(); + week_markup: &[DayMarkup], +) -> Result>> { + let mut result: Vec> = Vec::new(); let worksheet_end_row = worksheet.end().unwrap().0; let lesson_time_column = week_markup[0].column + 1; @@ -773,22 +714,21 @@ fn convert_groups_to_teachers( /// /// * `buffer`: XLS data containing schedule. /// -/// returns: Result -pub fn parse_xls(buffer: &Vec) -> Result { +/// returns: Result +pub fn parse_xls(buffer: &Vec) -> Result { let cursor = Cursor::new(&buffer); - let mut workbook: Xls<_> = - open_workbook_from_rs(cursor).map_err(|e| error::Error::BadXLS(std::sync::Arc::new(e)))?; + let mut workbook: Xls<_> = open_workbook_from_rs(cursor)?; let worksheet = { let (worksheet_name, worksheet) = workbook .worksheets() .first() - .ok_or(error::Error::NoWorkSheets)? + .ok_or(Error::NoWorkSheets)? .clone(); let worksheet_merges = workbook .worksheet_merge_cells(&worksheet_name) - .ok_or(error::Error::NoWorkSheets)?; + .ok_or(Error::NoWorkSheets)?; WorkSheet { data: worksheet, @@ -796,7 +736,11 @@ pub fn parse_xls(buffer: &Vec) -> Result = HashMap::new(); @@ -849,7 +793,7 @@ pub mod test_utils { use super::*; use base::ParsedSchedule; - pub fn test_result() -> Result { + pub fn test_result() -> Result { parse_xls(&include_bytes!("../../../../test-data/engels-polytechnic.xls").to_vec()) } } diff --git a/providers/provider-engels-polytechnic/src/parser/worksheet.rs b/providers/provider-engels-polytechnic/src/parser/worksheet.rs index 9c7fb5e..adc70b6 100644 --- a/providers/provider-engels-polytechnic/src/parser/worksheet.rs +++ b/providers/provider-engels-polytechnic/src/parser/worksheet.rs @@ -1,3 +1,4 @@ +use derive_more::Display; use regex::Regex; use std::ops::Deref; use std::sync::LazyLock; @@ -8,6 +9,18 @@ pub struct WorkSheet { pub merges: Vec, } +#[derive(Clone, Debug, Display, derive_more::Error)] +#[display("row {row}, column {column}")] +pub struct CellPos { + pub row: u32, + pub column: u32, +} + +pub struct CellRange { + pub start: CellPos, + pub end: CellPos, +} + impl Deref for WorkSheet { type Target = calamine::Range; @@ -45,14 +58,26 @@ impl WorkSheet { } /// Obtaining the boundaries of the cell along its upper left coordinate. - pub fn get_merge_from_start(&self, row: u32, column: u32) -> ((u32, u32), (u32, u32)) { + pub fn get_merge_from_start(&self, row: u32, column: u32) -> CellRange { match self .merges .iter() .find(|merge| merge.start.0 == row && merge.start.1 == column) { - Some(merge) => (merge.start, (merge.end.0 + 1, merge.end.1 + 1)), - None => ((row, column), (row + 1, column + 1)), + Some(merge) => CellRange { + start: CellPos::new(merge.start.0, merge.start.1), + end: CellPos::new(merge.end.0 + 1, merge.end.1 + 1), + }, + None => CellRange { + start: CellPos::new(row, column), + end: CellPos::new(row + 1, column + 1), + }, } } } + +impl CellPos { + pub fn new(row: u32, column: u32) -> Self { + Self { row, column } + } +} diff --git a/providers/provider-engels-polytechnic/src/updater/error.rs b/providers/provider-engels-polytechnic/src/updater/error.rs new file mode 100644 index 0000000..ac1e9ab --- /dev/null +++ b/providers/provider-engels-polytechnic/src/updater/error.rs @@ -0,0 +1,33 @@ +use crate::xls_downloader::FetchError; +use derive_more::{Display, Error, From}; + +#[derive(Debug, Display, Error, From)] +pub enum Error { + /// Occurs when the request to the Yandex Cloud API fails. + /// + /// This may be due to network issues, invalid API key, incorrect function ID, or other + /// problems with the Yandex Cloud Function invocation. + #[display("An error occurred during the request to the Yandex Cloud API: {_0}")] + Reqwest(reqwest::Error), + + #[display("Unable to get URI in 3 retries")] + EmptyUri, + + /// The ETag is the same (no update needed). + #[display("The ETag is the same.")] + SameETag, + + /// The URL query for the XLS file failed to execute, either due to network issues or invalid API parameters. + #[display("Failed to fetch URL: {_0}")] + ScheduleFetchFailed(FetchError), + + /// Downloading the XLS file content failed after successfully obtaining the URL. + #[display("Download failed: {_0}")] + ScheduleDownloadFailed(FetchError), + + /// The XLS file could not be parsed into a valid schedule format. + #[from] + InvalidSchedule(crate::parser::Error), +} + +pub type Result = core::result::Result; diff --git a/providers/provider-engels-polytechnic/src/updater.rs b/providers/provider-engels-polytechnic/src/updater/mod.rs similarity index 66% rename from providers/provider-engels-polytechnic/src/updater.rs rename to providers/provider-engels-polytechnic/src/updater/mod.rs index bc2ed77..b3fbc50 100644 --- a/providers/provider-engels-polytechnic/src/updater.rs +++ b/providers/provider-engels-polytechnic/src/updater/mod.rs @@ -1,7 +1,8 @@ +pub use self::error::{Error, Result}; use crate::parser::parse_xls; -use crate::updater::error::{Error, QueryUrlError, SnapshotCreationError}; use crate::xls_downloader::{FetchError, XlsDownloader}; use base::ScheduleSnapshot; +mod error; pub enum UpdateSource { Prepared(ScheduleSnapshot), @@ -19,59 +20,6 @@ pub struct Updater { update_source: UpdateSource, } -pub mod error { - use crate::xls_downloader::FetchError; - use derive_more::{Display, Error}; - - #[derive(Debug, Display, Error)] - pub enum Error { - /// An error occurred while querying the Yandex Cloud API for a URL. - /// - /// This may result from network failures, invalid API credentials, or issues with the Yandex Cloud Function invocation. - /// See [`QueryUrlError`] for more details about specific causes. - QueryUrlFailed(QueryUrlError), - - /// The schedule snapshot creation process failed. - /// - /// This can happen due to URL conflicts (same URL already in use), failed network requests, - /// download errors, or invalid XLS file content. See [`SnapshotCreationError`] for details. - SnapshotCreationFailed(SnapshotCreationError), - } - /// Errors that may occur when querying the Yandex Cloud API to retrieve a URL. - #[derive(Debug, Display, Error)] - pub enum QueryUrlError { - /// Occurs when the request to the Yandex Cloud API fails. - /// - /// This may be due to network issues, invalid API key, incorrect function ID, or other - /// problems with the Yandex Cloud Function invocation. - #[display("An error occurred during the request to the Yandex Cloud API: {_0}")] - RequestFailed(reqwest::Error), - - #[display("Unable to fetch Uri in 3 retries")] - UriFetchFailed, - } - - /// Errors that may occur during the creation of a schedule snapshot. - #[derive(Debug, Display, Error)] - pub enum SnapshotCreationError { - /// The ETag is the same (no update needed). - #[display("The ETag is the same.")] - Same, - - /// The URL query for the XLS file failed to execute, either due to network issues or invalid API parameters. - #[display("Failed to fetch URL: {_0}")] - FetchFailed(FetchError), - - /// Downloading the XLS file content failed after successfully obtaining the URL. - #[display("Download failed: {_0}")] - DownloadFailed(FetchError), - - /// The XLS file could not be parsed into a valid schedule format. - #[display("Schedule data is invalid: {_0}")] - InvalidSchedule(crate::parser::error::Error), - } -} - impl Updater { /// Constructs a new `ScheduleSnapshot` by downloading and parsing schedule data from the specified URL. /// @@ -85,40 +33,33 @@ impl Updater { /// * `url`: The source URL pointing to the XLS file containing schedule data. /// /// returns: Result - pub async fn new_snapshot( - downloader: &mut XlsDownloader, - url: String, - ) -> Result { + async fn new_snapshot(downloader: &mut XlsDownloader, url: String) -> Result { let head_result = downloader.set_url(&url).await.map_err(|error| { - if let FetchError::Unknown(error) = &error { + if let FetchError::Reqwest(error) = &error { sentry::capture_error(&error); } - SnapshotCreationError::FetchFailed(error) + Error::ScheduleFetchFailed(error) })?; if downloader.etag == Some(head_result.etag) { - return Err(SnapshotCreationError::Same); + return Err(Error::SameETag); } let xls_data = downloader .fetch(false) .await .map_err(|error| { - if let FetchError::Unknown(error) = &error { + if let FetchError::Reqwest(error) = &error { sentry::capture_error(&error); } - SnapshotCreationError::DownloadFailed(error) + Error::ScheduleDownloadFailed(error) })? .data .unwrap(); - let parse_result = parse_xls(&xls_data).map_err(|error| { - sentry::capture_error(&error); - - SnapshotCreationError::InvalidSchedule(error) - })?; + let parse_result = parse_xls(&xls_data)?; Ok(ScheduleSnapshot { fetched_at: head_result.requested_at, @@ -144,7 +85,7 @@ impl Updater { /// Result containing: /// - `Ok(String)` - Complete URL constructed from the Function's response /// - `Err(QueryUrlError)` - If the request or response processing fails - async fn query_url(api_key: &str, func_id: &str) -> Result { + async fn query_url(api_key: &str, func_id: &str) -> Result { let client = reqwest::Client::new(); let uri = { @@ -156,7 +97,7 @@ impl Updater { loop { if counter == 3 { - return Err(QueryUrlError::UriFetchFailed); + return Err(Error::EmptyUri); } counter += 1; @@ -169,10 +110,10 @@ impl Updater { .header("Authorization", format!("Api-Key {}", api_key)) .send() .await - .map_err(QueryUrlError::RequestFailed)? + .map_err(Error::Reqwest)? .text() .await - .map_err(QueryUrlError::RequestFailed)?; + .map_err(Error::Reqwest)?; if uri.is_empty() { log::warn!("[{}] Unable to get uri! Retrying in 5 seconds...", counter); @@ -201,7 +142,7 @@ impl Updater { /// Returns `Ok(())` if the snapshot was successfully initialized, or an `Error` if: /// - URL query to Yandex Cloud failed ([`QueryUrlError`]) /// - Schedule snapshot creation failed ([`SnapshotCreationError`]) - pub async fn new(update_source: UpdateSource) -> Result<(Self, ScheduleSnapshot), Error> { + pub async fn new(update_source: UpdateSource) -> Result<(Self, ScheduleSnapshot)> { let mut this = Updater { downloader: XlsDownloader::new(), update_source, @@ -222,19 +163,14 @@ impl Updater { yandex_func_id, } => { log::info!("Obtaining a link using FaaS..."); - Self::query_url(yandex_api_key, yandex_func_id) - .await - .map_err(Error::QueryUrlFailed)? + Self::query_url(yandex_api_key, yandex_func_id).await? } _ => unreachable!(), }; log::info!("For the initial setup, a link {} will be used", url); - let snapshot = Self::new_snapshot(&mut this.downloader, url) - .await - .map_err(Error::SnapshotCreationFailed)?; - + let snapshot = Self::new_snapshot(&mut this.downloader, url).await?; log::info!("Schedule snapshot successfully created!"); Ok((this, snapshot)) @@ -257,7 +193,7 @@ impl Updater { pub async fn update( &mut self, current_snapshot: &ScheduleSnapshot, - ) -> Result { + ) -> Result { if let UpdateSource::Prepared(snapshot) = &self.update_source { let mut snapshot = snapshot.clone(); snapshot.update(); @@ -269,21 +205,19 @@ impl Updater { UpdateSource::GrabFromSite { yandex_api_key, yandex_func_id, - } => Self::query_url(yandex_api_key.as_str(), yandex_func_id.as_str()) - .await - .map_err(Error::QueryUrlFailed)?, + } => Self::query_url(yandex_api_key.as_str(), yandex_func_id.as_str()).await?, _ => unreachable!(), }; let snapshot = match Self::new_snapshot(&mut self.downloader, url).await { Ok(snapshot) => snapshot, - Err(SnapshotCreationError::Same) => { + Err(Error::SameETag) => { let mut clone = current_snapshot.clone(); clone.update(); clone } - Err(error) => return Err(Error::SnapshotCreationFailed(error)), + Err(error) => return Err(error), }; Ok(snapshot) diff --git a/providers/provider-engels-polytechnic/src/xls_downloader.rs b/providers/provider-engels-polytechnic/src/xls_downloader.rs index eb9607e..f81e67b 100644 --- a/providers/provider-engels-polytechnic/src/xls_downloader.rs +++ b/providers/provider-engels-polytechnic/src/xls_downloader.rs @@ -14,7 +14,7 @@ pub enum FetchError { /// Unknown error. #[display("An unknown error occurred while downloading the file.")] #[schema(value_type = String)] - Unknown(Arc), + Reqwest(Arc), /// Server returned a status code different from 200. #[display("Server returned a status code {status_code}.")] @@ -31,7 +31,7 @@ pub enum FetchError { impl FetchError { pub fn unknown(error: Arc) -> Self { - Self::Unknown(error) + Self::Reqwest(error) } pub fn bad_status_code(status_code: u16) -> Self {