use std::{
io,
mem,
};
use reqwest::{
Client,
header,
multipart::{Form, Part},
RequestBuilder,
};
use crate::{
api,
drop::Package,
};
pub fn ship(
package: &Package,
token: &str,
) -> Result<reqwest::Response, ShipError> {
let url = api::url()?;
ship_at(&url, package, token)
}
pub fn ship_at(
api_url: &url::Url,
package: &Package,
token: &str,
) -> Result<reqwest::Response, ShipError> {
let url = api_url.join("/v1/packages/create")?;
ship_at_specific(url.as_str(), package, token)
}
pub fn ship_at_specific<U: reqwest::IntoUrl>(
url: U,
package: &Package,
token: &str,
) -> Result<reqwest::Response, ShipError> {
fn ship(
builder: RequestBuilder,
package: &Package,
token: &str,
) -> Result<reqwest::Response, ShipError> {
let version = package.manifest.meta.version.to_string();
let name = unsafe {
let name = package.manifest.meta.name.as_str();
mem::transmute::<&str, &'static str>(name)
};
let form = Form::new()
.text("name", name)
.text("version", version);
let package = Part::file(&package.path)?;
let form = form.part("packageFile", package);
let response = builder.multipart(form)
.header(header::COOKIE, format!("token={}", token))
.send()?;
eprintln!("Received response: {:#?}", response);
let status = response.status();
if !status.is_success() {
return Err(ShipError::from(status));
}
Ok(response)
}
ship(Client::new().post(url), package, token)
}
#[derive(Debug)]
pub enum ShipError {
ParseUrl(url::ParseError),
Io(io::Error),
SerializeManifest(serde_json::Error),
Request(reqwest::Error),
Status(http::StatusCode),
Unauthorized,
}
impl From<url::ParseError> for ShipError {
fn from(error: url::ParseError) -> Self {
Self::ParseUrl(error)
}
}
impl From<io::Error> for ShipError {
fn from(error: io::Error) -> Self {
Self::Io(error)
}
}
impl From<serde_json::Error> for ShipError {
fn from(error: serde_json::Error) -> Self {
Self::SerializeManifest(error)
}
}
impl From<reqwest::Error> for ShipError {
fn from(error: reqwest::Error) -> Self {
Self::Request(error)
}
}
impl From<http::StatusCode> for ShipError {
fn from(error: http::StatusCode) -> Self {
if error == http::StatusCode::UNAUTHORIZED {
Self::Unauthorized
} else {
Self::Status(error)
}
}
}
impl std::fmt::Display for ShipError {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
use self::ShipError::*;
match self {
ParseUrl(error) => error.fmt(f),
Io(error) => error.fmt(f),
SerializeManifest(error) => error.fmt(f),
Request(error) => error.fmt(f),
Status(code) => write!(f, "received response \"{}\"", code),
Unauthorized => write!(f, "incorrect username or password"),
}
}
}
impl std::error::Error for ShipError {}