swarm/api: refactor and improve HTTP API (#3773)
This PR deprecates the file related RPC calls in favour of an improved HTTP API. The main aim is to expose a simple to use API which can be consumed by thin clients (e.g. curl and HTML forms) without the need for complex logic (e.g. manipulating prefix trie manifests).
This commit is contained in:
committed by
Felix Lange
parent
9aca9e6deb
commit
71fdaa4238
104
swarm/api/api.go
104
swarm/api/api.go
@ -17,6 +17,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
@ -70,86 +71,50 @@ func (self *Api) Store(data io.Reader, size int64, wg *sync.WaitGroup) (key stor
|
||||
type ErrResolve error
|
||||
|
||||
// DNS Resolver
|
||||
func (self *Api) Resolve(hostPort string, nameresolver bool) (storage.Key, error) {
|
||||
log.Trace(fmt.Sprintf("Resolving : %v", hostPort))
|
||||
if hashMatcher.MatchString(hostPort) || self.dns == nil {
|
||||
log.Trace(fmt.Sprintf("host is a contentHash: '%v'", hostPort))
|
||||
return storage.Key(common.Hex2Bytes(hostPort)), nil
|
||||
func (self *Api) Resolve(uri *URI) (storage.Key, error) {
|
||||
log.Trace(fmt.Sprintf("Resolving : %v", uri.Addr))
|
||||
if hashMatcher.MatchString(uri.Addr) {
|
||||
log.Trace(fmt.Sprintf("addr is a hash: %q", uri.Addr))
|
||||
return storage.Key(common.Hex2Bytes(uri.Addr)), nil
|
||||
}
|
||||
if !nameresolver {
|
||||
return nil, fmt.Errorf("'%s' is not a content hash value.", hostPort)
|
||||
if uri.Immutable() {
|
||||
return nil, errors.New("refusing to resolve immutable address")
|
||||
}
|
||||
contentHash, err := self.dns.Resolve(hostPort)
|
||||
if self.dns == nil {
|
||||
return nil, fmt.Errorf("unable to resolve addr %q, resolver not configured", uri.Addr)
|
||||
}
|
||||
hash, err := self.dns.Resolve(uri.Addr)
|
||||
if err != nil {
|
||||
err = ErrResolve(err)
|
||||
log.Warn(fmt.Sprintf("DNS error : %v", err))
|
||||
log.Warn(fmt.Sprintf("DNS error resolving addr %q: %s", uri.Addr, err))
|
||||
return nil, ErrResolve(err)
|
||||
}
|
||||
log.Trace(fmt.Sprintf("host lookup: %v -> %v", hostPort, contentHash))
|
||||
return contentHash[:], err
|
||||
}
|
||||
func Parse(uri string) (hostPort, path string) {
|
||||
if uri == "" {
|
||||
return
|
||||
}
|
||||
parts := slashes.Split(uri, 3)
|
||||
var i int
|
||||
if len(parts) == 0 {
|
||||
return
|
||||
}
|
||||
// beginning with slash is now optional
|
||||
for len(parts[i]) == 0 {
|
||||
i++
|
||||
}
|
||||
hostPort = parts[i]
|
||||
for i < len(parts)-1 {
|
||||
i++
|
||||
if len(path) > 0 {
|
||||
path = path + "/" + parts[i]
|
||||
} else {
|
||||
path = parts[i]
|
||||
}
|
||||
}
|
||||
log.Debug(fmt.Sprintf("host: '%s', path '%s' requested.", hostPort, path))
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Api) parseAndResolve(uri string, nameresolver bool) (key storage.Key, hostPort, path string, err error) {
|
||||
hostPort, path = Parse(uri)
|
||||
//resolving host and port
|
||||
contentHash, err := self.Resolve(hostPort, nameresolver)
|
||||
log.Debug(fmt.Sprintf("Resolved '%s' to contentHash: '%s', path: '%s'", uri, contentHash, path))
|
||||
return contentHash[:], hostPort, path, err
|
||||
log.Trace(fmt.Sprintf("addr lookup: %v -> %v", uri.Addr, hash))
|
||||
return hash[:], nil
|
||||
}
|
||||
|
||||
// Put provides singleton manifest creation on top of dpa store
|
||||
func (self *Api) Put(content, contentType string) (string, error) {
|
||||
func (self *Api) Put(content, contentType string) (storage.Key, error) {
|
||||
r := strings.NewReader(content)
|
||||
wg := &sync.WaitGroup{}
|
||||
key, err := self.dpa.Store(r, int64(len(content)), wg, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
manifest := fmt.Sprintf(`{"entries":[{"hash":"%v","contentType":"%s"}]}`, key, contentType)
|
||||
r = strings.NewReader(manifest)
|
||||
key, err = self.dpa.Store(r, int64(len(manifest)), wg, nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
return nil, err
|
||||
}
|
||||
wg.Wait()
|
||||
return key.String(), nil
|
||||
return key, nil
|
||||
}
|
||||
|
||||
// Get uses iterative manifest retrieval and prefix matching
|
||||
// to resolve path to content using dpa retrieve
|
||||
// it returns a section reader, mimeType, status and an error
|
||||
func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
||||
key, _, path, err := self.parseAndResolve(uri, nameresolver)
|
||||
if err != nil {
|
||||
return nil, "", 500, fmt.Errorf("can't resolve: %v", err)
|
||||
}
|
||||
|
||||
quitC := make(chan bool)
|
||||
trie, err := loadManifest(self.dpa, key, quitC)
|
||||
func (self *Api) Get(key storage.Key, path string) (reader storage.LazySectionReader, mimeType string, status int, err error) {
|
||||
trie, err := loadManifest(self.dpa, key, nil)
|
||||
if err != nil {
|
||||
log.Warn(fmt.Sprintf("loadManifestTrie error: %v", err))
|
||||
return
|
||||
@ -173,32 +138,25 @@ func (self *Api) Get(uri string, nameresolver bool) (reader storage.LazySectionR
|
||||
return
|
||||
}
|
||||
|
||||
func (self *Api) Modify(uri, contentHash, contentType string, nameresolver bool) (newRootHash string, err error) {
|
||||
root, _, path, err := self.parseAndResolve(uri, nameresolver)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("can't resolve: %v", err)
|
||||
}
|
||||
|
||||
func (self *Api) Modify(key storage.Key, path, contentHash, contentType string) (storage.Key, error) {
|
||||
quitC := make(chan bool)
|
||||
trie, err := loadManifest(self.dpa, root, quitC)
|
||||
trie, err := loadManifest(self.dpa, key, quitC)
|
||||
if err != nil {
|
||||
return
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if contentHash != "" {
|
||||
entry := &manifestTrieEntry{
|
||||
entry := newManifestTrieEntry(&ManifestEntry{
|
||||
Path: path,
|
||||
Hash: contentHash,
|
||||
ContentType: contentType,
|
||||
}
|
||||
}, nil)
|
||||
entry.Hash = contentHash
|
||||
trie.addEntry(entry, quitC)
|
||||
} else {
|
||||
trie.deleteEntry(path, quitC)
|
||||
}
|
||||
|
||||
err = trie.recalcAndStore()
|
||||
if err != nil {
|
||||
return
|
||||
if err := trie.recalcAndStore(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return trie.hash.String(), nil
|
||||
return trie.hash, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user