Add TransportError type (#219)
- add TransportError type - adjust Transport trait
This commit is contained in:
parent
2dc6376533
commit
7e04a4240a
2 changed files with 51 additions and 13 deletions
|
@ -7,9 +7,27 @@ use crate::steamapi::{ApiRequest, ApiResponse, BuildableRequest};
|
||||||
|
|
||||||
pub trait Transport {
|
pub trait Transport {
|
||||||
fn send_request<Req: BuildableRequest + MessageFull, Res: MessageFull>(
|
fn send_request<Req: BuildableRequest + MessageFull, Res: MessageFull>(
|
||||||
&mut self,
|
&self,
|
||||||
req: ApiRequest<Req>,
|
req: ApiRequest<Req>,
|
||||||
) -> anyhow::Result<ApiResponse<Res>>;
|
) -> Result<ApiResponse<Res>, TransportError>;
|
||||||
|
|
||||||
fn close(&mut self);
|
fn close(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum TransportError {
|
||||||
|
#[error("Transport failed to parse response headers")]
|
||||||
|
HeaderParseFailure {
|
||||||
|
header: String,
|
||||||
|
#[source]
|
||||||
|
source: anyhow::Error,
|
||||||
|
},
|
||||||
|
#[error("Transport failed to parse response body")]
|
||||||
|
ProtobufError(#[from] protobuf::Error),
|
||||||
|
#[error("Unauthorized: Access token is missing or invalid")]
|
||||||
|
Unauthorized,
|
||||||
|
#[error("NetworkFailure: Transport failed to make request: {0}")]
|
||||||
|
NetworkFailure(#[from] reqwest::Error),
|
||||||
|
#[error("Unexpected error when transport was making request: {0}")]
|
||||||
|
Unknown(#[from] anyhow::Error),
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ use log::{debug, trace};
|
||||||
use protobuf::MessageFull;
|
use protobuf::MessageFull;
|
||||||
use reqwest::{blocking::multipart::Form, Url};
|
use reqwest::{blocking::multipart::Form, Url};
|
||||||
|
|
||||||
use super::Transport;
|
use super::{Transport, TransportError};
|
||||||
use crate::steamapi::{ApiRequest, ApiResponse, BuildableRequest, EResult};
|
use crate::steamapi::{ApiRequest, ApiResponse, BuildableRequest, EResult};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -36,9 +36,9 @@ impl WebApiTransport {
|
||||||
|
|
||||||
impl Transport for WebApiTransport {
|
impl Transport for WebApiTransport {
|
||||||
fn send_request<Req: BuildableRequest + MessageFull, Res: MessageFull>(
|
fn send_request<Req: BuildableRequest + MessageFull, Res: MessageFull>(
|
||||||
&mut self,
|
&self,
|
||||||
apireq: ApiRequest<Req>,
|
apireq: ApiRequest<Req>,
|
||||||
) -> anyhow::Result<ApiResponse<Res>> {
|
) -> anyhow::Result<ApiResponse<Res>, TransportError> {
|
||||||
// All the API endpoints accept 2 data formats: json and protobuf.
|
// All the API endpoints accept 2 data formats: json and protobuf.
|
||||||
// Depending on the http method for the request, the data can go in 2 places:
|
// Depending on the http method for the request, the data can go in 2 places:
|
||||||
// - GET: query string, with the key `input_protobuf_encoded` or `input_json`
|
// - GET: query string, with the key `input_protobuf_encoded` or `input_json`
|
||||||
|
@ -47,7 +47,7 @@ impl Transport for WebApiTransport {
|
||||||
// input protobuf data is always encoded in base64
|
// input protobuf data is always encoded in base64
|
||||||
|
|
||||||
if Req::requires_access_token() && apireq.access_token().is_none() {
|
if Req::requires_access_token() && apireq.access_token().is_none() {
|
||||||
return Err(anyhow::anyhow!("Access token required for this request"));
|
return Err(TransportError::Unauthorized);
|
||||||
}
|
}
|
||||||
|
|
||||||
let url = apireq.build_url();
|
let url = apireq.build_url();
|
||||||
|
@ -76,14 +76,31 @@ impl Transport for WebApiTransport {
|
||||||
debug!("Response HTTP status: {}", status);
|
debug!("Response HTTP status: {}", status);
|
||||||
|
|
||||||
let eresult = if let Some(eresult) = resp.headers().get("x-eresult") {
|
let eresult = if let Some(eresult) = resp.headers().get("x-eresult") {
|
||||||
debug!("HTTP Header x-eresult: {}", eresult.to_str()?);
|
let s = eresult
|
||||||
eresult.to_str()?.parse::<i32>()?.into()
|
.to_str()
|
||||||
|
.map_err(|err| TransportError::HeaderParseFailure {
|
||||||
|
header: "x-eresult".to_owned(),
|
||||||
|
source: err.into(),
|
||||||
|
})?;
|
||||||
|
debug!("HTTP Header x-eresult: {}", s);
|
||||||
|
s.parse::<i32>()
|
||||||
|
.map_err(|err| TransportError::HeaderParseFailure {
|
||||||
|
header: "x-eresult".to_owned(),
|
||||||
|
source: err.into(),
|
||||||
|
})?
|
||||||
|
.into()
|
||||||
} else {
|
} else {
|
||||||
EResult::Invalid
|
EResult::Invalid
|
||||||
};
|
};
|
||||||
let error_msg = if let Some(error_message) = resp.headers().get("x-error_message") {
|
let error_msg = if let Some(error_message) = resp.headers().get("x-error_message") {
|
||||||
debug!("HTTP Header x-error_message: {}", error_message.to_str()?);
|
let s = error_message
|
||||||
Some(error_message.to_str()?.to_owned())
|
.to_str()
|
||||||
|
.map_err(|err| TransportError::HeaderParseFailure {
|
||||||
|
header: "x-error_message".to_owned(),
|
||||||
|
source: err.into(),
|
||||||
|
})?;
|
||||||
|
debug!("HTTP Header x-error_message: {}", s);
|
||||||
|
Some(s.to_owned())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -91,6 +108,10 @@ impl Transport for WebApiTransport {
|
||||||
let bytes = resp.bytes()?;
|
let bytes = resp.bytes()?;
|
||||||
if !status.is_success() {
|
if !status.is_success() {
|
||||||
trace!("Response body (raw): {:?}", bytes);
|
trace!("Response body (raw): {:?}", bytes);
|
||||||
|
|
||||||
|
if status == reqwest::StatusCode::UNAUTHORIZED {
|
||||||
|
return Err(TransportError::Unauthorized);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let res = decode_msg::<Res>(bytes.as_ref())?;
|
let res = decode_msg::<Res>(bytes.as_ref())?;
|
||||||
|
@ -113,9 +134,8 @@ fn encode_msg<T: MessageFull>(msg: &T, config: base64::Config) -> anyhow::Result
|
||||||
Ok(b64)
|
Ok(b64)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn decode_msg<T: MessageFull>(bytes: &[u8]) -> anyhow::Result<T> {
|
fn decode_msg<T: MessageFull>(bytes: &[u8]) -> Result<T, protobuf::Error> {
|
||||||
let msg = T::parse_from_bytes(bytes)?;
|
T::parse_from_bytes(bytes)
|
||||||
Ok(msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in a new issue