aboutsummaryrefslogtreecommitdiffstats
path: root/cmd/swarm/upload.go
diff options
context:
space:
mode:
authorLewis Marshall <lewis@lmars.net>2017-04-05 06:20:07 +0800
committerFelix Lange <fjl@users.noreply.github.com>2017-04-05 06:20:07 +0800
commitb319f027a0be232a9cb307336b0349b36737c7f1 (patch)
treea17c7dc775c270aea9acdabc8e13292b3c2ae958 /cmd/swarm/upload.go
parent09777952ee476ff80d4b6e63b5041ff5ca0e441b (diff)
downloaddexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar
dexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar.gz
dexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar.bz2
dexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar.lz
dexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar.xz
dexon-b319f027a0be232a9cb307336b0349b36737c7f1.tar.zst
dexon-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.go163
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
-}