more sane error handling with thiserror
This commit is contained in:
215
src/error.rs
Normal file
215
src/error.rs
Normal file
@@ -0,0 +1,215 @@
|
||||
#![allow(unused)]
|
||||
use serde::Deserialize;
|
||||
use std::fmt;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ResponseConversionError {
|
||||
#[error("failed to convert Attribute")]
|
||||
Attribute(#[from] AttributeConversionError),
|
||||
#[error("failed to convert Response, got {0}")]
|
||||
Response(String),
|
||||
#[error("failed to convert Result, got {0}")]
|
||||
Result(String),
|
||||
#[error("failed to convert ContentType, got {0}")]
|
||||
ContentType(String),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum AttributeConversionError {
|
||||
#[error("failed to convert attribute Language, got {0}")]
|
||||
Language(String),
|
||||
#[error("failed to convert attribute Locale, got {0}")]
|
||||
Locale(String),
|
||||
#[error("failed to convert attribute LastVolume, got {0}")]
|
||||
LastVolume(String),
|
||||
#[error("failed to convert attribute LastChapter, got {0}")]
|
||||
LastChapter(String),
|
||||
#[error("failed to convert attribute CreatedAtDateTime, got {0}")]
|
||||
CreatedAtDateTime(String),
|
||||
#[error("failed to convert attribute UpdatedAtDateTime, got {0}")]
|
||||
UpdatedAtDateTime(String),
|
||||
#[error("failed to convert attribute State, got {0}")]
|
||||
State(String),
|
||||
#[error("failed to convert attribute ContentRating, got {0}")]
|
||||
ContentRating(String),
|
||||
#[error("failed to convert attribute Status, got {0}")]
|
||||
Status(String),
|
||||
#[error("failed to convert attribute PublicationDemographic, got {0}")]
|
||||
PublicationDemographic(String),
|
||||
#[error("failed to convert attribute DataType, got {0}")]
|
||||
DataType(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterImageError {
|
||||
#[error("chapter image result {0}")]
|
||||
Result(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum IdQueryResponseError {
|
||||
#[error("failed to convert id query response Result")]
|
||||
Result,
|
||||
#[error("failed to convert id query response Response")]
|
||||
Response,
|
||||
#[error("failed to convert id query response Data")]
|
||||
Data(#[from] ResponseConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum JsonError {
|
||||
#[error("failed to parse json, msg: {0}")]
|
||||
Message(String),
|
||||
#[error("failed to parse json, unexpected end of file")]
|
||||
Eof,
|
||||
#[error("failed to parse json, syntax error")]
|
||||
Syntax,
|
||||
#[error("failed to parse json, expected boolean")]
|
||||
ExpectedBoolean,
|
||||
#[error("failed to parse json, expected integer")]
|
||||
ExpectedInteger,
|
||||
#[error("failed to parse json, expected string")]
|
||||
ExpectedString,
|
||||
#[error("failed to parse json, expected null")]
|
||||
ExpectedNull,
|
||||
#[error("failed to parse json, expected array")]
|
||||
ExpectedArray,
|
||||
#[error("failed to parse json, expected array comma")]
|
||||
ExpectedArrayComma,
|
||||
#[error("failed to parse json, expected array end")]
|
||||
ExpectedArrayEnd,
|
||||
#[error("failed to parse json, expected map")]
|
||||
ExpectedMap,
|
||||
#[error("failed to parse json, expected map colon")]
|
||||
ExpectedMapColon,
|
||||
#[error("failed to parse json, expected map comma")]
|
||||
ExpectedMapComma,
|
||||
#[error("failed to parse json, expected map end")]
|
||||
ExpectedMapEnd,
|
||||
#[error("failed to parse json, expected enum")]
|
||||
ExpectedEnum,
|
||||
#[error("failed to parse json, expected trailing characters")]
|
||||
TrailingCharacters,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterFeedError {
|
||||
#[error("failed to parse json")]
|
||||
Serde(#[from] JsonError),
|
||||
#[error("failed to convert chapter feed")]
|
||||
Conversion(#[from] ChapterFeedConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterFeedConversionError {
|
||||
#[error("failed to convert chapter feed result, got {0}")]
|
||||
Result(String),
|
||||
#[error("failed to convert chapter feed response, got {0}")]
|
||||
Response(String),
|
||||
#[error("failed to convert chapter feed chapter")]
|
||||
Chapter(#[from] ChapterConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterConversionError {
|
||||
#[error("failed to convert chapter DataType, got {0}")]
|
||||
DataType(String),
|
||||
#[error("failed to convert chapter Id, got {0}")]
|
||||
Id(String),
|
||||
#[error("failed to convert chapter Relationship")]
|
||||
Relationship(#[from] ChapterRelationshipError),
|
||||
#[error("failed to convert chapter Attributes")]
|
||||
Attributes(#[from] ChapterAttributeConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterRelationshipError {
|
||||
#[error("failed to convert chapter relationship TypeData, got {0}")]
|
||||
TypeData(String),
|
||||
#[error("failed to convert chapter relationship Id, got {0}")]
|
||||
Id(String),
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum ChapterAttributeConversionError {
|
||||
#[error("unable to convert chapter attribute Volume, got {0}")]
|
||||
Volume(String),
|
||||
#[error("unable to convert chapter attribute Chapter, got {0}")]
|
||||
Chapter(String),
|
||||
#[error("unable to convert chapter attribute CreatedAt, got {0}")]
|
||||
CreatedAt(String),
|
||||
#[error("unable to convert chapter attribute UpdatedAt, got {0}")]
|
||||
UpdatedAt(String),
|
||||
#[error("unable to convert chapter attribute PublishedAt, got {0}")]
|
||||
PublishedAt(String),
|
||||
#[error("unable to convert chapter attribute TranslatedLanguage, got {0}")]
|
||||
TranslatedLanguage(String),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ChapterImagesError {
|
||||
#[error("failed to deserialize chapter images")]
|
||||
Image(#[from] ChapterImageError),
|
||||
#[error("failed to deserialize chapter images")]
|
||||
Content(#[from] ChapterImagesContentError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum SearchResultError {
|
||||
#[error("failed to deserialize json")]
|
||||
Serde(#[from] JsonError),
|
||||
#[error("failed to convert response to SearchResult")]
|
||||
SearchResult(#[from] ResponseConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum IdQueryResultError {
|
||||
#[error("failed to deserialize json")]
|
||||
Serde(#[from] JsonError),
|
||||
#[error("failed to convert to IdQueryResult")]
|
||||
IdQueryResult(#[from] IdQueryResponseError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApiError {
|
||||
pub id: String,
|
||||
pub status: u32,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChapterImagesContentError {
|
||||
pub result: String,
|
||||
pub errors: Vec<ApiError>,
|
||||
}
|
||||
|
||||
impl fmt::Display for ApiError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
format!(
|
||||
"Api Error:\nid: {}\nstatus: {}\ntitle: {}\ndetail: {}\ncontext{:?}",
|
||||
self.id, self.status, self.title, self.detail, self.context
|
||||
)
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for ChapterImagesContentError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
format!(
|
||||
"chapter images content error:\nresult: {}\nerrors: \n{:#?}",
|
||||
self.result, self.errors
|
||||
)
|
||||
.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl serde::de::Error for JsonError {
|
||||
fn custom<T: fmt::Display>(msg: T) -> Self {
|
||||
JsonError::Message(msg.to_string())
|
||||
}
|
||||
}
|
||||
39
src/main.rs
39
src/main.rs
@@ -1,6 +1,7 @@
|
||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
|
||||
use response_deserializer::{ChapterImages, SearchResult};
|
||||
use error::{ChapterImageError, ChapterImagesError};
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::path::Path;
|
||||
@@ -12,6 +13,8 @@ mod response_deserializer;
|
||||
mod select;
|
||||
mod test;
|
||||
mod util;
|
||||
mod error;
|
||||
mod client;
|
||||
|
||||
use response_deserializer::{Chapter, Id};
|
||||
use select::Entry;
|
||||
@@ -34,7 +37,7 @@ async fn main() {
|
||||
let client = &client;
|
||||
let filters = [
|
||||
// ("publicationDemographic[]", "seinen"),
|
||||
//("status[]", "completed"),
|
||||
// ("status[]", "completed"),
|
||||
// ("contentRating[]", "suggestive"),
|
||||
];
|
||||
let limit = config.result_limit;
|
||||
@@ -179,17 +182,25 @@ async fn main() {
|
||||
let result = response_deserializer::deserialize_chapter_images(&json);
|
||||
match result {
|
||||
Ok(v) => break v,
|
||||
Err(e) => {
|
||||
if e.result != "error" {
|
||||
panic!("brotha, api gone wrong (wild)");
|
||||
}
|
||||
for error in e.errors {
|
||||
if error.status == 429 {
|
||||
println!("you sent too many requests");
|
||||
Err(e) => match e {
|
||||
ChapterImagesError::Image(i) => match i {
|
||||
ChapterImageError::Result(s) => {
|
||||
eprintln!("chapter image error: {s}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
},
|
||||
ChapterImagesError::Content(e) => {
|
||||
if e.result != "error" {
|
||||
panic!("brotha, api gone wrong (wild)");
|
||||
}
|
||||
for error in e.errors {
|
||||
if error.status == 429 {
|
||||
eprintln!("you sent too many requests");
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(20000));
|
||||
}
|
||||
std::thread::sleep(std::time::Duration::from_millis(20000));
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
};
|
||||
println!(
|
||||
@@ -350,7 +361,7 @@ async fn get_chapters(client: &Client, id: &Id) -> Result<Vec<Chapter>, reqwest_
|
||||
let params = [("limit", limit.as_str()), ("translatedLanguage[]", "en")];
|
||||
let url = format!("{BASE}/manga/{id}/feed");
|
||||
let json = client.get(url).query(¶ms).send().await?.text().await?;
|
||||
let mut result = response_deserializer::deserialize_chapter_feed(&json);
|
||||
let mut result = response_deserializer::deserialize_chapter_feed(&json).unwrap();
|
||||
|
||||
let mut total_chapters_received = result.limit;
|
||||
while total_chapters_received < result.total {
|
||||
@@ -362,7 +373,7 @@ async fn get_chapters(client: &Client, id: &Id) -> Result<Vec<Chapter>, reqwest_
|
||||
];
|
||||
let url = format!("{BASE}/manga/{id}/feed");
|
||||
let json = client.get(url).query(¶ms).send().await?.text().await?;
|
||||
let mut new_result = response_deserializer::deserialize_chapter_feed(&json);
|
||||
let mut new_result = response_deserializer::deserialize_chapter_feed(&json).unwrap();
|
||||
result.data.append(&mut new_result.data);
|
||||
total_chapters_received += result.limit;
|
||||
}
|
||||
@@ -391,7 +402,7 @@ async fn search(
|
||||
.text()
|
||||
.await
|
||||
.unwrap();
|
||||
response_deserializer::deserializer(&json)
|
||||
response_deserializer::deserializer(&json).unwrap()
|
||||
}
|
||||
|
||||
async fn select_manga_from_search(
|
||||
@@ -473,5 +484,5 @@ async fn id_query_get_info(client: &Client, id: &Id) -> response_deserializer::I
|
||||
.text()
|
||||
.await
|
||||
.unwrap();
|
||||
response_deserializer::deserialize_id_query(&json)
|
||||
response_deserializer::deserialize_id_query(&json).unwrap()
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
// TODO: Remove this
|
||||
#![allow(unused)]
|
||||
// TODO: Remove this
|
||||
use crate::error::*;
|
||||
use chrono::{DateTime, FixedOffset};
|
||||
use serde::Deserialize;
|
||||
use std::fmt::Display;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Id(pub String);
|
||||
@@ -94,7 +95,6 @@ pub enum Language {
|
||||
Greenlandic,
|
||||
Guarani,
|
||||
Gujarati,
|
||||
Gwic,
|
||||
Haitian,
|
||||
Hausa,
|
||||
Hebrew,
|
||||
@@ -168,7 +168,6 @@ pub enum Language {
|
||||
NorwegianNynorsk,
|
||||
Nuosu,
|
||||
Nyanja,
|
||||
Nynors,
|
||||
Occidental,
|
||||
Occitan,
|
||||
Ojibwa,
|
||||
@@ -210,7 +209,6 @@ pub enum Language {
|
||||
Slovenian,
|
||||
Somali,
|
||||
Sotho,
|
||||
SouthNdebele,
|
||||
Spanish,
|
||||
Sundanese,
|
||||
Swahili,
|
||||
@@ -322,23 +320,6 @@ struct ChapterImagesContent {
|
||||
chapter: ChapterImageDataContent,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ApiError {
|
||||
pub id: String,
|
||||
pub status: u32,
|
||||
pub title: String,
|
||||
pub detail: String,
|
||||
pub context: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ChapterImagesContentError {
|
||||
pub result: String,
|
||||
pub errors: Vec<ApiError>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct ChapterImageDataContent {
|
||||
hash: String,
|
||||
@@ -612,19 +593,6 @@ pub struct Titles {
|
||||
pub en: String,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ResponseConversionError {
|
||||
AttributeError(AttributeConversionError),
|
||||
Response(String),
|
||||
Result(String),
|
||||
ContentType(String),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChapterImageError {
|
||||
Result(String),
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for State {
|
||||
type Error = ();
|
||||
|
||||
@@ -635,6 +603,7 @@ impl TryFrom<&str> for State {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for ContentRating {
|
||||
type Error = ();
|
||||
|
||||
@@ -648,6 +617,7 @@ impl TryFrom<&str> for ContentRating {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Language {
|
||||
type Error = ();
|
||||
|
||||
@@ -873,6 +843,7 @@ impl TryFrom<&str> for Language {
|
||||
"zh-ro" => Language::RomanizedChinese,
|
||||
"zh" => Language::SimplifiedChinese,
|
||||
"zh-hk" => Language::TraditionalChinese,
|
||||
"ko-ro" => Language::RomanizedKorean,
|
||||
"pt" => Language::Portuguese,
|
||||
"es" => Language::CastilianSpanish,
|
||||
"es-la" => Language::LatinAmericanSpanish,
|
||||
@@ -883,6 +854,7 @@ impl TryFrom<&str> for Language {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for PublicationDemographic {
|
||||
type Error = ();
|
||||
|
||||
@@ -896,6 +868,7 @@ impl TryFrom<&str> for PublicationDemographic {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for DataType {
|
||||
type Error = ();
|
||||
|
||||
@@ -915,6 +888,7 @@ impl TryFrom<&str> for DataType {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Status {
|
||||
type Error = ();
|
||||
|
||||
@@ -928,6 +902,7 @@ impl TryFrom<&str> for Status {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for ResponseResult {
|
||||
type Error = ();
|
||||
|
||||
@@ -938,6 +913,7 @@ impl TryFrom<&str> for ResponseResult {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for Response {
|
||||
type Error = ();
|
||||
|
||||
@@ -981,28 +957,13 @@ impl TryFrom<SearchResponse> for SearchResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum AttributeConversionError {
|
||||
Language(String),
|
||||
Locale(String),
|
||||
LastVolume(String),
|
||||
LastChapter(String),
|
||||
CreatedAtDateTime(String),
|
||||
UpdatedAtDateTime(String),
|
||||
State(String),
|
||||
ContentRating(String),
|
||||
Status(String),
|
||||
PublicationDemographic(String),
|
||||
DataType(String),
|
||||
}
|
||||
|
||||
impl Display for Id {
|
||||
impl fmt::Display for Id {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.0.fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Status {
|
||||
impl fmt::Display for Status {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Ongoing => "ongoing".fmt(f),
|
||||
@@ -1013,7 +974,7 @@ impl Display for Status {
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ContentRating {
|
||||
impl fmt::Display for ContentRating {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Safe => "safe".fmt(f),
|
||||
@@ -1167,79 +1128,55 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_id_query(json: &str) -> IdQueryResult {
|
||||
let id_query_response: IdQueryResponse = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: {e:#?}");
|
||||
std::fs::write("out.json", json).unwrap();
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
id_query_response.try_into().unwrap()
|
||||
pub fn deserialize_id_query(json: &str) -> Result<IdQueryResult, IdQueryResultError> {
|
||||
let id_query_response: IdQueryResponse = serde_json::from_str(json)
|
||||
.map_err(|e| IdQueryResultError::Serde(JsonError::Message(e.to_string())))?;
|
||||
id_query_response
|
||||
.try_into()
|
||||
.map_err(IdQueryResultError::IdQueryResult)
|
||||
}
|
||||
|
||||
impl TryFrom<IdQueryResponse> for IdQueryResult {
|
||||
type Error = AttributeConversionError;
|
||||
type Error = IdQueryResponseError;
|
||||
fn try_from(response: IdQueryResponse) -> Result<Self, Self::Error> {
|
||||
Ok(IdQueryResult {
|
||||
result: response.result.as_str().try_into().unwrap(),
|
||||
response: response.response.as_str().try_into().unwrap(),
|
||||
data: response.data.try_into().unwrap(),
|
||||
result: response
|
||||
.result
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| IdQueryResponseError::Result)?,
|
||||
response: response
|
||||
.response
|
||||
.as_str()
|
||||
.try_into()
|
||||
.map_err(|_| IdQueryResponseError::Response)?,
|
||||
data: response
|
||||
.data
|
||||
.try_into()
|
||||
.map_err(IdQueryResponseError::Data)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_chapter_feed(json: &str) -> ChapterFeed {
|
||||
pub fn deserialize_chapter_feed(json: &str) -> Result<ChapterFeed, ChapterFeedError> {
|
||||
let chapter_feed_response: ChapterFeedResponse = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: {e:#?}");
|
||||
std::fs::write("chapter_feed.json", json).unwrap();
|
||||
std::process::exit(1);
|
||||
// TODO: Actually do error handling here
|
||||
return Err(ChapterFeedError::Serde(JsonError::Message(e.to_string())));
|
||||
}
|
||||
};
|
||||
chapter_feed_response.try_into().unwrap()
|
||||
chapter_feed_response
|
||||
.try_into()
|
||||
.map_err(|e| ChapterFeedError::Conversion(e))
|
||||
}
|
||||
|
||||
pub fn deserializer(json: &str) -> SearchResult {
|
||||
let search_response: SearchResponse = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: {e:#?}");
|
||||
std::fs::write("search_result.json", json).unwrap();
|
||||
std::process::exit(1);
|
||||
}
|
||||
};
|
||||
let search_result = search_response.try_into();
|
||||
match search_result {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
eprintln!("ERROR: Failed to convert search response: {e:#?}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChapterFeedConversionError {
|
||||
Result(String),
|
||||
Response(String),
|
||||
Chapter(ChapterConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChapterConversionError {
|
||||
DataType(String),
|
||||
Id(String),
|
||||
Relationship(ChapterRelationshipError),
|
||||
Attributes(ChapterAttributeConversionError),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChapterRelationshipError {
|
||||
TypeData(String),
|
||||
Id(String),
|
||||
pub fn deserializer(json: &str) -> Result<SearchResult, SearchResultError> {
|
||||
let search_response: SearchResponse = serde_json::from_str(json)
|
||||
.map_err(|e| SearchResultError::Serde(JsonError::Message(e.to_string())))?;
|
||||
search_response
|
||||
.try_into()
|
||||
.map_err(SearchResultError::SearchResult)
|
||||
}
|
||||
|
||||
impl TryFrom<ChapterFeedResponse> for ChapterFeed {
|
||||
@@ -1308,16 +1245,6 @@ impl TryFrom<ChapterFeedResponse> for ChapterFeed {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ChapterAttributeConversionError {
|
||||
Volume(String),
|
||||
Chapter(String),
|
||||
CreatedAt(String),
|
||||
UpdatedAt(String),
|
||||
PublishedAt(String),
|
||||
TranslatedLanguage(String),
|
||||
}
|
||||
|
||||
impl TryFrom<ChapterAttributesContent> for ChapterAttributes {
|
||||
type Error = ChapterAttributeConversionError;
|
||||
fn try_from(attributes: ChapterAttributesContent) -> Result<Self, Self::Error> {
|
||||
@@ -1373,21 +1300,21 @@ impl TryFrom<ChapterImagesContent> for ChapterImages {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_chapter_images(json: &str) -> Result<ChapterImages, ChapterImagesContentError> {
|
||||
pub fn deserialize_chapter_images(json: &str) -> Result<ChapterImages, ChapterImagesError> {
|
||||
let chapter_images: ChapterImagesContent = match serde_json::from_str(json) {
|
||||
Ok(v) => v,
|
||||
Err(e) => {
|
||||
match serde_json::from_str::<ChapterImagesContentError>(json) {
|
||||
Ok(v) => return Err(v),
|
||||
Err(e) => {
|
||||
Ok(v) => return Err(ChapterImagesError::Content(v)),
|
||||
Err(f) => {
|
||||
// If you can't parse the error then there is no point in continuing.
|
||||
eprintln!("ERROR: {e:#?}");
|
||||
eprintln!("ERROR: {e:#?}, with {f:#?}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Ok(chapter_images.try_into().unwrap())
|
||||
chapter_images.try_into().map_err(ChapterImagesError::Image)
|
||||
}
|
||||
|
||||
impl TryFrom<ContentData> for Manga {
|
||||
@@ -1396,14 +1323,12 @@ impl TryFrom<ContentData> for Manga {
|
||||
Ok(Manga {
|
||||
id: Id(m.id),
|
||||
data_type: (m.type_name.as_str()).try_into().map_err(|_| {
|
||||
ResponseConversionError::AttributeError(AttributeConversionError::DataType(
|
||||
m.type_name,
|
||||
))
|
||||
ResponseConversionError::Attribute(AttributeConversionError::DataType(m.type_name))
|
||||
})?,
|
||||
attributes: m
|
||||
.attributes
|
||||
.try_into()
|
||||
.map_err(ResponseConversionError::AttributeError)?,
|
||||
.map_err(ResponseConversionError::Attribute)?,
|
||||
relationships: {
|
||||
let mut relationships = Vec::with_capacity(m.relationships.len());
|
||||
for m in m.relationships {
|
||||
@@ -1458,7 +1383,7 @@ impl TryFrom<ContentData> for Manga {
|
||||
})
|
||||
}
|
||||
})()
|
||||
.map_err(ResponseConversionError::AttributeError)?,
|
||||
.map_err(ResponseConversionError::Attribute)?,
|
||||
);
|
||||
}
|
||||
relationships
|
||||
|
||||
Reference in New Issue
Block a user