mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-07 03:56:42 +01:00
feat(doit): json decode and delegation
Now json errors are handled and delegated with the option to retry, and all other values are just decoded according to plan. For now, I brutally unwrap json values assuming this will work, because it really should work.
This commit is contained in:
@@ -42,7 +42,7 @@ impl<T: Seek + Read> ReadSeek for T {}
|
||||
|
||||
/// A utility type which can decode a server response that indicates error
|
||||
#[derive(RustcDecodable)]
|
||||
struct JsonServerError {
|
||||
pub struct JsonServerError {
|
||||
error: String,
|
||||
error_description: Option<String>
|
||||
}
|
||||
@@ -68,6 +68,22 @@ pub trait Delegate {
|
||||
fn api_key(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Called whenever the Authenticator didn't yield a token. The delegate
|
||||
/// may attempt to provide one, or just take is a general information about the
|
||||
/// pending impending failure
|
||||
fn token(&mut self) -> Option<oauth2::Token> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Called whenever the http request returns with a non-success status code.
|
||||
/// This can involve authentication issues, or anything else that very much
|
||||
/// depends on the used API method.
|
||||
/// The delegate should check the status, header and decoded json error to decide
|
||||
/// whether to retry or not. In the latter case, the underlying call will fail.
|
||||
fn http_failure(&mut self, _: &hyper::client::Response, JsonServerError) -> oauth2::Retry {
|
||||
oauth2::Retry::Abort
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -91,6 +107,9 @@ pub enum Result<T = ()> {
|
||||
/// An additional, free form field clashed with one of the built-in optional ones
|
||||
FieldClash(&'static str),
|
||||
|
||||
/// Indicates an HTTP repsonse with a non-success status code
|
||||
Failure(hyper::client::Response),
|
||||
|
||||
/// It worked !
|
||||
Success(T),
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@ use std::borrow::BorrowMut;
|
||||
use std::default::Default;
|
||||
use std::collections::BTreeMap;
|
||||
use std::marker::PhantomData;
|
||||
use rustc_serialize::json;
|
||||
use std::io;
|
||||
use std::fs;
|
||||
use std::old_io::timer::sleep;
|
||||
|
||||
@@ -334,11 +334,11 @@ match result {
|
||||
where = ''
|
||||
qualifier = 'pub '
|
||||
add_args = ''
|
||||
rtype = 'cmn::Result<()>'
|
||||
rtype = 'cmn::Result<hyper::client::Response>'
|
||||
response_schema = method_response(c, m)
|
||||
|
||||
if response_schema:
|
||||
rtype = 'cmn::Result<%s>' % (response_schema.id)
|
||||
rtype = 'cmn::Result<(hyper::client::Response, %s)>' % (response_schema.id)
|
||||
|
||||
if media_params:
|
||||
stripped = lambda s: s.strip().strip(',')
|
||||
@@ -365,26 +365,20 @@ match result {
|
||||
client = '(*self.hub.client.borrow_mut()).borrow_mut()'
|
||||
|
||||
if supports_scopes(auth):
|
||||
all_scopes = auth.oauth2.scopes.keys()
|
||||
all_scopes = sorted(auth.oauth2.scopes.keys())
|
||||
default_scope = all_scopes[0]
|
||||
assert 'readonly' not in default_scope
|
||||
if m.httpMethod in ('HEAD', 'GET', 'OPTIONS', 'TRACE'):
|
||||
for scope in all_scopes:
|
||||
if 'readonly' in scope:
|
||||
default_scope = scope
|
||||
break
|
||||
# end for each scope
|
||||
# end try to find read-only default scope
|
||||
# end handle default scope
|
||||
%>
|
||||
/// Perform the operation you have build so far.
|
||||
${action_fn} {
|
||||
use hyper::method::Method;
|
||||
use hyper::header::UserAgent;
|
||||
% if request_value or response_schema:
|
||||
use hyper::header::ContentType;
|
||||
use mime::{Mime, TopLevel, SubLevel};
|
||||
use rustc_serialize::json;
|
||||
% endif
|
||||
use std::io::Read;
|
||||
let mut params: Vec<(&str, String)> = Vec::with_capacity(${len(params)} + ${paddfields}.len());
|
||||
% for p in field_params:
|
||||
<%
|
||||
@@ -463,19 +457,22 @@ else {
|
||||
|
||||
loop {
|
||||
% if supports_scopes(auth):
|
||||
let token = ${auth_call}.token(self.${api.properties.scopes}.keys());
|
||||
let mut token = ${auth_call}.token(self.${api.properties.scopes}.keys());
|
||||
if token.is_none() && ${delegate}.is_some() {
|
||||
token = ${delegate_call}.token();
|
||||
}
|
||||
if token.is_none() {
|
||||
return cmn::Result::MissingToken
|
||||
}
|
||||
let auth_header = hyper::header::Authorization(token.unwrap().access_token);
|
||||
% endif
|
||||
match ${client}.request(Method::Extension("${m.httpMethod}".to_string()), url.as_slice())
|
||||
.header(UserAgent("google-api-rust-client/${cargo.build_version}".to_string()))
|
||||
match ${client}.request(hyper::method::Method::Extension("${m.httpMethod}".to_string()), url.as_slice())
|
||||
.header(hyper::header::UserAgent("google-api-rust-client/${cargo.build_version}".to_string()))
|
||||
% if supports_scopes(auth):
|
||||
.header(auth_header)
|
||||
% endif
|
||||
% if request_value:
|
||||
.header(ContentType(Mime(TopLevel::Application, SubLevel::Json, Default::default())))
|
||||
.header(hyper::header::ContentType(mime::Mime(mime::TopLevel::Application, mime::SubLevel::Json, Default::default())))
|
||||
.body(json::encode(&self.${property(REQUEST_VALUE_PROPERTY_NAME)}).unwrap().as_slice())
|
||||
% endif
|
||||
.send() {
|
||||
@@ -493,19 +490,29 @@ else {
|
||||
}
|
||||
}
|
||||
Ok(mut res) => {
|
||||
|
||||
break;
|
||||
if !res.status.is_success() {
|
||||
if ${delegate}.is_some() {
|
||||
let mut json_err = String::new();
|
||||
res.read_to_string(&mut json_err).ok();
|
||||
let error_info: cmn::JsonServerError = json::decode(&json_err).unwrap();
|
||||
if let oauth2::Retry::After(d) = ${delegate_call}.http_failure(&res, error_info) {
|
||||
sleep(d);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return cmn::Result::Failure(res)
|
||||
}
|
||||
% if response_schema:
|
||||
let mut json_response = String::new();
|
||||
res.read_to_string(&mut json_response).ok();
|
||||
let result_value = (res, json::decode(&json_response).unwrap());
|
||||
% else:
|
||||
let result_value = res;
|
||||
% endif
|
||||
return cmn::Result::Success(result_value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
% if response_schema:
|
||||
let response: ${response_schema.id} = Default::default();
|
||||
% else:
|
||||
let response = ();
|
||||
% endif
|
||||
|
||||
cmn::Result::Success(response)
|
||||
}
|
||||
|
||||
% for p in media_params:
|
||||
|
||||
@@ -40,7 +40,7 @@ impl<T: Seek + Read> ReadSeek for T {}
|
||||
|
||||
/// A utility type which can decode a server response that indicates error
|
||||
#[derive(RustcDecodable)]
|
||||
struct JsonServerError {
|
||||
pub struct JsonServerError {
|
||||
error: String,
|
||||
error_description: Option<String>
|
||||
}
|
||||
@@ -66,6 +66,22 @@ pub trait Delegate {
|
||||
fn api_key(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Called whenever the Authenticator didn't yield a token. The delegate
|
||||
/// may attempt to provide one, or just take is a general information about the
|
||||
/// pending impending failure
|
||||
fn token(&mut self) -> Option<oauth2::Token> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Called whenever the http request returns with a non-success status code.
|
||||
/// This can involve authentication issues, or anything else that very much
|
||||
/// depends on the used API method.
|
||||
/// The delegate should check the status, header and decoded json error to decide
|
||||
/// whether to retry or not. In the latter case, the underlying call will fail.
|
||||
fn http_failure(&mut self, _: &hyper::client::Response, JsonServerError) -> oauth2::Retry {
|
||||
oauth2::Retry::Abort
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -89,6 +105,9 @@ pub enum Result<T = ()> {
|
||||
/// An additional, free form field clashed with one of the built-in optional ones
|
||||
FieldClash(&'static str),
|
||||
|
||||
/// Indicates an HTTP repsonse with a non-success status code
|
||||
Failure(hyper::client::Response),
|
||||
|
||||
/// It worked !
|
||||
Success(T),
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user