[#251] object/address: Refactor and document package functionality

Merge `address` package into `oid` one. Bring `session.Object`
implementation into conformity with the NeoFS API protocol.

Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
Leonard Lyubich 2022-05-25 12:03:22 +03:00 committed by LeL
parent bef4618cd6
commit f0a5eb6dbc
15 changed files with 429 additions and 468 deletions

View file

@ -1,192 +0,0 @@
package address
import (
"errors"
"fmt"
"strings"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
// Address represents v2-compatible object address.
type Address refs.Address
var errInvalidAddressString = errors.New("incorrect format of the string object address")
const (
addressParts = 2
addressSeparator = "/"
)
// NewAddressFromV2 converts v2 Address message to Address.
//
// Nil refs.Address converts to nil.
func NewAddressFromV2(aV2 *refs.Address) *Address {
return (*Address)(aV2)
}
// NewAddress creates and initializes blank Address.
//
// Works similar as NewAddressFromV2(new(Address)).
//
// Defaults:
// - cid: nil;
// - oid: nil.
func NewAddress() *Address {
return NewAddressFromV2(new(refs.Address))
}
// ToV2 converts Address to v2 Address message.
//
// Nil Address converts to nil.
func (a *Address) ToV2() *refs.Address {
return (*refs.Address)(a)
}
// ContainerID returns container identifier.
func (a *Address) ContainerID() (v cid.ID, isSet bool) {
v2 := (*refs.Address)(a)
cidV2 := v2.GetContainerID()
if cidV2 != nil {
_ = v.ReadFromV2(*cidV2)
isSet = true
}
return
}
// SetContainerID sets container identifier.
func (a *Address) SetContainerID(id cid.ID) {
var cidV2 refs.ContainerID
id.WriteToV2(&cidV2)
(*refs.Address)(a).SetContainerID(&cidV2)
}
// ObjectID returns object identifier.
func (a *Address) ObjectID() (v oid.ID, isSet bool) {
v2 := (*refs.Address)(a)
oidV2 := v2.GetObjectID()
if oidV2 != nil {
_ = v.ReadFromV2(*oidV2)
isSet = true
}
return
}
// SetObjectID sets object identifier.
func (a *Address) SetObjectID(id oid.ID) {
var oidV2 refs.ObjectID
id.WriteToV2(&oidV2)
(*refs.Address)(a).SetObjectID(&oidV2)
}
// Parse converts base58 string representation into Address.
func (a *Address) Parse(s string) error {
var (
err error
oid oid.ID
id cid.ID
parts = strings.Split(s, addressSeparator)
)
if len(parts) != addressParts {
return errInvalidAddressString
} else if err = id.DecodeString(parts[0]); err != nil {
return err
} else if err = oid.DecodeString(parts[1]); err != nil {
return err
}
a.SetObjectID(oid)
a.SetContainerID(id)
return nil
}
// String returns string representation of Object.Address.
func (a *Address) String() string {
var cidStr, oidStr string
if cID, set := a.ContainerID(); set {
cidStr = cID.String()
}
if oID, set := a.ObjectID(); set {
oidStr = oID.String()
}
return strings.Join([]string{cidStr, oidStr}, addressSeparator)
}
// Marshal marshals Address into a protobuf binary form.
func (a *Address) Marshal() ([]byte, error) {
return (*refs.Address)(a).StableMarshal(nil)
}
var errCIDNotSet = errors.New("container ID is not set")
var errOIDNotSet = errors.New("object ID is not set")
// Unmarshal unmarshals protobuf binary representation of Address.
func (a *Address) Unmarshal(data []byte) error {
err := (*refs.Address)(a).Unmarshal(data)
if err != nil {
return err
}
v2 := a.ToV2()
return checkFormat(v2)
}
// MarshalJSON encodes Address to protobuf JSON format.
func (a *Address) MarshalJSON() ([]byte, error) {
return (*refs.Address)(a).MarshalJSON()
}
// UnmarshalJSON decodes Address from protobuf JSON format.
func (a *Address) UnmarshalJSON(data []byte) error {
v2 := (*refs.Address)(a)
err := v2.UnmarshalJSON(data)
if err != nil {
return err
}
return checkFormat(v2)
}
func checkFormat(v2 *refs.Address) error {
var (
cID cid.ID
oID oid.ID
)
cidV2 := v2.GetContainerID()
if cidV2 == nil {
return errCIDNotSet
}
err := cID.ReadFromV2(*cidV2)
if err != nil {
return fmt.Errorf("could not convert V2 container ID: %w", err)
}
oidV2 := v2.GetObjectID()
if oidV2 == nil {
return errOIDNotSet
}
err = oID.ReadFromV2(*oidV2)
if err != nil {
return fmt.Errorf("could not convert V2 object ID: %w", err)
}
return nil
}

View file

@ -1,129 +0,0 @@
package address
import (
"strings"
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
func TestAddress_SetContainerID(t *testing.T) {
a := NewAddress()
id := cidtest.ID()
a.SetContainerID(id)
cID, set := a.ContainerID()
require.True(t, set)
require.Equal(t, id, cID)
}
func TestAddress_SetObjectID(t *testing.T) {
a := NewAddress()
oid := oidtest.ID()
a.SetObjectID(oid)
oID, set := a.ObjectID()
require.True(t, set)
require.Equal(t, oid, oID)
}
func TestAddress_Parse(t *testing.T) {
cid := cidtest.ID()
oid := oidtest.ID()
t.Run("should parse successful", func(t *testing.T) {
s := strings.Join([]string{cid.String(), oid.String()}, addressSeparator)
a := NewAddress()
require.NoError(t, a.Parse(s))
oID, set := a.ObjectID()
require.True(t, set)
require.Equal(t, oid, oID)
cID, set := a.ContainerID()
require.True(t, set)
require.Equal(t, cid, cID)
})
t.Run("should fail for bad address", func(t *testing.T) {
s := strings.Join([]string{cid.String()}, addressSeparator)
require.EqualError(t, NewAddress().Parse(s), errInvalidAddressString.Error())
})
t.Run("should fail on container.ID", func(t *testing.T) {
s := strings.Join([]string{"1", "2"}, addressSeparator)
require.Error(t, NewAddress().Parse(s))
})
t.Run("should fail on object.ID", func(t *testing.T) {
s := strings.Join([]string{cid.String(), "2"}, addressSeparator)
require.Error(t, NewAddress().Parse(s))
})
}
func TestAddressEncoding(t *testing.T) {
a := NewAddress()
a.SetObjectID(oidtest.ID())
a.SetContainerID(cidtest.ID())
t.Run("binary", func(t *testing.T) {
data, err := a.Marshal()
require.NoError(t, err)
a2 := NewAddress()
require.NoError(t, a2.Unmarshal(data))
require.Equal(t, a, a2)
})
t.Run("json", func(t *testing.T) {
data, err := a.MarshalJSON()
require.NoError(t, err)
a2 := NewAddress()
require.NoError(t, a2.UnmarshalJSON(data))
require.Equal(t, a, a2)
})
}
func TestNewAddressFromV2(t *testing.T) {
t.Run("from nil", func(t *testing.T) {
var x *refs.Address
require.Nil(t, NewAddressFromV2(x))
})
}
func TestAddress_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *Address
require.Nil(t, x.ToV2())
})
}
func TestNewAddress(t *testing.T) {
t.Run("default values", func(t *testing.T) {
a := NewAddress()
// check initial values
_, set := a.ContainerID()
require.False(t, set)
_, set = a.ObjectID()
require.False(t, set)
// convert to v2 message
aV2 := a.ToV2()
require.Nil(t, aV2.GetContainerID())
require.Nil(t, aV2.GetObjectID())
})
}

