#![crate_type = "lib"]
#![crate_name = "crates_api"]
#![feature(proc_macro)]
extern crate hyper;
extern crate serde;
extern crate serde_json;
#[macro_use] extern crate serde_derive;
use hyper::Url;
use hyper::Error as HyperError;
use hyper::client::Client;
use hyper::error::ParseError;
use hyper::header::{Accept, qitem};
use hyper::mime::{Mime, TopLevel, SubLevel};
use serde_json::Error as JsonError;
use serde::Deserialize;
use std::io::Read;
#[derive(Debug, Deserialize)]
pub struct CrateData {
#[serde(rename="crate")]
pub metadata : CrateMetadata,
pub versions : Vec<CrateVersion>,
}
#[derive(Debug, Deserialize)]
pub struct CrateMetadata {
pub name : String,
pub id : String,
pub max_version : String,
pub description : String,
pub license : String,
pub downloads : usize,
pub keywords : Vec<String>,
pub homepage : Option<String>,
pub documentation : Option<String>,
pub repository : Option<String>,
pub versions : Vec<usize>,
}
#[derive(Debug, Deserialize)]
pub struct CrateVersion {
#[serde(rename="crate")]
pub name : String,
pub downloads : usize,
pub yanked : bool,
pub id : usize,
pub num : String,
}
#[derive(Debug, Deserialize)]
struct CrateVersions_ {
pub versions : Vec<CrateVersion>,
}
#[derive(Debug)]
pub enum CratesApiError {
UrlError(ParseError),
RequestError(HyperError),
DeserializationError(JsonError),
}
pub fn poll_api <T : Deserialize> (path : &str) -> Result<T, CratesApiError> {
let full_path = format!("https://crates.io/api/v1{}", path);
let url = match Url::parse(&full_path) {
Ok(url) => url,
Err(error) => {
return Err(CratesApiError::UrlError(error));
},
};
let client = Client::new();
let request = client
.get(url)
.header(Accept(vec![
qitem(Mime(TopLevel::Application, SubLevel::Json, vec![]))
]))
.send();
let mut response = match request {
Ok(res) => res,
Err(error) => {
return Err(CratesApiError::RequestError(error));
},
};
let mut body = String::new();
let _ = response.read_to_string(&mut body);
let api_result : T = match serde_json::from_str(&body) {
Ok(data) => data,
Err(deserialization_error) => {
return Err(CratesApiError::DeserializationError(deserialization_error));
},
};
return Ok(api_result);
}
pub fn get_crate (name : &str) -> Result<CrateData, CratesApiError> {
let path = format!("/crates/{}", name);
return poll_api(&path);
}
pub fn get_versions (name : &str) -> Result<Vec<CrateVersion>, CratesApiError> {
let path = format!("/crates/{}/versions", name);
return poll_api(&path).map(|c : CrateVersions_| c.versions);
}