Skip to content

Commit

Permalink
handlers/objects: Deduplicate object writing code
Browse files Browse the repository at this point in the history
`NewUploadContainerObject`, `UploadContainerObject` and `PutObject` put
objects to the NeoFS in a very similar way.

Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
  • Loading branch information
cthulhu-rider committed Jun 25, 2024
1 parent eece01f commit 917a404
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 92 deletions.
46 changes: 15 additions & 31 deletions handlers/newObjects.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver"
"github.com/nspcc-dev/neofs-rest-gw/internal/util"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/client"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
Expand All @@ -22,7 +21,6 @@ import (
func (a *RestAPI) NewUploadContainerObject(ctx echo.Context, containerID apiserver.ContainerId, params apiserver.NewUploadContainerObjectParams) error {
var (
err error
idObj oid.ID
addr oid.Address
btoken *bearer.Token
)
Expand Down Expand Up @@ -98,40 +96,26 @@ func (a *RestAPI) NewUploadContainerObject(ctx echo.Context, containerID apiserv
}
}

var obj object.Object
obj.SetContainerID(idCnr)
a.setOwner(&obj, btoken)
obj.SetAttributes(attributes...)
var hdr object.Object
hdr.SetContainerID(idCnr)
a.setOwner(&hdr, btoken)
hdr.SetAttributes(attributes...)

var prmPutInit client.PrmObjectPutInit
if btoken != nil {
prmPutInit.WithBearerToken(*btoken)
}

writer, err := a.pool.ObjectPutInit(ctx.Request().Context(), obj, a.signer, prmPutInit)
if err != nil {
resp := a.logAndGetErrorResponse("put object init", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

if cln := ctx.Request().ContentLength; cln >= 0 && uint64(cln) < a.payloadBufferSize { // negative means unknown
if cln != 0 { // otherwise io.CopyBuffer panics
_, err = io.CopyBuffer(writer, ctx.Request().Body, make([]byte, cln))
idObj, err := a.putObject(ctx, hdr, btoken, func(w io.Writer) error {
var err error
if cln := ctx.Request().ContentLength; cln >= 0 && uint64(cln) < a.payloadBufferSize { // negative means unknown
if cln != 0 { // otherwise io.CopyBuffer panics
_, err = io.CopyBuffer(w, ctx.Request().Body, make([]byte, cln))
}
} else {
_, err = io.CopyBuffer(w, ctx.Request().Body, make([]byte, a.payloadBufferSize))
}
} else {
_, err = io.CopyBuffer(writer, ctx.Request().Body, make([]byte, a.payloadBufferSize))
}
return err
})
if err != nil {
resp := a.logAndGetErrorResponse("write", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

if err = writer.Close(); err != nil {
resp := a.logAndGetErrorResponse("writer close", err)
return ctx.JSON(http.StatusBadRequest, resp)
return err
}

idObj = writer.GetResult().StoredObjectID()
addr.SetObject(idObj)
addr.SetContainer(idCnr)

Expand Down
88 changes: 27 additions & 61 deletions handlers/objects.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,37 +117,19 @@ func (a *RestAPI) PutObject(ctx echo.Context, params apiserver.PutObjectParams)
return ctx.JSON(http.StatusBadRequest, resp)
}

var obj object.Object
obj.SetContainerID(cnrID)
attachOwner(&obj, btoken)
obj.SetAttributes(attributes...)

var prmPutInit client.PrmObjectPutInit
if btoken != nil {
prmPutInit.WithBearerToken(*btoken)
}

writer, err := a.pool.ObjectPutInit(ctx.Request().Context(), obj, a.signer, prmPutInit)
if err != nil {
resp := a.logAndGetErrorResponse("put object init", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

var objID oid.ID

_, err = writer.Write(payload)
var hdr object.Object
hdr.SetContainerID(cnrID)
attachOwner(&hdr, btoken)
hdr.SetAttributes(attributes...)

objID, err := a.putObject(ctx, hdr, btoken, func(w io.Writer) error {
_, err := w.Write(payload)
return err
})
if err != nil {
resp := a.logAndGetErrorResponse("write", err)
return ctx.JSON(http.StatusBadRequest, resp)
return err
}

if err = writer.Close(); err != nil {
resp := a.logAndGetErrorResponse("writer close", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

objID = writer.GetResult().StoredObjectID()

var resp apiserver.Address
resp.ContainerId = body.ContainerId
resp.ObjectId = objID.String()
Expand Down Expand Up @@ -913,7 +895,6 @@ func (a *RestAPI) UploadContainerObject(ctx echo.Context, containerID apiserver.
header *multipart.FileHeader
file multipart.File
err error
idObj oid.ID
addr oid.Address
btoken *bearer.Token
)
Expand Down Expand Up @@ -1016,42 +997,27 @@ func (a *RestAPI) UploadContainerObject(ctx echo.Context, containerID apiserver.
attributes = append(attributes, *timestamp)
}

var obj object.Object
obj.SetContainerID(idCnr)
a.setOwner(&obj, btoken)
obj.SetAttributes(attributes...)
var hdr object.Object
hdr.SetContainerID(idCnr)
a.setOwner(&hdr, btoken)
hdr.SetAttributes(attributes...)

var prmPutInit client.PrmObjectPutInit
if btoken != nil {
prmPutInit.WithBearerToken(*btoken)
}

writer, err := a.pool.ObjectPutInit(ctx.Request().Context(), obj, a.signer, prmPutInit)
if err != nil {
resp := a.logAndGetErrorResponse("put object init", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

var buf []byte
if header.Size > 0 && uint64(header.Size) < a.payloadBufferSize {
buf = make([]byte, header.Size)
} else {
// Size field is not documented, so we cannot be sure what exactly non-positive
// values mean. Thus, it's better to keep default behavior for them.
buf = make([]byte, a.payloadBufferSize)
}
_, err = io.CopyBuffer(writer, file, buf)
idObj, err := a.putObject(ctx, hdr, btoken, func(w io.Writer) error {
var buf []byte
if header.Size > 0 && uint64(header.Size) < a.payloadBufferSize {
buf = make([]byte, header.Size)
} else {
// Size field is not documented, so we cannot be sure what exactly non-positive
// values mean. Thus, it's better to keep default behavior for them.
buf = make([]byte, a.payloadBufferSize)
}
_, err = io.CopyBuffer(w, file, buf)
return err
})
if err != nil {
resp := a.logAndGetErrorResponse("write", err)
return ctx.JSON(http.StatusBadRequest, resp)
}

if err = writer.Close(); err != nil {
resp := a.logAndGetErrorResponse("writer close", err)
return ctx.JSON(http.StatusBadRequest, resp)
return err
}

idObj = writer.GetResult().StoredObjectID()
addr.SetObject(idObj)
addr.SetContainer(idCnr)

Expand Down
30 changes: 30 additions & 0 deletions handlers/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,20 @@ import (
"encoding/json"
"errors"
"fmt"
"io"
"math"
"net/http"
"strconv"
"strings"
"time"

"github.com/labstack/echo/v4"
"github.com/nspcc-dev/neofs-rest-gw/handlers/apiserver"
"github.com/nspcc-dev/neofs-sdk-go/bearer"
"github.com/nspcc-dev/neofs-sdk-go/client"
"github.com/nspcc-dev/neofs-sdk-go/container/acl"
"github.com/nspcc-dev/neofs-sdk-go/object"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/pool"
"github.com/nspcc-dev/neofs-sdk-go/session"
"go.uber.org/zap"
Expand Down Expand Up @@ -400,3 +404,29 @@ func addExpirationHeaders(headers map[string]string, params apiserver.NewUploadC
headers[ExpirationRFC3339Attr] = *params.XNeofsExpirationRFC3339
}
}

// shares code of NeoFS object recording performed by various RestAPI methods.
func (a *RestAPI) putObject(ctx echo.Context, hdr object.Object, bt *bearer.Token, wp func(io.Writer) error) (oid.ID, error) {
var opts client.PrmObjectPutInit
if bt != nil {
opts.WithBearerToken(*bt)
}
writer, err := a.pool.ObjectPutInit(ctx.Request().Context(), hdr, a.signer, opts)
if err != nil {
resp := a.logAndGetErrorResponse("put object init", err)
return oid.ID{}, ctx.JSON(http.StatusBadRequest, resp)
}

err = wp(writer)
if err != nil {
resp := a.logAndGetErrorResponse("write", err)
return oid.ID{}, ctx.JSON(http.StatusBadRequest, resp)
}

if err = writer.Close(); err != nil {
resp := a.logAndGetErrorResponse("writer close", err)
return oid.ID{}, ctx.JSON(http.StatusBadRequest, resp)
}

return writer.GetResult().StoredObjectID(), nil
}

0 comments on commit 917a404

Please sign in to comment.