Move to vendor

Signed-off-by: Olivier Gambier <olivier@docker.com>
This commit is contained in:
Olivier Gambier 2016-03-18 14:07:13 -07:00
parent c8d8e7e357
commit 77e69b9cf3
1268 changed files with 34 additions and 24 deletions

128
vendor/google.golang.org/cloud/internal/cloud.go generated vendored Normal file
View file

@ -0,0 +1,128 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package internal provides support for the cloud packages.
//
// Users should not import this package directly.
package internal
import (
"fmt"
"net/http"
"sync"
"golang.org/x/net/context"
)
type contextKey struct{}
func WithContext(parent context.Context, projID string, c *http.Client) context.Context {
if c == nil {
panic("nil *http.Client passed to WithContext")
}
if projID == "" {
panic("empty project ID passed to WithContext")
}
return context.WithValue(parent, contextKey{}, &cloudContext{
ProjectID: projID,
HTTPClient: c,
})
}
const userAgent = "gcloud-golang/0.1"
type cloudContext struct {
ProjectID string
HTTPClient *http.Client
mu sync.Mutex // guards svc
svc map[string]interface{} // e.g. "storage" => *rawStorage.Service
}
// Service returns the result of the fill function if it's never been
// called before for the given name (which is assumed to be an API
// service name, like "datastore"). If it has already been cached, the fill
// func is not run.
// It's safe for concurrent use by multiple goroutines.
func Service(ctx context.Context, name string, fill func(*http.Client) interface{}) interface{} {
return cc(ctx).service(name, fill)
}
func (c *cloudContext) service(name string, fill func(*http.Client) interface{}) interface{} {
c.mu.Lock()
defer c.mu.Unlock()
if c.svc == nil {
c.svc = make(map[string]interface{})
} else if v, ok := c.svc[name]; ok {
return v
}
v := fill(c.HTTPClient)
c.svc[name] = v
return v
}
// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type Transport struct {
// Base represents the actual http.RoundTripper
// the requests will be delegated to.
Base http.RoundTripper
}
// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req)
ua := req.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = fmt.Sprintf("%s %s", ua, userAgent)
}
req.Header.Set("User-Agent", ua)
return t.Base.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
func ProjID(ctx context.Context) string {
return cc(ctx).ProjectID
}
func HTTPClient(ctx context.Context) *http.Client {
return cc(ctx).HTTPClient
}
// cc returns the internal *cloudContext (cc) state for a context.Context.
// It panics if the user did it wrong.
func cc(ctx context.Context) *cloudContext {
if c, ok := ctx.Value(contextKey{}).(*cloudContext); ok {
return c
}
panic("invalid context.Context type; it should be created with cloud.NewContext")
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,606 @@
// Copyright 2013 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// The datastore v1 service proto definitions
syntax = "proto2";
package datastore;
option java_package = "com.google.api.services.datastore";
// An identifier for a particular subset of entities.
//
// Entities are partitioned into various subsets, each used by different
// datasets and different namespaces within a dataset and so forth.
//
// All input partition IDs are normalized before use.
// A partition ID is normalized as follows:
// If the partition ID is unset or is set to an empty partition ID, replace it
// with the context partition ID.
// Otherwise, if the partition ID has no dataset ID, assign it the context
// partition ID's dataset ID.
// Unless otherwise documented, the context partition ID has the dataset ID set
// to the context dataset ID and no other partition dimension set.
//
// A partition ID is empty if all of its fields are unset.
//
// Partition dimension:
// A dimension may be unset.
// A dimension's value must never be "".
// A dimension's value must match [A-Za-z\d\.\-_]{1,100}
// If the value of any dimension matches regex "__.*__",
// the partition is reserved/read-only.
// A reserved/read-only partition ID is forbidden in certain documented contexts.
//
// Dataset ID:
// A dataset id's value must never be "".
// A dataset id's value must match
// ([a-z\d\-]{1,100}~)?([a-z\d][a-z\d\-\.]{0,99}:)?([a-z\d][a-z\d\-]{0,99}
message PartitionId {
// The dataset ID.
optional string dataset_id = 3;
// The namespace.
optional string namespace = 4;
}
// A unique identifier for an entity.
// If a key's partition id or any of its path kinds or names are
// reserved/read-only, the key is reserved/read-only.
// A reserved/read-only key is forbidden in certain documented contexts.
message Key {
// Entities are partitioned into subsets, currently identified by a dataset
// (usually implicitly specified by the project) and namespace ID.
// Queries are scoped to a single partition.
optional PartitionId partition_id = 1;
// A (kind, ID/name) pair used to construct a key path.
//
// At most one of name or ID may be set.
// If either is set, the element is complete.
// If neither is set, the element is incomplete.
message PathElement {
// The kind of the entity.
// A kind matching regex "__.*__" is reserved/read-only.
// A kind must not contain more than 500 characters.
// Cannot be "".
required string kind = 1;
// The ID of the entity.
// Never equal to zero. Values less than zero are discouraged and will not
// be supported in the future.
optional int64 id = 2;
// The name of the entity.
// A name matching regex "__.*__" is reserved/read-only.
// A name must not be more than 500 characters.
// Cannot be "".
optional string name = 3;
}
// The entity path.
// An entity path consists of one or more elements composed of a kind and a
// string or numerical identifier, which identify entities. The first
// element identifies a <em>root entity</em>, the second element identifies
// a <em>child</em> of the root entity, the third element a child of the
// second entity, and so forth. The entities identified by all prefixes of
// the path are called the element's <em>ancestors</em>.
// An entity path is always fully complete: ALL of the entity's ancestors
// are required to be in the path along with the entity identifier itself.
// The only exception is that in some documented cases, the identifier in the
// last path element (for the entity) itself may be omitted. A path can never
// be empty.
repeated PathElement path_element = 2;
}
// A message that can hold any of the supported value types and associated
// metadata.
//
// At most one of the <type>Value fields may be set.
// If none are set the value is "null".
//
message Value {
// A boolean value.
optional bool boolean_value = 1;
// An integer value.
optional int64 integer_value = 2;
// A double value.
optional double double_value = 3;
// A timestamp value.
optional int64 timestamp_microseconds_value = 4;
// A key value.
optional Key key_value = 5;
// A blob key value.
optional string blob_key_value = 16;
// A UTF-8 encoded string value.
optional string string_value = 17;
// A blob value.
optional bytes blob_value = 18;
// An entity value.
// May have no key.
// May have a key with an incomplete key path.
// May have a reserved/read-only key.
optional Entity entity_value = 6;
// A list value.
// Cannot contain another list value.
// Cannot also have a meaning and indexing set.
repeated Value list_value = 7;
// The <code>meaning</code> field is reserved and should not be used.
optional int32 meaning = 14;
// If the value should be indexed.
//
// The <code>indexed</code> property may be set for a
// <code>null</code> value.
// When <code>indexed</code> is <code>true</code>, <code>stringValue</code>
// is limited to 500 characters and the blob value is limited to 500 bytes.
// Exception: If meaning is set to 2, string_value is limited to 2038
// characters regardless of indexed.
// When indexed is true, meaning 15 and 22 are not allowed, and meaning 16
// will be ignored on input (and will never be set on output).
// Input values by default have <code>indexed</code> set to
// <code>true</code>; however, you can explicitly set <code>indexed</code> to
// <code>true</code> if you want. (An output value never has
// <code>indexed</code> explicitly set to <code>true</code>.) If a value is
// itself an entity, it cannot have <code>indexed</code> set to
// <code>true</code>.
// Exception: An entity value with meaning 9, 20 or 21 may be indexed.
optional bool indexed = 15 [default = true];
}
// An entity property.
message Property {
// The name of the property.
// A property name matching regex "__.*__" is reserved.
// A reserved property name is forbidden in certain documented contexts.
// The name must not contain more than 500 characters.
// Cannot be "".
required string name = 1;
// The value(s) of the property.
// Each value can have only one value property populated. For example,
// you cannot have a values list of <code>{ value: { integerValue: 22,
// stringValue: "a" } }</code>, but you can have <code>{ value: { listValue:
// [ { integerValue: 22 }, { stringValue: "a" } ] }</code>.
required Value value = 4;
}
// An entity.
//
// An entity is limited to 1 megabyte when stored. That <em>roughly</em>
// corresponds to a limit of 1 megabyte for the serialized form of this
// message.
message Entity {
// The entity's key.
//
// An entity must have a key, unless otherwise documented (for example,
// an entity in <code>Value.entityValue</code> may have no key).
// An entity's kind is its key's path's last element's kind,
// or null if it has no key.
optional Key key = 1;
// The entity's properties.
// Each property's name must be unique for its entity.
repeated Property property = 2;
}
// The result of fetching an entity from the datastore.
message EntityResult {
// Specifies what data the 'entity' field contains.
// A ResultType is either implied (for example, in LookupResponse.found it
// is always FULL) or specified by context (for example, in message
// QueryResultBatch, field 'entity_result_type' specifies a ResultType
// for all the values in field 'entity_result').
enum ResultType {
FULL = 1; // The entire entity.
PROJECTION = 2; // A projected subset of properties.
// The entity may have no key.
// A property value may have meaning 18.
KEY_ONLY = 3; // Only the key.
}
// The resulting entity.
required Entity entity = 1;
}
// A query.
message Query {
// The projection to return. If not set the entire entity is returned.
repeated PropertyExpression projection = 2;
// The kinds to query (if empty, returns entities from all kinds).
repeated KindExpression kind = 3;
// The filter to apply (optional).
optional Filter filter = 4;
// The order to apply to the query results (if empty, order is unspecified).
repeated PropertyOrder order = 5;
// The properties to group by (if empty, no grouping is applied to the
// result set).
repeated PropertyReference group_by = 6;
// A starting point for the query results. Optional. Query cursors are
// returned in query result batches.
optional bytes /* serialized QueryCursor */ start_cursor = 7;
// An ending point for the query results. Optional. Query cursors are
// returned in query result batches.
optional bytes /* serialized QueryCursor */ end_cursor = 8;
// The number of results to skip. Applies before limit, but after all other
// constraints (optional, defaults to 0).
optional int32 offset = 10 [default=0];
// The maximum number of results to return. Applies after all other
// constraints. Optional.
optional int32 limit = 11;
}
// A representation of a kind.
message KindExpression {
// The name of the kind.
required string name = 1;
}
// A reference to a property relative to the kind expressions.
// exactly.
message PropertyReference {
// The name of the property.
required string name = 2;
}
// A representation of a property in a projection.
message PropertyExpression {
enum AggregationFunction {
FIRST = 1;
}
// The property to project.
required PropertyReference property = 1;
// The aggregation function to apply to the property. Optional.
// Can only be used when grouping by at least one property. Must
// then be set on all properties in the projection that are not
// being grouped by.
optional AggregationFunction aggregation_function = 2;
}
// The desired order for a specific property.
message PropertyOrder {
enum Direction {
ASCENDING = 1;
DESCENDING = 2;
}
// The property to order by.
required PropertyReference property = 1;
// The direction to order by.
optional Direction direction = 2 [default=ASCENDING];
}
// A holder for any type of filter. Exactly one field should be specified.
message Filter {
// A composite filter.
optional CompositeFilter composite_filter = 1;
// A filter on a property.
optional PropertyFilter property_filter = 2;
}
// A filter that merges the multiple other filters using the given operation.
message CompositeFilter {
enum Operator {
AND = 1;
}
// The operator for combining multiple filters.
required Operator operator = 1;
// The list of filters to combine.
// Must contain at least one filter.
repeated Filter filter = 2;
}
// A filter on a specific property.
message PropertyFilter {
enum Operator {
LESS_THAN = 1;
LESS_THAN_OR_EQUAL = 2;
GREATER_THAN = 3;
GREATER_THAN_OR_EQUAL = 4;
EQUAL = 5;
HAS_ANCESTOR = 11;
}
// The property to filter by.
required PropertyReference property = 1;
// The operator to filter by.
required Operator operator = 2;
// The value to compare the property to.
required Value value = 3;
}
// A GQL query.
message GqlQuery {
required string query_string = 1;
// When false, the query string must not contain a literal.
optional bool allow_literal = 2 [default = false];
// A named argument must set field GqlQueryArg.name.
// No two named arguments may have the same name.
// For each non-reserved named binding site in the query string,
// there must be a named argument with that name,
// but not necessarily the inverse.
repeated GqlQueryArg name_arg = 3;
// Numbered binding site @1 references the first numbered argument,
// effectively using 1-based indexing, rather than the usual 0.
// A numbered argument must NOT set field GqlQueryArg.name.
// For each binding site numbered i in query_string,
// there must be an ith numbered argument.
// The inverse must also be true.
repeated GqlQueryArg number_arg = 4;
}
// A binding argument for a GQL query.
// Exactly one of fields value and cursor must be set.
message GqlQueryArg {
// Must match regex "[A-Za-z_$][A-Za-z_$0-9]*".
// Must not match regex "__.*__".
// Must not be "".
optional string name = 1;
optional Value value = 2;
optional bytes cursor = 3;
}
// A batch of results produced by a query.
message QueryResultBatch {
// The possible values for the 'more_results' field.
enum MoreResultsType {
NOT_FINISHED = 1; // There are additional batches to fetch from this query.
MORE_RESULTS_AFTER_LIMIT = 2; // The query is finished, but there are more
// results after the limit.
NO_MORE_RESULTS = 3; // The query has been exhausted.
}
// The result type for every entity in entityResults.
required EntityResult.ResultType entity_result_type = 1;
// The results for this batch.
repeated EntityResult entity_result = 2;
// A cursor that points to the position after the last result in the batch.
// May be absent.
optional bytes /* serialized QueryCursor */ end_cursor = 4;
// The state of the query after the current batch.
required MoreResultsType more_results = 5;
// The number of results skipped because of <code>Query.offset</code>.
optional int32 skipped_results = 6;
}
// A set of changes to apply.
//
// No entity in this message may have a reserved property name,
// not even a property in an entity in a value.
// No value in this message may have meaning 18,
// not even a value in an entity in another value.
//
// If entities with duplicate keys are present, an arbitrary choice will
// be made as to which is written.
message Mutation {
// Entities to upsert.
// Each upserted entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity upsert = 1;
// Entities to update.
// Each updated entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity update = 2;
// Entities to insert.
// Each inserted entity's key must have a complete path and
// must not be reserved/read-only.
repeated Entity insert = 3;
// Insert entities with a newly allocated ID.
// Each inserted entity's key must omit the final identifier in its path and
// must not be reserved/read-only.
repeated Entity insert_auto_id = 4;
// Keys of entities to delete.
// Each key must have a complete key path and must not be reserved/read-only.
repeated Key delete = 5;
// Ignore a user specified read-only period. Optional.
optional bool force = 6;
}
// The result of applying a mutation.
message MutationResult {
// Number of index writes.
required int32 index_updates = 1;
// Keys for <code>insertAutoId</code> entities. One per entity from the
// request, in the same order.
repeated Key insert_auto_id_key = 2;
}
// Options shared by read requests.
message ReadOptions {
enum ReadConsistency {
DEFAULT = 0;
STRONG = 1;
EVENTUAL = 2;
}
// The read consistency to use.
// Cannot be set when transaction is set.
// Lookup and ancestor queries default to STRONG, global queries default to
// EVENTUAL and cannot be set to STRONG.
optional ReadConsistency read_consistency = 1 [default=DEFAULT];
// The transaction to use. Optional.
optional bytes /* serialized Transaction */ transaction = 2;
}
// The request for Lookup.
message LookupRequest {
// Options for this lookup request. Optional.
optional ReadOptions read_options = 1;
// Keys of entities to look up from the datastore.
repeated Key key = 3;
}
// The response for Lookup.
message LookupResponse {
// The order of results in these fields is undefined and has no relation to
// the order of the keys in the input.
// Entities found as ResultType.FULL entities.
repeated EntityResult found = 1;
// Entities not found as ResultType.KEY_ONLY entities.
repeated EntityResult missing = 2;
// A list of keys that were not looked up due to resource constraints.
repeated Key deferred = 3;
}
// The request for RunQuery.
message RunQueryRequest {
// The options for this query.
optional ReadOptions read_options = 1;
// Entities are partitioned into subsets, identified by a dataset (usually
// implicitly specified by the project) and namespace ID. Queries are scoped
// to a single partition.
// This partition ID is normalized with the standard default context
// partition ID, but all other partition IDs in RunQueryRequest are
// normalized with this partition ID as the context partition ID.
optional PartitionId partition_id = 2;
// The query to run.
// Either this field or field gql_query must be set, but not both.
optional Query query = 3;
// The GQL query to run.
// Either this field or field query must be set, but not both.
optional GqlQuery gql_query = 7;
}
// The response for RunQuery.
message RunQueryResponse {
// A batch of query results (always present).
optional QueryResultBatch batch = 1;
}
// The request for BeginTransaction.
message BeginTransactionRequest {
enum IsolationLevel {
SNAPSHOT = 0; // Read from a consistent snapshot. Concurrent transactions
// conflict if their mutations conflict. For example:
// Read(A),Write(B) may not conflict with Read(B),Write(A),
// but Read(B),Write(B) does conflict with Read(B),Write(B).
SERIALIZABLE = 1; // Read from a consistent snapshot. Concurrent
// transactions conflict if they cannot be serialized.
// For example Read(A),Write(B) does conflict with
// Read(B),Write(A) but Read(A) may not conflict with
// Write(A).
}
// The transaction isolation level.
optional IsolationLevel isolation_level = 1 [default=SNAPSHOT];
}
// The response for BeginTransaction.
message BeginTransactionResponse {
// The transaction identifier (always present).
optional bytes /* serialized Transaction */ transaction = 1;
}
// The request for Rollback.
message RollbackRequest {
// The transaction identifier, returned by a call to
// <code>beginTransaction</code>.
required bytes /* serialized Transaction */ transaction = 1;
}
// The response for Rollback.
message RollbackResponse {
// Empty
}
// The request for Commit.
message CommitRequest {
enum Mode {
TRANSACTIONAL = 1;
NON_TRANSACTIONAL = 2;
}
// The transaction identifier, returned by a call to
// <code>beginTransaction</code>. Must be set when mode is TRANSACTIONAL.
optional bytes /* serialized Transaction */ transaction = 1;
// The mutation to perform. Optional.
optional Mutation mutation = 2;
// The type of commit to perform. Either TRANSACTIONAL or NON_TRANSACTIONAL.
optional Mode mode = 5 [default=TRANSACTIONAL];
}
// The response for Commit.
message CommitResponse {
// The result of performing the mutation (if any).
optional MutationResult mutation_result = 1;
}
// The request for AllocateIds.
message AllocateIdsRequest {
// A list of keys with incomplete key paths to allocate IDs for.
// No key may be reserved/read-only.
repeated Key key = 1;
}
// The response for AllocateIds.
message AllocateIdsResponse {
// The keys specified in the request (in the same order), each with
// its key path completed with a newly allocated ID.
repeated Key key = 1;
}
// Each rpc normalizes the partition IDs of the keys in its input entities,
// and always returns entities with keys with normalized partition IDs.
// (Note that applies to all entities, including entities in values.)
service DatastoreService {
// Look up some entities by key.
rpc Lookup(LookupRequest) returns (LookupResponse) {
};
// Query for entities.
rpc RunQuery(RunQueryRequest) returns (RunQueryResponse) {
};
// Begin a new transaction.
rpc BeginTransaction(BeginTransactionRequest) returns (BeginTransactionResponse) {
};
// Commit a transaction, optionally creating, deleting or modifying some
// entities.
rpc Commit(CommitRequest) returns (CommitResponse) {
};
// Roll back a transaction.
rpc Rollback(RollbackRequest) returns (RollbackResponse) {
};
// Allocate IDs for incomplete keys (useful for referencing an entity before
// it is inserted).
rpc AllocateIds(AllocateIdsRequest) returns (AllocateIdsResponse) {
};
}

24
vendor/google.golang.org/cloud/internal/opts/option.go generated vendored Normal file
View file

@ -0,0 +1,24 @@
// Package opts holds the DialOpts struct, configurable by
// cloud.ClientOptions to set up transports for cloud packages.
//
// This is a separate page to prevent cycles between the core
// cloud packages.
package opts
import (
"net/http"
"golang.org/x/oauth2"
"google.golang.org/grpc"
)
type DialOpt struct {
Endpoint string
Scopes []string
UserAgent string
TokenSource oauth2.TokenSource
HTTPClient *http.Client
GRPCClient *grpc.ClientConn
}

View file

@ -0,0 +1,69 @@
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package testutil contains helper functions for writing tests.
package testutil
import (
"io/ioutil"
"log"
"net/http"
"os"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/cloud"
)
const (
envProjID = "GCLOUD_TESTS_GOLANG_PROJECT_ID"
envPrivateKey = "GCLOUD_TESTS_GOLANG_KEY"
)
func ProjID() string {
projID := os.Getenv(envProjID)
if projID == "" {
log.Fatal(envProjID + " must be set. See CONTRIBUTING.md for details.")
}
return projID
}
func TokenSource(ctx context.Context, scopes ...string) oauth2.TokenSource {
key := os.Getenv(envPrivateKey)
if key == "" {
log.Fatal(envPrivateKey + " must be set. See CONTRIBUTING.md for details.")
}
jsonKey, err := ioutil.ReadFile(key)
if err != nil {
log.Fatalf("Cannot read the JSON key file, err: %v", err)
}
conf, err := google.JWTConfigFromJSON(jsonKey, scopes...)
if err != nil {
log.Fatalf("google.JWTConfigFromJSON: %v", err)
}
return conf.TokenSource(ctx)
}
// TODO(djd): Delete this function when it's no longer used.
func Context(scopes ...string) context.Context {
ctx := oauth2.NoContext
ts := TokenSource(ctx, scopes...)
return cloud.NewContext(ProjID(), oauth2.NewClient(ctx, ts))
}
// TODO(djd): Delete this function when it's no longer used.
func NoAuthContext() context.Context {
return cloud.NewContext(ProjID(), &http.Client{Transport: http.DefaultTransport})
}

View file

@ -0,0 +1,29 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build go1.5
package transport
import "net/http"
// makeReqCancel returns a closure that cancels the given http.Request
// when called.
func makeReqCancel(req *http.Request) func(http.RoundTripper) {
c := make(chan struct{})
req.Cancel = c
return func(http.RoundTripper) {
close(c)
}
}

View file

@ -0,0 +1,31 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// +build !go1.5
package transport
import "net/http"
// makeReqCancel returns a closure that cancels the given http.Request
// when called.
func makeReqCancel(req *http.Request) func(http.RoundTripper) {
// Go 1.4 and prior do not have a reliable way of cancelling a request.
// Transport.CancelRequest will only work if the request is already in-flight.
return func(r http.RoundTripper) {
if t, ok := r.(*http.Transport); ok {
t.CancelRequest(req)
}
}
}

View file

@ -0,0 +1,134 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package transport
import (
"errors"
"fmt"
"net/http"
"golang.org/x/net/context"
"golang.org/x/oauth2"
"golang.org/x/oauth2/google"
"google.golang.org/cloud"
"google.golang.org/cloud/internal/opts"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/credentials/oauth"
)
// ErrHTTP is returned when on a non-200 HTTP response.
type ErrHTTP struct {
StatusCode int
Body []byte
err error
}
func (e *ErrHTTP) Error() string {
if e.err == nil {
return fmt.Sprintf("error during call, http status code: %v %s", e.StatusCode, e.Body)
}
return e.err.Error()
}
// NewHTTPClient returns an HTTP client for use communicating with a Google cloud
// service, configured with the given ClientOptions. It also returns the endpoint
// for the service as specified in the options.
func NewHTTPClient(ctx context.Context, opt ...cloud.ClientOption) (*http.Client, string, error) {
var o opts.DialOpt
for _, opt := range opt {
opt.Resolve(&o)
}
if o.GRPCClient != nil {
return nil, "", errors.New("unsupported GRPC base transport specified")
}
// TODO(djd): Wrap all http.Clients with appropriate internal version to add
// UserAgent header and prepend correct endpoint.
if o.HTTPClient != nil {
return o.HTTPClient, o.Endpoint, nil
}
if o.TokenSource == nil {
var err error
o.TokenSource, err = google.DefaultTokenSource(ctx, o.Scopes...)
if err != nil {
return nil, "", fmt.Errorf("google.DefaultTokenSource: %v", err)
}
}
return oauth2.NewClient(ctx, o.TokenSource), o.Endpoint, nil
}
// NewProtoClient returns a ProtoClient for communicating with a Google cloud service,
// configured with the given ClientOptions.
func NewProtoClient(ctx context.Context, opt ...cloud.ClientOption) (*ProtoClient, error) {
var o opts.DialOpt
for _, opt := range opt {
opt.Resolve(&o)
}
if o.GRPCClient != nil {
return nil, errors.New("unsupported GRPC base transport specified")
}
var client *http.Client
switch {
case o.HTTPClient != nil:
if o.TokenSource != nil {
return nil, errors.New("at most one of WithTokenSource or WithBaseHTTP may be provided")
}
client = o.HTTPClient
case o.TokenSource != nil:
client = oauth2.NewClient(ctx, o.TokenSource)
default:
var err error
client, err = google.DefaultClient(ctx, o.Scopes...)
if err != nil {
return nil, err
}
}
return &ProtoClient{
client: client,
endpoint: o.Endpoint,
userAgent: o.UserAgent,
}, nil
}
// DialGRPC returns a GRPC connection for use communicating with a Google cloud
// service, configured with the given ClientOptions.
func DialGRPC(ctx context.Context, opt ...cloud.ClientOption) (*grpc.ClientConn, error) {
var o opts.DialOpt
for _, opt := range opt {
opt.Resolve(&o)
}
if o.HTTPClient != nil {
return nil, errors.New("unsupported HTTP base transport specified")
}
if o.GRPCClient != nil {
return o.GRPCClient, nil
}
if o.TokenSource == nil {
var err error
o.TokenSource, err = google.DefaultTokenSource(ctx, o.Scopes...)
if err != nil {
return nil, fmt.Errorf("google.DefaultTokenSource: %v", err)
}
}
grpcOpts := []grpc.DialOption{
grpc.WithPerRPCCredentials(oauth.TokenSource{o.TokenSource}),
grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(nil, "")),
}
if o.UserAgent != "" {
grpcOpts = append(grpcOpts, grpc.WithUserAgent(o.UserAgent))
}
return grpc.Dial(o.Endpoint, grpcOpts...)
}

