diff options
author | Lewis Marshall <lewis@lmars.net> | 2017-04-05 06:20:07 +0800 |
---|---|---|
committer | Felix Lange <fjl@users.noreply.github.com> | 2017-04-05 06:20:07 +0800 |
commit | b319f027a0be232a9cb307336b0349b36737c7f1 (patch) | |
tree | a17c7dc775c270aea9acdabc8e13292b3c2ae958 /cmd/swarm/upload.go | |
parent | 09777952ee476ff80d4b6e63b5041ff5ca0e441b (diff) | |
download | go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar.gz go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar.bz2 go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar.lz go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar.xz go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.tar.zst go-tangerine-b319f027a0be232a9cb307336b0349b36737c7f1.zip |
cmd/swarm, swarm/api/client: add HTTP API client and 'swarm ls' command (#3742)
This adds a swarm ls command which lists files and directories stored in a
manifest. Rather than listing all files, it uses "directory prefixes" in case there are a
lot of files in a manifest but you just want to traverse it.
This also includes some refactoring to the tests and the introduction of a
swarm/api/client package to make things easier to test.
Diffstat (limited to 'cmd/swarm/upload.go')
-rw-r--r-- | cmd/swarm/upload.go | 163 |
1 files changed, 6 insertions, 157 deletions
diff --git a/cmd/swarm/upload.go b/cmd/swarm/upload.go index 7b4961778..696b907d2 100644 --- a/cmd/swarm/upload.go +++ b/cmd/swarm/upload.go @@ -18,21 +18,15 @@ package main import ( - "bytes" "encoding/json" "fmt" - "io" - "io/ioutil" - "mime" - "net/http" "os" "os/user" "path" - "path/filepath" "strings" "github.com/ethereum/go-ethereum/cmd/utils" - "github.com/ethereum/go-ethereum/log" + swarm "github.com/ethereum/go-ethereum/swarm/api/client" "gopkg.in/urfave/cli.v1" ) @@ -50,7 +44,7 @@ func upload(ctx *cli.Context) { var ( file = args[0] - client = &client{api: bzzapi} + client = swarm.NewClient(bzzapi) ) fi, err := os.Stat(expandPath(file)) if err != nil { @@ -63,25 +57,25 @@ func upload(ctx *cli.Context) { if !wantManifest { utils.Fatalf("Manifest is required for directory uploads") } - mhash, err := client.uploadDirectory(file, defaultPath) + mhash, err := client.UploadDirectory(file, defaultPath) if err != nil { utils.Fatalf("Failed to upload directory: %v", err) } fmt.Println(mhash) return } - entry, err := client.uploadFile(file, fi) + entry, err := client.UploadFile(file, fi) if err != nil { utils.Fatalf("Upload failed: %v", err) } - mroot := manifest{[]manifestEntry{entry}} + mroot := swarm.Manifest{Entries: []swarm.ManifestEntry{entry}} if !wantManifest { // Print the manifest. This is the only output to stdout. mrootJSON, _ := json.MarshalIndent(mroot, "", " ") fmt.Println(string(mrootJSON)) return } - hash, err := client.uploadManifest(mroot) + hash, err := client.UploadManifest(mroot) if err != nil { utils.Fatalf("Manifest upload failed: %v", err) } @@ -111,148 +105,3 @@ func homeDir() string { } return "" } - -// client wraps interaction with the swarm HTTP gateway. -type client struct { - api string -} - -// manifest is the JSON representation of a swarm manifest. -type manifestEntry struct { - Hash string `json:"hash,omitempty"` - ContentType string `json:"contentType,omitempty"` - Path string `json:"path,omitempty"` -} - -// manifest is the JSON representation of a swarm manifest. -type manifest struct { - Entries []manifestEntry `json:"entries,omitempty"` -} - -func (c *client) uploadDirectory(dir string, defaultPath string) (string, error) { - mhash, err := c.postRaw("application/json", 2, ioutil.NopCloser(bytes.NewReader([]byte("{}")))) - if err != nil { - return "", fmt.Errorf("failed to upload empty manifest") - } - if len(defaultPath) > 0 { - fi, err := os.Stat(defaultPath) - if err != nil { - return "", err - } - mhash, err = c.uploadToManifest(mhash, "", defaultPath, fi) - if err != nil { - return "", err - } - } - prefix := filepath.ToSlash(filepath.Clean(dir)) + "/" - err = filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error { - if err != nil || fi.IsDir() { - return err - } - if !strings.HasPrefix(path, dir) { - return fmt.Errorf("path %s outside directory %s", path, dir) - } - uripath := strings.TrimPrefix(filepath.ToSlash(filepath.Clean(path)), prefix) - mhash, err = c.uploadToManifest(mhash, uripath, path, fi) - return err - }) - return mhash, err -} - -func (c *client) uploadFile(file string, fi os.FileInfo) (manifestEntry, error) { - hash, err := c.uploadFileContent(file, fi) - m := manifestEntry{ - Hash: hash, - ContentType: mime.TypeByExtension(filepath.Ext(fi.Name())), - } - return m, err -} - -func (c *client) uploadFileContent(file string, fi os.FileInfo) (string, error) { - fd, err := os.Open(file) - if err != nil { - return "", err - } - defer fd.Close() - log.Info("Uploading swarm content", "file", file, "bytes", fi.Size()) - return c.postRaw("application/octet-stream", fi.Size(), fd) -} - -func (c *client) uploadManifest(m manifest) (string, error) { - jsm, err := json.Marshal(m) - if err != nil { - panic(err) - } - log.Info("Uploading swarm manifest") - return c.postRaw("application/json", int64(len(jsm)), ioutil.NopCloser(bytes.NewReader(jsm))) -} - -func (c *client) uploadToManifest(mhash string, path string, fpath string, fi os.FileInfo) (string, error) { - fd, err := os.Open(fpath) - if err != nil { - return "", err - } - defer fd.Close() - log.Info("Uploading swarm content and path", "file", fpath, "bytes", fi.Size(), "path", path) - req, err := http.NewRequest("PUT", c.api+"/bzz:/"+mhash+"/"+path, fd) - if err != nil { - return "", err - } - req.Header.Set("content-type", mime.TypeByExtension(filepath.Ext(fi.Name()))) - req.ContentLength = fi.Size() - resp, err := http.DefaultClient.Do(req) - if err != nil { - return "", err - } - defer resp.Body.Close() - if resp.StatusCode >= 400 { - return "", fmt.Errorf("bad status: %s", resp.Status) - } - content, err := ioutil.ReadAll(resp.Body) - return string(content), err -} - -func (c *client) postRaw(mimetype string, size int64, body io.ReadCloser) (string, error) { - req, err := http.NewRequest("POST", c.api+"/bzzr:/", body) - if err != nil { - return "", err - } - req.Header.Set("content-type", mimetype) - req.ContentLength = size - resp, err := http.DefaultClient.Do(req) - if err != nil { - return "", err - } - defer resp.Body.Close() - if resp.StatusCode >= 400 { - return "", fmt.Errorf("bad status: %s", resp.Status) - } - content, err := ioutil.ReadAll(resp.Body) - return string(content), err -} - -func (c *client) downloadManifest(mhash string) (manifest, error) { - - mroot := manifest{} - req, err := http.NewRequest("GET", c.api+"/bzzr:/"+mhash, nil) - if err != nil { - return mroot, err - } - resp, err := http.DefaultClient.Do(req) - if err != nil { - return mroot, err - } - defer resp.Body.Close() - - if resp.StatusCode >= 400 { - return mroot, fmt.Errorf("bad status: %s", resp.Status) - - } - content, err := ioutil.ReadAll(resp.Body) - - err = json.Unmarshal(content, &mroot) - if err != nil { - return mroot, fmt.Errorf("Manifest %v is malformed: %v", mhash, err) - } - return mroot, err -} |