View file

@ -1,17 +0,0 @@
package address
import (
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
"github.com/nspcc-dev/neofs-sdk-go/object/address"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
)
// Address returns random object.Address.
func Address() *address.Address {
x := address.NewAddress()
x.SetContainerID(cidtest.ID())
x.SetObjectID(oidtest.ID())
return x
}

148
object/id/address.go Normal file
View file

@ -0,0 +1,148 @@
package oid
import (
"errors"
"fmt"
"strings"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
)
// Address represents global object identifier in NeoFS network. Each object
// belongs to exactly one container and is uniquely addressed within the container.
//
// Address is mutually compatible with github.com/nspcc-dev/neofs-api-go/v2/refs.Address
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
// _ = Address(refs.Address{}) // not recommended
type Address struct {
cnr cid.ID
obj ID
}
// ReadFromV2 reads Address from the refs.Address message. Returns an error if
// the message is malformed according to the NeoFS API V2 protocol.
//
// See also WriteToV2.
func (x *Address) ReadFromV2(m refs.Address) error {
cnr := m.GetContainerID()
if cnr == nil {
return errors.New("missing container ID")
}
obj := m.GetObjectID()
if obj == nil {
return errors.New("missing object ID")
}
err := x.cnr.ReadFromV2(*cnr)
if err != nil {
return fmt.Errorf("invalid container ID: %w", err)
}
err = x.obj.ReadFromV2(*obj)
if err != nil {
return fmt.Errorf("invalid object ID: %w", err)
}
return nil
}
// WriteToV2 writes Address to the refs.Address message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x Address) WriteToV2(m *refs.Address) {
var obj refs.ObjectID
x.obj.WriteToV2(&obj)
var cnr refs.ContainerID
x.cnr.WriteToV2(&cnr)
m.SetObjectID(&obj)
m.SetContainerID(&cnr)
}
// Container sets unique identifier of the NeoFS object container.
//
// Zero Address has zero container ID, which is incorrect according to NeoFS
// API protocol.
//
// See also SetContainer.
func (x Address) Container() cid.ID {
return x.cnr
}
// SetContainer sets unique identifier of the NeoFS object container.
//
// See also Container.
func (x *Address) SetContainer(id cid.ID) {
x.cnr = id
}
// Object returns unique identifier of the object in the container
// identified by Container().
//
// Zero Address has zero object ID, which is incorrect according to NeoFS
// API protocol.
//
// See also SetObject.
func (x Address) Object() ID {
return x.obj
}
// SetObject sets unique identifier of the object in the container
// identified by Container().
//
// See also Object.
func (x *Address) SetObject(id ID) {
x.obj = id
}
// delimiter of container and object IDs in Address protocol string.
const idDelimiter = "/"
// EncodeToString encodes Address into NeoFS API protocol string: concatenation
// of the string-encoded container and object IDs delimited by a slash.
//
// See also DecodeString.
func (x Address) EncodeToString() string {
return x.cnr.EncodeToString() + "/" + x.obj.EncodeToString()
}
// DecodeString decodes string into Address according to NeoFS API protocol. Returns
// an error if s is malformed.
//
// See also DecodeString.
func (x *Address) DecodeString(s string) error {
indDelimiter := strings.Index(s, idDelimiter)
if indDelimiter < 0 {
return errors.New("missing delimiter")
}
err := x.cnr.DecodeString(s[:indDelimiter])
if err != nil {
return fmt.Errorf("decode container string: %w", err)
}
err = x.obj.DecodeString(s[indDelimiter+1:])
if err != nil {
return fmt.Errorf("decode object string: %w", err)
}
return nil
}
// String implements fmt.Stringer.
//
// String is designed to be human-readable, and its format MAY differ between
// SDK versions. String MAY return same result as EncodeToString. String MUST NOT
// be used to encode Address into NeoFS protocol string.
func (x Address) String() string {
return x.EncodeToString()
}

