forked from TrueCloudLab/frostfs-sdk-go
[#60] container: move package from neofs-api-go
Also, remove deprecated methods and types. Close #60. Signed-off-by: Evgenii Stratonikov <evgeniy@nspcc.ru>
This commit is contained in:
parent
8d313dbd5d
commit
73686827d3
10 changed files with 1012 additions and 0 deletions
77
container/announcement.go
Normal file
77
container/announcement.go
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
)
|
||||||
|
|
||||||
|
// UsedSpaceAnnouncement is an announcement message used by storage nodes to
|
||||||
|
// estimate actual container sizes.
|
||||||
|
type UsedSpaceAnnouncement container.UsedSpaceAnnouncement
|
||||||
|
|
||||||
|
// NewAnnouncement initialize empty UsedSpaceAnnouncement message.
|
||||||
|
//
|
||||||
|
// Defaults:
|
||||||
|
// - epoch: 0;
|
||||||
|
// - usedSpace: 0;
|
||||||
|
// - cid: nil.
|
||||||
|
func NewAnnouncement() *UsedSpaceAnnouncement {
|
||||||
|
return NewAnnouncementFromV2(new(container.UsedSpaceAnnouncement))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAnnouncementFromV2 wraps protocol dependent version of
|
||||||
|
// UsedSpaceAnnouncement message.
|
||||||
|
//
|
||||||
|
// Nil container.UsedSpaceAnnouncement converts to nil.
|
||||||
|
func NewAnnouncementFromV2(v *container.UsedSpaceAnnouncement) *UsedSpaceAnnouncement {
|
||||||
|
return (*UsedSpaceAnnouncement)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Epoch of the announcement.
|
||||||
|
func (a *UsedSpaceAnnouncement) Epoch() uint64 {
|
||||||
|
return (*container.UsedSpaceAnnouncement)(a).GetEpoch()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEpoch sets announcement epoch value.
|
||||||
|
func (a *UsedSpaceAnnouncement) SetEpoch(epoch uint64) {
|
||||||
|
(*container.UsedSpaceAnnouncement)(a).SetEpoch(epoch)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerID of the announcement.
|
||||||
|
func (a *UsedSpaceAnnouncement) ContainerID() *cid.ID {
|
||||||
|
return cid.NewFromV2(
|
||||||
|
(*container.UsedSpaceAnnouncement)(a).GetContainerID(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetContainerID sets announcement container value.
|
||||||
|
func (a *UsedSpaceAnnouncement) SetContainerID(cid *cid.ID) {
|
||||||
|
(*container.UsedSpaceAnnouncement)(a).SetContainerID(cid.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
// UsedSpace in container.
|
||||||
|
func (a *UsedSpaceAnnouncement) UsedSpace() uint64 {
|
||||||
|
return (*container.UsedSpaceAnnouncement)(a).GetUsedSpace()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetUsedSpace sets used space value by specified container.
|
||||||
|
func (a *UsedSpaceAnnouncement) SetUsedSpace(value uint64) {
|
||||||
|
(*container.UsedSpaceAnnouncement)(a).SetUsedSpace(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 returns protocol dependent version of UsedSpaceAnnouncement message.
|
||||||
|
//
|
||||||
|
// Nil UsedSpaceAnnouncement converts to nil.
|
||||||
|
func (a *UsedSpaceAnnouncement) ToV2() *container.UsedSpaceAnnouncement {
|
||||||
|
return (*container.UsedSpaceAnnouncement)(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals UsedSpaceAnnouncement into a protobuf binary form.
|
||||||
|
func (a *UsedSpaceAnnouncement) Marshal() ([]byte, error) {
|
||||||
|
return a.ToV2().StableMarshal(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals protobuf binary representation of UsedSpaceAnnouncement.
|
||||||
|
func (a *UsedSpaceAnnouncement) Unmarshal(data []byte) error {
|
||||||
|
return a.ToV2().Unmarshal(data)
|
||||||
|
}
|
99
container/announcement_test.go
Normal file
99
container/announcement_test.go
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
package container_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
containerv2 "github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
|
containertest "github.com/nspcc-dev/neofs-sdk-go/container/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAnnouncement(t *testing.T) {
|
||||||
|
const epoch, usedSpace uint64 = 10, 100
|
||||||
|
|
||||||
|
cidValue := [sha256.Size]byte{1, 2, 3}
|
||||||
|
id := cidtest.GenerateIDWithChecksum(cidValue)
|
||||||
|
|
||||||
|
a := container.NewAnnouncement()
|
||||||
|
a.SetEpoch(epoch)
|
||||||
|
a.SetContainerID(id)
|
||||||
|
a.SetUsedSpace(usedSpace)
|
||||||
|
|
||||||
|
require.Equal(t, epoch, a.Epoch())
|
||||||
|
require.Equal(t, usedSpace, a.UsedSpace())
|
||||||
|
require.Equal(t, id, a.ContainerID())
|
||||||
|
|
||||||
|
t.Run("test v2", func(t *testing.T) {
|
||||||
|
const newEpoch, newUsedSpace uint64 = 20, 200
|
||||||
|
|
||||||
|
newCidValue := [32]byte{4, 5, 6}
|
||||||
|
newCID := new(refs.ContainerID)
|
||||||
|
newCID.SetValue(newCidValue[:])
|
||||||
|
|
||||||
|
v2 := a.ToV2()
|
||||||
|
require.Equal(t, usedSpace, v2.GetUsedSpace())
|
||||||
|
require.Equal(t, epoch, v2.GetEpoch())
|
||||||
|
require.Equal(t, cidValue[:], v2.GetContainerID().GetValue())
|
||||||
|
|
||||||
|
v2.SetEpoch(newEpoch)
|
||||||
|
v2.SetUsedSpace(newUsedSpace)
|
||||||
|
v2.SetContainerID(newCID)
|
||||||
|
|
||||||
|
newA := container.NewAnnouncementFromV2(v2)
|
||||||
|
|
||||||
|
require.Equal(t, newEpoch, newA.Epoch())
|
||||||
|
require.Equal(t, newUsedSpace, newA.UsedSpace())
|
||||||
|
require.Equal(t, cid.NewFromV2(newCID), newA.ContainerID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUsedSpaceEncoding(t *testing.T) {
|
||||||
|
a := containertest.UsedSpaceAnnouncement()
|
||||||
|
|
||||||
|
t.Run("binary", func(t *testing.T) {
|
||||||
|
data, err := a.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
a2 := container.NewAnnouncement()
|
||||||
|
require.NoError(t, a2.Unmarshal(data))
|
||||||
|
|
||||||
|
require.Equal(t, a, a2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUsedSpaceAnnouncement_ToV2(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x *container.UsedSpaceAnnouncement
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("default values", func(t *testing.T) {
|
||||||
|
announcement := container.NewAnnouncement()
|
||||||
|
|
||||||
|
// check initial values
|
||||||
|
require.Zero(t, announcement.Epoch())
|
||||||
|
require.Zero(t, announcement.UsedSpace())
|
||||||
|
require.Nil(t, announcement.ContainerID())
|
||||||
|
|
||||||
|
// convert to v2 message
|
||||||
|
announcementV2 := announcement.ToV2()
|
||||||
|
|
||||||
|
require.Zero(t, announcementV2.GetEpoch())
|
||||||
|
require.Zero(t, announcementV2.GetUsedSpace())
|
||||||
|
require.Nil(t, announcementV2.GetContainerID())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAnnouncementFromV2(t *testing.T) {
|
||||||
|
t.Run("from nil", func(t *testing.T) {
|
||||||
|
var x *containerv2.UsedSpaceAnnouncement
|
||||||
|
|
||||||
|
require.Nil(t, container.NewAnnouncementFromV2(x))
|
||||||
|
})
|
||||||
|
}
|
137
container/attribute.go
Normal file
137
container/attribute.go
Normal file
|
@ -0,0 +1,137 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Attribute container.Attribute
|
||||||
|
Attributes []*Attribute
|
||||||
|
)
|
||||||
|
|
||||||
|
// NewAttribute creates and initializes blank Attribute.
|
||||||
|
//
|
||||||
|
// Defaults:
|
||||||
|
// - key: "";
|
||||||
|
// - value: "".
|
||||||
|
func NewAttribute() *Attribute {
|
||||||
|
return NewAttributeFromV2(new(container.Attribute))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Attribute) SetKey(v string) {
|
||||||
|
(*container.Attribute)(a).SetKey(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Attribute) SetValue(v string) {
|
||||||
|
(*container.Attribute)(a).SetValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Attribute) Key() string {
|
||||||
|
return (*container.Attribute)(a).GetKey()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Attribute) Value() string {
|
||||||
|
return (*container.Attribute)(a).GetValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewAttributeFromV2 wraps protocol dependent version of
|
||||||
|
// Attribute message.
|
||||||
|
//
|
||||||
|
// Nil container.Attribute converts to nil.
|
||||||
|
func NewAttributeFromV2(v *container.Attribute) *Attribute {
|
||||||
|
return (*Attribute)(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 converts Attribute to v2 Attribute message.
|
||||||
|
//
|
||||||
|
// Nil Attribute converts to nil.
|
||||||
|
func (a *Attribute) ToV2() *container.Attribute {
|
||||||
|
return (*container.Attribute)(a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAttributesFromV2(v []*container.Attribute) Attributes {
|
||||||
|
if v == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := make(Attributes, 0, len(v))
|
||||||
|
for i := range v {
|
||||||
|
attrs = append(attrs, NewAttributeFromV2(v[i]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a Attributes) ToV2() []*container.Attribute {
|
||||||
|
if a == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
attrs := make([]*container.Attribute, 0, len(a))
|
||||||
|
for i := range a {
|
||||||
|
attrs = append(attrs, a[i].ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
|
// sets value of the attribute by key.
|
||||||
|
func setAttribute(c *Container, key, value string) {
|
||||||
|
var a *Attribute
|
||||||
|
|
||||||
|
iterateAttributes(c, func(a_ *Attribute) bool {
|
||||||
|
if a_.Key() == key {
|
||||||
|
a = a_
|
||||||
|
}
|
||||||
|
|
||||||
|
return a != nil
|
||||||
|
})
|
||||||
|
|
||||||
|
if a == nil {
|
||||||
|
a = NewAttribute()
|
||||||
|
a.SetKey(key)
|
||||||
|
|
||||||
|
c.SetAttributes(append(c.Attributes(), a))
|
||||||
|
}
|
||||||
|
|
||||||
|
a.SetValue(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// iterates over container attributes. Stops at f's true return.
|
||||||
|
//
|
||||||
|
// Handler must not be nil.
|
||||||
|
func iterateAttributes(c *Container, f func(*Attribute) bool) {
|
||||||
|
for _, a := range c.Attributes() {
|
||||||
|
if f(a) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNativeNameWithZone sets container native name and its zone.
|
||||||
|
//
|
||||||
|
// Use SetNativeName to set default zone.
|
||||||
|
func SetNativeNameWithZone(c *Container, name, zone string) {
|
||||||
|
setAttribute(c, container.SysAttributeName, name)
|
||||||
|
setAttribute(c, container.SysAttributeZone, zone)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNativeName sets container native name with default zone (container).
|
||||||
|
func SetNativeName(c *Container, name string) {
|
||||||
|
SetNativeNameWithZone(c, name, container.SysAttributeZoneDefault)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetNativeNameWithZone returns container native name and its zone.
|
||||||
|
func GetNativeNameWithZone(c *Container) (name string, zone string) {
|
||||||
|
iterateAttributes(c, func(a *Attribute) bool {
|
||||||
|
if key := a.Key(); key == container.SysAttributeName {
|
||||||
|
name = a.Value()
|
||||||
|
} else if key == container.SysAttributeZone {
|
||||||
|
zone = a.Value()
|
||||||
|
}
|
||||||
|
|
||||||
|
return name != "" && zone != ""
|
||||||
|
})
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
155
container/attribute_test.go
Normal file
155
container/attribute_test.go
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
package container_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
containerv2 "github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestAttribute(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x *container.Attribute
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("default values", func(t *testing.T) {
|
||||||
|
attr := container.NewAttribute()
|
||||||
|
|
||||||
|
// check initial values
|
||||||
|
require.Empty(t, attr.Key())
|
||||||
|
require.Empty(t, attr.Value())
|
||||||
|
|
||||||
|
// convert to v2 message
|
||||||
|
attrV2 := attr.ToV2()
|
||||||
|
require.Empty(t, attrV2.GetKey())
|
||||||
|
require.Empty(t, attrV2.GetValue())
|
||||||
|
})
|
||||||
|
|
||||||
|
const (
|
||||||
|
key = "key"
|
||||||
|
value = "value"
|
||||||
|
)
|
||||||
|
|
||||||
|
attr := container.NewAttribute()
|
||||||
|
attr.SetKey(key)
|
||||||
|
attr.SetValue(value)
|
||||||
|
|
||||||
|
require.Equal(t, key, attr.Key())
|
||||||
|
require.Equal(t, value, attr.Value())
|
||||||
|
|
||||||
|
t.Run("test v2", func(t *testing.T) {
|
||||||
|
const (
|
||||||
|
newKey = "newKey"
|
||||||
|
newValue = "newValue"
|
||||||
|
)
|
||||||
|
|
||||||
|
v2 := attr.ToV2()
|
||||||
|
require.Equal(t, key, v2.GetKey())
|
||||||
|
require.Equal(t, value, v2.GetValue())
|
||||||
|
|
||||||
|
v2.SetKey(newKey)
|
||||||
|
v2.SetValue(newValue)
|
||||||
|
|
||||||
|
newAttr := container.NewAttributeFromV2(v2)
|
||||||
|
|
||||||
|
require.Equal(t, newKey, newAttr.Key())
|
||||||
|
require.Equal(t, newValue, newAttr.Value())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAttributes(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x container.Attributes
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
|
||||||
|
require.Nil(t, container.NewAttributesFromV2(nil))
|
||||||
|
})
|
||||||
|
|
||||||
|
var (
|
||||||
|
keys = []string{"key1", "key2", "key3"}
|
||||||
|
vals = []string{"val1", "val2", "val3"}
|
||||||
|
)
|
||||||
|
|
||||||
|
attrs := make(container.Attributes, 0, len(keys))
|
||||||
|
|
||||||
|
for i := range keys {
|
||||||
|
attr := container.NewAttribute()
|
||||||
|
attr.SetKey(keys[i])
|
||||||
|
attr.SetValue(vals[i])
|
||||||
|
|
||||||
|
attrs = append(attrs, attr)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("test v2", func(t *testing.T) {
|
||||||
|
const postfix = "x"
|
||||||
|
|
||||||
|
v2 := attrs.ToV2()
|
||||||
|
require.Len(t, v2, len(keys))
|
||||||
|
|
||||||
|
for i := range v2 {
|
||||||
|
k := v2[i].GetKey()
|
||||||
|
v := v2[i].GetValue()
|
||||||
|
|
||||||
|
require.Equal(t, keys[i], k)
|
||||||
|
require.Equal(t, vals[i], v)
|
||||||
|
|
||||||
|
v2[i].SetKey(k + postfix)
|
||||||
|
v2[i].SetValue(v + postfix)
|
||||||
|
}
|
||||||
|
|
||||||
|
newAttrs := container.NewAttributesFromV2(v2)
|
||||||
|
require.Len(t, newAttrs, len(keys))
|
||||||
|
|
||||||
|
for i := range newAttrs {
|
||||||
|
require.Equal(t, keys[i]+postfix, newAttrs[i].Key())
|
||||||
|
require.Equal(t, vals[i]+postfix, newAttrs[i].Value())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewAttributeFromV2(t *testing.T) {
|
||||||
|
t.Run("from nil", func(t *testing.T) {
|
||||||
|
var x *containerv2.Attribute
|
||||||
|
|
||||||
|
require.Nil(t, container.NewAttributeFromV2(x))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetNameWithZone(t *testing.T) {
|
||||||
|
c := container.New()
|
||||||
|
|
||||||
|
for _, item := range [...]struct {
|
||||||
|
name, zone string
|
||||||
|
}{
|
||||||
|
{"name1", ""},
|
||||||
|
{"name1", "zone1"},
|
||||||
|
{"name2", "zone1"},
|
||||||
|
{"name2", "zone2"},
|
||||||
|
{"", "zone2"},
|
||||||
|
{"", ""},
|
||||||
|
} {
|
||||||
|
container.SetNativeNameWithZone(c, item.name, item.zone)
|
||||||
|
|
||||||
|
name, zone := container.GetNativeNameWithZone(c)
|
||||||
|
|
||||||
|
require.Equal(t, item.name, name, item.name)
|
||||||
|
require.Equal(t, item.zone, zone, item.zone)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetNativeName(t *testing.T) {
|
||||||
|
c := container.New()
|
||||||
|
|
||||||
|
const nameDefZone = "some name"
|
||||||
|
|
||||||
|
container.SetNativeName(c, nameDefZone)
|
||||||
|
|
||||||
|
name, zone := container.GetNativeNameWithZone(c)
|
||||||
|
|
||||||
|
require.Equal(t, nameDefZone, name)
|
||||||
|
require.Equal(t, containerv2.SysAttributeZoneDefault, zone)
|
||||||
|
}
|
191
container/container.go
Normal file
191
container/container.go
Normal file
|
@ -0,0 +1,191 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/sha256"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/nspcc-dev/neofs-api-go/v2/container"
|
||||||
|
cid "github.com/nspcc-dev/neofs-sdk-go/container/id"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/session"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/signature"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/version"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Container struct {
|
||||||
|
v2 container.Container
|
||||||
|
|
||||||
|
token *session.Token
|
||||||
|
|
||||||
|
sig *signature.Signature
|
||||||
|
}
|
||||||
|
|
||||||
|
// New creates, initializes and returns blank Container instance.
|
||||||
|
//
|
||||||
|
// Defaults:
|
||||||
|
// - token: nil;
|
||||||
|
// - sig: nil;
|
||||||
|
// - basicACL: acl.PrivateBasicRule;
|
||||||
|
// - version: nil;
|
||||||
|
// - nonce: random UUID;
|
||||||
|
// - attr: nil;
|
||||||
|
// - policy: nil;
|
||||||
|
// - ownerID: nil.
|
||||||
|
func New(opts ...NewOption) *Container {
|
||||||
|
cnrOptions := defaultContainerOptions()
|
||||||
|
|
||||||
|
for i := range opts {
|
||||||
|
opts[i].apply(&cnrOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
cnr := new(Container)
|
||||||
|
cnr.SetNonceUUID(cnrOptions.nonce)
|
||||||
|
cnr.SetBasicACL(cnrOptions.acl)
|
||||||
|
|
||||||
|
if cnrOptions.owner != nil {
|
||||||
|
cnr.SetOwnerID(cnrOptions.owner)
|
||||||
|
}
|
||||||
|
|
||||||
|
if cnrOptions.policy != nil {
|
||||||
|
cnr.SetPlacementPolicy(cnrOptions.policy)
|
||||||
|
}
|
||||||
|
|
||||||
|
cnr.SetAttributes(cnrOptions.attributes)
|
||||||
|
|
||||||
|
return cnr
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToV2 returns the v2 Container message.
|
||||||
|
//
|
||||||
|
// Nil Container converts to nil.
|
||||||
|
func (c *Container) ToV2() *container.Container {
|
||||||
|
if c == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return &c.v2
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewVerifiedFromV2 constructs Container from NeoFS API V2 Container message.
|
||||||
|
//
|
||||||
|
// Does not perform if message meets NeoFS API V2 specification. To do this
|
||||||
|
// use NewVerifiedFromV2 constructor.
|
||||||
|
func NewContainerFromV2(c *container.Container) *Container {
|
||||||
|
cnr := new(Container)
|
||||||
|
|
||||||
|
if c != nil {
|
||||||
|
cnr.v2 = *c
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnr
|
||||||
|
}
|
||||||
|
|
||||||
|
// CalculateID calculates container identifier
|
||||||
|
// based on its structure.
|
||||||
|
func CalculateID(c *Container) *cid.ID {
|
||||||
|
data, err := c.ToV2().StableMarshal(nil)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
id := cid.New()
|
||||||
|
id.SetSHA256(sha256.Sum256(data))
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) Version() *version.Version {
|
||||||
|
return version.NewFromV2(c.v2.GetVersion())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) SetVersion(v *version.Version) {
|
||||||
|
c.v2.SetVersion(v.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) OwnerID() *owner.ID {
|
||||||
|
return owner.NewIDFromV2(c.v2.GetOwnerID())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) SetOwnerID(v *owner.ID) {
|
||||||
|
c.v2.SetOwnerID(v.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns container nonce in UUID format.
|
||||||
|
//
|
||||||
|
// Returns error if container nonce is not a valid UUID.
|
||||||
|
func (c *Container) NonceUUID() (uuid.UUID, error) {
|
||||||
|
return uuid.FromBytes(c.v2.GetNonce())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetNonceUUID sets container nonce as UUID.
|
||||||
|
func (c *Container) SetNonceUUID(v uuid.UUID) {
|
||||||
|
data, _ := v.MarshalBinary()
|
||||||
|
c.v2.SetNonce(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) BasicACL() uint32 {
|
||||||
|
return c.v2.GetBasicACL()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) SetBasicACL(v uint32) {
|
||||||
|
c.v2.SetBasicACL(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) Attributes() Attributes {
|
||||||
|
return NewAttributesFromV2(c.v2.GetAttributes())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) SetAttributes(v Attributes) {
|
||||||
|
c.v2.SetAttributes(v.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) PlacementPolicy() *netmap.PlacementPolicy {
|
||||||
|
return netmap.NewPlacementPolicyFromV2(c.v2.GetPlacementPolicy())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Container) SetPlacementPolicy(v *netmap.PlacementPolicy) {
|
||||||
|
c.v2.SetPlacementPolicy(v.ToV2())
|
||||||
|
}
|
||||||
|
|
||||||
|
// SessionToken returns token of the session within
|
||||||
|
// which container was created.
|
||||||
|
func (c Container) SessionToken() *session.Token {
|
||||||
|
return c.token
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSessionToken sets token of the session within
|
||||||
|
// which container was created.
|
||||||
|
func (c *Container) SetSessionToken(t *session.Token) {
|
||||||
|
c.token = t
|
||||||
|
}
|
||||||
|
|
||||||
|
// Signature returns signature of the marshaled container.
|
||||||
|
func (c Container) Signature() *signature.Signature {
|
||||||
|
return c.sig
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSignature sets signature of the marshaled container.
|
||||||
|
func (c *Container) SetSignature(sig *signature.Signature) {
|
||||||
|
c.sig = sig
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal marshals Container into a protobuf binary form.
|
||||||
|
func (c *Container) Marshal() ([]byte, error) {
|
||||||
|
return c.v2.StableMarshal(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unmarshal unmarshals protobuf binary representation of Container.
|
||||||
|
func (c *Container) Unmarshal(data []byte) error {
|
||||||
|
return c.v2.Unmarshal(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MarshalJSON encodes Container to protobuf JSON format.
|
||||||
|
func (c *Container) MarshalJSON() ([]byte, error) {
|
||||||
|
return c.v2.MarshalJSON()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnmarshalJSON decodes Container from protobuf JSON format.
|
||||||
|
func (c *Container) UnmarshalJSON(data []byte) error {
|
||||||
|
return c.v2.UnmarshalJSON(data)
|
||||||
|
}
|
135
container/container_test.go
Normal file
135
container/container_test.go
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
package container_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
containertest "github.com/nspcc-dev/neofs-sdk-go/container/test"
|
||||||
|
netmaptest "github.com/nspcc-dev/neofs-sdk-go/netmap/test"
|
||||||
|
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
|
||||||
|
sessiontest "github.com/nspcc-dev/neofs-sdk-go/session/test"
|
||||||
|
sigtest "github.com/nspcc-dev/neofs-sdk-go/signature/test"
|
||||||
|
versiontest "github.com/nspcc-dev/neofs-sdk-go/version/test"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestNewContainer(t *testing.T) {
|
||||||
|
c := container.New()
|
||||||
|
|
||||||
|
nonce := uuid.New()
|
||||||
|
|
||||||
|
ownerID := ownertest.GenerateID()
|
||||||
|
policy := netmaptest.PlacementPolicy()
|
||||||
|
|
||||||
|
c.SetBasicACL(acl.PublicBasicRule)
|
||||||
|
|
||||||
|
attrs := containertest.Attributes()
|
||||||
|
c.SetAttributes(attrs)
|
||||||
|
|
||||||
|
c.SetPlacementPolicy(policy)
|
||||||
|
c.SetNonceUUID(nonce)
|
||||||
|
c.SetOwnerID(ownerID)
|
||||||
|
|
||||||
|
ver := versiontest.Version()
|
||||||
|
c.SetVersion(ver)
|
||||||
|
|
||||||
|
v2 := c.ToV2()
|
||||||
|
newContainer := container.NewContainerFromV2(v2)
|
||||||
|
|
||||||
|
require.EqualValues(t, newContainer.PlacementPolicy(), policy)
|
||||||
|
require.EqualValues(t, newContainer.Attributes(), attrs)
|
||||||
|
require.EqualValues(t, newContainer.BasicACL(), acl.PublicBasicRule)
|
||||||
|
|
||||||
|
newNonce, err := newContainer.NonceUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.EqualValues(t, newNonce, nonce)
|
||||||
|
require.EqualValues(t, newContainer.OwnerID(), ownerID)
|
||||||
|
require.EqualValues(t, newContainer.Version(), ver)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerEncoding(t *testing.T) {
|
||||||
|
c := containertest.Container()
|
||||||
|
|
||||||
|
t.Run("binary", func(t *testing.T) {
|
||||||
|
data, err := c.Marshal()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
c2 := container.New()
|
||||||
|
require.NoError(t, c2.Unmarshal(data))
|
||||||
|
|
||||||
|
require.Equal(t, c, c2)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("json", func(t *testing.T) {
|
||||||
|
data, err := c.MarshalJSON()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
c2 := container.New()
|
||||||
|
require.NoError(t, c2.UnmarshalJSON(data))
|
||||||
|
|
||||||
|
require.Equal(t, c, c2)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainer_SessionToken(t *testing.T) {
|
||||||
|
tok := sessiontest.Generate()
|
||||||
|
|
||||||
|
cnr := container.New()
|
||||||
|
|
||||||
|
cnr.SetSessionToken(tok)
|
||||||
|
|
||||||
|
require.Equal(t, tok, cnr.SessionToken())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainer_Signature(t *testing.T) {
|
||||||
|
sig := sigtest.Signature()
|
||||||
|
|
||||||
|
cnr := container.New()
|
||||||
|
cnr.SetSignature(sig)
|
||||||
|
|
||||||
|
require.Equal(t, sig, cnr.Signature())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainer_ToV2(t *testing.T) {
|
||||||
|
t.Run("nil", func(t *testing.T) {
|
||||||
|
var x *container.Container
|
||||||
|
|
||||||
|
require.Nil(t, x.ToV2())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("default values", func(t *testing.T) {
|
||||||
|
cnt := container.New()
|
||||||
|
|
||||||
|
// check initial values
|
||||||
|
require.Nil(t, cnt.SessionToken())
|
||||||
|
require.Nil(t, cnt.Signature())
|
||||||
|
require.Nil(t, cnt.Version())
|
||||||
|
require.Nil(t, cnt.Attributes())
|
||||||
|
require.Nil(t, cnt.PlacementPolicy())
|
||||||
|
require.Nil(t, cnt.OwnerID())
|
||||||
|
|
||||||
|
require.EqualValues(t, acl.PrivateBasicRule, cnt.BasicACL())
|
||||||
|
|
||||||
|
nonce, err := cnt.NonceUUID()
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, nonce)
|
||||||
|
|
||||||
|
// convert to v2 message
|
||||||
|
cntV2 := cnt.ToV2()
|
||||||
|
|
||||||
|
nonceV2, err := uuid.FromBytes(cntV2.GetNonce())
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
require.Equal(t, nonce.String(), nonceV2.String())
|
||||||
|
|
||||||
|
require.Nil(t, cntV2.GetVersion())
|
||||||
|
require.Nil(t, cntV2.GetAttributes())
|
||||||
|
require.Nil(t, cntV2.GetPlacementPolicy())
|
||||||
|
require.Nil(t, cntV2.GetOwnerID())
|
||||||
|
|
||||||
|
require.Equal(t, uint32(acl.PrivateBasicRule), cntV2.GetBasicACL())
|
||||||
|
})
|
||||||
|
}
|
104
container/opts.go
Normal file
104
container/opts.go
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/acl"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/owner"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
NewOption interface {
|
||||||
|
apply(*containerOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerOptions struct {
|
||||||
|
acl uint32
|
||||||
|
policy *netmap.PlacementPolicy
|
||||||
|
attributes Attributes
|
||||||
|
owner *owner.ID
|
||||||
|
nonce uuid.UUID
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func defaultContainerOptions() containerOptions {
|
||||||
|
rand, err := uuid.NewRandom()
|
||||||
|
if err != nil {
|
||||||
|
panic("can't create new random " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return containerOptions{
|
||||||
|
acl: acl.PrivateBasicRule,
|
||||||
|
nonce: rand,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type funcContainerOption struct {
|
||||||
|
f func(*containerOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fco *funcContainerOption) apply(co *containerOptions) {
|
||||||
|
fco.f(co)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newFuncContainerOption(f func(option *containerOptions)) *funcContainerOption {
|
||||||
|
return &funcContainerOption{
|
||||||
|
f: f,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithPublicBasicACL() NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.acl = acl.PublicBasicRule
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithReadOnlyBasicACL() NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.acl = acl.ReadOnlyBasicRule
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithCustomBasicACL(acl uint32) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.acl = acl
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithNonce(nonce uuid.UUID) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.nonce = nonce
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithOwnerID(id *owner.ID) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.owner = id
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithNEO3Wallet(w *owner.NEO3Wallet) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
if option.owner == nil {
|
||||||
|
option.owner = new(owner.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
option.owner.SetNeo3Wallet(w)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithPolicy(policy *netmap.PlacementPolicy) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
option.policy = policy
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithAttribute(key, value string) NewOption {
|
||||||
|
return newFuncContainerOption(func(option *containerOptions) {
|
||||||
|
attr := NewAttribute()
|
||||||
|
attr.SetKey(key)
|
||||||
|
attr.SetValue(value)
|
||||||
|
|
||||||
|
option.attributes = append(option.attributes, attr)
|
||||||
|
})
|
||||||
|
}
|
48
container/test/generate.go
Normal file
48
container/test/generate.go
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
package containertest
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/nspcc-dev/neofs-sdk-go/container"
|
||||||
|
cidtest "github.com/nspcc-dev/neofs-sdk-go/container/id/test"
|
||||||
|
netmaptest "github.com/nspcc-dev/neofs-sdk-go/netmap/test"
|
||||||
|
ownertest "github.com/nspcc-dev/neofs-sdk-go/owner/test"
|
||||||
|
versiontest "github.com/nspcc-dev/neofs-sdk-go/version/test"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Attribute returns random container.Attribute.
|
||||||
|
func Attribute() *container.Attribute {
|
||||||
|
x := container.NewAttribute()
|
||||||
|
|
||||||
|
x.SetKey("key")
|
||||||
|
x.SetValue("value")
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes returns random container.Attributes.
|
||||||
|
func Attributes() container.Attributes {
|
||||||
|
return container.Attributes{Attribute(), Attribute()}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container returns random container.Container.
|
||||||
|
func Container() *container.Container {
|
||||||
|
x := container.New()
|
||||||
|
|
||||||
|
x.SetVersion(versiontest.Version())
|
||||||
|
x.SetAttributes(Attributes())
|
||||||
|
x.SetOwnerID(ownertest.GenerateID())
|
||||||
|
x.SetBasicACL(123)
|
||||||
|
x.SetPlacementPolicy(netmaptest.PlacementPolicy())
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// UsedSpaceAnnouncement returns random container.UsedSpaceAnnouncement.
|
||||||
|
func UsedSpaceAnnouncement() *container.UsedSpaceAnnouncement {
|
||||||
|
x := container.NewAnnouncement()
|
||||||
|
|
||||||
|
x.SetContainerID(cidtest.GenerateID())
|
||||||
|
x.SetEpoch(55)
|
||||||
|
x.SetUsedSpace(999)
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
11
container/wellknown_attributes.go
Normal file
11
container/wellknown_attributes.go
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
package container
|
||||||
|
|
||||||
|
const (
|
||||||
|
// AttributeName is an attribute key that is commonly used to denote
|
||||||
|
// human-friendly name.
|
||||||
|
AttributeName = "Name"
|
||||||
|
|
||||||
|
// AttributeTimestamp is an attribute key that is commonly used to denote
|
||||||
|
// user-defined local time of container creation in Unix Timestamp format.
|
||||||
|
AttributeTimestamp = "Timestamp"
|
||||||
|
)
|
|
@ -2,6 +2,61 @@ package test
|
||||||
|
|
||||||
import "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
import "github.com/nspcc-dev/neofs-sdk-go/netmap"
|
||||||
|
|
||||||
|
func filter(withInner bool) *netmap.Filter {
|
||||||
|
x := netmap.NewFilter()
|
||||||
|
|
||||||
|
x.SetName("name")
|
||||||
|
x.SetKey("key")
|
||||||
|
x.SetValue("value")
|
||||||
|
x.SetOperation(netmap.OpAND)
|
||||||
|
|
||||||
|
if withInner {
|
||||||
|
x.SetInnerFilters(filter(false), filter(false))
|
||||||
|
}
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filter returns random netmap.Filter.
|
||||||
|
func Filter() *netmap.Filter {
|
||||||
|
return filter(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replica returns random netmap.Replica.
|
||||||
|
func Replica() *netmap.Replica {
|
||||||
|
x := netmap.NewReplica()
|
||||||
|
|
||||||
|
x.SetCount(666)
|
||||||
|
x.SetSelector("selector")
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// Selector returns random netmap.Selector.
|
||||||
|
func Selector() *netmap.Selector {
|
||||||
|
x := netmap.NewSelector()
|
||||||
|
|
||||||
|
x.SetCount(11)
|
||||||
|
x.SetName("name")
|
||||||
|
x.SetFilter("filter")
|
||||||
|
x.SetAttribute("attribute")
|
||||||
|
x.SetClause(netmap.ClauseDistinct)
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
|
// PlacementPolicy returns random netmap.PlacementPolicy.
|
||||||
|
func PlacementPolicy() *netmap.PlacementPolicy {
|
||||||
|
x := netmap.NewPlacementPolicy()
|
||||||
|
|
||||||
|
x.SetContainerBackupFactor(9)
|
||||||
|
x.SetFilters(Filter(), Filter())
|
||||||
|
x.SetReplicas(Replica(), Replica())
|
||||||
|
x.SetSelectors(Selector(), Selector())
|
||||||
|
|
||||||
|
return x
|
||||||
|
}
|
||||||
|
|
||||||
// NetworkParameter returns random netmap.NetworkParameter.
|
// NetworkParameter returns random netmap.NetworkParameter.
|
||||||
func NetworkParameter() *netmap.NetworkParameter {
|
func NetworkParameter() *netmap.NetworkParameter {
|
||||||
x := netmap.NewNetworkParameter()
|
x := netmap.NewNetworkParameter()
|
||||||
|
|
Loading…
Reference in a new issue