Update Error handle

This commit is contained in:
2023-10-05 08:26:31 +00:00
committed by GitHub
parent 1b7867151f
commit 60d2d6dd87
7 changed files with 175 additions and 2 deletions

View File

@@ -259,6 +259,9 @@ pub async fn download_artwork(
let app_ok = helper.refresh_token().is_some();
if app_ok && helper.use_app_api() {
if let Err(e) = download_artwork_app(ac, pw.clone(), id).await {
if e.is_not_found() {
return Err(e);
}
println!("{}{}", gettext("Warning: Failed to download artwork with app api, trying to download with web api: "), e);
download_artwork_web(pw.clone(), id).await?;
}

View File

@@ -28,6 +28,7 @@ pub enum PixivDownloaderError {
OpenSSLError(openssl::error::ErrorStack),
ParseIntError(std::num::ParseIntError),
ReqwestError(reqwest::Error),
PixivAppError(crate::pixivapp::error::PixivAppError),
}
impl std::error::Error for PixivDownloaderError {}
@@ -44,6 +45,15 @@ impl From<http::header::InvalidHeaderValue> for PixivDownloaderError {
}
}
impl PixivDownloaderError {
pub fn is_not_found(&self) -> bool {
match self {
Self::PixivAppError(e) => e.is_not_found(),
_ => false,
}
}
}
#[macro_export]
macro_rules! concat_pixiv_downloader_error {
($exp1:expr, $exp2:expr) => {

View File

@@ -41,6 +41,7 @@ mod parser;
mod pixiv_app;
mod pixiv_link;
mod pixiv_web;
mod pixivapp;
mod push;
mod retry_interval;
#[cfg(feature = "server")]

View File

@@ -5,6 +5,7 @@ use crate::ext::atomic::AtomicQuick;
use crate::ext::replace::ReplaceWith2;
use crate::ext::rw_lock::GetRwLock;
use crate::opthelper::OptHelper;
use crate::pixivapp::error::handle_error;
use crate::webclient::{ReqMiddleware, WebClient};
use crate::{get_helper, gettext};
use chrono::{DateTime, Local, SecondsFormat, Utc};
@@ -69,6 +70,7 @@ pub struct PixivAppClientInternal {
}
impl PixivAppClientInternal {
#[cfg(not(feature = "db"))]
pub fn new() -> Self {
Self {
client: WebClient::default(),
@@ -247,8 +249,7 @@ impl PixivAppClientInternal {
)
.await
.ok_or(gettext("Failed to get illust details."))?;
let status = re.status();
let obj = json::parse(&re.text().await?)?;
let obj = handle_error(re).await?;
if get_helper().verbose() {
println!("{}{}", gettext("Illust details:"), obj.pretty(2).as_str());
}
@@ -264,6 +265,7 @@ pub struct PixivAppClient {
}
impl PixivAppClient {
#[cfg(not(feature = "db"))]
pub fn new() -> Self {
let r = Self {
internal: Arc::new(PixivAppClientInternal::new()),

4
src/pixivapp/check.rs Normal file
View File

@@ -0,0 +1,4 @@
/// Check if have data that we don't handle
pub trait CheckUnknown {
fn check_unknown(&self) -> Result<(), String>;
}

150
src/pixivapp/error.rs Normal file
View File

@@ -0,0 +1,150 @@
use super::check::CheckUnknown;
use crate::error::PixivDownloaderError;
use json::JsonValue;
use proc_macros::check_json_keys;
use reqwest::{Response, StatusCode};
#[derive(Debug)]
pub struct PixivAppHTTPError {
status: StatusCode,
}
impl PixivAppHTTPError {
pub fn new(status: StatusCode) -> Self {
Self { status }
}
}
impl std::fmt::Display for PixivAppHTTPError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{} {}",
self.status.as_u16(),
self.status.canonical_reason().unwrap_or("")
)
}
}
pub struct PixivAppAPIError {
data: JsonValue,
status: StatusCode,
}
impl CheckUnknown for PixivAppAPIError {
fn check_unknown(&self) -> Result<(), String> {
check_json_keys!(
"user_message"+,
"message"+,
"reason"+,
"user_message_details"
);
Ok(())
}
}
impl PixivAppAPIError {
pub fn new(data: JsonValue, status: StatusCode) -> Self {
Self { data, status }
}
pub fn user_message(&self) -> Option<&str> {
self.data["user_message"].as_str()
}
pub fn message(&self) -> Option<&str> {
self.data["message"].as_str()
}
pub fn reason(&self) -> Option<&str> {
self.data["reason"].as_str()
}
pub fn user_message_details(&self) -> &JsonValue {
&self.data["user_message_details"]
}
}
impl std::error::Error for PixivAppAPIError {}
impl std::fmt::Debug for PixivAppAPIError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("PixivAppAPIError")
.field("user_message", &self.user_message())
.field("message", &self.message())
.field("reason", &self.reason())
.field("user_message_details", &self.user_message_details())
.field("status", &self.status)
.finish_non_exhaustive()
}
}
impl std::fmt::Display for PixivAppAPIError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(user_message) = self.user_message() {
write!(
f,
"{} ({} {})",
user_message,
self.status.as_u16(),
self.status.canonical_reason().unwrap_or("")
)
} else if let Some(message) = self.message() {
write!(f, "{} (", message)?;
if let Some(reason) = self.reason() {
write!(f, "{}, ", reason)?;
}
write!(
f,
"{} {})",
self.status.as_u16(),
self.status.canonical_reason().unwrap_or("")
)
} else {
write!(
f,
"{} {}: ",
self.status.as_u16(),
self.status.canonical_reason().unwrap_or("")
)?;
write!(f, "{}", self.data.pretty(2).as_str())
}
}
}
#[derive(Debug, derive_more::From, derive_more::Display)]
pub enum PixivAppError {
HTTP(PixivAppHTTPError),
API(PixivAppAPIError),
}
impl PixivAppError {
pub fn is_not_found(&self) -> bool {
match self {
Self::HTTP(err) => err.status.as_u16() == 404,
Self::API(err) => err.status.as_u16() == 404,
}
}
}
pub async fn handle_error(res: Response) -> Result<JsonValue, PixivDownloaderError> {
let status = res.status();
if let Ok(obj) = json::parse(&res.text().await?) {
let err = &obj["error"];
if status.is_success() && err.is_null() {
Ok(obj)
} else if !err.is_null() {
Err(PixivDownloaderError::from(PixivAppError::from(
PixivAppAPIError::new(err.clone(), status),
)))
} else {
Err(PixivDownloaderError::from(PixivAppError::from(
PixivAppHTTPError::new(status),
)))
}
} else {
Err(PixivDownloaderError::from(PixivAppError::from(
PixivAppHTTPError::new(status),
)))
}
}

3
src/pixivapp/mod.rs Normal file
View File

@@ -0,0 +1,3 @@
pub mod check;
/// Error handling for pixiv app api
pub mod error;