extern crate serde;
extern crate serde_json;
mod hyper {
extern crate hyper;
extern crate hyper_tls;
pub use self::hyper::error::Error;
pub use self::hyper::{Client, Request, Method, Response, StatusCode, Chunk};
pub use self::hyper::header::{ContentType, ContentLength, Referer, Origin, UserAgent, Accept};
pub use self::hyper::client::{HttpConnector, FutureResponse};
pub use self::hyper_tls::{HttpsConnector};
header! { (XRequestedWith, "X-Requested-With") => [String] }
}
use ::tokio_core::reactor::{
Handle
};
const TRACKER_URL: &'static str = "https://www.17track.net/restapi/handlertrack.ashx";
pub mod payload {
use super::serde;
use super::serde::Deserialize;
use std::fmt;
#[derive(Serialize, Debug)]
pub struct RequestData {
pub num: String
}
#[derive(Serialize, Debug)]
pub struct Request {
guid: String,
data: Vec<RequestData>
}
impl Request {
pub fn simple(num: String) -> Self {
Request {
guid: "".to_string(),
data: vec![RequestData {
num
}]
}
}
}
#[derive(Deserialize, Debug)]
pub struct TrackEvent {
#[serde(rename = "a")]
date: String,
#[serde(rename = "c")]
location: String,
#[serde(rename = "z")]
message: String,
}
impl fmt::Display for TrackEvent {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{} {}, {}", self.date, self.location, self.message)
}
}
#[derive(Deserialize, Debug)]
pub struct TrackData {
#[serde(rename = "z0")]
pub last: TrackEvent,
#[serde(rename = "z1")]
pub all: Vec<TrackEvent>
}
impl fmt::Display for TrackData {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Last:\n{}\n", self.last)?;
for event in self.all.iter() {
write!(f, "----------\n{}\n", event)?;
}
Ok(())
}
}
#[derive(Deserialize, Debug)]
pub struct ResponsData {
#[serde(rename = "no")]
pub num: String,
pub delay: usize,
pub track: Option<TrackData>
}
pub fn response_result_de<'de, D: serde::de::Deserializer<'de>>(result: D) -> Result<Result<(), String>, D::Error> {
let result = String::deserialize(result)?;
match result.as_ref() {
"Ok" => Ok(Ok(())),
_ => Ok(Err(result))
}
}
#[derive(Deserialize, Debug)]
pub struct Response {
#[serde(rename = "msg")]
#[serde(deserialize_with="response_result_de")]
pub result: Result<(), String>,
#[serde(rename = "dat")]
pub data: Vec<ResponsData>
}
}
pub struct Client {
hyper: hyper::Client<hyper::HttpsConnector<hyper::HttpConnector>>,
}
impl Client {
pub fn new(handle: Handle) -> Self {
let hyper = hyper::Client::configure().keep_alive(true)
.connector(hyper::HttpsConnector::new(4, &handle).unwrap())
.build(&handle);
Client {
hyper,
}
}
pub fn track(&self, num: &str) -> hyper::FutureResponse {
let mut req = hyper::Request::new(hyper::Method::Post, TRACKER_URL.parse().unwrap());
let payload = payload::Request::simple(num.to_string());
req.headers_mut().set(hyper::ContentType::json());
req.headers_mut().set(hyper::Origin::new("https", "www.17track.net", None));
req.headers_mut().set(hyper::Referer::new(format!("http://www.17track.net/pt/track?nums={}&fc=0", num)));
req.headers_mut().set(hyper::UserAgent::new("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36"));
req.headers_mut().set(hyper::XRequestedWith("XMLHttpRequest".to_string()));
req.headers_mut().set(hyper::Accept::star());
req.headers_mut().set(hyper::ContentType::form_url_encoded());
req.set_body(serde_json::to_string(&payload).unwrap());
self.hyper.request(req)
}
pub fn parse_track_response(body: hyper::Chunk) -> Result<payload::Response, serde_json::Error> {
serde_json::from_slice(&body)
}
}