95
object/id/address_test.go Normal file
View file

@ -0,0 +1,95 @@
package oid_test
import (
"testing"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
)
func TestAddress_SetContainer(t *testing.T) {
var x oid.Address
require.Zero(t, x.Container())
cnr := cidtest.ID()
x.SetContainer(cnr)
require.Equal(t, cnr, x.Container())
}
func TestAddress_SetObject(t *testing.T) {
var x oid.Address
require.Zero(t, x.Object())
obj := oidtest.ID()
x.SetObject(obj)
require.Equal(t, obj, x.Object())
}
func TestAddress_ReadFromV2(t *testing.T) {
var x oid.Address
var xV2 refs.Address
require.Error(t, x.ReadFromV2(xV2))
var cnrV2 refs.ContainerID
xV2.SetContainerID(&cnrV2)
require.Error(t, x.ReadFromV2(xV2))
cnr := cidtest.ID()
cnr.WriteToV2(&cnrV2)
require.Error(t, x.ReadFromV2(xV2))
var objV2 refs.ObjectID
xV2.SetObjectID(&objV2)
require.Error(t, x.ReadFromV2(xV2))
obj := oidtest.ID()
obj.WriteToV2(&objV2)
require.NoError(t, x.ReadFromV2(xV2))
require.Equal(t, cnr, x.Container())
require.Equal(t, obj, x.Object())
var xV2To refs.Address
x.WriteToV2(&xV2To)
require.Equal(t, xV2, xV2To)
}
func TestAddress_DecodeString(t *testing.T) {
var x, x2 oid.Address
require.NoError(t, x2.DecodeString(x.EncodeToString()))
require.Equal(t, x, x2)
cnr := cidtest.ID()
obj := oidtest.ID()
x.SetContainer(cnr)
x.SetObject(obj)
require.NoError(t, x2.DecodeString(x.EncodeToString()))
require.Equal(t, x, x2)
strCnr := cnr.EncodeToString()
strObj := obj.EncodeToString()
require.Error(t, x2.DecodeString(""))
require.Error(t, x2.DecodeString("/"))
require.Error(t, x2.DecodeString(strCnr))
require.Error(t, x2.DecodeString(strCnr+"/"))
require.Error(t, x2.DecodeString("/"+strCnr))
require.Error(t, x2.DecodeString(strCnr+strObj))
require.Error(t, x2.DecodeString(strCnr+"\\"+strObj))
require.NoError(t, x2.DecodeString(strCnr+"/"+strObj))
}

