tracker/metainfoclient/client.go (68 lines of code) (raw):

// Copyright (c) 2016-2019 Uber Technologies, Inc. // // 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 metainfoclient import ( "crypto/tls" "errors" "fmt" "io/ioutil" "net/http" "net/url" "time" "github.com/cenkalti/backoff" "github.com/uber/kraken/core" "github.com/uber/kraken/lib/hashring" "github.com/uber/kraken/utils/httputil" ) // Client errors. var ( ErrNotFound = errors.New("metainfo not found") ) // Client defines operations on torrent metainfo. type Client interface { Download(namespace string, d core.Digest) (*core.MetaInfo, error) } type client struct { ring hashring.PassiveRing tls *tls.Config } // New returns a new Client. func New(ring hashring.PassiveRing, tls *tls.Config) Client { return &client{ring, tls} } // Download returns the MetaInfo associated with name. Returns ErrNotFound if // no torrent exists under name. func (c *client) Download(namespace string, d core.Digest) (*core.MetaInfo, error) { var resp *http.Response var err error for _, addr := range c.ring.Locations(d) { resp, err = httputil.PollAccepted( fmt.Sprintf( "http://%s/namespace/%s/blobs/%s/metainfo", addr, url.PathEscape(namespace), d), &backoff.ExponentialBackOff{ InitialInterval: time.Second, RandomizationFactor: 0.05, Multiplier: 1.3, MaxInterval: 5 * time.Second, MaxElapsedTime: 15 * time.Minute, Clock: backoff.SystemClock, }, httputil.SendTimeout(10*time.Second), httputil.SendTLS(c.tls)) if err != nil { if httputil.IsNetworkError(err) { c.ring.Failed(addr) continue } if httputil.IsNotFound(err) { return nil, ErrNotFound } return nil, err } defer resp.Body.Close() b, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, fmt.Errorf("read body: %s", err) } mi, err := core.DeserializeMetaInfo(b) if err != nil { return nil, fmt.Errorf("deserialize metainfo: %s", err) } return mi, nil } return nil, err }