feat(downloads): alt 'media' handling to allow dls

This also includes documentation to state which methods actually support
media download, and how to achieve that.

Added TODO to not forget we should tell the user how to achieve these
kinds of things.

Fixes #21
This commit is contained in:
Sebastian Thiel
2015-03-19 09:31:11 +01:00
parent 4a27ac7e1d
commit 02d7a06fdf
30 changed files with 838 additions and 655 deletions

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/LJI9qShCZjBHg072lrR-8ZdwqHs\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/aZqXglKYhHRY6tGe90wBk2vmheM\"",
"discoveryVersion": "v1",
"id": "adexchangeseller:v1.1",
"name": "adexchangeseller",
"canonicalName": "Ad Exchange Seller",
"version": "v1.1",
"revision": "20150225",
"revision": "20150313",
"title": "Ad Exchange Seller API",
"description": "Gives Ad Exchange seller users access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/Udv6xd2CTeF5gBc5RK-Xrdwi5BU\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/gjjXjsHj8UTCjwoWB0KNSdU5LXw\"",
"discoveryVersion": "v1",
"id": "adexchangeseller:v1",
"name": "adexchangeseller",
"canonicalName": "Ad Exchange Seller",
"version": "v1",
"revision": "20150225",
"revision": "20150313",
"title": "Ad Exchange Seller API",
"description": "Gives Ad Exchange seller users access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/-2ppmthl020S47FH8VO33hbOboc\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/eWJUNKoCWvcmB-gqHTIWg1zs684\"",
"discoveryVersion": "v1",
"id": "adexchangeseller:v2.0",
"name": "adexchangeseller",
"canonicalName": "Ad Exchange Seller",
"version": "v2.0",
"revision": "20150225",
"revision": "20150313",
"title": "Ad Exchange Seller API",
"description": "Gives Ad Exchange seller users access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/qR09Xr4WyuppZd0FxNauFU4HZEY\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/_i2OsA9ICnxLuGp5SQSlE-RCl-A\"",
"discoveryVersion": "v1",
"id": "adsense:v1.2",
"name": "adsense",
"canonicalName": "AdSense",
"version": "v1.2",
"revision": "20150126",
"revision": "20150312",
"title": "AdSense Management API",
"description": "Gives AdSense publishers access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/QLzYLvfST0FjKuQb6H8Y9VPJgoE\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/Y1tUkFc0QQNBtKHfd75UEcFQizo\"",
"discoveryVersion": "v1",
"id": "adsense:v1.3",
"name": "adsense",
"canonicalName": "AdSense",
"version": "v1.3",
"revision": "20150126",
"revision": "20150312",
"title": "AdSense Management API",
"description": "Gives AdSense publishers access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/GwVBOvnObENRnA8st3Br2OCaQxE\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/WPPN58Hu3NNElRYylPbHwGhmbWg\"",
"discoveryVersion": "v1",
"id": "adsense:v1.4",
"name": "adsense",
"canonicalName": "AdSense",
"version": "v1.4",
"revision": "20150126",
"revision": "20150312",
"title": "AdSense Management API",
"description": "Gives AdSense publishers access to their inventory and the ability to generate reports",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/Ot75-sAq1Vj9vLc-q6gHNxVJqjQ\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/VI6vr1MPx9avVWB1RXoHKqps2IQ\"",
"discoveryVersion": "v1",
"id": "adsensehost:v4.1",
"name": "adsensehost",
"canonicalName": "AdSense Host",
"version": "v4.1",
"revision": "20150118",
"revision": "20150302",
"title": "AdSense Host API",
"description": "Gives AdSense Hosts access to report generation, ad code generation, and publisher management capabilities.",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/RcOjYGQDsg144Y5EM1meYl_XNYw\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/IldvChjq6UkiEW0nig_gOjP89aY\"",
"discoveryVersion": "v1",
"id": "analytics:v2.4",
"name": "analytics",
"version": "v2.4",
"revision": "20141118",
"revision": "20150308",
"title": "Google Analytics API",
"description": "View and manage your Google Analytics data",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/aw3TpXPEnqSVSodmCVhPn55WgQk\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/6NlFUYEBMf81bxiwpXwPhu5e1RQ\"",
"discoveryVersion": "v1",
"id": "analytics:v3",
"name": "analytics",
"version": "v3",
"revision": "20141118",
"revision": "20150308",
"title": "Google Analytics API",
"description": "View and manage your Google Analytics data",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/MCWK2CQLEDojVXJw1b4YdNiAmeY\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/QxG7oirHrzfDxJoQseQwOqPzaG0\"",
"discoveryVersion": "v1",
"id": "bigquery:v2",
"name": "bigquery",
"version": "v2",
"revision": "20150309",
"revision": "20141112",
"title": "BigQuery API",
"description": "A data platform for customers to create, manage, share and query data.",
"ownerDomain": "google.com",
@@ -1071,6 +1071,10 @@
"id": "TableDataInsertAllRequest",
"type": "object",
"properties": {
"ignoreUnknownValues": {
"type": "boolean",
"description": "[Optional] Accept rows that contain values that do not match the schema. The unknown values are ignored. Default is false, which treats unknown values as errors."
},
"kind": {
"type": "string",
"description": "The resource type of the response.",
@@ -1092,6 +1096,10 @@
}
}
}
},
"skipInvalidRows": {
"type": "boolean",
"description": "[Optional] Insert all valid rows of a request, even if invalid rows exist. The default value is false, which causes the entire request to fail if any invalid rows exist."
}
}
},

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/kNB4QIeM_hYb1gDtvlVUUPro4uQ\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/7vCHfrhi9Lj_cY5xxg_5Db6xPtw\"",
"discoveryVersion": "v1",
"id": "books:v1",
"name": "books",
"version": "v1",
"revision": "20150115",
"revision": "20150309",
"title": "Books API",
"description": "Lets you search for books and manage your Google Books library.",
"ownerDomain": "google.com",
@@ -2817,34 +2817,6 @@
"https://www.googleapis.com/auth/books"
]
},
"get": {
"id": "books.mylibrary.annotations.get",
"path": "mylibrary/annotations/{annotationId}",
"httpMethod": "GET",
"description": "Gets an annotation by its ID.",
"parameters": {
"annotationId": {
"type": "string",
"description": "The ID for the annotation to retrieve.",
"required": true,
"location": "path"
},
"source": {
"type": "string",
"description": "String to identify the originator of this request.",
"location": "query"
}
},
"parameterOrder": [
"annotationId"
],
"response": {
"$ref": "Annotation"
},
"scopes": [
"https://www.googleapis.com/auth/books"
]
},
"insert": {
"id": "books.mylibrary.annotations.insert",
"path": "mylibrary/annotations",
@@ -2907,12 +2879,6 @@
"maximum": "40",
"location": "query"
},
"pageIds": {
"type": "string",
"description": "The page ID(s) for the volume that is being queried.",
"repeated": true,
"location": "query"
},
"pageToken": {
"type": "string",
"description": "The value of the nextToken from the previous page.",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/43YyX2L2OP2AOVrWhgb-fE2Qsgk\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/chLcvyYPKZ3ZS_IQi224D9BXunY\"",
"discoveryVersion": "v1",
"id": "calendar:v3",
"name": "calendar",
"version": "v3",
"revision": "20150118",
"revision": "20141123",
"title": "Calendar API",
"description": "Lets you manipulate events and other calendar data.",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/kwpiRqjQBcnxhE5-xYxQ0kF3ilA\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/O_5j_7aKimaeibrW3NmYraO3Ajs\"",
"discoveryVersion": "v1",
"id": "compute:v1",
"name": "compute",
"version": "v1",
"revision": "20150303",
"revision": "20150302",
"title": "Compute Engine API",
"description": "API for the Google Compute Engine service.",
"ownerDomain": "google.com",
@@ -803,11 +803,11 @@
"properties": {
"destinationZone": {
"type": "string",
"description": "The URL of the zone to which the disk will be moved."
"description": "The URL of the destination zone to move the disk to. This can be a full or partial URL. For example, the following are all valid URLs to a zone: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone \n- projects/project/zones/zone \n- zones/zone"
},
"targetDisk": {
"type": "string",
"description": "The URL of the target disk to be moved."
"description": "The URL of the target disk to move. This can be a full or partial URL. For example, the following are all valid URLs to a disk: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/disks/disk \n- projects/project/zones/zone/disks/disk \n- zones/zone/disks/disk"
}
}
},
@@ -1880,11 +1880,11 @@
"properties": {
"destinationZone": {
"type": "string",
"description": "The URL of the zone to move the instance to."
"description": "The URL of the destination zone to move the instance to. This can be a full or partial URL. For example, the following are all valid URLs to a zone: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone \n- projects/project/zones/zone \n- zones/zone"
},
"targetInstance": {
"type": "string",
"description": "The URL of the target instance to move."
"description": "The URL of the target instance to move. This can be a full or partial URL. For example, the following are all valid URLs to an instance: \n- https://www.googleapis.com/compute/v1/projects/project/zones/zone/instances/instance \n- projects/project/zones/zone/instances/instance \n- zones/zone/instances/instance"
}
}
},
@@ -2948,20 +2948,14 @@
"enum": [
"BACKEND_SERVICES",
"CPUS",
"DISKS",
"DISKS_TOTAL_GB",
"EPHEMERAL_ADDRESSES",
"FIREWALLS",
"FORWARDING_RULES",
"HEALTH_CHECKS",
"IMAGES",
"IMAGES_TOTAL_GB",
"IN_USE_ADDRESSES",
"KERNELS",
"KERNELS_TOTAL_GB",
"LOCAL_SSD_TOTAL_GB",
"NETWORKS",
"OPERATIONS",
"ROUTES",
"SNAPSHOTS",
"SSD_TOTAL_GB",
@@ -2989,12 +2983,6 @@
"",
"",
"",
"",
"",
"",
"",
"",
"",
""
]
},
@@ -5030,6 +5018,7 @@
"id": "compute.disks.createSnapshot",
"path": "{project}/zones/{zone}/disks/{disk}/createSnapshot",
"httpMethod": "POST",
"description": "Creates a snapshot of this disk.",
"parameters": {
"disk": {
"type": "string",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/ruh8vDKnI53dg6K4wnCZiPZpScI\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/aHn3JVvIgem2cQ4taTnQ3LnIpWc\"",
"discoveryVersion": "v1",
"id": "deploymentmanager:v2beta1",
"name": "deploymentmanager",
"version": "v2beta1",
"revision": "20150210",
"revision": "20141215",
"title": "Google Cloud Deployment Manager API V2",
"description": "The Deployment Manager API allows users to declaratively configure, deploy and run complex solutions on the Google Cloud Platform.",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/uftxkEqaj-t-6C93huW22geUJjs\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/Avr5yLDEaSyBxOoYvm8FoDAE8-g\"",
"discoveryVersion": "v1",
"id": "genomics:v1beta2",
"name": "genomics",
"version": "v1beta2",
"revision": "20150307",
"revision": "20150303",
"title": "Genomics API",
"description": "Provides access to Genomics data.",
"ownerDomain": "google.com",
@@ -552,7 +552,7 @@
"properties": {
"exportUri": {
"type": "string",
"description": "A Google Cloud Storage URI where the exported BAM file will be created. The currently authenticated user must have write access to the new file location. An error will be returned if the URI already contains data."
"description": "A Google Cloud Storage URI for the exported BAM file. The currently authenticated user must have write access to the new file. An error will be returned if the URI already contains data."
},
"projectNumber": {
"type": "string",
@@ -1484,7 +1484,7 @@
},
"description": {
"type": "string",
"description": "free text description of this reference set."
"description": "Free text description of this reference set."
},
"id": {
"type": "string",
@@ -1765,7 +1765,7 @@
},
"pageSize": {
"type": "integer",
"description": "Specifies number of results to return in a single page. If unspecified, it will default to 128. The maximum value is 1024.",
"description": "Specifies number of results to return in a single page. If unspecified, it will default to 256. The maximum value is 1024.",
"format": "int32"
},
"pageToken": {
@@ -2856,12 +2856,11 @@
"id": "genomics.datasets.list",
"path": "datasets",
"httpMethod": "GET",
"description": "Lists all datasets.",
"description": "Lists datasets within a project.",
"parameters": {
"pageSize": {
"type": "integer",
"description": "The maximum number of results returned by this request.",
"default": "50",
"description": "The maximum number of results returned by this request. If unspecified, defaults to 50.",
"format": "int32",
"location": "query"
},
@@ -3241,7 +3240,6 @@
"pageSize": {
"type": "integer",
"description": "The maximum number of results to return in a single page. If unspecified, defaults to 1024. The maximum value is 2048.",
"default": "1024",
"format": "int32",
"location": "query"
},

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/u55VLYY4MP7i0aXvJvy-8Bykhic\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/5025FW69eRcOdd_mm4_PTDhGzHE\"",
"discoveryVersion": "v1",
"id": "gmail:v1",
"name": "gmail",
"version": "v1",
"revision": "20150303",
"revision": "20150313",
"title": "Gmail API",
"description": "The Gmail REST API.",
"ownerDomain": "google.com",
@@ -1333,6 +1333,12 @@
"httpMethod": "POST",
"description": "Directly inserts a message into only this user's mailbox similar to IMAP APPEND, bypassing most scanning and classification. Does not send a message.",
"parameters": {
"deleted": {
"type": "boolean",
"description": "Mark the email as permanently deleted (not TRASH) and only visible in Google Apps Vault to a Vault administrator. Only used for Google Apps for Work accounts.",
"default": "false",
"location": "query"
},
"internalDateSource": {
"type": "string",
"description": "Source for Gmail's internal date of the message.",

View File

@@ -1,6 +1,6 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/uMvgRqCygYBIh2d3lXb4f8cUWOw\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/8sBrpk7dyPsmoiW1fArUb0ZoCGY\"",
"discoveryVersion": "v1",
"id": "groupsmigration:v1",
"name": "groupsmigration",
@@ -67,6 +67,15 @@
"location": "query"
}
},
"auth": {
"oauth2": {
"scopes": {
"https://www.googleapis.com/auth/apps.groups.migration": {
"description": "Manage messages in groups on your domain"
}
}
}
},
"schemas": {
"Groups": {
"id": "Groups",
@@ -107,6 +116,9 @@
"response": {
"$ref": "Groups"
},
"scopes": [
"https://www.googleapis.com/auth/apps.groups.migration"
],
"supportsMediaUpload": true,
"mediaUpload": {
"accept": [

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/q8dY4UIVNRcK1B68dybhQ1dBwWc\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/ORNICSF2Z1YjV7yMXdU4V945lGo\"",
"discoveryVersion": "v1",
"id": "plus:v1",
"name": "plus",
"version": "v1",
"revision": "20150122",
"revision": "20150303",
"title": "Google+ API",
"description": "The Google+ API enables developers to build on top of the Google+ platform.",
"ownerDomain": "google.com",

View File

@@ -1,11 +1,11 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/D2Y34Y6W4h84dfzmMIBIqWNmCLk\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/pzJb3bipFURG3pTFQAI_x_KdTEY\"",
"discoveryVersion": "v1",
"id": "plusDomains:v1",
"name": "plusDomains",
"version": "v1",
"revision": "20150122",
"revision": "20150303",
"title": "Google+ Domains API",
"description": "The Google+ API enables developers to build on top of the Google+ platform.",
"ownerDomain": "google.com",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/Zoj2QNc62Iq34KyKgNb23b-JnD8\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/lfXuvexGjLWvv2bGYOX_MVmrKM4\"",
"discoveryVersion": "v1",
"id": "youtubeAnalytics:v1",
"name": "youtubeAnalytics",
"canonicalName": "YouTube Analytics",
"version": "v1",
"revision": "20150227",
"revision": "20150304",
"title": "YouTube Analytics API",
"description": "Retrieve your YouTube Analytics reports.",
"ownerDomain": "google.com",
@@ -638,6 +638,12 @@
"httpMethod": "GET",
"description": "Retrieve your YouTube Analytics reports.",
"parameters": {
"currency": {
"type": "string",
"description": "The currency to which financial metrics should be converted. The default is US Dollar (USD). If the result contains no financial metrics, this flag will be ignored. Responds with an error if the specified currency is not recognized.",
"pattern": "[A-Z]{3}",
"location": "query"
},
"dimensions": {
"type": "string",
"description": "A comma-separated list of YouTube Analytics dimensions, such as views or ageGroup,gender. See the Available Reports document for a list of the reports that you can retrieve and the dimensions used for those reports. Also see the Dimensions document for definitions of those dimensions.",

View File

@@ -1,12 +1,12 @@
{
"kind": "discovery#restDescription",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/OA1845UIyhDx4Pbq_uwDYxxJabA\"",
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/ID2nf7n7eRyIPf4mFz5QF1inEVE\"",
"discoveryVersion": "v1",
"id": "youtubeAnalytics:v1beta1",
"name": "youtubeAnalytics",
"canonicalName": "YouTube Analytics",
"version": "v1beta1",
"revision": "20150227",
"revision": "20150304",
"title": "YouTube Analytics API",
"description": "Retrieve your YouTube Analytics reports.",
"ownerDomain": "google.com",
@@ -641,6 +641,12 @@
"httpMethod": "GET",
"description": "Retrieve your YouTube Analytics reports.",
"parameters": {
"currency": {
"type": "string",
"description": "The currency to which financial metrics should be converted. The default is US Dollar (USD). If the result contains no financial metrics, this flag will be ignored. Responds with an error if the specified currency is not recognized.",
"pattern": "[A-Z]{3}",
"location": "query"
},
"dimensions": {
"type": "string",
"description": "A comma-separated list of YouTube Analytics dimensions, such as views or ageGroup,gender. See the Available Reports document for a list of the reports that you can retrieve and the dimensions used for those reports. Also see the Dimensions document for definitions of those dimensions.",

View File

@@ -76,7 +76,7 @@ To use this library, you would put the following lines into your `Cargo.toml` fi
```toml
[dependencies]
youtube3 = "0.0.1"
google-youtube3 = "0.0.1"
```
## A complete example
@@ -85,7 +85,7 @@ youtube3 = "0.0.1"
extern crate hyper;
extern crate "yup-oauth2" as oauth2;
extern crate "rustc-serialize" as rustc_serialize;
extern crate youtube3;
extern crate "google-youtube3" as youtube3;
use youtube3::cmn::Result;
use std::default::Default;
use oauth2::{Authenticator, DefaultAuthenticatorDelegate, ApplicationSecret, MemoryStorage};

View File

@@ -3,7 +3,7 @@
# DO NOT EDIT !
[package]
name = "youtube3"
name = "google-youtube3"
version = "0.0.1"
authors = ["Sebastian Thiel <byronimo@gmail>"]
description = "A complete library to interact with YouTube (protocol v3)"

View File

@@ -2,7 +2,6 @@
// DO NOT EDIT
use std::marker::MarkerTrait;
use std::io::{self, Read, Seek, Cursor, Write, SeekFrom};
use std::default::Default;
use mime::{Mime, TopLevel, SubLevel, Attr, Value};
use oauth2;
@@ -186,22 +185,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();

File diff suppressed because it is too large Load Diff

View File

@@ -11,8 +11,8 @@
doc_root = directories.output + '/doc'
doc_index = doc_root + '/index.html'
to_doc_root = lambda gen_root, api_name: gen_root + '/target/doc/' + api_name
central_api_index = lambda api_name: doc_root + '/' + api_name + '/index.html'
to_doc_root = lambda gen_root, crate_name: gen_root + '/target/doc/' + crate_name
central_api_index = lambda crate_name: doc_root + '/' + crate_name + '/index.html'
discovery_url = 'https://www.googleapis.com/discovery/v1/'
apis = json.loads(urllib2.urlopen(discovery_url + "apis").read())
@@ -27,6 +27,7 @@
import util
import os
api_name = util.library_name(an, version)
crate_name = util.library_to_crate_name(api_name)
gen_root = directories.output + '/' + api_name
gen_root_stamp = gen_root + '/.timestamp'
api_common = gen_root + '/src/cmn.rs'
@@ -34,7 +35,7 @@
api_cargo = api_name + '-cargo'
api_doc = api_name + '-doc'
api_doc_root = to_doc_root(gen_root, api_name)
api_doc_root = to_doc_root(gen_root, crate_name)
api_doc_index = api_doc_root + '/index.html'
# source, destination of individual output files
@@ -70,9 +71,9 @@ ${api_doc_index}: ${api_name}
${api_doc}: ${api_doc_index}
${central_api_index(api_name)}: ${api_doc_index}
${central_api_index(crate_name)}: ${api_doc_index}
@mkdir -p ${doc_root}
cp -Rf ${os.path.dirname(to_doc_root(gen_root, api_name))}/* ${doc_root}
cp -Rf ${os.path.dirname(to_doc_root(gen_root, crate_name))}/* ${doc_root}
${api_clean}:
-rm -Rf ${gen_root}
@@ -83,7 +84,7 @@ clean-apis: ${space_join(1)} docs-clean
cargo: ${space_join(2)}
apis: ${space_join(0)}
${doc_index}: ${' '.join(central_api_index(a[0]) for a in api_info)} $(MAKO_STANDARD_DEPENDENCIES)
${doc_index}: ${' '.join(central_api_index(util.library_to_crate_name(a[0])) for a in api_info)} $(MAKO_STANDARD_DEPENDENCIES)
$(MAKO) --var DOC_ROOT=${doc_root} -io $(MAKO_SRC)/index.html.mako=$@ --data-files $(API_SHARED_INFO) $(API_LIST)
@echo Documentation index created at '$@'

View File

@@ -132,6 +132,10 @@ ${link('Hub Delegate', delegate_url)}, or the ${link('Authenticator Delegate', u
When delegates handle errors or intermediate values, they may have a chance to instruct the system to retry. This
makes the system potentially resilient to all kinds of errors.
${'##'} About Uploads and Downlods
TODO: 'alt' media for downloads, custom methods for uploads (simple, resumable)
${'##'} About Customization/Callbacks
You may alter the way an `${api.terms.action}()` method is called by providing a ${link('delegate', delegate_url)} to the

View File

@@ -35,6 +35,8 @@
fn_name = 'add_' + fn_name
return fn_name
add_param_fn = 'param'
%>\
<%namespace name="util" file="util.mako"/>\
<%namespace name="lib" file="lib.mako"/>\
@@ -46,6 +48,8 @@
<%
hub_type_name = hub_type(schemas,util.canonical_name())
m = c.fqan_map[to_fqan(c.rtc_map[resource], resource, method)]
response_schema = method_response(c, m)
# an identifier for a property. We prefix them to prevent clashes with the setters
mb_tparams = mb_type_params_s(m)
ThisType = mb_type(resource, method) + mb_tparams
@@ -60,6 +64,15 @@
${m.description | rust_doc_comment}
///
% endif
% if m.get('supportsMediaDownload', False):
/// This method supports **media download**. To enable it, set the *alt* parameter to *media*, .i.e.
/// `.${add_param_fn}("alt", "media")`.
% if response_schema:
/// Please note that due to missing multi-part support on the server side, you will only receive the media,
/// but not the `${response_schema.id}` structure that you would usually get. The latter will be a default value.
% endif
///
% endif ## supports media download
/// A builder for the *${method}* method supported by a *${singular(resource)}* resource.
/// It is not used directly, but through a `${rb_type(resource)}`.
///
@@ -135,7 +148,7 @@ ${self._setter_fn(resource, method, m, p, part_prop, ThisType, c)}\
/// * *${opn}* (${op.location}-${op.type}) - ${op.description}
% endfor
% endif
pub fn param<T>(mut self, name: T, value: T) -> ${ThisType}
pub fn ${add_param_fn}<T>(mut self, name: T, value: T) -> ${ThisType}
where T: Str {
self.${api.properties.params}.insert(name.as_slice().to_string(), value.as_slice().to_string());
self
@@ -370,10 +383,12 @@ match result {
rtype = 'cmn::Result<hyper::client::Response>'
response_schema = method_response(c, m)
supports_download = m.get('supportsMediaDownload', False);
reserved_params = []
if response_schema:
if not supports_download:
reserved_params = ['alt']
rtype = 'cmn::Result<(hyper::client::Response, %s)>' % (response_schema.id)
reserved_params = ['alt']
mtype_param = 'RS'
mtype_where = 'ReadSeek'
@@ -462,12 +477,8 @@ match result {
## "the trait `core::marker::Sized` is not implemented for the type `std::io::Read`"
use hyper::client::IntoBody;
use std::io::{Read, Seek};
use hyper::header::{ContentType, ContentLength};
let mut params = Vec::new();
params.reserve_exact((${len(params) + len(reserved_params)} + ${paddfields}.len()));
% if response_schema:
params.push(("alt", "json".to_string()));
% endif
use hyper::header::{ContentType, ContentLength, Authorization, UserAgent};
let mut params: Vec<(&str, String)> = Vec::with_capacity((${len(params) + len(reserved_params)} + ${paddfields}.len()));
% for p in field_params:
<%
pname = 'self.' + property(p.name) # property identifier
@@ -510,6 +521,30 @@ match result {
params.push((&name, value.clone()));
}
% if response_schema:
% if supports_download:
let (json_field_missing, enable_resource_parsing) = {
let mut enable = true;
let mut field_present = true;
for &(name, ref value) in params.iter() {
if name == "alt" {
field_present = false;
if value.as_slice() != "json" {
enable = false;
}
break;
}
}
(field_present, enable)
};
if json_field_missing {
params.push(("alt", "json".to_string()));
}
% else:
params.push(("alt", "json".to_string()));
% endif ## supportsMediaDownload
% endif ## response schema
% if media_params:
let (mut url, protocol) = \
% for mp in media_params:
@@ -613,7 +648,7 @@ else {
if token.is_none() {
return cmn::Result::MissingToken
}
let auth_header = hyper::header::Authorization(token.unwrap().access_token);
let auth_header = Authorization(token.unwrap().access_token);
% endif
% if request_value:
request_value_reader.seek(io::SeekFrom::Start(0)).unwrap();
@@ -634,7 +669,7 @@ else {
% endif
let mut req = client.borrow_mut().request(hyper::method::Method::Extension("${m.httpMethod}".to_string()), url.as_slice())
.header(hyper::header::UserAgent(self.hub._user_agent.clone()))\
.header(UserAgent(self.hub._user_agent.clone()))\
% if supports_scopes(auth):
.header(auth_header)\
@@ -690,9 +725,20 @@ else {
return cmn::Result::Failure(res)
}
% if response_schema:
let mut json_response = String::new();
res.read_to_string(&mut json_response).unwrap();
let result_value = (res, json::decode(&json_response).unwrap());
## If 'alt' is not json, we cannot attempt to decode the response
let result_value = \
% if supports_download:
if enable_resource_parsing \
% endif
{
let mut json_response = String::new();
res.read_to_string(&mut json_response).unwrap();
(res, json::decode(&json_response).unwrap())
}\
% if supports_download:
else { (res, Default::default()) }\
% endif
;
% else:
let result_value = res;
% endif

View File

@@ -24,7 +24,7 @@ ${util.library_name(name, version)}\
</%def>
<%def name="crate_name()" buffered="True">\
google-${self.library_name()}\
${util.library_to_crate_name(util.library_name(name, version))}\
</%def>
## All crates and standard `use` declaration, required for all examples

View File

@@ -748,6 +748,10 @@ def library_name(name, version):
version = 'v' + version
return normalize_library_name(name) + version
# return crate name for given result of `library_name()`
def library_to_crate_name(name):
return 'google-' + name
# return type name of a resource method builder, from a resource name
def rb_type(r):
return "%sMethodsBuilder" % singular(canonical_type_name(r))