[#226] v2/tombstone: Implement unified message structure with methods
Signed-off-by: Leonard Lyubich <leonard@nspcc.ru>
This commit is contained in:
parent
2f3e5742d3
commit
6037a26a35
7 changed files with 310 additions and 0 deletions
53
v2/tombstone/convert.go
Normal file
53
v2/tombstone/convert.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package tombstone
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||
refsGRPC "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc"
|
||||
tombstone "github.com/nspcc-dev/neofs-api-go/v2/tombstone/grpc"
|
||||
)
|
||||
|
||||
// TombstoneToGRPCMessage converts unified tombstone message into gRPC message.
|
||||
func TombstoneToGRPCMessage(t *Tombstone) *tombstone.Tombstone {
|
||||
if t == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
m := new(tombstone.Tombstone)
|
||||
|
||||
m.SetExpirationEpoch(t.GetExpirationEpoch())
|
||||
m.SetSplitId(t.GetSplitID())
|
||||
|
||||
members := t.GetMembers()
|
||||
memberMsg := make([]*refsGRPC.ObjectID, 0, len(members))
|
||||
|
||||
for i := range members {
|
||||
memberMsg = append(memberMsg, refs.ObjectIDToGRPCMessage(members[i]))
|
||||
}
|
||||
|
||||
m.SetMembers(memberMsg)
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
// TombstoneFromGRPCMessage converts gRPC message into unified tombstone message.
|
||||
func TombstoneFromGRPCMessage(m *tombstone.Tombstone) *Tombstone {
|
||||
if m == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
t := new(Tombstone)
|
||||
|
||||
t.SetExpirationEpoch(m.GetExpirationEpoch())
|
||||
t.SetSplitID(m.GetSplitId())
|
||||
|
||||
memberMsg := m.GetMembers()
|
||||
members := make([]*refs.ObjectID, 0, len(memberMsg))
|
||||
|
||||
for i := range memberMsg {
|
||||
members = append(members, refs.ObjectIDFromGRPCMessage(memberMsg[i]))
|
||||
}
|
||||
|
||||
t.SetMembers(members)
|
||||
|
||||
return t
|
||||
}
|
26
v2/tombstone/grpc/types.go
Normal file
26
v2/tombstone/grpc/types.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package tombstone
|
||||
|
||||
import (
|
||||
refs "github.com/nspcc-dev/neofs-api-go/v2/refs/grpc"
|
||||
)
|
||||
|
||||
// SetExpirationEpoch sets number of tombstone expiration epoch.
|
||||
func (x *Tombstone) SetExpirationEpoch(v uint64) {
|
||||
if x != nil {
|
||||
x.ExpirationEpoch = v
|
||||
}
|
||||
}
|
||||
|
||||
// SetSplitId sets identifier of split object hierarchy.
|
||||
func (x *Tombstone) SetSplitId(v []byte) {
|
||||
if x != nil {
|
||||
x.SplitId = v
|
||||
}
|
||||
}
|
||||
|
||||
// SetMembers sets list of objects to be deleted.
|
||||
func (x *Tombstone) SetMembers(v []*refs.ObjectID) {
|
||||
if x != nil {
|
||||
x.Members = v
|
||||
}
|
||||
}
|
26
v2/tombstone/json.go
Normal file
26
v2/tombstone/json.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package tombstone
|
||||
|
||||
import (
|
||||
tombstone "github.com/nspcc-dev/neofs-api-go/v2/tombstone/grpc"
|
||||
"google.golang.org/protobuf/encoding/protojson"
|
||||
)
|
||||
|
||||
func (s *Tombstone) MarshalJSON() ([]byte, error) {
|
||||
return protojson.MarshalOptions{
|
||||
EmitUnpopulated: true,
|
||||
}.Marshal(
|
||||
TombstoneToGRPCMessage(s),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *Tombstone) UnmarshalJSON(data []byte) error {
|
||||
msg := new(tombstone.Tombstone)
|
||||
|
||||
if err := protojson.Unmarshal(data, msg); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s = *TombstoneFromGRPCMessage(msg)
|
||||
|
||||
return nil
|
||||
}
|
20
v2/tombstone/json_test.go
Normal file
20
v2/tombstone/json_test.go
Normal file
|
@ -0,0 +1,20 @@
|
|||
package tombstone_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/tombstone"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTombstoneJSON(t *testing.T) {
|
||||
from := generateTombstone()
|
||||
|
||||
data, err := from.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
|
||||
to := new(tombstone.Tombstone)
|
||||
require.NoError(t, to.UnmarshalJSON(data))
|
||||
|
||||
require.Equal(t, from, to)
|
||||
}
|
83
v2/tombstone/marshal.go
Normal file
83
v2/tombstone/marshal.go
Normal file
|
@ -0,0 +1,83 @@
|
|||
package tombstone
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/util/proto"
|
||||
tombstone "github.com/nspcc-dev/neofs-api-go/v2/tombstone/grpc"
|
||||
goproto "google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
const (
|
||||
expFNum = 1
|
||||
splitIDFNum = 2
|
||||
membersFNum = 3
|
||||
)
|
||||
|
||||
// StableMarshal marshals unified tombstone message in a protobuf
|
||||
// compatible way without field order shuffle.
|
||||
func (s *Tombstone) StableMarshal(buf []byte) ([]byte, error) {
|
||||
if s == nil {
|
||||
return []byte{}, nil
|
||||
}
|
||||
|
||||
if buf == nil {
|
||||
buf = make([]byte, s.StableSize())
|
||||
}
|
||||
|
||||
var (
|
||||
offset, n int
|
||||
err error
|
||||
)
|
||||
|
||||
n, err = proto.UInt64Marshal(expFNum, buf[offset:], s.exp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset += n
|
||||
|
||||
n, err = proto.BytesMarshal(splitIDFNum, buf[offset:], s.splitID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset += n
|
||||
|
||||
for i := range s.members {
|
||||
n, err = proto.NestedStructureMarshal(membersFNum, buf[offset:], s.members[i])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
offset += n
|
||||
}
|
||||
|
||||
return buf, nil
|
||||
}
|
||||
|
||||
// StableSize returns size of tombstone message marshalled by StableMarshal function.
|
||||
func (s *Tombstone) StableSize() (size int) {
|
||||
if s == nil {
|
||||
return 0
|
||||
}
|
||||
|
||||
size += proto.UInt64Size(expFNum, s.exp)
|
||||
size += proto.BytesSize(splitIDFNum, s.splitID)
|
||||
|
||||
for i := range s.members {
|
||||
size += proto.NestedStructureSize(membersFNum, s.members[i])
|
||||
}
|
||||
|
||||
return size
|
||||
}
|
||||
|
||||
// Unmarshal unmarshal tombstone message from its binary representation.
|
||||
func (s *Tombstone) Unmarshal(data []byte) error {
|
||||
m := new(tombstone.Tombstone)
|
||||
if err := goproto.Unmarshal(data, m); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*s = *TombstoneFromGRPCMessage(m)
|
||||
|
||||
return nil
|
||||
}
|
39
v2/tombstone/marshal_test.go
Normal file
39
v2/tombstone/marshal_test.go
Normal file
|
@ -0,0 +1,39 @@
|
|||
package tombstone_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/tombstone"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestTombstone_StableMarshal(t *testing.T) {
|
||||
from := generateTombstone()
|
||||
|
||||
t.Run("non empty", func(t *testing.T) {
|
||||
wire, err := from.StableMarshal(nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
to := new(tombstone.Tombstone)
|
||||
require.NoError(t, to.Unmarshal(wire))
|
||||
|
||||
require.Equal(t, from, to)
|
||||
})
|
||||
}
|
||||
|
||||
func generateTombstone() *tombstone.Tombstone {
|
||||
t := new(tombstone.Tombstone)
|
||||
|
||||
oid1 := new(refs.ObjectID)
|
||||
oid1.SetValue([]byte("Object ID 1"))
|
||||
|
||||
oid2 := new(refs.ObjectID)
|
||||
oid2.SetValue([]byte("Object ID 2"))
|
||||
|
||||
t.SetExpirationEpoch(100)
|
||||
t.SetSplitID([]byte("split ID"))
|
||||
t.SetMembers([]*refs.ObjectID{oid1, oid2})
|
||||
|
||||
return t
|
||||
}
|
63
v2/tombstone/types.go
Normal file
63
v2/tombstone/types.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package tombstone
|
||||
|
||||
import (
|
||||
"github.com/nspcc-dev/neofs-api-go/v2/refs"
|
||||
)
|
||||
|
||||
// Tombstone is a unified structure of Tombstone
|
||||
// message from proto definition.
|
||||
type Tombstone struct {
|
||||
exp uint64
|
||||
|
||||
splitID []byte
|
||||
|
||||
members []*refs.ObjectID
|
||||
}
|
||||
|
||||
// GetExpirationEpoch returns number of tombstone expiration epoch.
|
||||
func (s *Tombstone) GetExpirationEpoch() uint64 {
|
||||
if s != nil {
|
||||
return s.exp
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
// SetExpirationEpoch sets number of tombstone expiration epoch.
|
||||
func (s *Tombstone) SetExpirationEpoch(v uint64) {
|
||||
if s != nil {
|
||||
s.exp = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetSplitID returns identifier of split object hierarchy.
|
||||
func (s *Tombstone) GetSplitID() []byte {
|
||||
if s != nil {
|
||||
return s.splitID
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetSplitID sets identifier of split object hierarchy.
|
||||
func (s *Tombstone) SetSplitID(v []byte) {
|
||||
if s != nil {
|
||||
s.splitID = v
|
||||
}
|
||||
}
|
||||
|
||||
// GetMembers returns list of objects to be deleted.
|
||||
func (s *Tombstone) GetMembers() []*refs.ObjectID {
|
||||
if s != nil {
|
||||
return s.members
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// SetMembers sets list of objects to be deleted.
|
||||
func (s *Tombstone) SetMembers(v []*refs.ObjectID) {
|
||||
if s != nil {
|
||||
s.members = v
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue