Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

api, chunk: progress bar support #1649

Merged
merged 12 commits into from
Aug 26, 2019
Prev Previous commit
Next Next commit
Pulled master and resolved merge conflicts
  • Loading branch information
jmozah committed Aug 15, 2019
commit 5289e8b5f69b18f10dbadb2e7abdbb176a169712
101 changes: 99 additions & 2 deletions api/http/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,19 @@ var (
getTagCount = metrics.NewRegisteredCounter("api.http.get.tag.count", nil)
getTagNotFound = metrics.NewRegisteredCounter("api.http.get.tag.notfound", nil)
getTagFail = metrics.NewRegisteredCounter("api.http.get.tag.fail", nil)
getPinCount = metrics.NewRegisteredCounter("api.http.get.pin.count", nil)
getPinFail = metrics.NewRegisteredCounter("api.http.get.pin.fail", nil)
postPinCount = metrics.NewRegisteredCounter("api.http.post.pin.count", nil)
postPinFail = metrics.NewRegisteredCounter("api.http.post.pin.fail", nil)
deletePinCount = metrics.NewRegisteredCounter("api.http.delete.pin.count", nil)
deletePinFail = metrics.NewRegisteredCounter("api.http.delete.pin.fail", nil)
)

const (
TagHeaderName = "x-swarm-tag"
PinHeaderName = "x-swarm-pin" // Presence of this in header indicates pinning required
TagHeaderName = "x-swarm-tag" // Presence of this in header indicates the tag
PinHeaderName = "x-swarm-pin" // Presence of this in header indicates pinning required
encryptAddr = "encrypt"
tarContentType = "application/x-tar"
)

