mirror of
https://github.com/OMGeeky/google-apis-rs.git
synced 2026-01-02 17:42:16 +01:00
feat(doit): optimizations and simplification; seek
* MultiPartReader is using match to handle state, reducing unnecessary calls to 0 in that regard. * Fixed seek() calls on readers, assuring they are reset to start each time the loop is done. * both media-parameters now use `ReadSeek` streams. * Use `seek()` to figure out size, simplifying the interface. Closes #17
This commit is contained in:
@@ -375,17 +375,18 @@ match result {
|
||||
rtype = 'cmn::Result<(hyper::client::Response, %s)>' % (response_schema.id)
|
||||
reserved_params = ['alt']
|
||||
|
||||
|
||||
mtype_param = 'RS'
|
||||
mtype_where = 'ReadSeek'
|
||||
|
||||
possible_urls = [m.path]
|
||||
simple_media_param = None
|
||||
if media_params:
|
||||
stripped = lambda s: s.strip().strip(',')
|
||||
qualifier = ''
|
||||
type_params = mtype_param
|
||||
where = mtype_param + ': ' + mtype_where
|
||||
for p in media_params:
|
||||
type_params += p.type.param + ', '
|
||||
where += p.type.param + ': ' + p.type.where + ', '
|
||||
add_args += 'mut ' + p.type.arg_name + ': ' + ('Option<(%s, u64, mime::Mime)>' % p.type.param) + ', '
|
||||
add_args += 'mut ' + p.type.arg_name + ': ' + ('Option<(%s, mime::Mime)>' % mtype_param) + ', '
|
||||
possible_urls.append(p.path)
|
||||
if p.protocol == 'simple':
|
||||
simple_media_param = p
|
||||
@@ -422,6 +423,7 @@ match result {
|
||||
all_required_param_name = set(p.name for p in params if is_required_property(p))
|
||||
MULTI_SLASH = 'multi-slash-prefix'
|
||||
URL_ENCODE = 'url-encode'
|
||||
READER_SEEK = "let size = reader.seek(io::SeekFrom::End(0)).unwrap();\nreader.seek(io::SeekFrom::Start(0)).unwrap();"
|
||||
|
||||
special_cases = set()
|
||||
for possible_url in possible_urls:
|
||||
@@ -595,8 +597,10 @@ else {
|
||||
}
|
||||
|
||||
% if request_value:
|
||||
let json_encoded_request = json::encode(&self.${property(REQUEST_VALUE_PROPERTY_NAME)}).unwrap();
|
||||
let mut json_mime_type = mime::Mime(mime::TopLevel::Application, mime::SubLevel::Json, Default::default());
|
||||
let mut request_value_reader = io::Cursor::new(json::encode(&self.${property(REQUEST_VALUE_PROPERTY_NAME)}).unwrap().into_bytes());
|
||||
let request_size = request_value_reader.seek(io::SeekFrom::End(0)).unwrap();
|
||||
request_value_reader.seek(io::SeekFrom::Start(0)).unwrap();
|
||||
% endif
|
||||
|
||||
let mut client = &mut *self.hub.client.borrow_mut();
|
||||
@@ -611,15 +615,16 @@ else {
|
||||
}
|
||||
let auth_header = hyper::header::Authorization(token.unwrap().access_token);
|
||||
% endif
|
||||
% if request_value:
|
||||
request_value_reader.seek(io::SeekFrom::Start(0)).unwrap();
|
||||
% endif
|
||||
% if request_value and simple_media_param:
|
||||
let mut request_value_reader = io::Cursor::new(json_encoded_request.clone().into_bytes());
|
||||
let mut mp_reader: cmn::MultiPartReader = Default::default();
|
||||
let (mut body_reader, content_type) = match ${simple_media_param.type.arg_name}.as_mut() {
|
||||
Some(&mut (ref mut reader, size, ref mime)) => {
|
||||
Some(&mut (ref mut reader, ref mime)) => {
|
||||
mp_reader.reserve_exact(2);
|
||||
let rsize = request_value_reader.seek(io::SeekFrom::End(0)).unwrap();
|
||||
request_value_reader.seek(io::SeekFrom::Start(0)).unwrap();
|
||||
mp_reader.add_part(&mut request_value_reader, rsize, json_mime_type.clone())
|
||||
${READER_SEEK | indent_all_but_first_by(5)}
|
||||
mp_reader.add_part(&mut request_value_reader, request_size, json_mime_type.clone())
|
||||
.add_part(reader, size, mime.clone());
|
||||
let mime_type = mp_reader.mime_type();
|
||||
(&mut mp_reader as &mut io::Read, ContentType(mime_type))
|
||||
@@ -638,8 +643,8 @@ else {
|
||||
% if not simple_media_param:
|
||||
|
||||
.header(ContentType(json_mime_type.clone()))
|
||||
.header(ContentLength(json_encoded_request.len() as u64))
|
||||
.body(json_encoded_request.as_slice())\
|
||||
.header(ContentLength(request_size as u64))
|
||||
.body(request_value_reader.into_body())\
|
||||
% else:
|
||||
|
||||
.header(content_type)
|
||||
@@ -648,7 +653,8 @@ else {
|
||||
% endif
|
||||
;
|
||||
% if simple_media_param and not request_value:
|
||||
if let Some(&mut (ref mut reader, size, ref mime)) = ${simple_media_param.type.arg_name}.as_mut() {
|
||||
if let Some(&mut (ref mut reader, ref mime)) = ${simple_media_param.type.arg_name}.as_mut() {
|
||||
${READER_SEEK | indent_all_but_first_by(4)}
|
||||
req = req.header(ContentType(mime.clone()))
|
||||
.header(ContentLength(size))
|
||||
.body(reader.into_body());
|
||||
@@ -697,23 +703,20 @@ else {
|
||||
}
|
||||
|
||||
% for p in media_params:
|
||||
<%
|
||||
none_type = 'None::<(' + p.type.default + ', u64, mime::Mime)>'
|
||||
%>\
|
||||
${p.description | rust_doc_comment, indent_all_but_first_by(1)}
|
||||
///
|
||||
% for item_name, item in p.info.iteritems():
|
||||
/// * *${split_camelcase_s(item_name)}*: ${isinstance(item, (list, tuple)) and put_and(enclose_in("'", item)) or str(item)}
|
||||
% endfor
|
||||
pub fn ${api.terms.upload_action}${p.type.suffix}<${p.type.param}>(self, ${p.type.arg_name}: ${p.type.param}, size: u64, mime_type: mime::Mime) -> ${rtype}
|
||||
where ${p.type.param}: ${p.type.where} {
|
||||
pub fn ${api.terms.upload_action}${p.type.suffix}<${mtype_param}>(self, ${p.type.arg_name}: ${mtype_param}, mime_type: mime::Mime) -> ${rtype}
|
||||
where ${mtype_param}: ${mtype_where} {
|
||||
self.${api.terms.action}(\
|
||||
% for _ in range(0, loop.index):
|
||||
${none_type}, \
|
||||
None, \
|
||||
% endfor
|
||||
Some((${p.type.arg_name}, size, mime_type)), \
|
||||
Some((${p.type.arg_name}, mime_type)), \
|
||||
% for _ in range(loop.index+1, len(media_params)):
|
||||
${none_type}, \
|
||||
None, \
|
||||
% endfor
|
||||
)
|
||||
}
|
||||
|
||||
@@ -71,26 +71,22 @@ DELEGATE_PROPERTY_NAME = 'delegate'
|
||||
PROTOCOL_TYPE_INFO = {
|
||||
'simple' : {
|
||||
'arg_name': 'stream',
|
||||
'param': 'R',
|
||||
'description': """Upload media all at once.
|
||||
If the upload fails for whichever reason, all progress is lost.""",
|
||||
'default': 'fs::File',
|
||||
'where': 'ReadSeek',
|
||||
'suffix': '',
|
||||
'example_value': 'fs::File::open("file.ext").unwrap(), 148, "application/octet-stream".parse().unwrap()'
|
||||
'example_value': 'fs::File::open("file.ext").unwrap(), "application/octet-stream".parse().unwrap()'
|
||||
},
|
||||
'resumable' : {
|
||||
'arg_name': 'resumeable_stream',
|
||||
'param': 'RS',
|
||||
'description': """Upload media in a resumeable fashion.
|
||||
Even if the upload fails or is interrupted, it can be resumed for a
|
||||
certain amount of time as the server maintains state temporarily.
|
||||
|
||||
TODO: Write more about how delegation works in this particular case.""",
|
||||
'default': 'fs::File',
|
||||
'where': 'ReadSeek',
|
||||
'suffix': '_resumable',
|
||||
'example_value': 'fs::File::open("file.ext").unwrap(), 282, "application/octet-stream".parse().unwrap()'
|
||||
'example_value': 'fs::File::open("file.ext").unwrap(), "application/octet-stream".parse().unwrap()'
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -183,22 +183,28 @@ impl<'a> MultiPartReader<'a> {
|
||||
|
||||
impl<'a> Read for MultiPartReader<'a> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||
if self.last_part_boundary.is_some() {
|
||||
let br = self.last_part_boundary.as_mut().unwrap().read(buf).unwrap_or(0);
|
||||
if br < buf.len() {
|
||||
self.last_part_boundary = None;
|
||||
match (self.raw_parts.len(),
|
||||
self.current_part.is_none(),
|
||||
self.last_part_boundary.is_none()) {
|
||||
(_, _, false) => {
|
||||
let br = self.last_part_boundary.as_mut().unwrap().read(buf).unwrap_or(0);
|
||||
if br < buf.len() {
|
||||
self.last_part_boundary = None;
|
||||
}
|
||||
return Ok(br)
|
||||
},
|
||||
(0, true, true) => return Ok(0),
|
||||
(n, true, _) if n > 0 => {
|
||||
let (headers, reader) = self.raw_parts.remove(0);
|
||||
let mut c = Cursor::new(Vec::<u8>::new());
|
||||
write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING,
|
||||
headers, LINE_ENDING).unwrap();
|
||||
c.seek(SeekFrom::Start(0)).unwrap();
|
||||
self.current_part = Some((c, reader));
|
||||
}
|
||||
return Ok(br)
|
||||
} else if self.is_depleted() {
|
||||
return Ok(0)
|
||||
} else if self.raw_parts.len() > 0 && self.current_part.is_none() {
|
||||
let (headers, reader) = self.raw_parts.remove(0);
|
||||
let mut c = Cursor::new(Vec::<u8>::new());
|
||||
write!(&mut c, "{}--{}{}{}{}", LINE_ENDING, BOUNDARY, LINE_ENDING,
|
||||
headers, LINE_ENDING).unwrap();
|
||||
c.seek(SeekFrom::Start(0)).unwrap();
|
||||
self.current_part = Some((c, reader));
|
||||
_ => {},
|
||||
}
|
||||
|
||||
// read headers as long as possible
|
||||
let (hb, rr) = {
|
||||
let &mut (ref mut c, ref mut reader) = self.current_part.as_mut().unwrap();
|
||||
|
||||
@@ -17,6 +17,7 @@ mod tests {
|
||||
use self::hyper_mock::*;
|
||||
use std::io::Read;
|
||||
use std::default::Default;
|
||||
use std::old_path::BytesContainer;
|
||||
|
||||
const EXPECTED: &'static str =
|
||||
"\r\n--MDuXWGyeE33QFXGchb2VFWc4Z7945d\r\n\
|
||||
|
||||
Reference in New Issue
Block a user