diff --git a/client/object_put.go b/client/object_put.go index ce5cf8cc..09f292a1 100644 --- a/client/object_put.go +++ b/client/object_put.go @@ -13,10 +13,13 @@ import ( v2session "github.com/nspcc-dev/neofs-api-go/v2/session" "github.com/nspcc-dev/neofs-sdk-go/bearer" apistatus "github.com/nspcc-dev/neofs-sdk-go/client/status" + cid "github.com/nspcc-dev/neofs-sdk-go/container/id" neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto" "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/object/slicer" "github.com/nspcc-dev/neofs-sdk-go/session" + "github.com/nspcc-dev/neofs-sdk-go/user" ) // PrmObjectPutInit groups parameters of ObjectPutInit operation. @@ -263,3 +266,87 @@ func (c *Client) ObjectPutInit(ctx context.Context, prm PrmObjectPutInit) (*Obje return &w, nil } + +type objectWriter struct { + context context.Context + client *Client +} + +func (x *objectWriter) InitDataStream(header object.Object) (io.Writer, error) { + var prm PrmObjectPutInit + + stream, err := x.client.ObjectPutInit(x.context, prm) + if err != nil { + return nil, fmt.Errorf("init object stream: %w", err) + } + + if stream.WriteHeader(header) { + return &payloadWriter{ + stream: stream, + }, nil + } + + res, err := stream.Close() + if err != nil { + return nil, err + } + + return nil, apistatus.ErrFromStatus(res.Status()) +} + +type payloadWriter struct { + stream *ObjectWriter +} + +func (x *payloadWriter) Write(p []byte) (int, error) { + if !x.stream.WritePayloadChunk(p) { + return 0, x.Close() + } + + return len(p), nil +} + +func (x *payloadWriter) Close() error { + res, err := x.stream.Close() + if err != nil { + return err + } + + return apistatus.ErrFromStatus(res.Status()) +} + +// CreateObject creates new NeoFS object with given payload data and stores it +// in specified container of the NeoFS network using provided Client connection. +// The object is created on behalf of provided neofscrypto.Signer, and owned by +// the specified user.ID. +// +// In terms of NeoFS, parameterized neofscrypto.Signer represents object owner, +// object signer and request sender. Container SHOULD be public-write or sender +// SHOULD have corresponding rights. +// +// Client connection MUST be opened in advance, see Dial method for details. +// Network communication is carried out within a given context, so it MUST NOT +// be nil. +// +// Notice: This API is EXPERIMENTAL and is planned to be replaced/changed in the +// future. Be ready to refactor your code regarding imports and call mechanics, +// in essence the operation will not change. +func CreateObject(ctx context.Context, cli *Client, signer neofscrypto.Signer, cnr cid.ID, owner user.ID, data io.Reader, attributes ...string) (oid.ID, error) { + resNetInfo, err := cli.NetworkInfo(ctx, PrmNetworkInfo{}) + if err != nil { + return oid.ID{}, fmt.Errorf("read current network info: %w", err) + } + + netInfo := resNetInfo.Info() + + var opts slicer.Options + opts.SetObjectPayloadLimit(netInfo.MaxObjectSize()) + opts.SetCurrentNeoFSEpoch(netInfo.CurrentEpoch()) + + s := slicer.New(signer, cnr, owner, &objectWriter{ + context: ctx, + client: cli, + }, opts) + + return s.Slice(data, attributes...) +}