1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112
extern crate tokio_core; extern crate hyper; extern crate hyper_tls; #[macro_use] extern crate serde_derive; extern crate serde_json; extern crate serde_urlencoded; extern crate futures; use futures::Future; use futures::Stream; pub struct Translate { api_key: String, client: hyper::Client<hyper_tls::HttpsConnector<hyper::client::HttpConnector>> } impl Translate { pub fn new(handle: &tokio_core::reactor::Handle, api_key: &str) -> Translate { Translate { api_key: api_key.to_owned(), client: hyper::Client::configure() .connector(hyper_tls::HttpsConnector::new(4, handle).expect("Failed to initialize HttpsConnector")) .build(handle) } } pub fn translate(&self, text: &str, from_lang: &str, to_lang: &str) -> Box<Future<Item=String,Error=Error>> { let uri = "https://translate.yandex.net/api/v1.5/tr.json/translate".parse().unwrap(); let body = TranslateRequestBody { text: text.to_owned(), key: self.api_key.to_owned(), lang: format!("{}-{}", from_lang, to_lang) }; let body = match serde_urlencoded::to_string(&body) { Ok(x) => x, Err(err) => return Box::new(futures::future::err(Error::Other( format!("Failed to serialize request body: {:?}", err)))) }; let mut req = hyper::Request::new(hyper::Method::Post, uri); req.headers_mut().set(hyper::header::ContentType::form_url_encoded()); req.headers_mut().set(hyper::header::ContentLength(body.len() as u64)); req.set_body(body); Box::new(self.client.request(req) .map_err(|e| Error::Other(format!("Failed to send request: {:?}", e))) .and_then(|res| { res.body().concat2().map_err(|e| Error::Other(format!("Failed to get response: {:?}", e))) }) .and_then(|res| { let result = serde_json::from_slice(&res); match result { Ok(TranslateResponse::Error(err_res)) => Err(match err_res.code { _ => Error::Other(format!("Unable to translate: {}", err_res.message)) }), Ok(TranslateResponse::Success(resp)) => resp.text.into_iter().next().ok_or_else(|| Error::Other("No strings returned.".to_owned())), Err(e) => Err(Error::Other(format!("Unable to parse response: {:?}", e))) } })) } } pub enum Error { Other(String) } impl std::fmt::Debug for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { std::fmt::Display::fmt(self, fmt) } } impl std::fmt::Display for Error { fn fmt(&self, fmt: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { write!(fmt, "{}", std::error::Error::description(self)) } } impl std::error::Error for Error { fn description(&self) -> &str { match *self { Error::Other(ref x) => &x } } } #[derive(Serialize)] struct TranslateRequestBody { text: String, key: String, lang: String } #[derive(Deserialize)] struct TranslateErrorResponse { code: u16, message: String } #[derive(Deserialize)] struct TranslateSuccessResponse { text: Vec<String> } #[derive(Deserialize)] #[serde(untagged)] enum TranslateResponse { Error(TranslateErrorResponse), Success(TranslateSuccessResponse) }