use std::fmt::Display;
use std::str::FromStr;
use serde::Deserialize;
pub enum Authentication {
Password{
username: String,
password: String
},
ApiKey{
username: String,
key: String
},
OAuth{
provider: String,
token: String
}
}
#[derive(Debug)]
pub struct Sha256 {
hex: String
}
impl std::fmt::Display for Sha256 {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.hex)
}
}
impl std::ops::Deref for Sha256 {
type Target = str;
fn deref(&self) -> &Self::Target {
&self.hex
}
}
impl FromStr for Sha256 {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let hex = s.trim().to_ascii_lowercase();
if hex.len() != 64 || !hex.chars().all(|c|c.is_ascii_hexdigit()) {
return Err(Error::InvalidSha256)
}
return Ok(Sha256{ hex })
}
}
impl<'de> Deserialize<'de> for Sha256 {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de> {
let content = String::deserialize(deserializer)?;
content.parse().map_err(serde::de::Error::custom)
}
}
pub type JsonMap = serde_json::Map<String, serde_json::Value>;
#[derive(Debug)]
pub enum Error {
Client{
message: String,
status: u32,
api_version: Option<String>,
api_response: Option<String>
},
TransportError(String),
InvalidHeader,
MalformedResponse,
InvalidSha256,
InvalidSubmitFilePath,
InvalidSubmitUrl,
IO(std::io::Error),
Serialization(serde_json::Error),
ParameterSerialization,
}
impl Error {
pub (crate) fn client_error(message: String, status: u32) -> Self {
return Error::Client { message, status, api_response: None, api_version: None }
}
}
impl Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Error::Client { message, status, .. } =>
f.write_fmt(format_args!("Client error [{status}]: {message}")),
Error::TransportError(message) =>
f.write_fmt(format_args!("Error communicating with server: {message}")),
Error::InvalidHeader =>
f.write_str("An invalid HTTP header name or value was encountered"),
Error::MalformedResponse =>
f.write_str("A server response was malformed"),
Error::InvalidSha256 =>
f.write_str("An invalid SHA256 string was provided"),
Error::InvalidSubmitFilePath =>
f.write_str("An invalid path was given for submission"),
Error::InvalidSubmitUrl =>
f.write_str("An invalid URL was given for submission, try setting the file name explicitly"),
Error::IO(error) =>
f.write_fmt(format_args!("An IO error ocurred: {error}")),
Error::Serialization(error) =>
f.write_fmt(format_args!("An error occurred serializing a body: {error}")),
Error::ParameterSerialization =>
f.write_str("Parameter serialization yielded unexpected type."),
}
}
}
impl From<reqwest::Error> for Error {
fn from(value: reqwest::Error) -> Self {
if let Some(code) = value.status() {
Error::client_error(value.to_string(), code.as_u16() as u32)
} else {
Error::TransportError(value.to_string())
}
}
}
impl From<reqwest::header::InvalidHeaderName> for Error {
fn from(_value: reqwest::header::InvalidHeaderName) -> Self {
Self::InvalidHeader
}
}
impl From<reqwest::header::InvalidHeaderValue> for Error {
fn from(_value: reqwest::header::InvalidHeaderValue) -> Self {
Self::InvalidHeader
}
}
impl From<serde_json::Error> for Error {
fn from(value: serde_json::Error) -> Self {
Self::Serialization(value)
}
}
impl From<std::io::Error> for Error {
fn from(value: std::io::Error) -> Self {
Self::IO(value)
}
}
impl From<url::ParseError> for Error {
fn from(_value: url::ParseError) -> Self {
Self::InvalidSubmitUrl
}
}
impl std::error::Error for Error {
}