| OLD | NEW |
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 package gs | 5 package gs |
| 6 | 6 |
| 7 import ( | 7 import ( |
| 8 "io" | 8 "io" |
| 9 "net/http" | 9 "net/http" |
| 10 "time" | 10 "time" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 // NewReader instantiates a new Reader instance for the named bucket/pat
h. | 38 // NewReader instantiates a new Reader instance for the named bucket/pat
h. |
| 39 NewReader(bucket, relpath string, o Options) (io.ReadCloser, error) | 39 NewReader(bucket, relpath string, o Options) (io.ReadCloser, error) |
| 40 // NewWriter instantiates a new Writer instance for the named bucket/pat
h. | 40 // NewWriter instantiates a new Writer instance for the named bucket/pat
h. |
| 41 NewWriter(bucket, relpath string) (Writer, error) | 41 NewWriter(bucket, relpath string) (Writer, error) |
| 42 // Delete deletes the named Google Storage object. If the object doesn't | 42 // Delete deletes the named Google Storage object. If the object doesn't |
| 43 // exist, a nil error will be returned. | 43 // exist, a nil error will be returned. |
| 44 Delete(bucket, relpath string) error | 44 Delete(bucket, relpath string) error |
| 45 } | 45 } |
| 46 | 46 |
| 47 // Options are the set of extra options to apply to the Google Storage request. |
| 48 type Options struct { |
| 49 // From is the range request starting index. If >0, the beginning of the |
| 50 // range request will be set. |
| 51 From int64 |
| 52 // To is the range request ending index. If >0, the end of the |
| 53 // range request will be set. |
| 54 // |
| 55 // If no From index is set, this will result in a request indexed from t
he end |
| 56 // of the object. |
| 57 To int64 |
| 58 } |
| 59 |
| 47 // prodGSObject is an implementation of Client interface using the production | 60 // prodGSObject is an implementation of Client interface using the production |
| 48 // Google Storage client. | 61 // Google Storage client. |
| 49 type prodClient struct { | 62 type prodClient struct { |
| 50 context.Context | 63 context.Context |
| 51 | 64 |
| 52 » // rt is the http.RoundTripper to use for communication. | 65 » // rt is the RoundTripper to use, or nil for the cloud service default. |
| 53 rt http.RoundTripper | 66 rt http.RoundTripper |
| 54 // baseClient is a basic Google Storage client instance. It is used for | 67 // baseClient is a basic Google Storage client instance. It is used for |
| 55 // operations that don't need custom header injections. | 68 // operations that don't need custom header injections. |
| 56 baseClient *gs.Client | 69 baseClient *gs.Client |
| 57 } | 70 } |
| 58 | 71 |
| 59 // NewProdClient creates a new Client instance that uses production Cloud | 72 // NewProdClient creates a new Client instance that uses production Cloud |
| 60 // Storage. | 73 // Storage. |
| 61 // | 74 // |
| 62 // The supplied RoundTripper will be used to make connections. If nil, | 75 // The supplied RoundTripper will be used to make connections. If nil, the |
| 63 // the default http.Client RoundTripper will be used. | 76 // default HTTP client will be used. |
| 64 func NewProdClient(ctx context.Context, rt http.RoundTripper) (Client, error) { | 77 func NewProdClient(ctx context.Context, rt http.RoundTripper) (Client, error) { |
| 65 c := prodClient{ | 78 c := prodClient{ |
| 66 Context: ctx, | 79 Context: ctx, |
| 67 rt: rt, | 80 rt: rt, |
| 68 } | 81 } |
| 69 var err error | 82 var err error |
| 70 » c.baseClient, err = c.newClient(nil) | 83 » c.baseClient, err = c.newClient() |
| 71 if err != nil { | 84 if err != nil { |
| 72 return nil, err | 85 return nil, err |
| 73 } | 86 } |
| 74 return &c, nil | 87 return &c, nil |
| 75 } | 88 } |
| 76 | 89 |
| 77 func (c *prodClient) Close() error { | 90 func (c *prodClient) Close() error { |
| 78 return c.baseClient.Close() | 91 return c.baseClient.Close() |
| 79 } | 92 } |
| 80 | 93 |
| 81 func (c *prodClient) NewWriter(bucket, relpath string) (Writer, error) { | 94 func (c *prodClient) NewWriter(bucket, relpath string) (Writer, error) { |
| 82 return &prodWriter{ | 95 return &prodWriter{ |
| 83 Context: c, | 96 Context: c, |
| 84 client: c, | 97 client: c, |
| 85 bucket: bucket, | 98 bucket: bucket, |
| 86 relpath: relpath, | 99 relpath: relpath, |
| 87 }, nil | 100 }, nil |
| 88 } | 101 } |
| 89 | 102 |
| 90 func (c *prodClient) NewReader(bucket, relpath string, o Options) (io.ReadCloser
, error) { | 103 func (c *prodClient) NewReader(bucket, relpath string, o Options) (io.ReadCloser
, error) { |
| 91 » client, err := c.newClient(&o) | 104 » if o.From < 0 { |
| 92 » if err != nil { | 105 » » o.From = 0 |
| 93 » » return nil, err | |
| 94 } | 106 } |
| 95 » return client.Bucket(bucket).Object(relpath).NewReader(c) | 107 » if o.To <= 0 { |
| 108 » » o.To = -1 |
| 109 » } |
| 110 » return c.baseClient.Bucket(bucket).Object(relpath).NewRangeReader(c, o.F
rom, o.To) |
| 96 } | 111 } |
| 97 | 112 |
| 98 func (c *prodClient) Delete(bucket, relpath string) error { | 113 func (c *prodClient) Delete(bucket, relpath string) error { |
| 99 obj := c.baseClient.Bucket(bucket).Object(relpath) | 114 obj := c.baseClient.Bucket(bucket).Object(relpath) |
| 100 return retry.Retry(c, retry.TransientOnly(retry.Default), func() error { | 115 return retry.Retry(c, retry.TransientOnly(retry.Default), func() error { |
| 101 if err := obj.Delete(c); err != nil { | 116 if err := obj.Delete(c); err != nil { |
| 102 // The storage library doesn't return gs.ErrObjectNotExi
st when Delete | 117 // The storage library doesn't return gs.ErrObjectNotExi
st when Delete |
| 103 // returns a 404. Catch that explicitly. | 118 // returns a 404. Catch that explicitly. |
| 104 if t, ok := err.(*googleapi.Error); ok { | 119 if t, ok := err.(*googleapi.Error); ok { |
| 105 switch t.Code { | 120 switch t.Code { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 116 }, func(err error, d time.Duration) { | 131 }, func(err error, d time.Duration) { |
| 117 log.Fields{ | 132 log.Fields{ |
| 118 log.ErrorKey: err, | 133 log.ErrorKey: err, |
| 119 "delay": d, | 134 "delay": d, |
| 120 "bucket": bucket, | 135 "bucket": bucket, |
| 121 "path": relpath, | 136 "path": relpath, |
| 122 }.Warningf(c, "Transient error deleting GS file. Retrying...") | 137 }.Warningf(c, "Transient error deleting GS file. Retrying...") |
| 123 }) | 138 }) |
| 124 } | 139 } |
| 125 | 140 |
| 126 func (c *prodClient) newClient(o *Options) (*gs.Client, error) { | 141 func (c *prodClient) newClient() (*gs.Client, error) { |
| 127 » rt := c.rt | 142 » var optsArray [1]cloud.ClientOption |
| 128 » if rt == nil { | 143 » opts := optsArray[:0] |
| 129 » » rt = http.DefaultTransport | 144 » if c.rt != nil { |
| 145 » » opts = append(opts, cloud.WithBaseHTTP(&http.Client{ |
| 146 » » » Transport: c.rt, |
| 147 » » })) |
| 130 } | 148 } |
| 131 | 149 » return gs.NewClient(c, opts...) |
| 132 » // This is a hack. Unfortunately, it is necessary since the Cloud Storag
e API | |
| 133 » // doesn't support setting range request headers. This installation enab
les | |
| 134 » // us to request ranges from Cloud Storage objects, which is super usefu
l for | |
| 135 » // range requests since we have an index. | |
| 136 » // | |
| 137 » // The Client construction logic is taken from here: | |
| 138 » // https://godoc.org/google.golang.org/cloud/internal/transport#NewHTTPC
lient | |
| 139 » // | |
| 140 » // We have to replicate the token source confguration b/c our only entry
point | |
| 141 » // into header editing is the "cloud.WithClient", which preempts all of
the | |
| 142 » // token source generation logic. | |
| 143 » if o != nil { | |
| 144 » » rt = &gsRoundTripper{ | |
| 145 » » » RoundTripper: rt, | |
| 146 » » » Options: o, | |
| 147 » » } | |
| 148 » } | |
| 149 » client := http.Client{ | |
| 150 » » Transport: rt, | |
| 151 » } | |
| 152 | |
| 153 » gsc, err := gs.NewClient(c, cloud.WithBaseHTTP(&client)) | |
| 154 » if err != nil { | |
| 155 » » return nil, err | |
| 156 » } | |
| 157 | |
| 158 » return gsc, nil | |
| 159 } | 150 } |
| OLD | NEW |