forked from TrueCloudLab/frostfs-node
[#33] service/object: Implement object Put distributed service
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
dcfb6a6b3a
commit
57f8d3745d
10 changed files with 711 additions and 0 deletions
106
pkg/services/object/put/distributed.go
Normal file
106
pkg/services/object/put/distributed.go
Normal file
|
@ -0,0 +1,106 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type distributedTarget struct {
|
||||
traverseOpts []placement.Option
|
||||
|
||||
workerPool util.WorkerPool
|
||||
|
||||
obj *object.RawObject
|
||||
|
||||
chunks [][]byte
|
||||
|
||||
nodeTargetInitializer func(*network.Address) transformer.ObjectTarget
|
||||
}
|
||||
|
||||
var errIncompletePut = errors.New("incomplete object put")
|
||||
|
||||
func (t *distributedTarget) WriteHeader(obj *object.RawObject) error {
|
||||
t.obj = obj
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *distributedTarget) Write(p []byte) (n int, err error) {
|
||||
t.chunks = append(t.chunks, p)
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (t *distributedTarget) Close() (*transformer.AccessIdentifiers, error) {
|
||||
traverser, err := placement.NewTraverser(
|
||||
append(t.traverseOpts, placement.ForObject(t.obj.GetID()))...,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not create object placement traverser", t)
|
||||
}
|
||||
|
||||
sz := 0
|
||||
|
||||
for i := range t.chunks {
|
||||
sz += len(t.chunks[i])
|
||||
}
|
||||
|
||||
payload := make([]byte, 0, sz)
|
||||
|
||||
for i := range t.chunks {
|
||||
payload = append(payload, t.chunks[i]...)
|
||||
}
|
||||
|
||||
t.obj.SetPayload(payload)
|
||||
|
||||
loop:
|
||||
for {
|
||||
addrs := traverser.Next()
|
||||
if len(addrs) == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
wg := new(sync.WaitGroup)
|
||||
|
||||
for i := range addrs {
|
||||
wg.Add(1)
|
||||
|
||||
addr := addrs[i]
|
||||
|
||||
if err := t.workerPool.Submit(func() {
|
||||
defer wg.Done()
|
||||
|
||||
target := t.nodeTargetInitializer(addr)
|
||||
|
||||
if err := target.WriteHeader(t.obj); err != nil {
|
||||
// TODO: log error
|
||||
return
|
||||
} else if _, err := target.Close(); err != nil {
|
||||
// TODO: log error
|
||||
return
|
||||
}
|
||||
|
||||
traverser.SubmitSuccess()
|
||||
}); err != nil {
|
||||
wg.Done()
|
||||
// TODO: log error
|
||||
break loop
|
||||
}
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
if !traverser.Success() {
|
||||
return nil, errIncompletePut
|
||||
}
|
||||
|
||||
return new(transformer.AccessIdentifiers).
|
||||
WithSelfID(t.obj.GetID()), nil
|
||||
}
|
72
pkg/services/object/put/local.go
Normal file
72
pkg/services/object/put/local.go
Normal file
|
@ -0,0 +1,72 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/netmap"
|
||||
objectSDK "github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type localPlacement struct {
|
||||
builder placement.Builder
|
||||
|
||||
localAddrSrc network.LocalAddressSource
|
||||
}
|
||||
|
||||
func (p *localPlacement) BuildPlacement(addr *objectSDK.Address, policy *netmap.PlacementPolicy) ([]netmap.Nodes, error) {
|
||||
vs, err := p.builder.BuildPlacement(addr, policy)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not build object placement", p)
|
||||
}
|
||||
|
||||
for i := range vs {
|
||||
for j := range vs[i] {
|
||||
addr, err := network.AddressFromString(vs[i][j].NetworkAddress())
|
||||
if err != nil {
|
||||
// TODO: log error
|
||||
continue
|
||||
}
|
||||
|
||||
if network.IsLocalAddress(p.localAddrSrc, addr) {
|
||||
return []netmap.Nodes{{vs[i][j]}}, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil, errors.Errorf("(%T) local node is outside of object placement", p)
|
||||
}
|
||||
|
||||
type localTarget struct {
|
||||
storage *localstore.Storage
|
||||
|
||||
obj *object.RawObject
|
||||
|
||||
payload []byte
|
||||
}
|
||||
|
||||
func (t *localTarget) WriteHeader(obj *object.RawObject) error {
|
||||
t.obj = obj
|
||||
|
||||
t.payload = make([]byte, 0, obj.GetPayloadSize())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *localTarget) Write(p []byte) (n int, err error) {
|
||||
t.payload = append(t.payload, p...)
|
||||
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
func (t *localTarget) Close() (*transformer.AccessIdentifiers, error) {
|
||||
if err := t.storage.Put(t.obj.Object()); err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not put object to local storage", t)
|
||||
}
|
||||
|
||||
return new(transformer.AccessIdentifiers).
|
||||
WithSelfID(t.obj.GetID()), nil
|
||||
}
|
53
pkg/services/object/put/prm.go
Normal file
53
pkg/services/object/put/prm.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||
)
|
||||
|
||||
type PutInitPrm struct {
|
||||
local bool
|
||||
|
||||
hdr *object.RawObject
|
||||
|
||||
token *token.SessionToken
|
||||
|
||||
traverseOpts []placement.Option
|
||||
}
|
||||
|
||||
type PutChunkPrm struct {
|
||||
chunk []byte
|
||||
}
|
||||
|
||||
func (p *PutInitPrm) WithObject(v *object.RawObject) *PutInitPrm {
|
||||
if p != nil {
|
||||
p.hdr = v
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PutInitPrm) WithSession(v *token.SessionToken) *PutInitPrm {
|
||||
if p != nil {
|
||||
p.token = v
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PutInitPrm) OnlyLocal(v bool) *PutInitPrm {
|
||||
if p != nil {
|
||||
p.local = v
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
func (p *PutChunkPrm) WithChunk(v []byte) *PutChunkPrm {
|
||||
if p != nil {
|
||||
p.chunk = v
|
||||
}
|
||||
|
||||
return p
|
||||
}
|
54
pkg/services/object/put/remote.go
Normal file
54
pkg/services/object/put/remote.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/client"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type remoteTarget struct {
|
||||
transformer.ObjectTarget
|
||||
|
||||
ctx context.Context
|
||||
|
||||
key *ecdsa.PrivateKey
|
||||
|
||||
addr *network.Address
|
||||
|
||||
obj *object.Object
|
||||
}
|
||||
|
||||
func (t *remoteTarget) WriteHeader(obj *object.RawObject) error {
|
||||
t.obj = obj.Object()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *remoteTarget) Close() (*transformer.AccessIdentifiers, error) {
|
||||
addr := t.addr.NetAddr()
|
||||
|
||||
c, err := client.New(t.key,
|
||||
client.WithAddress(addr),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not create SDK client %s", t, addr)
|
||||
}
|
||||
|
||||
id, err := c.PutObject(t.ctx, new(client.PutObjectParams).
|
||||
WithObject(
|
||||
t.obj.SDK(),
|
||||
),
|
||||
client.WithTTL(1), // FIXME: use constant
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not put object to %s", t, addr)
|
||||
}
|
||||
|
||||
return new(transformer.AccessIdentifiers).
|
||||
WithSelfID(id), nil
|
||||
}
|
13
pkg/services/object/put/res.go
Normal file
13
pkg/services/object/put/res.go
Normal file
|
@ -0,0 +1,13 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/object"
|
||||
)
|
||||
|
||||
type PutResponse struct {
|
||||
id *object.ID
|
||||
}
|
||||
|
||||
func (r *PutResponse) ObjectID() *object.ID {
|
||||
return r.id
|
||||
}
|
114
pkg/services/object/put/service.go
Normal file
114
pkg/services/object/put/service.go
Normal file
|
@ -0,0 +1,114 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/container"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/local_object_storage/localstore"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/session/storage"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/util"
|
||||
)
|
||||
|
||||
type MaxSizeSource interface {
|
||||
MaxObjectSize() uint64
|
||||
}
|
||||
|
||||
type Service struct {
|
||||
*cfg
|
||||
}
|
||||
|
||||
type Option func(*cfg)
|
||||
|
||||
type cfg struct {
|
||||
key *ecdsa.PrivateKey
|
||||
|
||||
maxSizeSrc MaxSizeSource
|
||||
|
||||
tokenStore *storage.TokenStore
|
||||
|
||||
localStore *localstore.Storage
|
||||
|
||||
cnrSrc container.Source
|
||||
|
||||
netMapSrc netmap.Source
|
||||
|
||||
workerPool util.WorkerPool
|
||||
|
||||
localAddrSrc network.LocalAddressSource
|
||||
}
|
||||
|
||||
func defaultCfg() *cfg {
|
||||
return &cfg{
|
||||
workerPool: new(util.SyncWorkerPool),
|
||||
}
|
||||
}
|
||||
|
||||
func NewService(opts ...Option) *Service {
|
||||
c := defaultCfg()
|
||||
|
||||
for i := range opts {
|
||||
opts[i](c)
|
||||
}
|
||||
|
||||
return &Service{
|
||||
cfg: c,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Service) Put(ctx context.Context) (*Streamer, error) {
|
||||
return &Streamer{
|
||||
cfg: p.cfg,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func WithKey(v *ecdsa.PrivateKey) Option {
|
||||
return func(c *cfg) {
|
||||
c.key = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithMaxSizeSource(v MaxSizeSource) Option {
|
||||
return func(c *cfg) {
|
||||
c.maxSizeSrc = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithTokenStorage(v *storage.TokenStore) Option {
|
||||
return func(c *cfg) {
|
||||
c.tokenStore = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithLocalStorage(v *localstore.Storage) Option {
|
||||
return func(c *cfg) {
|
||||
c.localStore = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithContainerSource(v container.Source) Option {
|
||||
return func(c *cfg) {
|
||||
c.cnrSrc = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithNetworkMapSource(v netmap.Source) Option {
|
||||
return func(c *cfg) {
|
||||
c.netMapSrc = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithWorkerPool(v util.WorkerPool) Option {
|
||||
return func(c *cfg) {
|
||||
c.workerPool = v
|
||||
}
|
||||
}
|
||||
|
||||
func WithLocalAddressSource(v network.LocalAddressSource) Option {
|
||||
return func(c *cfg) {
|
||||
c.localAddrSrc = v
|
||||
}
|
||||
}
|
170
pkg/services/object/put/streamer.go
Normal file
170
pkg/services/object/put/streamer.go
Normal file
|
@ -0,0 +1,170 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/netmap"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/network"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/placement"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/services/object_manager/transformer"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type Streamer struct {
|
||||
*cfg
|
||||
|
||||
ctx context.Context
|
||||
|
||||
target transformer.ObjectTarget
|
||||
}
|
||||
|
||||
var errNotInit = errors.New("stream not initialized")
|
||||
|
||||
var errInitRecall = errors.New("init recall")
|
||||
|
||||
var errPrivateTokenNotFound = errors.New("private token not found")
|
||||
|
||||
func (p *Streamer) Init(prm *PutInitPrm) error {
|
||||
// initialize destination target
|
||||
if err := p.initTarget(prm); err != nil {
|
||||
return errors.Wrapf(err, "(%T) could not initialize object target", p)
|
||||
}
|
||||
|
||||
return errors.Wrapf(
|
||||
p.target.WriteHeader(prm.hdr),
|
||||
"(%T) could not write header to target", p,
|
||||
)
|
||||
}
|
||||
|
||||
func (p *Streamer) initTarget(prm *PutInitPrm) error {
|
||||
// prevent re-calling
|
||||
if p.target != nil {
|
||||
return errInitRecall
|
||||
}
|
||||
|
||||
// prepare needed put parameters
|
||||
if err := p.preparePrm(prm); err != nil {
|
||||
return errors.Wrapf(err, "(%T) could not prepare put parameters", p)
|
||||
}
|
||||
|
||||
if prm.token == nil {
|
||||
// prepare untrusted-Put object target
|
||||
p.target = p.newCommonTarget(prm)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// prepare trusted-Put object target
|
||||
|
||||
// get private token from local storage
|
||||
pToken := p.tokenStore.Get(prm.token.OwnerID(), prm.token.ID())
|
||||
if pToken == nil {
|
||||
return errPrivateTokenNotFound
|
||||
}
|
||||
|
||||
p.target = transformer.NewPayloadSizeLimiter(
|
||||
p.maxSizeSrc.MaxObjectSize(),
|
||||
func() transformer.ObjectTarget {
|
||||
return transformer.NewFormatTarget(pToken.SessionKey(), p.newCommonTarget(prm))
|
||||
},
|
||||
)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Streamer) preparePrm(prm *PutInitPrm) error {
|
||||
var err error
|
||||
|
||||
// get latest network map
|
||||
nm, err := netmap.GetLatestNetworkMap(p.netMapSrc)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "(%T) could not get latest network map", p)
|
||||
}
|
||||
|
||||
// get container to store the object
|
||||
cnr, err := p.cnrSrc.Get(prm.hdr.GetContainerID())
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "(%T) could not get container by ID", p)
|
||||
}
|
||||
|
||||
// allocate placement traverser options
|
||||
prm.traverseOpts = make([]placement.Option, 0, 4)
|
||||
|
||||
// add common options
|
||||
prm.traverseOpts = append(prm.traverseOpts,
|
||||
// set processing container
|
||||
placement.ForContainer(cnr),
|
||||
|
||||
// set identifier of the processing object
|
||||
placement.ForObject(prm.hdr.GetID()),
|
||||
)
|
||||
|
||||
// create placement builder from network map
|
||||
builder := placement.NewNetworkMapBuilder(nm)
|
||||
|
||||
if prm.local {
|
||||
// restrict success count to 1 stored copy (to local storage)
|
||||
prm.traverseOpts = append(prm.traverseOpts, placement.SuccessAfter(1))
|
||||
|
||||
// use local-only placement builder
|
||||
builder = &localPlacement{
|
||||
builder: placement.NewNetworkMapBuilder(nm),
|
||||
localAddrSrc: p.localAddrSrc,
|
||||
}
|
||||
}
|
||||
|
||||
// set placement builder
|
||||
prm.traverseOpts = append(prm.traverseOpts, placement.UseBuilder(builder))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Streamer) newCommonTarget(prm *PutInitPrm) transformer.ObjectTarget {
|
||||
return &distributedTarget{
|
||||
traverseOpts: prm.traverseOpts,
|
||||
workerPool: p.workerPool,
|
||||
nodeTargetInitializer: func(addr *network.Address) transformer.ObjectTarget {
|
||||
if network.IsLocalAddress(p.localAddrSrc, addr) {
|
||||
return &localTarget{
|
||||
storage: p.localStore,
|
||||
}
|
||||
} else {
|
||||
return &remoteTarget{
|
||||
ctx: p.ctx,
|
||||
key: p.key,
|
||||
addr: addr,
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Streamer) SendChunk(prm *PutChunkPrm) error {
|
||||
if p.target == nil {
|
||||
return errNotInit
|
||||
}
|
||||
|
||||
_, err := p.target.Write(prm.chunk)
|
||||
|
||||
return errors.Wrapf(err, "(%T) could not write payload chunk to target", p)
|
||||
}
|
||||
|
||||
func (p *Streamer) Close() (*PutResponse, error) {
|
||||
if p.target == nil {
|
||||
return nil, errNotInit
|
||||
}
|
||||
|
||||
ids, err := p.target.Close()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not close object target", p)
|
||||
}
|
||||
|
||||
id := ids.ParentID()
|
||||
if id == nil {
|
||||
id = ids.SelfID()
|
||||
}
|
||||
|
||||
return &PutResponse{
|
||||
id: id,
|
||||
}, nil
|
||||
}
|
52
pkg/services/object/put/v2/service.go
Normal file
52
pkg/services/object/put/v2/service.go
Normal file
|
@ -0,0 +1,52 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
putsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/put"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Service implements Put operation of Object service v2.
|
||||
type Service struct {
|
||||
*cfg
|
||||
}
|
||||
|
||||
// Option represents Service constructor option.
|
||||
type Option func(*cfg)
|
||||
|
||||
type cfg struct {
|
||||
svc *putsvc.Service
|
||||
}
|
||||
|
||||
// NewService constructs Service instance from provided options.
|
||||
func NewService(opts ...Option) *Service {
|
||||
c := new(cfg)
|
||||
|
||||
for i := range opts {
|
||||
opts[i](c)
|
||||
}
|
||||
|
||||
return &Service{
|
||||
cfg: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Put calls internal service and returns v2 object streamer.
|
||||
func (s *Service) Put(ctx context.Context) (objectV2.PutObjectStreamer, error) {
|
||||
stream, err := s.svc.Put(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not open object put stream", s)
|
||||
}
|
||||
|
||||
return &streamer{
|
||||
stream: stream,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func WithInternalService(v *putsvc.Service) Option {
|
||||
return func(c *cfg) {
|
||||
c.svc = v
|
||||
}
|
||||
}
|
37
pkg/services/object/put/v2/streamer.go
Normal file
37
pkg/services/object/put/v2/streamer.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
putsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/put"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
type streamer struct {
|
||||
stream *putsvc.Streamer
|
||||
}
|
||||
|
||||
func (s *streamer) Send(req *object.PutRequest) (err error) {
|
||||
switch v := req.GetBody().GetObjectPart().(type) {
|
||||
case *object.PutObjectPartInit:
|
||||
if err = s.stream.Init(toInitPrm(v, req.GetMetaHeader().GetSessionToken(), req.GetMetaHeader().GetTTL())); err != nil {
|
||||
err = errors.Wrapf(err, "(%T) could not init object put stream", s)
|
||||
}
|
||||
case *object.PutObjectPartChunk:
|
||||
if err = s.stream.SendChunk(toChunkPrm(v)); err != nil {
|
||||
err = errors.Wrapf(err, "(%T) could not send payload chunk", s)
|
||||
}
|
||||
default:
|
||||
err = errors.Errorf("(%T) invalid object put stream part type %T", s, v)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (s *streamer) CloseAndRecv() (*object.PutResponse, error) {
|
||||
resp, err := s.stream.Close()
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "(%T) could not object put stream", s)
|
||||
}
|
||||
|
||||
return fromPutResponse(resp), nil
|
||||
}
|
40
pkg/services/object/put/v2/util.go
Normal file
40
pkg/services/object/put/v2/util.go
Normal file
|
@ -0,0 +1,40 @@
|
|||
package putsvc
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/pkg/token"
|
||||
objectV2 "github.com/nspcc-dev/neofs-api-go/v2/object"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/session"
|
||||
"github.com/nspcc-dev/neofs-node/pkg/core/object"
|
||||
putsvc "github.com/nspcc-dev/neofs-node/pkg/services/object/put"
|
||||
)
|
||||
|
||||
func toInitPrm(req *objectV2.PutObjectPartInit, t *session.SessionToken, ttl uint32) *putsvc.PutInitPrm {
|
||||
oV2 := new(objectV2.Object)
|
||||
oV2.SetObjectID(req.GetObjectID())
|
||||
oV2.SetSignature(req.GetSignature())
|
||||
oV2.SetHeader(req.GetHeader())
|
||||
|
||||
return new(putsvc.PutInitPrm).
|
||||
WithObject(
|
||||
object.NewRawFromV2(oV2),
|
||||
).
|
||||
WithSession(
|
||||
token.NewSessionTokenFromV2(t),
|
||||
).
|
||||
OnlyLocal(ttl == 1) // FIXME: use constant
|
||||
}
|
||||
|
||||
func toChunkPrm(req *objectV2.PutObjectPartChunk) *putsvc.PutChunkPrm {
|
||||
return new(putsvc.PutChunkPrm).
|
||||
WithChunk(req.GetChunk())
|
||||
}
|
||||
|
||||
func fromPutResponse(r *putsvc.PutResponse) *objectV2.PutResponse {
|
||||
body := new(objectV2.PutResponseBody)
|
||||
body.SetObjectID(r.ObjectID().ToV2())
|
||||
|
||||
resp := new(objectV2.PutResponse)
|
||||
resp.SetBody(body)
|
||||
|
||||
return resp
|
||||
}
|
Loading…
Reference in a new issue