Skip to content

Commit 32f6cfa

Browse files
committed
improved error handling for authorization and connection errors
1 parent 4329ff8 commit 32f6cfa

File tree

4 files changed

+43
-23
lines changed

4 files changed

+43
-23
lines changed

tmc-langs-cli/src/main.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
mod app;
44
mod output;
55

6-
use output::{ErrorData, Output, OutputResult, Status};
6+
use output::{ErrorData, Kind, Output, OutputResult, Status};
77

88
use anyhow::{Context, Result};
99
use clap::{ArgMatches, Error, ErrorKind};
@@ -36,13 +36,13 @@ fn main() {
3636
if let Err(e) = run() {
3737
let causes: Vec<String> = e.chain().map(|e| format!("Caused by: {}", e)).collect();
3838
let message = error_message_special_casing(&e);
39-
let http_status_code = find_http_error_code(&e);
39+
let kind = solve_error_kind(&e);
4040
let error_output = Output {
4141
status: Status::Finished,
4242
message: Some(message),
4343
result: OutputResult::Error,
4444
data: Some(ErrorData {
45-
http_status_code,
45+
kind,
4646
trace: causes,
4747
}),
4848
percent_done: 1.0,
@@ -63,13 +63,24 @@ fn main() {
6363
}
6464
}
6565

66-
fn find_http_error_code(e: &anyhow::Error) -> Option<u16> {
66+
fn solve_error_kind(e: &anyhow::Error) -> Kind {
6767
for cause in e.chain() {
68-
if let Some(CoreError::HttpStatus(_, status_code, _)) = cause.downcast_ref::<CoreError>() {
69-
return Some(status_code.as_u16());
68+
// check for authorization error
69+
println!("{:?}", cause);
70+
if let Some(CoreError::HttpError(_, status_code, _)) = cause.downcast_ref::<CoreError>() {
71+
if status_code.as_u16() == 403 {
72+
return Kind::AuthorizationError;
73+
} else {
74+
return Kind::HttpError(status_code.as_u16());
75+
}
76+
}
77+
// check for connection error
78+
if let Some(CoreError::ConnectionError(..)) = cause.downcast_ref::<CoreError>() {
79+
return Kind::ConnectionError;
7080
}
7181
}
72-
None
82+
83+
Kind::Generic
7384
}
7485

7586
// goes through the error chain and returns the first special cased error message, if any

tmc-langs-cli/src/output.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,14 @@ impl From<StatusType> for OutputResult {
5858

5959
#[derive(Debug, Serialize)]
6060
pub struct ErrorData {
61-
pub http_status_code: Option<u16>,
61+
pub kind: Kind,
6262
pub trace: Vec<String>,
6363
}
64+
65+
#[derive(Debug, Serialize)]
66+
#[serde(rename_all = "kebab-case")]
67+
pub enum Kind {
68+
Generic,
69+
AuthorizationError,
70+
ConnectionError,
71+
}

tmc-langs-core/src/error.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//! The core error type.
22
33
use crate::response;
4-
use reqwest::StatusCode;
4+
use reqwest::{Method, StatusCode};
55
use std::path::PathBuf;
66
use thiserror::Error;
77
use url::Url;
@@ -28,17 +28,15 @@ pub enum CoreError {
2828

2929
// network
3030
#[error("HTTP error {1} for {0}: {2}")]
31-
HttpStatus(Url, StatusCode, String),
31+
HttpError(Url, StatusCode, String),
32+
#[error("Connection error trying to {0} {1}")]
33+
ConnectionError(Method, Url, #[source] reqwest::Error),
3234
#[error("OAuth2 password exchange error")]
3335
Token(#[source] Box<TokenError>),
3436
#[error("OAuth2 unexpected token response: {0}")]
3537
TokenParse(String, #[source] serde_json::error::Error),
3638
#[error("Failed to parse as URL: {0}")]
3739
UrlParse(String, #[source] url::ParseError),
38-
#[error("Failed to GET {0}")]
39-
HttpGet(Url, #[source] reqwest::Error),
40-
#[error("Failed to POST {0}")]
41-
HttpPost(Url, #[source] reqwest::Error),
4240
#[error("Failed to write response to {0}")]
4341
HttpWriteResponse(PathBuf, #[source] reqwest::Error),
4442
#[error("Failed to deserialize response as JSON")]

tmc-langs-core/src/tmc_core/api.rs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ use crate::{
99
};
1010

1111
use oauth2::TokenResponse;
12-
use reqwest::blocking::{multipart::Form, RequestBuilder, Response as ReqwestResponse};
12+
use reqwest::{
13+
blocking::{multipart::Form, RequestBuilder, Response as ReqwestResponse},
14+
Method,
15+
};
1316
use serde::de::DeserializeOwned;
1417
use serde_json::Value;
1518
use std::collections::HashMap;
@@ -69,7 +72,7 @@ impl CoreExt for ReqwestResponse {
6972
})
7073
})
7174
.unwrap_or(text);
72-
Err(CoreError::HttpStatus(url, status, parsed))
75+
Err(CoreError::HttpError(url, status, parsed))
7376
}
7477
}
7578
}
@@ -109,7 +112,7 @@ impl TmcCore {
109112
.get(url.clone())
110113
.core_headers(self)
111114
.send()
112-
.map_err(|e| CoreError::HttpGet(url.clone(), e))?
115+
.map_err(|e| CoreError::ConnectionError(Method::GET, url.clone(), e))?
113116
.check_error(url)?
114117
.json_res()
115118
}
@@ -128,7 +131,7 @@ impl TmcCore {
128131
.get(url.clone())
129132
.core_headers(self)
130133
.send()
131-
.map_err(|e| CoreError::HttpGet(url.clone(), e))?
134+
.map_err(|e| CoreError::ConnectionError(Method::GET, url.clone(), e))?
132135
.check_error(url)?
133136
.copy_to(&mut target_file)
134137
.map_err(|e| CoreError::HttpWriteResponse(target.to_path_buf(), e))?;
@@ -144,7 +147,7 @@ impl TmcCore {
144147
.get(url.clone())
145148
.core_headers(self)
146149
.send()
147-
.map_err(|e| CoreError::HttpGet(url.clone(), e))?
150+
.map_err(|e| CoreError::ConnectionError(Method::GET, url.clone(), e))?
148151
.check_error(url)?
149152
.copy_to(&mut target_file)
150153
.map_err(|e| CoreError::HttpWriteResponse(target.to_path_buf(), e))?;
@@ -612,7 +615,7 @@ impl TmcCore {
612615
.multipart(form)
613616
.core_headers(self)
614617
.send()
615-
.map_err(|e| CoreError::HttpPost(submission_url.clone(), e))?
618+
.map_err(|e| CoreError::ConnectionError(Method::POST, submission_url.clone(), e))?
616619
.check_error(submission_url)?
617620
.json_res()?;
618621
log::debug!("received {:?}", res);
@@ -652,7 +655,7 @@ impl TmcCore {
652655
.multipart(form)
653656
.core_headers(self)
654657
.send()
655-
.map_err(|e| CoreError::HttpPost(feedback_url.clone(), e))?
658+
.map_err(|e| CoreError::ConnectionError(Method::POST, feedback_url.clone(), e))?
656659
.check_error(feedback_url)?
657660
.json_res()
658661
}
@@ -677,7 +680,7 @@ impl TmcCore {
677680
.query(&[("review[points]", review_points)])
678681
.core_headers(self)
679682
.send()
680-
.map_err(|e| CoreError::HttpPost(url.clone(), e))?
683+
.map_err(|e| CoreError::ConnectionError(Method::POST, url.clone(), e))?
681684
.check_error(url)?
682685
.json_res()?;
683686
log::trace!("received {:?}", res);
@@ -699,7 +702,7 @@ impl TmcCore {
699702
.post(url.clone())
700703
.multipart(form)
701704
.send()
702-
.map_err(|e| CoreError::HttpPost(url.clone(), e))?
705+
.map_err(|e| CoreError::ConnectionError(Method::POST, url.clone(), e))?
703706
.check_error(url)?
704707
.json_res()
705708
}

0 commit comments

Comments
 (0)