Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package allocation
import (
"context"
"encoding/json"
"os"

"github.com/0chain/blobber/code/go/0chain.net/blobbercore/datastore"
"github.com/0chain/blobber/code/go/0chain.net/blobbercore/filestore"
"github.com/0chain/blobber/code/go/0chain.net/blobbercore/reference"
"github.com/0chain/blobber/code/go/0chain.net/core/common"
. "github.com/0chain/blobber/code/go/0chain.net/core/logging"

"go.uber.org/zap"
Expand Down Expand Up @@ -56,15 +58,20 @@ func (nf *DeleteFileChange) DeleteTempFile() error {

func (nf *DeleteFileChange) CommitToFileStore(ctx context.Context) error {
db := datastore.GetStore().GetTransaction(ctx)
var errFileWasDeleted error
for contenthash := range nf.ContentHash {
var count int64
err := db.Table((&reference.Ref{}).TableName()).Where(db.Where(&reference.Ref{ThumbnailHash: contenthash}).Or(&reference.Ref{ContentHash: contenthash})).Where("deleted_at IS null").Where(&reference.Ref{AllocationID: nf.AllocationID}).Count(&count).Error
if err == nil && count == 0 {
Logger.Info("Deleting content file", zap.String("content_hash", contenthash))
if err := filestore.GetFileStore().DeleteFile(nf.AllocationID, contenthash); err != nil {
if os.IsNotExist(err) {
errFileWasDeleted = common.ErrFileWasDeleted
continue
}
Logger.Error("FileStore_DeleteFile", zap.String("allocation_id", nf.AllocationID), zap.Error(err))
}
}
}
return nil
return errFileWasDeleted
}
13 changes: 10 additions & 3 deletions code/go/0chain.net/blobbercore/handler/file_command_delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@ package handler

import (
"context"
"errors"
"net/http"

"github.com/0chain/blobber/code/go/0chain.net/blobbercore/allocation"
"github.com/0chain/blobber/code/go/0chain.net/blobbercore/blobberhttp"
"github.com/0chain/blobber/code/go/0chain.net/blobbercore/reference"
"github.com/0chain/blobber/code/go/0chain.net/core/common"
"github.com/0chain/gosdk/constants"
"gorm.io/gorm"
)

// FileCommandDelete command for deleting file
Expand All @@ -28,12 +30,17 @@ func (cmd *FileCommandDelete) IsAuthorized(ctx context.Context, req *http.Reques
if path == "" {
return common.NewError("invalid_parameters", "Invalid path")
}
cmd.exisitingFileRef, _ = reference.GetReference(ctx, allocationObj.ID, path)

if cmd.exisitingFileRef == nil {
return common.NewErrorfWithStatusCode(204, "invalid_file", "File does not exist at path")
fileRef, err := reference.GetReference(ctx, allocationObj.ID, path)
if err != nil {
if errors.Is(gorm.ErrRecordNotFound, err) {
return common.ErrFileWasDeleted
}
return common.NewError("bad_db_operation", err.Error())
}

cmd.exisitingFileRef = fileRef

return nil
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (b *blobberGRPCService) Commit(ctx context.Context, req *blobbergrpc.Commit
httpRequestWithMetaData(r, getGRPCMetaDataFromCtx(ctx), req.Allocation)
r.Header.Set("Content-Type", writer.FormDataContentType())

resp, err := CommitHandler(ctx, r)
resp, _, err := CommitHandler(ctx, r)
if err != nil {
return nil, err
}
Expand Down
41 changes: 37 additions & 4 deletions code/go/0chain.net/blobbercore/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func SetupHandlers(r *mux.Router) {
r.HandleFunc("/v1/dir/{allocation}", common.ToJSONResponse(WithConnection(CreateDirHandler))).Methods(http.MethodPost, http.MethodOptions)
r.HandleFunc("/v1/dir/{allocation}", common.ToJSONResponse(WithConnection(CreateDirHandler))).Methods(http.MethodDelete, http.MethodOptions)

r.HandleFunc("/v1/connection/commit/{allocation}", common.ToJSONResponse(WithConnection(CommitHandler)))
r.HandleFunc("/v1/connection/commit/{allocation}", common.ToStatusCode(WithStatusConnection(CommitHandler)))
r.HandleFunc("/v1/file/commitmetatxn/{allocation}", common.ToJSONResponse(WithConnection(CommitMetaTxnHandler)))
r.HandleFunc("/v1/file/collaborator/{allocation}", common.ToJSONResponse(WithConnection(CollaboratorHandler)))
r.HandleFunc("/v1/file/calculatehash/{allocation}", common.ToJSONResponse(WithConnection(CalculateHashHandler)))
Expand Down Expand Up @@ -121,6 +121,34 @@ func WithConnection(handler common.JSONResponderF) common.JSONResponderF {
}
}

func WithStatusConnection(handler common.StatusCodeResponderF) common.StatusCodeResponderF {
return func(ctx context.Context, r *http.Request) (resp interface{}, statusCode int, err error) {
ctx = GetMetaDataStore().CreateTransaction(ctx)
resp, statusCode, err = handler(ctx, r)

defer func() {
if err != nil {
var rollErr = GetMetaDataStore().GetTransaction(ctx).
Rollback().Error
if rollErr != nil {
Logger.Error("couldn't rollback", zap.Error(err))
}
}
}()

if err != nil {
Logger.Error("Error in handling the request." + err.Error())
return
}
err = GetMetaDataStore().GetTransaction(ctx).Commit().Error
if err != nil {
return resp, statusCode, common.NewErrorf("commit_error",
"error committing to meta store: %v", err)
}
return
}
}

func setupHandlerContext(ctx context.Context, r *http.Request) context.Context {
var vars = mux.Vars(r)
ctx = context.WithValue(ctx, constants.ContextKeyClient,
Expand Down Expand Up @@ -239,15 +267,20 @@ func ListHandler(ctx context.Context, r *http.Request) (interface{}, error) {
}

/*CommitHandler is the handler to respond to upload requests fro clients*/
func CommitHandler(ctx context.Context, r *http.Request) (interface{}, error) {
func CommitHandler(ctx context.Context, r *http.Request) (interface{}, int, error) {
ctx = setupHandlerContext(ctx, r)

response, err := storageHandler.CommitWrite(ctx, r)

if err != nil {
return nil, err

if errors.Is(common.ErrFileWasDeleted, err) {
return response, http.StatusNoContent, nil
}
return nil, http.StatusBadRequest, err
}

return response, nil
return response, http.StatusOK, nil
}

func ReferencePathHandler(ctx context.Context, r *http.Request) (interface{}, error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,9 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b
}
err = connectionObj.CommitToFileStore(ctx)
if err != nil {
return nil, common.NewError("file_store_error", "Error committing to file store. "+err.Error())
if !errors.Is(common.ErrFileWasDeleted, err) {
return nil, common.NewError("file_store_error", "Error committing to file store. "+err.Error())
}
}

result.Changes = connectionObj.Changes
Expand All @@ -529,6 +531,9 @@ func (fsh *StorageHandler) CommitWrite(ctx context.Context, r *http.Request) (*b
result.Success = true
result.ErrorMessage = ""

if errors.Is(common.ErrFileWasDeleted, err) {
return &result, err
}
return &result, nil
}

Expand Down
3 changes: 3 additions & 0 deletions code/go/0chain.net/core/common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ var (

// ErrEntityNotFound entity can't found in db
ErrEntityNotFound = errors.New("entity not found")

// ErrFileWasDeleted file already was deleted
ErrFileWasDeleted = errors.New("file was deleted")
)
10 changes: 2 additions & 8 deletions code/go/0chain.net/core/common/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ import (

/*Error type for a new application error */
type Error struct {
Code string `json:"code,omitempty"`
Msg string `json:"msg"`
StatusCode int `json:"status_code,omitempty"`
Code string `json:"code,omitempty"`
Msg string `json:"msg"`
}

func (err *Error) Error() string {
Expand All @@ -25,11 +24,6 @@ func NewErrorf(code, format string, args ...interface{}) *Error {
return &Error{Code: code, Msg: fmt.Sprintf(format, args...)}
}

/*NewErrorf - create a new error with format */
func NewErrorfWithStatusCode(statusCode int, errCode, format string, args ...interface{}) *Error {
return &Error{StatusCode: statusCode, Code: errCode, Msg: fmt.Sprintf(format, args...)}
}

/*InvalidRequest - create error messages that are needed when validating request input */
func InvalidRequest(msg string) error {
return NewError("invalid_request", fmt.Sprintf("Invalid request (%v)", msg))
Expand Down
62 changes: 56 additions & 6 deletions code/go/0chain.net/core/common/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,14 @@ func ToByteStream(handler JSONResponderF) ReqRespHandlerf {
ctx := r.Context()
data, err := handler(ctx, r)
if err != nil {
statusCode := 400
if cerr, ok := err.(*Error); ok {
w.Header().Set(AppErrorHeader, cerr.Code)
if cerr.StatusCode != 0 {
statusCode = cerr.StatusCode
}
}
if data != nil {
responseString, _ := json.Marshal(data)
http.Error(w, string(responseString), statusCode)
http.Error(w, string(responseString), 400)
} else {
http.Error(w, err.Error(), statusCode)
http.Error(w, err.Error(), 400)
}
} else if data != nil {
rawdata, ok := data.([]byte)
Expand Down Expand Up @@ -154,3 +150,57 @@ func JSONString(json map[string]interface{}, field string, required bool) (strin
return fmt.Sprintf("%v", sval), nil
}
}

type StatusCodeResponderF func(ctx context.Context, r *http.Request) (interface{}, int, error)

func ToStatusCode(handler StatusCodeResponderF) ReqRespHandlerf {
return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*") // CORS for all.
if r.Method == "OPTIONS" {
SetupCORSResponse(w, r)
return
}

ctx := r.Context()

data, statusCode, err := handler(ctx, r)

if err != nil {
if statusCode == 0 {
statusCode = http.StatusBadRequest
}

w.WriteHeader(statusCode)
w.Header().Set("Content-Type", "application/json")

if data != nil {
json.NewEncoder(w).Encode(data) //nolint:errcheck
} else {
//nolint:errcheck
json.NewEncoder(w).Encode(map[string]string{
"error": err.Error(),
})
}

return
}

if statusCode == 0 {
statusCode = http.StatusOK
}

w.WriteHeader(statusCode)

if data != nil {

rawdata, ok := data.([]byte)
if ok {
w.Header().Set("Content-Type", "application/octet-stream")
w.Write(rawdata) //nolint:errcheck
} else {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(data) //nolint:errcheck
}
}
}
}