#![allow(missing_docs, unused_doc_comments)]
use failure;
use reqwest;
use serde_json;
use std::collections::BTreeMap;
use std::io;
use std::path::PathBuf;
use std::result;
use url::Url;
pub type Result<T, E = Error> = result::Result<T, E>;
#[derive(Debug, Fail)]
pub enum Error {
#[fail(display = "error accessing '{}': {}", url, error)]
CouldNotAccessUrl {
url: Url,
error: failure::Error,
},
#[fail(display = "could not get WhizzML output '{}': {}", name, error)]
CouldNotGetOutput {
name: String,
error: failure::Error,
},
#[fail(display = "could not read file {:?}: {}", path, error)]
CouldNotReadFile {
path: PathBuf,
error: failure::Error,
},
#[fail(display = "WhizzML output is not (yet?) available")]
OutputNotAvailable,
#[fail(display = "BigML payment required for {} ({})", url, body)]
PaymentRequired { url: Url, body: String },
#[fail(display = "The operation timed out")]
Timeout,
#[fail(display = "{} for {} ({})", status, url, body)]
UnexpectedHttpStatus {
url: Url,
status: reqwest::StatusCode,
body: String,
},
#[fail(display = "https://bigml.com/dashboard/{} failed ({})", id, message)]
WaitFailed {
id: String,
message: String,
},
#[fail(
display = "Expected BigML resource ID starting with '{}', found '{}'",
expected, found
)]
WrongResourceType {
expected: &'static str,
found: String,
},
#[fail(display = "{}", error)]
Other { error: failure::Error, },
#[doc(none)]
#[fail(display = "This error should never have occurred")]
__Nonexclusive,
}
impl Error {
pub(crate) fn could_not_access_url<E>(url: &Url, error: E) -> Error
where
E: Into<failure::Error>,
{
Error::CouldNotAccessUrl {
url: url_without_api_key(&url),
error: error.into(),
}
}
pub(crate) fn could_not_get_output<E>(name: &str, error: E) -> Error
where
E: Into<failure::Error>,
{
Error::CouldNotGetOutput {
name: name.to_owned(),
error: error.into(),
}
}
pub(crate) fn could_not_read_file<P, E>(path: P, error: E) -> Error
where
P: Into<PathBuf>,
E: Into<failure::Error>,
{
Error::CouldNotReadFile {
path: path.into(),
error: error.into(),
}
}
}
impl From<failure::Error> for Error {
fn from(error: failure::Error) -> Error {
Error::Other { error }
}
}
impl From<io::Error> for Error {
fn from(error: io::Error) -> Error {
Error::Other {
error: error.into(),
}
}
}
impl From<reqwest::Error> for Error {
fn from(error: reqwest::Error) -> Error {
Error::Other {
error: error.into(),
}
}
}
impl From<serde_json::Error> for Error {
fn from(error: serde_json::Error) -> Error {
Error::Other {
error: error.into(),
}
}
}
pub(crate) fn url_without_api_key(url: &Url) -> Url {
let mut query = BTreeMap::new();
for (k, v) in url.query_pairs() {
query.insert(k.into_owned(), v.into_owned());
}
let mut new_url = url.to_owned();
{
let mut serializer = new_url.query_pairs_mut();
serializer.clear();
for (k, v) in query.iter() {
if k == "api_key" {
serializer.append_pair(k, "*****");
} else {
serializer.append_pair(k, v);
}
}
}
new_url
}
#[test]
fn url_without_api_key_is_sanitized() {
let url = Url::parse("https://www.example.com/foo?a=b&api_key=12345")
.expect("could not parse URL");
let cleaned = url_without_api_key(&url);
assert_eq!(
cleaned.as_str(),
"https://www.example.com/foo?a=b&api_key=*****"
);
}