github.com/uber/kraken@v0.1.4/tracker/metainfoclient/client.go (about) 1 // Copyright (c) 2016-2019 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package metainfoclient 15 16 import ( 17 "crypto/tls" 18 "errors" 19 "fmt" 20 "io/ioutil" 21 "net/http" 22 "net/url" 23 "time" 24 25 "github.com/cenkalti/backoff" 26 27 "github.com/uber/kraken/core" 28 "github.com/uber/kraken/lib/hashring" 29 "github.com/uber/kraken/utils/httputil" 30 ) 31 32 // Client errors. 33 var ( 34 ErrNotFound = errors.New("metainfo not found") 35 ) 36 37 // Client defines operations on torrent metainfo. 38 type Client interface { 39 Download(namespace string, d core.Digest) (*core.MetaInfo, error) 40 } 41 42 type client struct { 43 ring hashring.PassiveRing 44 tls *tls.Config 45 } 46 47 // New returns a new Client. 48 func New(ring hashring.PassiveRing, tls *tls.Config) Client { 49 return &client{ring, tls} 50 } 51 52 // Download returns the MetaInfo associated with name. Returns ErrNotFound if 53 // no torrent exists under name. 54 func (c *client) Download(namespace string, d core.Digest) (*core.MetaInfo, error) { 55 var resp *http.Response 56 var err error 57 for _, addr := range c.ring.Locations(d) { 58 resp, err = httputil.PollAccepted( 59 fmt.Sprintf( 60 "http://%s/namespace/%s/blobs/%s/metainfo", 61 addr, url.PathEscape(namespace), d), 62 &backoff.ExponentialBackOff{ 63 InitialInterval: time.Second, 64 RandomizationFactor: 0.05, 65 Multiplier: 1.3, 66 MaxInterval: 5 * time.Second, 67 MaxElapsedTime: 15 * time.Minute, 68 Clock: backoff.SystemClock, 69 }, 70 httputil.SendTimeout(10*time.Second), 71 httputil.SendTLS(c.tls)) 72 if err != nil { 73 if httputil.IsNetworkError(err) { 74 c.ring.Failed(addr) 75 continue 76 } 77 if httputil.IsNotFound(err) { 78 return nil, ErrNotFound 79 } 80 return nil, err 81 } 82 defer resp.Body.Close() 83 b, err := ioutil.ReadAll(resp.Body) 84 if err != nil { 85 return nil, fmt.Errorf("read body: %s", err) 86 } 87 mi, err := core.DeserializeMetaInfo(b) 88 if err != nil { 89 return nil, fmt.Errorf("deserialize metainfo: %s", err) 90 } 91 return mi, nil 92 } 93 return nil, err 94 }