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())
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/main.rs
23
src/main.rs
@@ -1,6 +1,7 @@
|
|||||||
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
use reqwest_middleware::{ClientBuilder, ClientWithMiddleware};
|
||||||
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
|
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
|
||||||
use response_deserializer::{ChapterImages, SearchResult};
|
use response_deserializer::{ChapterImages, SearchResult};
|
||||||
|
use error::{ChapterImageError, ChapterImagesError};
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -12,6 +13,8 @@ mod response_deserializer;
|
|||||||
mod select;
|
mod select;
|
||||||
mod test;
|
mod test;
|
||||||
mod util;
|
mod util;
|
||||||
|
mod error;
|
||||||
|
mod client;
|
||||||
|
|
||||||
use response_deserializer::{Chapter, Id};
|
use response_deserializer::{Chapter, Id};
|
||||||
use select::Entry;
|
use select::Entry;
|
||||||
@@ -179,17 +182,25 @@ async fn main() {
|
|||||||
let result = response_deserializer::deserialize_chapter_images(&json);
|
let result = response_deserializer::deserialize_chapter_images(&json);
|
||||||
match result {
|
match result {
|
||||||
Ok(v) => break v,
|
Ok(v) => break v,
|
||||||
Err(e) => {
|
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" {
|
if e.result != "error" {
|
||||||
panic!("brotha, api gone wrong (wild)");
|
panic!("brotha, api gone wrong (wild)");
|
||||||
}
|
}
|
||||||
for error in e.errors {
|
for error in e.errors {
|
||||||
if error.status == 429 {
|
if error.status == 429 {
|
||||||
println!("you sent too many requests");
|
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!(
|
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 params = [("limit", limit.as_str()), ("translatedLanguage[]", "en")];
|
||||||
let url = format!("{BASE}/manga/{id}/feed");
|
let url = format!("{BASE}/manga/{id}/feed");
|
||||||
let json = client.get(url).query(¶ms).send().await?.text().await?;
|
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;
|
let mut total_chapters_received = result.limit;
|
||||||
while total_chapters_received < result.total {
|
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 url = format!("{BASE}/manga/{id}/feed");
|
||||||
let json = client.get(url).query(¶ms).send().await?.text().await?;
|
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);
|
result.data.append(&mut new_result.data);
|
||||||
total_chapters_received += result.limit;
|
total_chapters_received += result.limit;
|
||||||
}
|
}
|
||||||
@@ -391,7 +402,7 @@ async fn search(
|
|||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
response_deserializer::deserializer(&json)
|
response_deserializer::deserializer(&json).unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn select_manga_from_search(
|
async fn select_manga_from_search(
|
||||||
@@ -473,5 +484,5 @@ async fn id_query_get_info(client: &Client, id: &Id) -> response_deserializer::I
|
|||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
response_deserializer::deserialize_id_query(&json)
|
response_deserializer::deserialize_id_query(&json).unwrap()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
// TODO: Remove this
|
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
// TODO: Remove this
|
||||||
|
use crate::error::*;
|
||||||
use chrono::{DateTime, FixedOffset};
|
use chrono::{DateTime, FixedOffset};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::fmt::Display;
|
use std::fmt;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Id(pub String);
|
pub struct Id(pub String);
|
||||||
@@ -94,7 +95,6 @@ pub enum Language {
|
|||||||
Greenlandic,
|
Greenlandic,
|
||||||
Guarani,
|
Guarani,
|
||||||
Gujarati,
|
Gujarati,
|
||||||
Gwic,
|
|
||||||
Haitian,
|
Haitian,
|
||||||
Hausa,
|
Hausa,
|
||||||
Hebrew,
|
Hebrew,
|
||||||
@@ -168,7 +168,6 @@ pub enum Language {
|
|||||||
NorwegianNynorsk,
|
NorwegianNynorsk,
|
||||||
Nuosu,
|
Nuosu,
|
||||||
Nyanja,
|
Nyanja,
|
||||||
Nynors,
|
|
||||||
Occidental,
|
Occidental,
|
||||||
Occitan,
|
Occitan,
|
||||||
Ojibwa,
|
Ojibwa,
|
||||||
@@ -210,7 +209,6 @@ pub enum Language {
|
|||||||
Slovenian,
|
Slovenian,
|
||||||
Somali,
|
Somali,
|
||||||
Sotho,
|
Sotho,
|
||||||
SouthNdebele,
|
|
||||||
Spanish,
|
Spanish,
|
||||||
Sundanese,
|
Sundanese,
|
||||||
Swahili,
|
Swahili,
|
||||||
@@ -322,23 +320,6 @@ struct ChapterImagesContent {
|
|||||||
chapter: ChapterImageDataContent,
|
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)]
|
#[derive(Debug, Deserialize)]
|
||||||
struct ChapterImageDataContent {
|
struct ChapterImageDataContent {
|
||||||
hash: String,
|
hash: String,
|
||||||
@@ -612,19 +593,6 @@ pub struct Titles {
|
|||||||
pub en: String,
|
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 {
|
impl TryFrom<&str> for State {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -635,6 +603,7 @@ impl TryFrom<&str> for State {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for ContentRating {
|
impl TryFrom<&str> for ContentRating {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -648,6 +617,7 @@ impl TryFrom<&str> for ContentRating {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for Language {
|
impl TryFrom<&str> for Language {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -873,6 +843,7 @@ impl TryFrom<&str> for Language {
|
|||||||
"zh-ro" => Language::RomanizedChinese,
|
"zh-ro" => Language::RomanizedChinese,
|
||||||
"zh" => Language::SimplifiedChinese,
|
"zh" => Language::SimplifiedChinese,
|
||||||
"zh-hk" => Language::TraditionalChinese,
|
"zh-hk" => Language::TraditionalChinese,
|
||||||
|
"ko-ro" => Language::RomanizedKorean,
|
||||||
"pt" => Language::Portuguese,
|
"pt" => Language::Portuguese,
|
||||||
"es" => Language::CastilianSpanish,
|
"es" => Language::CastilianSpanish,
|
||||||
"es-la" => Language::LatinAmericanSpanish,
|
"es-la" => Language::LatinAmericanSpanish,
|
||||||
@@ -883,6 +854,7 @@ impl TryFrom<&str> for Language {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for PublicationDemographic {
|
impl TryFrom<&str> for PublicationDemographic {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -896,6 +868,7 @@ impl TryFrom<&str> for PublicationDemographic {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for DataType {
|
impl TryFrom<&str> for DataType {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -915,6 +888,7 @@ impl TryFrom<&str> for DataType {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for Status {
|
impl TryFrom<&str> for Status {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -928,6 +902,7 @@ impl TryFrom<&str> for Status {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for ResponseResult {
|
impl TryFrom<&str> for ResponseResult {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -938,6 +913,7 @@ impl TryFrom<&str> for ResponseResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for Response {
|
impl TryFrom<&str> for Response {
|
||||||
type Error = ();
|
type Error = ();
|
||||||
|
|
||||||
@@ -981,28 +957,13 @@ impl TryFrom<SearchResponse> for SearchResult {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl fmt::Display for Id {
|
||||||
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 {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.fmt(f)
|
self.0.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Status {
|
impl fmt::Display for Status {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Ongoing => "ongoing".fmt(f),
|
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 {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Safe => "safe".fmt(f),
|
Self::Safe => "safe".fmt(f),
|
||||||
@@ -1167,79 +1128,55 @@ impl TryFrom<ContentAttributes> for MangaAttributes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize_id_query(json: &str) -> IdQueryResult {
|
pub fn deserialize_id_query(json: &str) -> Result<IdQueryResult, IdQueryResultError> {
|
||||||
let id_query_response: IdQueryResponse = match serde_json::from_str(json) {
|
let id_query_response: IdQueryResponse = serde_json::from_str(json)
|
||||||
Ok(v) => v,
|
.map_err(|e| IdQueryResultError::Serde(JsonError::Message(e.to_string())))?;
|
||||||
Err(e) => {
|
id_query_response
|
||||||
eprintln!("ERROR: {e:#?}");
|
.try_into()
|
||||||
std::fs::write("out.json", json).unwrap();
|
.map_err(IdQueryResultError::IdQueryResult)
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
id_query_response.try_into().unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<IdQueryResponse> for IdQueryResult {
|
impl TryFrom<IdQueryResponse> for IdQueryResult {
|
||||||
type Error = AttributeConversionError;
|
type Error = IdQueryResponseError;
|
||||||
fn try_from(response: IdQueryResponse) -> Result<Self, Self::Error> {
|
fn try_from(response: IdQueryResponse) -> Result<Self, Self::Error> {
|
||||||
Ok(IdQueryResult {
|
Ok(IdQueryResult {
|
||||||
result: response.result.as_str().try_into().unwrap(),
|
result: response
|
||||||
response: response.response.as_str().try_into().unwrap(),
|
.result
|
||||||
data: response.data.try_into().unwrap(),
|
.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) {
|
let chapter_feed_response: ChapterFeedResponse = match serde_json::from_str(json) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!("ERROR: {e:#?}");
|
// TODO: Actually do error handling here
|
||||||
std::fs::write("chapter_feed.json", json).unwrap();
|
return Err(ChapterFeedError::Serde(JsonError::Message(e.to_string())));
|
||||||
std::process::exit(1);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
chapter_feed_response.try_into().unwrap()
|
chapter_feed_response
|
||||||
|
.try_into()
|
||||||
|
.map_err(|e| ChapterFeedError::Conversion(e))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserializer(json: &str) -> SearchResult {
|
pub fn deserializer(json: &str) -> Result<SearchResult, SearchResultError> {
|
||||||
let search_response: SearchResponse = match serde_json::from_str(json) {
|
let search_response: SearchResponse = serde_json::from_str(json)
|
||||||
Ok(v) => v,
|
.map_err(|e| SearchResultError::Serde(JsonError::Message(e.to_string())))?;
|
||||||
Err(e) => {
|
search_response
|
||||||
eprintln!("ERROR: {e:#?}");
|
.try_into()
|
||||||
std::fs::write("search_result.json", json).unwrap();
|
.map_err(SearchResultError::SearchResult)
|
||||||
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),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ChapterFeedResponse> for ChapterFeed {
|
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 {
|
impl TryFrom<ChapterAttributesContent> for ChapterAttributes {
|
||||||
type Error = ChapterAttributeConversionError;
|
type Error = ChapterAttributeConversionError;
|
||||||
fn try_from(attributes: ChapterAttributesContent) -> Result<Self, Self::Error> {
|
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) {
|
let chapter_images: ChapterImagesContent = match serde_json::from_str(json) {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
match serde_json::from_str::<ChapterImagesContentError>(json) {
|
match serde_json::from_str::<ChapterImagesContentError>(json) {
|
||||||
Ok(v) => return Err(v),
|
Ok(v) => return Err(ChapterImagesError::Content(v)),
|
||||||
Err(e) => {
|
Err(f) => {
|
||||||
// If you can't parse the error then there is no point in continuing.
|
// 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);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(chapter_images.try_into().unwrap())
|
chapter_images.try_into().map_err(ChapterImagesError::Image)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<ContentData> for Manga {
|
impl TryFrom<ContentData> for Manga {
|
||||||
@@ -1396,14 +1323,12 @@ impl TryFrom<ContentData> for Manga {
|
|||||||
Ok(Manga {
|
Ok(Manga {
|
||||||
id: Id(m.id),
|
id: Id(m.id),
|
||||||
data_type: (m.type_name.as_str()).try_into().map_err(|_| {
|
data_type: (m.type_name.as_str()).try_into().map_err(|_| {
|
||||||
ResponseConversionError::AttributeError(AttributeConversionError::DataType(
|
ResponseConversionError::Attribute(AttributeConversionError::DataType(m.type_name))
|
||||||
m.type_name,
|
|
||||||
))
|
|
||||||
})?,
|
})?,
|
||||||
attributes: m
|
attributes: m
|
||||||
.attributes
|
.attributes
|
||||||
.try_into()
|
.try_into()
|
||||||
.map_err(ResponseConversionError::AttributeError)?,
|
.map_err(ResponseConversionError::Attribute)?,
|
||||||
relationships: {
|
relationships: {
|
||||||
let mut relationships = Vec::with_capacity(m.relationships.len());
|
let mut relationships = Vec::with_capacity(m.relationships.len());
|
||||||
for m in m.relationships {
|
for m in m.relationships {
|
||||||
@@ -1458,7 +1383,7 @@ impl TryFrom<ContentData> for Manga {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
.map_err(ResponseConversionError::AttributeError)?,
|
.map_err(ResponseConversionError::Attribute)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
relationships
|
relationships
|
||||||
|
|||||||
Reference in New Issue
Block a user