swarm/api: upload defaultpath file only once

This commit is contained in:
Janos Guljas 2018-07-31 16:59:20 +02:00
parent 46d4721519
commit e3e5583ec5
5 changed files with 48 additions and 23 deletions

View file

@ -701,11 +701,12 @@ func (a *API) AddFile(ctx context.Context, mhash, path, fname string, content []
return fkey, newMkey.String(), nil return fkey, newMkey.String(), nil
} }
func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath string, mw *ManifestWriter) (storage.Address, error) { func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestPath, defaultPath string, mw *ManifestWriter) (storage.Address, error) {
apiUploadTarCount.Inc(1) apiUploadTarCount.Inc(1)
var contentKey storage.Address var contentKey storage.Address
tr := tar.NewReader(bodyReader) tr := tar.NewReader(bodyReader)
defer bodyReader.Close() defer bodyReader.Close()
var defaultPathFound bool
for { for {
hdr, err := tr.Next() hdr, err := tr.Next()
if err == io.EOF { if err == io.EOF {
@ -734,6 +735,25 @@ func (a *API) UploadTar(ctx context.Context, bodyReader io.ReadCloser, manifestP
apiUploadTarFail.Inc(1) apiUploadTarFail.Inc(1)
return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err) return nil, fmt.Errorf("error adding manifest entry from tar stream: %s", err)
} }
if hdr.Name == defaultPath {
entry := &ManifestEntry{
Hash: contentKey.Hex(),
Path: "", // default entry
ContentType: hdr.Xattrs["user.swarm.content-type"],
Mode: hdr.Mode,
Size: hdr.Size,
ModTime: hdr.ModTime,
}
contentKey, err = mw.AddEntry(ctx, nil, entry)
if err != nil {
apiUploadTarFail.Inc(1)
return nil, fmt.Errorf("error adding default manifest entry from tar stream: %s", err)
}
defaultPathFound = true
}
}
if defaultPath != "" && !defaultPathFound {
return contentKey, fmt.Errorf("default path %q not found", defaultPath)
} }
return contentKey, nil return contentKey, nil
} }

View file