View file

@ -0,0 +1,80 @@
// Copyright 2015 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package transport
import (
"bytes"
"io/ioutil"
"net/http"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
)
type ProtoClient struct {
client *http.Client
endpoint string
userAgent string
}
func (c *ProtoClient) Call(ctx context.Context, method string, req, resp proto.Message) error {
payload, err := proto.Marshal(req)
if err != nil {
return err
}
httpReq, err := http.NewRequest("POST", c.endpoint+method, bytes.NewReader(payload))
if err != nil {
return err
}
httpReq.Header.Set("Content-Type", "application/x-protobuf")
if ua := c.userAgent; ua != "" {
httpReq.Header.Set("User-Agent", ua)
}
errc := make(chan error, 1)
cancel := makeReqCancel(httpReq)
go func() {
r, err := c.client.Do(httpReq)
if err != nil {
errc <- err
return
}
defer r.Body.Close()
body, err := ioutil.ReadAll(r.Body)
if r.StatusCode != http.StatusOK {
err = &ErrHTTP{
StatusCode: r.StatusCode,
Body: body,
err: err,
}
}
if err != nil {
errc <- err
return
}
errc <- proto.Unmarshal(body, resp)
}()
select {
case <-ctx.Done():
cancel(c.client.Transport) // Cancel the HTTP request.
return ctx.Err()
case err := <-errc:
return err
}
}