type methodHandler map[string]http.Handler
Expand Down Expand Up @@ -171,6 +179,20 @@ func NewServer(api *api.API, pinAPI *pin.API, corsString string) *Server {
defaultMiddlewares...,
),
})
mux.Handle("/bzz-pin:/", methodHandler{
"GET": Adapt(
http.HandlerFunc(server.HandleGetPins),
defaultMiddlewares...,
),
"POST": Adapt(
http.HandlerFunc(server.HandlePin),
defaultPostMiddlewares...,
),
"DELETE": Adapt(
http.HandlerFunc(server.HandleUnpin),
defaultMiddlewares...,
),
})
mux.Handle("/", methodHandler{
"GET": Adapt(
http.HandlerFunc(server.HandleRootPaths),
Expand Down Expand Up @@ -967,6 +989,81 @@ func (s *Server) HandleGetTag(w http.ResponseWriter, r *http.Request) {
}
}

// HandlePin takes a root hash as argument and pins a given file or collection in the local Swarm DB
func (s *Server) HandlePin(w http.ResponseWriter, r *http.Request) {
postPinCount.Inc(1)
ruid := GetRUID(r.Context())
uri := GetURI(r.Context())
fileAddr := uri.Address()
log.Debug("handle.post.pin", "ruid", ruid, "uri", r.RequestURI)

if fileAddr == nil {
postPinFail.Inc(1)
respondError(w, r, "missig hash to pin ", http.StatusBadRequest)
return
}

isRaw := false
isRawString := r.URL.Query().Get("raw")
if strings.ToLower(isRawString) == "true" {
isRaw = true
}

err := s.pinAPI.PinFiles(fileAddr, isRaw, "")
if err != nil {
postPinFail.Inc(1)
respondError(w, r, fmt.Sprintf("error pinning file %s: %s", fileAddr.Hex(), err), http.StatusInternalServerError)
return
}

log.Debug("pinned content", "ruid", ruid, "key", fileAddr.Hex())
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
}

// HandleUnpin takes a root hash as argument and unpins the file or collection from the local Swarm DB
func (s *Server) HandleUnpin(w http.ResponseWriter, r *http.Request) {
deletePinCount.Inc(1)
ruid := GetRUID(r.Context())
uri := GetURI(r.Context())
fileAddr := uri.Address()
log.Debug("handle.delete.pin", "ruid", ruid, "uri", r.RequestURI)

if fileAddr == nil {
deletePinFail.Inc(1)
respondError(w, r, "missig hash to unpin ", http.StatusBadRequest)
return
}

err := s.pinAPI.UnpinFiles(fileAddr, "")
if err != nil {
deletePinFail.Inc(1)
respondError(w, r, fmt.Sprintf("error pinning file %s: %s", fileAddr.Hex(), err), http.StatusInternalServerError)
return
}

log.Debug("unpinned content", "ruid", ruid, "key", fileAddr.Hex())
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(http.StatusOK)
}

// HandleGetPins return information about all the hashes pinned at this moment
func (s *Server) HandleGetPins(w http.ResponseWriter, r *http.Request) {
getPinCount.Inc(1)
ruid := GetRUID(r.Context())
log.Debug("handle.get.pin", "ruid", ruid, "uri", r.RequestURI)

pinnedFiles, err := s.pinAPI.ListPins()
if err != nil {
getPinFail.Inc(1)
respondError(w, r, fmt.Sprintf("error getting pinned files: %s", err), http.StatusInternalServerError)
return
}

w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(&pinnedFiles)
}

// calculateNumberOfChunks calculates the number of chunks in an arbitrary content length
func calculateNumberOfChunks(contentLength int64, isEncrypted bool) int64 {
if contentLength < 4096 {
Expand Down
60 changes: 60 additions & 0 deletions api/http/server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,66 @@ func TestGetTagUsingTagId(t *testing.T) {

}

// TestPinUnpinAPI function tests the pinning and unpinning through HTTP API.
// It does the following
// 1) upload a file
// 2) pin file using HTTP API
// 3) list all the files using HTTP API and check if the pinned file is present
// 4) unpin the pinned file
// 5) list pinned files and check if the unpinned files is not there anymore
func TestPinUnpinAPI(t *testing.T) {
// Initialize Swarm test server
srv := NewTestSwarmServer(t, serverFunc, nil, nil)
defer srv.Close()

// upload a file
data := testutil.RandomBytes(1, 10000)
rootHash := uploadFile(t, srv, data)

// pin it
pinFile(t, srv, rootHash)

// get the list of files pinned
pinnedInfo := listPinnedFiles(t, srv)
listInfos := make([]pin.PinInfo, 0)
err := json.Unmarshal(pinnedInfo, &listInfos)
if err != nil {
t.Fatal(err)
}

// Check if the pinned file is present in the list pin command
fileInfo := listInfos[0]
if hex.EncodeToString(fileInfo.Address) != string(rootHash) {
t.Fatalf("roothash not in list of pinned files")
}
if !fileInfo.IsRaw {
t.Fatalf("pinned file is not raw")
}
if fileInfo.PinCounter != 1 {
t.Fatalf("pin counter is not 1")
}
if fileInfo.FileSize != uint64(len(data)) {
t.Fatalf("data size mismatch, expected %x, got %x", len(data), fileInfo.FileSize)
}

// unpin it
unpinFile(t, srv, rootHash)

// get the list of files pinned again
unpinnedInfo := listPinnedFiles(t, srv)
listInfosUnpin := make([]pin.PinInfo, 0)
err = json.Unmarshal(unpinnedInfo, &listInfosUnpin)
if err != nil {
t.Fatal(err)
}

// Check if the pinned file is not present in the list pin command
if len(listInfosUnpin) != 0 {
t.Fatalf("roothash is in list of pinned files")
}

}

// Test the transparent resolving of feed updates with bzz:// scheme
//
// First upload data to bzz:, and store the Swarm hash to the resulting manifest in a feed update.
Expand Down
4 changes: 3 additions & 1 deletion api/uri.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ func Parse(rawuri string) (*URI, error) {

// check the scheme is valid
switch uri.Scheme {
case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed", "bzz-tag":
case "bzz", "bzz-raw", "bzz-immutable", "bzz-list", "bzz-hash", "bzz-feed", "bzz-tag", "bzz-pin":
default:
return nil, fmt.Errorf("unknown scheme %q", u.Scheme)
}
Expand All @@ -109,6 +109,7 @@ func Parse(rawuri string) (*URI, error) {
return uri, nil
}

// Tag returns the string representation of the tag uri scheme
func (u *URI) Tag() bool {
return u.Scheme == "bzz-tag"
}
Expand All @@ -133,6 +134,7 @@ func (u *URI) Hash() bool {
return u.Scheme == "bzz-hash"
}

// Pin returns the string representation of the pin uri scheme
func (u *URI) Pin() bool {
return u.Scheme == "bzz-pin"
}
Expand Down
24 changes: 15 additions & 9 deletions storage/pin/pin.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,19 +239,25 @@ func (p *API) UnpinFiles(addr []byte, credentials string) error {
// 1) Whether the file is a RAW file or not
// 2) Size of the pinned file or collection
// 3) the number of times that particular file or collection is pinned.
func (p *API) ListPinFiles() (map[string]FileInfo, error) {
pinnedFiles := make(map[string]FileInfo)

func (p *API) ListPins() ([]PinInfo, error) {
pinnedFiles := make([]PinInfo, 0)
iterFunc := func(key []byte, value []byte) (stop bool, err error) {
hash := string(key[4:])
fileInfo := FileInfo{}
err = fileInfo.UnmarshalBinary(value)
pinInfo := PinInfo{}
err = pinInfo.UnmarshalBinary(value)
if err != nil {
log.Debug("Error unmarshaling pininfo from state store", "Address", hash)
return
}
pinInfo.Address, err = hex.DecodeString(hash)
if err != nil {
log.Debug("Error unmarshaling fileinfo from state store", "Address", hash)
return false, err
log.Debug("Error unmarshaling pininfo from state store", "Address", hash)
return
}
log.Trace("Pinned file", "Address", hash, "IsRAW", fileInfo.isRaw,
"fileSize", fileInfo.fileSize, "pinCounter", fileInfo.pinCounter)
pinnedFiles[hash] = fileInfo
log.Trace("Pinned file", "Address", hash, "IsRAW", pinInfo.IsRaw,
"FileSize", pinInfo.FileSize, "PinCounter", pinInfo.PinCounter)
pinnedFiles = append(pinnedFiles, pinInfo)
return true, nil
}
err := p.state.Iterate("pin_", iterFunc)
Expand Down
You are viewing a condensed version of this merge commit. You can view the full changes here.