@ -138,7 +138,7 @@ func (c *Client) Upload(file *File, manifest string, toEncrypt bool) (string, er
if file.Size <= 0 { if file.Size <= 0 {
return "", errors.New("file size must be greater than zero") return "", errors.New("file size must be greater than zero")
} }
return c.TarUpload(manifest, &FileUploader{file}, toEncrypt) return c.TarUpload(manifest, &FileUploader{file}, "", toEncrypt)
} }
// Download downloads a file with the given path from the swarm manifest with // Download downloads a file with the given path from the swarm manifest with
@ -175,7 +175,10 @@ func (c *Client) UploadDirectory(dir, defaultPath, manifest string, toEncrypt bo
} else if !stat.IsDir() { } else if !stat.IsDir() {
return "", fmt.Errorf("not a directory: %s", dir) return "", fmt.Errorf("not a directory: %s", dir)
} }
return c.TarUpload(manifest, &DirectoryUploader{dir, defaultPath}, toEncrypt) if _, err := os.Stat(filepath.Join(dir, defaultPath)); err != nil {
return "", fmt.Errorf("default path: %v", err)
}
return c.TarUpload(manifest, &DirectoryUploader{dir}, defaultPath, toEncrypt)
} }
// DownloadDirectory downloads the files contained in a swarm manifest under // DownloadDirectory downloads the files contained in a swarm manifest under
@ -390,20 +393,10 @@ func (u UploaderFunc) Upload(upload UploadFn) error {
// a file to the default path // a file to the default path
type DirectoryUploader struct { type DirectoryUploader struct {
Dir string Dir string
DefaultPath string
} }
// Upload performs the upload of the directory and default path // Upload performs the upload of the directory and default path
func (d *DirectoryUploader) Upload(upload UploadFn) error { func (d *DirectoryUploader) Upload(upload UploadFn) error {
if d.DefaultPath != "" {
file, err := Open(d.DefaultPath)
if err != nil {
return err
}
if err := upload(file); err != nil {
return err
}
}
return filepath.Walk(d.Dir, func(path string, f os.FileInfo, err error) error { return filepath.Walk(d.Dir, func(path string, f os.FileInfo, err error) error {
if err != nil { if err != nil {
return err return err
@ -441,7 +434,7 @@ type UploadFn func(file *File) error
// TarUpload uses the given Uploader to upload files to swarm as a tar stream, // TarUpload uses the given Uploader to upload files to swarm as a tar stream,
// returning the resulting manifest hash // returning the resulting manifest hash
func (c *Client) TarUpload(hash string, uploader Uploader, toEncrypt bool) (string, error) { func (c *Client) TarUpload(hash string, uploader Uploader, defaultPath string, toEncrypt bool) (string, error) {
reqR, reqW := io.Pipe() reqR, reqW := io.Pipe()
defer reqR.Close() defer reqR.Close()
addr := hash addr := hash
@ -458,6 +451,11 @@ func (c *Client) TarUpload(hash string, uploader Uploader, toEncrypt bool) (stri
return "", err return "", err
} }
req.Header.Set("Content-Type", "application/x-tar") req.Header.Set("Content-Type", "application/x-tar")
if defaultPath != "" {
q := req.URL.Query()
q.Set("defaultpath", defaultPath)
req.URL.RawQuery = q.Encode()
}
// use 'Expect: 100-continue' so we don't send the request body if // use 'Expect: 100-continue' so we don't send the request body if
// the server refuses the request // the server refuses the request

View file

@ -194,7 +194,7 @@ func TestClientUploadDownloadDirectory(t *testing.T) {
// upload the directory // upload the directory
client := NewClient(srv.URL) client := NewClient(srv.URL)
defaultPath := filepath.Join(dir, testDirFiles[0]) defaultPath := testDirFiles[0]
hash, err := client.UploadDirectory(dir, defaultPath, "", false) hash, err := client.UploadDirectory(dir, defaultPath, "", false)
if err != nil { if err != nil {
t.Fatalf("error uploading directory: %s", err) t.Fatalf("error uploading directory: %s", err)

View file

@ -386,7 +386,9 @@ func (s *Server) HandlePostFiles(w http.ResponseWriter, r *Request) {
func (s *Server) handleTarUpload(r *Request, mw *api.ManifestWriter) (storage.Address, error) { func (s *Server) handleTarUpload(r *Request, mw *api.ManifestWriter) (storage.Address, error) {
log.Debug("handle.tar.upload", "ruid", r.ruid) log.Debug("handle.tar.upload", "ruid", r.ruid)
key, err := s.api.UploadTar(r.Context(), r.Body, r.uri.Path, mw) defaultPath := r.URL.Query().Get("defaultpath")
key, err := s.api.UploadTar(r.Context(), r.Body, r.uri.Path, defaultPath, mw)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -106,13 +106,18 @@ func (a *API) NewManifestWriter(ctx context.Context, addr storage.Address, quitC
} }
// AddEntry stores the given data and adds the resulting key to the manifest // AddEntry stores the given data and adds the resulting key to the manifest
func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (storage.Address, error) { func (m *ManifestWriter) AddEntry(ctx context.Context, data io.Reader, e *ManifestEntry) (key storage.Address, err error) {
key, _, err := m.api.Store(ctx, data, e.Size, m.trie.encrypted) entry := newManifestTrieEntry(e, nil)
if data != nil {
key, _, err = m.api.Store(ctx, data, e.Size, m.trie.encrypted)
if err != nil { if err != nil {
return nil, err return nil, err
} }
entry := newManifestTrieEntry(e, nil)
entry.Hash = key.Hex() entry.Hash = key.Hex()
}
if entry.Hash == "" {
return key, errors.New("missing entry hash")
}
m.trie.addEntry(entry, m.quitC) m.trie.addEntry(entry, m.quitC)
return key, nil return key, nil
} }