github.com/uber/kraken@v0.1.4/lib/backend/testfs/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 testfs 15 16 import ( 17 "encoding/json" 18 "errors" 19 "fmt" 20 "io" 21 "path" 22 "strconv" 23 24 "github.com/uber/kraken/core" 25 "github.com/uber/kraken/lib/backend" 26 "github.com/uber/kraken/lib/backend/backenderrors" 27 "github.com/uber/kraken/lib/backend/namepath" 28 "github.com/uber/kraken/utils/httputil" 29 30 "gopkg.in/yaml.v2" 31 ) 32 33 const _testfs = "testfs" 34 35 func init() { 36 backend.Register(_testfs, &factory{}) 37 } 38 39 type factory struct{} 40 41 func (f *factory) Create( 42 confRaw interface{}, authConfRaw interface{}) (backend.Client, error) { 43 44 confBytes, err := yaml.Marshal(confRaw) 45 if err != nil { 46 return nil, errors.New("marshal testfs config") 47 } 48 49 var config Config 50 if err := yaml.Unmarshal(confBytes, &config); err != nil { 51 return nil, errors.New("unmarshal testfs config") 52 } 53 54 return NewClient(config) 55 } 56 57 // Client wraps HTTP calls to Server. 58 type Client struct { 59 config Config 60 pather namepath.Pather 61 } 62 63 // NewClient returns a new Client. 64 func NewClient(config Config) (*Client, error) { 65 if config.Addr == "" { 66 return nil, errors.New("no addr configured") 67 } 68 pather, err := namepath.New(config.Root, config.NamePath) 69 if err != nil { 70 return nil, fmt.Errorf("namepath: %s", err) 71 } 72 return &Client{config, pather}, nil 73 } 74 75 // Addr returns the configured server address. 76 func (c *Client) Addr() string { 77 return c.config.Addr 78 } 79 80 // Stat returns blob info for name. 81 func (c *Client) Stat(namespace, name string) (*core.BlobInfo, error) { 82 p, err := c.pather.BlobPath(name) 83 if err != nil { 84 return nil, fmt.Errorf("pather: %s", err) 85 } 86 resp, err := httputil.Head( 87 fmt.Sprintf("http://%s/files/%s", c.config.Addr, p)) 88 if err != nil { 89 if httputil.IsNotFound(err) { 90 return nil, backenderrors.ErrBlobNotFound 91 } 92 return nil, err 93 } 94 size, err := strconv.ParseInt(resp.Header.Get("Size"), 10, 64) 95 if err != nil { 96 return nil, fmt.Errorf("parse size: %s", err) 97 } 98 return core.NewBlobInfo(size), nil 99 } 100 101 // Upload uploads src to name. 102 func (c *Client) Upload(namespace, name string, src io.Reader) error { 103 p, err := c.pather.BlobPath(name) 104 if err != nil { 105 return fmt.Errorf("pather: %s", err) 106 } 107 _, err = httputil.Post( 108 fmt.Sprintf("http://%s/files/%s", c.config.Addr, p), 109 httputil.SendBody(src)) 110 return err 111 } 112 113 // Download downloads name to dst. 114 func (c *Client) Download(namespace, name string, dst io.Writer) error { 115 p, err := c.pather.BlobPath(name) 116 if err != nil { 117 return fmt.Errorf("pather: %s", err) 118 } 119 resp, err := httputil.Get( 120 fmt.Sprintf("http://%s/files/%s", c.config.Addr, p)) 121 if err != nil { 122 if httputil.IsNotFound(err) { 123 return backenderrors.ErrBlobNotFound 124 } 125 return err 126 } 127 defer resp.Body.Close() 128 if _, err := io.Copy(dst, resp.Body); err != nil { 129 return fmt.Errorf("copy: %s", err) 130 } 131 return nil 132 } 133 134 // List lists names starting with prefix. 135 func (c *Client) List(prefix string, opts ...backend.ListOption) (*backend.ListResult, error) { 136 options := backend.DefaultListOptions() 137 for _, opt := range opts { 138 opt(options) 139 } 140 141 if options.Paginated { 142 return nil, errors.New("pagination not supported") 143 } 144 145 resp, err := httputil.Get( 146 fmt.Sprintf("http://%s/list/%s", c.config.Addr, path.Join(c.pather.BasePath(), prefix))) 147 if err != nil { 148 return nil, err 149 } 150 defer resp.Body.Close() 151 var paths []string 152 if err := json.NewDecoder(resp.Body).Decode(&paths); err != nil { 153 return nil, fmt.Errorf("json: %s", err) 154 } 155 var names []string 156 for _, p := range paths { 157 name, err := c.pather.NameFromBlobPath(p) 158 if err != nil { 159 return nil, fmt.Errorf("invalid path %s: %s", p, err) 160 } 161 names = append(names, name) 162 } 163 return &backend.ListResult{ 164 Names: names, 165 }, nil 166 }