View file

@ -1,6 +1,9 @@
/*
Package oid provides primitives to work with object identification in NeoFS.
Address type is used for global object identity inside the NeoFS network,
while ID represents identity within a fixed container.
Using package types in an application is recommended to potentially work with
different protocol versions with which these types are compatible.

View file

@ -19,7 +19,7 @@ import (
// Instances can be created using built-in var declaration.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
// _ = ObjectID([32]byte{}) // not recommended
// _ = ID([32]byte{}) // not recommended
type ID [sha256.Size]byte
// ReadFromV2 reads ID from the refs.ObjectID message. Returns an error if

View file

@ -6,7 +6,7 @@ Note that importing the package into source files is highly discouraged.
Random instance generation functions can be useful when testing expects any value, e.g.:
import oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
dec := oidtest.ID()
value := oidtest.ID()
// test the value
*/

View file

@ -4,10 +4,11 @@ import (
"crypto/sha256"
"math/rand"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
)
// ID returns random object.ID.
// ID returns random oid.ID.
func ID() oid.ID {
checksum := [sha256.Size]byte{}
@ -16,7 +17,7 @@ func ID() oid.ID {
return idWithChecksum(checksum)
}
// idWithChecksum returns object.ID initialized
// idWithChecksum returns oid.ID initialized
// with specified checksum.
func idWithChecksum(cs [sha256.Size]byte) oid.ID {
var id oid.ID
@ -24,3 +25,13 @@ func idWithChecksum(cs [sha256.Size]byte) oid.ID {
return id
}
// Address returns random object.Address.
func Address() oid.Address {
var x oid.Address
x.SetContainer(cidtest.ID())
x.SetObject(ID())
return x
}

View file

@ -25,7 +25,6 @@ import (
"github.com/nspcc-dev/neofs-sdk-go/eacl"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/object/address"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/user"
@ -293,14 +292,8 @@ func (c *clientWrapper) objectPut(ctx context.Context, prm PrmObjectPut) (*oid.I
func (c *clientWrapper) objectDelete(ctx context.Context, prm PrmObjectDelete) error {
var cliPrm sdkClient.PrmObjectDelete
if cnr, set := prm.addr.ContainerID(); set {
cliPrm.FromContainer(cnr)
}
if obj, set := prm.addr.ObjectID(); set {
cliPrm.ByID(obj)
}
cliPrm.FromContainer(prm.addr.Container())
cliPrm.ByID(prm.addr.Object())
if prm.stoken != nil {
cliPrm.WithinSession(*prm.stoken)
@ -319,22 +312,8 @@ func (c *clientWrapper) objectDelete(ctx context.Context, prm PrmObjectDelete) e
func (c *clientWrapper) objectGet(ctx context.Context, prm PrmObjectGet) (*ResGetObject, error) {
var cliPrm sdkClient.PrmObjectGet
if cnr, set := prm.addr.ContainerID(); set {
cliPrm.FromContainer(cnr)
}
if obj, set := prm.addr.ObjectID(); set {
cliPrm.ByID(obj)
}
if cnr, set := prm.addr.ContainerID(); set {
cliPrm.FromContainer(cnr)
}
if obj, set := prm.addr.ObjectID(); set {
cliPrm.ByID(obj)
}
cliPrm.FromContainer(prm.addr.Container())
cliPrm.ByID(prm.addr.Object())
if prm.stoken != nil {
cliPrm.WithinSession(*prm.stoken)
@ -367,14 +346,8 @@ func (c *clientWrapper) objectGet(ctx context.Context, prm PrmObjectGet) (*ResGe
func (c *clientWrapper) objectHead(ctx context.Context, prm PrmObjectHead) (*object.Object, error) {
var cliPrm sdkClient.PrmObjectHead
if cnr, set := prm.addr.ContainerID(); set {
cliPrm.FromContainer(cnr)
}
if obj, set := prm.addr.ObjectID(); set {
cliPrm.ByID(obj)
}
cliPrm.FromContainer(prm.addr.Container())
cliPrm.ByID(prm.addr.Object())
if prm.stoken != nil {
cliPrm.WithinSession(*prm.stoken)
@ -403,18 +376,11 @@ func (c *clientWrapper) objectHead(ctx context.Context, prm PrmObjectHead) (*obj
func (c *clientWrapper) objectRange(ctx context.Context, prm PrmObjectRange) (*ResObjectRange, error) {
var cliPrm sdkClient.PrmObjectRange
cliPrm.FromContainer(prm.addr.Container())
cliPrm.ByID(prm.addr.Object())
cliPrm.SetOffset(prm.off)
cliPrm.SetLength(prm.ln)
if cnr, set := prm.addr.ContainerID(); set {
cliPrm.FromContainer(cnr)
}
if obj, set := prm.addr.ObjectID(); set {
cliPrm.ByID(obj)
}
if prm.stoken != nil {
cliPrm.WithinSession(*prm.stoken)
}
@ -609,15 +575,24 @@ type clientPack struct {
type prmContext struct {
defaultSession bool
verb session.ObjectVerb
addr address.Address
cnr cid.ID
objSet bool
obj oid.ID
}
func (x *prmContext) useDefaultSession() {
x.defaultSession = true
}
func (x *prmContext) useAddress(addr address.Address) {
x.addr = addr
func (x *prmContext) useContainer(cnr cid.ID) {
x.cnr = cnr
}
func (x *prmContext) useAddress(addr oid.Address) {
x.cnr = addr.Container()
x.obj = addr.Object()
x.objSet = true
}
func (x *prmContext) useVerb(verb session.ObjectVerb) {
@ -669,11 +644,11 @@ func (x *PrmObjectPut) SetPayload(payload io.Reader) {
type PrmObjectDelete struct {
prmCommon
addr address.Address
addr oid.Address
}
// SetAddress specifies NeoFS address of the object.
func (x *PrmObjectDelete) SetAddress(addr address.Address) {
func (x *PrmObjectDelete) SetAddress(addr oid.Address) {
x.addr = addr
}
@ -681,11 +656,11 @@ func (x *PrmObjectDelete) SetAddress(addr address.Address) {
type PrmObjectGet struct {
prmCommon
addr address.Address
addr oid.Address
}
// SetAddress specifies NeoFS address of the object.
func (x *PrmObjectGet) SetAddress(addr address.Address) {
func (x *PrmObjectGet) SetAddress(addr oid.Address) {
x.addr = addr
}
@ -693,11 +668,11 @@ func (x *PrmObjectGet) SetAddress(addr address.Address) {
type PrmObjectHead struct {
prmCommon
addr address.Address
addr oid.Address
}
// SetAddress specifies NeoFS address of the object.
func (x *PrmObjectHead) SetAddress(addr address.Address) {
func (x *PrmObjectHead) SetAddress(addr oid.Address) {
x.addr = addr
}
@ -705,12 +680,12 @@ func (x *PrmObjectHead) SetAddress(addr address.Address) {
type PrmObjectRange struct {
prmCommon
addr address.Address
addr oid.Address
off, ln uint64
}
// SetAddress specifies NeoFS address of the object.
func (x *PrmObjectRange) SetAddress(addr address.Address) {
func (x *PrmObjectRange) SetAddress(addr oid.Address) {
x.addr = addr
}
@ -1283,7 +1258,9 @@ type callContext struct {
sessionDefault bool
sessionTarget func(session.Object)
sessionVerb session.ObjectVerb
sessionAddr address.Address
sessionCnr cid.ID
sessionObjSet bool
sessionObj oid.ID
}
func (p *Pool) initCallContext(ctx *callContext, cfg prmCommon, prmCtx prmContext) error {
@ -1309,7 +1286,9 @@ func (p *Pool) initCallContext(ctx *callContext, cfg prmCommon, prmCtx prmContex
ctx.sessionDefault = cfg.stoken == nil && prmCtx.defaultSession
if ctx.sessionDefault {
ctx.sessionVerb = prmCtx.verb
ctx.sessionAddr = prmCtx.addr
ctx.sessionCnr = prmCtx.cnr
ctx.sessionObjSet = prmCtx.objSet
ctx.sessionObj = prmCtx.obj
}
return err
@ -1333,7 +1312,11 @@ func (p *Pool) openDefaultSession(ctx *callContext) error {
}
tok.ForVerb(ctx.sessionVerb)
tok.ApplyTo(ctx.sessionAddr)
tok.BindContainer(ctx.sessionCnr)
if ctx.sessionObjSet {
tok.LimitByObject(ctx.sessionObj)
}
// sign the token
if err := tok.Sign(*ctx.key); err != nil {
@ -1372,15 +1355,12 @@ func (p *Pool) fillAppropriateKey(prm *prmCommon) {
// PutObject writes an object through a remote server using NeoFS API protocol.
func (p *Pool) PutObject(ctx context.Context, prm PrmObjectPut) (*oid.ID, error) {
var cIDp *cid.ID
if cID, set := prm.hdr.ContainerID(); set {
cIDp = &cID
}
cnr, _ := prm.hdr.ContainerID()
var prmCtx prmContext
prmCtx.useDefaultSession()
prmCtx.useVerb(session.VerbObjectPut)
prmCtx.useAddress(*newAddressFromCnrID(cIDp))
prmCtx.useContainer(cnr)
p.fillAppropriateKey(&prm.prmCommon)
@ -1604,7 +1584,7 @@ func (p *Pool) SearchObjects(ctx context.Context, prm PrmObjectSearch) (*ResObje
var prmCtx prmContext
prmCtx.useDefaultSession()
prmCtx.useVerb(session.VerbObjectSearch)
prmCtx.useAddress(*newAddressFromCnrID(&prm.cnrID))
prmCtx.useContainer(prm.cnrID)
p.fillAppropriateKey(&prm.prmCommon)
@ -1795,11 +1775,3 @@ func (p *Pool) Close() {
p.cancel()
<-p.closedCh
}
func newAddressFromCnrID(cnrID *cid.ID) *address.Address {
addr := address.NewAddress()
if cnrID != nil {
addr.SetContainerID(*cnrID)
}
return addr
}

View file

@ -17,7 +17,7 @@ import (
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/netmap"
"github.com/nspcc-dev/neofs-sdk-go/object"
"github.com/nspcc-dev/neofs-sdk-go/object/address"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/session"
"github.com/nspcc-dev/neofs-sdk-go/user"
"github.com/stretchr/testify/require"
@ -418,7 +418,7 @@ func TestSessionCache(t *testing.T) {
require.True(t, containsTokens(tokens, &st))
var prm PrmObjectGet
prm.SetAddress(address.Address{})
prm.SetAddress(oid.Address{})
prm.UseSession(session.Object{})
_, err = pool.GetObject(ctx, prm)
@ -565,7 +565,7 @@ func TestSessionCacheWithKey(t *testing.T) {
require.True(t, containsTokens(tokens, &st))
var prm PrmObjectGet
prm.SetAddress(address.Address{})
prm.SetAddress(oid.Address{})
prm.UseKey(newPrivateKey(t))
_, err = pool.GetObject(ctx, prm)

View file

@ -57,7 +57,7 @@ func (x *Container) ReadFromV2(m session.Token) error {
}
c, ok := b.GetContext().(*session.ContainerSessionContext)
if !ok {
if !ok || c == nil {
return fmt.Errorf("invalid context %T", b.GetContext())
}
@ -70,11 +70,7 @@ func (x *Container) ReadFromV2(m session.Token) error {
x.body = *b
if c != nil {
x.c = *c
} else {
x.c = session.ContainerSessionContext{}
}
lt := b.GetLifetime()
if lt != nil {

View file

@ -9,9 +9,10 @@ import (
"github.com/google/uuid"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
"github.com/nspcc-dev/neofs-api-go/v2/session"
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/object/address"
oid "github.com/nspcc-dev/neofs-sdk-go/object/id"
"github.com/nspcc-dev/neofs-sdk-go/user"
)
@ -57,25 +58,22 @@ func (x *Object) ReadFromV2(m session.Token) error {
}
c, ok := b.GetContext().(*session.ObjectSessionContext)
if !ok {
if !ok || c == nil {
return fmt.Errorf("invalid context %T", b.GetContext())
}
x.body = *b
if c != nil {
x.c = *c
obj := c.GetAddress()
if obj != nil {
cnr := obj.GetContainerID()
if cnr == nil {
return errors.New("missing bound container")
}
x.obj = *obj
} else {
x.obj = refs.Address{}
}
} else {
x.c = session.ObjectSessionContext{}
x.obj = refs.Address{}
}
lt := b.GetLifetime()
if lt != nil {
@ -209,23 +207,63 @@ func (x Object) VerifySignature() bool {
return x.sig.Verify(data)
}
// ApplyTo limits session scope to a given author object.
// BindContainer binds the Object session to a given container. Each session
// MUST be bound to exactly one container.
//
// See also AppliedTo.
func (x *Object) ApplyTo(a address.Address) {
x.obj = *a.ToV2()
// See also AssertContainer.
func (x *Object) BindContainer(cnr cid.ID) {
var cnrV2 refs.ContainerID
cnr.WriteToV2(&cnrV2)
x.obj.SetContainerID(&cnrV2)
}
// AppliedTo checks if session scope is limited by a given object.
// AssertContainer checks if Object session bound to a given container.
//
// Zero Object isn't applied to any author's object.
// Zero Object isn't bound to any container which is incorrect according to
// NeoFS API protocol.
//
// See also ApplyTo.
func (x Object) AppliedTo(obj address.Address) bool {
objv2 := *address.NewAddressFromV2(&x.obj)
// See also BindContainer.
func (x Object) AssertContainer(cnr cid.ID) bool {
cnrV2 := x.obj.GetContainerID()
if cnrV2 == nil {
return false
}
// FIXME: use Equals method
return obj.String() == objv2.String()
var cnr2 cid.ID
err := cnr2.ReadFromV2(*cnrV2)
return err == nil && cnr2.Equals(cnr)
}
// LimitByObject limits session scope to a given object from the container
// to which Object session is bound.
//
// See also AssertObject.
func (x *Object) LimitByObject(obj oid.ID) {
var objV2 refs.ObjectID
obj.WriteToV2(&objV2)
x.obj.SetObjectID(&objV2)
}
// AssertObject checks if Object session is applied to a given object.
//
// Zero Object is applied to all objects in the container.
//
// See also LimitByObject.
func (x Object) AssertObject(obj oid.ID) bool {
objV2 := x.obj.GetObjectID()
if objV2 == nil {
return true
}
var obj2 oid.ID
err := obj2.ReadFromV2(*objV2)
return err == nil && obj2.Equals(obj)
}
// ObjectVerb enumerates object operations.

View file

@ -9,11 +9,12 @@ import (
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neofs-api-go/v2/refs"
v2session "github.com/nspcc-dev/neofs-api-go/v2/session"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
neofscrypto "github.com/nspcc-dev/neofs-sdk-go/crypto"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neofs-sdk-go/object/address"
addresstest "github.com/nspcc-dev/neofs-sdk-go/object/address/test"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/nspcc-dev/neofs-sdk-go/session"
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
"github.com/nspcc-dev/neofs-sdk-go/user"
@ -41,6 +42,14 @@ func TestObject_ReadFromV2(t *testing.T) {
var c v2session.ObjectSessionContext
id := uuid.New()
cnr := cidtest.ID()
var cnrV2 refs.ContainerID
cnr.WriteToV2(&cnrV2)
var addrV2 refs.Address
addrV2.SetContainerID(&cnrV2)
t.Run("protocol violation", func(t *testing.T) {
require.Error(t, x.ReadFromV2(m))
@ -54,27 +63,32 @@ func TestObject_ReadFromV2(t *testing.T) {
b.SetContext(&c)
require.Error(t, x.ReadFromV2(m))
c.SetAddress(&addrV2)
require.NoError(t, x.ReadFromV2(m))
})
m.SetBody(&b)
c.SetAddress(&addrV2)
b.SetContext(&c)
b.SetID(id[:])
t.Run("object", func(t *testing.T) {
var obj address.Address
require.NoError(t, x.ReadFromV2(m))
require.True(t, x.AssertContainer(cnr))
obj := oidtest.Address()
var objV2 refs.Address
obj.WriteToV2(&objV2)
c.SetAddress(&objV2)
require.NoError(t, x.ReadFromV2(m))
require.True(t, x.AppliedTo(obj))
obj = *addresstest.Address()
objv2 := *obj.ToV2()
c.SetAddress(&objv2)
require.NoError(t, x.ReadFromV2(m))
require.True(t, x.AppliedTo(obj))
require.True(t, x.AssertContainer(obj.Container()))
require.True(t, x.AssertObject(obj.Object()))
})
t.Run("verb", func(t *testing.T) {
@ -157,16 +171,31 @@ func TestEncodingObject(t *testing.T) {
})
}
func TestObjectAppliedTo(t *testing.T) {
func TestObject_BindContainer(t *testing.T) {
var x session.Object
a := *addresstest.Address()
cnr := cidtest.ID()
require.False(t, x.AppliedTo(a))
require.False(t, x.AssertContainer(cnr))
x.ApplyTo(a)
x.BindContainer(cnr)
require.True(t, x.AppliedTo(a))
require.True(t, x.AssertContainer(cnr))
}
func TestObject_LimitByObject(t *testing.T) {
var x session.Object
obj := oidtest.ID()
obj2 := oidtest.ID()
require.True(t, x.AssertObject(obj))
require.True(t, x.AssertObject(obj2))
x.LimitByObject(obj)
require.True(t, x.AssertObject(obj))
require.False(t, x.AssertObject(obj2))
}
func TestObjectExp(t *testing.T) {
@ -250,7 +279,8 @@ func TestObjectSignature(t *testing.T) {
const exp = 33
id := uuid.New()
key := randPublicKey()
obj := *addresstest.Address()
cnr := cidtest.ID()
obj := oidtest.ID()
verb := session.VerbObjectDelete
signer := randSigner()
@ -275,8 +305,11 @@ func TestObjectSignature(t *testing.T) {
func() { x.SetAuthKey(key) },
func() { x.SetAuthKey(randPublicKey()) },
func() { x.ApplyTo(obj) },
func() { x.ApplyTo(*addresstest.Address()) },
func() { x.BindContainer(cnr) },
func() { x.BindContainer(cidtest.ID()) },
func() { x.LimitByObject(obj) },
func() { x.LimitByObject(oidtest.ID()) },
func() { x.ForVerb(verb) },
func() { x.ForVerb(verb + 1) },

View file

@ -9,7 +9,7 @@ import (
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
neofsecdsa "github.com/nspcc-dev/neofs-sdk-go/crypto/ecdsa"
addresstest "github.com/nspcc-dev/neofs-sdk-go/object/address/test"
oidtest "github.com/nspcc-dev/neofs-sdk-go/object/id/test"
"github.com/nspcc-dev/neofs-sdk-go/session"
)
@ -71,8 +71,11 @@ func Object() *session.Object {
panic(err)
}
addr := oidtest.Address()
tok.ForVerb(session.VerbObjectPut)
tok.ApplyTo(*addresstest.Address())
tok.BindContainer(addr.Container())
tok.LimitByObject(addr.Object())
tok.SetID(uuid.New())
tok.SetAuthKey((*neofsecdsa.PublicKey)(&priv.PublicKey))
tok.SetExp(11)