WIP: [#100] types: Make sdk types as protobuf wrappers #100

Closed
aarifullin wants to merge 1 commit from aarifullin/frostfs-sdk-go:feature/40-decorate_protobufs into master
135 changed files with 2870 additions and 2190 deletions
Showing only changes of commit 6281a25556 - Show all commits

View file

@ -1,34 +1,45 @@
package accounting
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
import (
accgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting/grpc"
"github.com/golang/protobuf/proto"
)
// Decimal represents decimal number for accounting operations.
//
// Decimal is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting.Decimal
// Decimal is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accgrpc.Decimal
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
// Instances must be created by NewDecimal() constructor.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
//
// _ = Decimal(accounting.Decimal{}) // not recommended
type Decimal accounting.Decimal
// _ = Decimal(accgrpc.Decimal{}) // not recommended
type Decimal struct {
decimal *accgrpc.Decimal
}
// ReadFromV2 reads Decimal from the accounting.Decimal message. Checks if the
func NewDecimal() Decimal {
return Decimal{
decimal: &accgrpc.Decimal{},
}
}
// ReadFromV2 reads Decimal from the accgrpc.Decimal message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (d *Decimal) ReadFromV2(m accounting.Decimal) error {
*d = Decimal(m)
return nil
func (d *Decimal) ReadFromV2(m *accgrpc.Decimal) {
proto.Merge(d.decimal, m)
}
// WriteToV2 writes Decimal to the accounting.Decimal message.
// WriteToV2 writes Decimal to the accgrpc.Decimal message.
// The message must not be nil.
//
// See also ReadFromV2.
func (d Decimal) WriteToV2(m *accounting.Decimal) {
*m = (accounting.Decimal)(d)
func (d *Decimal) WriteToV2(m *accgrpc.Decimal) {
m.Reset()
proto.Merge(m, d.decimal)
}
// Value returns value of the decimal number.
@ -37,14 +48,14 @@ func (d Decimal) WriteToV2(m *accounting.Decimal) {
//
// See also SetValue.
func (d Decimal) Value() int64 {
return (*accounting.Decimal)(&d).GetValue()
return d.decimal.GetValue()
}
// SetValue sets value of the decimal number.
//
// See also Value.
func (d *Decimal) SetValue(v int64) {
(*accounting.Decimal)(d).SetValue(v)
d.decimal.SetValue(v)
}
// Precision returns precision of the decimal number.
@ -52,13 +63,13 @@ func (d *Decimal) SetValue(v int64) {
// Zero Decimal has zero precision.
//
// See also SetPrecision.
func (d Decimal) Precision() uint32 {
return (*accounting.Decimal)(&d).GetPrecision()
func (d *Decimal) Precision() uint32 {
return d.decimal.GetPrecision()
}
// SetPrecision sets precision of the decimal number.
//
// See also Precision.
func (d *Decimal) SetPrecision(p uint32) {
(*accounting.Decimal)(d).SetPrecision(p)
d.decimal.SetPrecision(p)
}

View file

@ -3,7 +3,7 @@ package accounting_test
import (
"testing"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
accgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting"
"github.com/stretchr/testify/require"
)
@ -11,7 +11,7 @@ import (
func TestDecimalData(t *testing.T) {
const v, p = 4, 2
var d accounting.Decimal
d := accounting.NewDecimal()
require.Zero(t, d.Value())
require.Zero(t, d.Precision())
@ -25,21 +25,21 @@ func TestDecimalData(t *testing.T) {
func TestDecimalMessageV2(t *testing.T) {
var (
d accounting.Decimal
m v2accounting.Decimal
d = accounting.NewDecimal()
m accgrpc.Decimal
)
m.SetValue(7)
m.SetPrecision(8)
require.NoError(t, d.ReadFromV2(m))
d.ReadFromV2(&m)
require.EqualValues(t, m.GetValue(), d.Value())
require.EqualValues(t, m.GetPrecision(), d.Precision())
var m2 v2accounting.Decimal
m2 := new(accgrpc.Decimal)
d.WriteToV2(&m2)
d.WriteToV2(m2)
require.EqualValues(t, d.Value(), m2.GetValue())
require.EqualValues(t, d.Precision(), m2.GetPrecision())

View file

@ -8,7 +8,7 @@ import (
// Decimal returns random accounting.Decimal.
func Decimal() *accounting.Decimal {
var d accounting.Decimal
d := accounting.NewDecimal()
d.SetValue(rand.Int63())
d.SetPrecision(rand.Uint32())

View file

@ -5,13 +5,15 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Token represents bearer token for object service operations.
@ -19,26 +21,31 @@ import (
// Token is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl.BearerToken
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
// Instances must be created by NewToken() constructor.
type Token struct {
targetUserSet bool
targetUser user.ID
eaclTableSet bool
eaclTable eacl.Table
eaclTable *eacl.Table
lifetimeSet bool
iat, nbf, exp uint64
sigSet bool
sig refs.Signature
sig *refsgrpc.Signature
impersonate bool
}
// reads Token from the acl.BearerToken message. If checkFieldPresence is set,
func NewToken() Token {
return Token{
sig: &refsgrpc.Signature{},
}
}
// reads Token from the aclgrpc.BearerToken message. If checkFieldPresence is set,
// returns an error on absence of any protocol-required field.
func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
func (b *Token) readFromV2(m *aclgrpc.BearerToken, checkFieldPresence bool) error {
var err error
body := m.GetBody()
@ -46,18 +53,18 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
return errors.New("missing token body")
}
b.impersonate = body.GetImpersonate()
b.impersonate = body.GetAllowImpersonate()
eaclTable := body.GetEACL()
if b.eaclTableSet = eaclTable != nil; b.eaclTableSet {
b.eaclTable = *eacl.NewTableFromV2(eaclTable)
b.eaclTable = nil
if eaclTable := body.GetEaclTable(); eaclTable != nil {
b.eaclTable = eacl.NewTableFromV2(eaclTable)
} else if checkFieldPresence && !b.impersonate {
return errors.New("missing eACL table")
}
targetUser := body.GetOwnerID()
targetUser := body.GetOwnerId()
if b.targetUserSet = targetUser != nil; b.targetUserSet {
err = b.targetUser.ReadFromV2(*targetUser)
err = b.targetUser.ReadFromV2(targetUser)
if err != nil {
return fmt.Errorf("invalid target user: %w", err)
}
@ -74,7 +81,10 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
sig := m.GetSignature()
if b.sigSet = sig != nil; sig != nil {
b.sig = *sig
if b.sig == nil {
b.sig = new(refsgrpc.Signature)
}
proto.Merge(b.sig, sig)
} else if checkFieldPresence {
return errors.New("missing body signature")
}
@ -82,33 +92,30 @@ func (b *Token) readFromV2(m acl.BearerToken, checkFieldPresence bool) error {
return nil
}
// ReadFromV2 reads Token from the acl.BearerToken message.
// ReadFromV2 reads Token from the aclgrpc.BearerToken message.
//
// See also WriteToV2.
func (b *Token) ReadFromV2(m acl.BearerToken) error {
func (b *Token) ReadFromV2(m *aclgrpc.BearerToken) error {
return b.readFromV2(m, true)
}
func (b Token) fillBody() *acl.BearerTokenBody {
if !b.eaclTableSet && !b.targetUserSet && !b.lifetimeSet && !b.impersonate {
func (b *Token) fillBody() *aclgrpc.BearerToken_Body {
if b.eaclTable == nil && !b.targetUserSet && !b.lifetimeSet && !b.impersonate {
return nil
}
var body acl.BearerTokenBody
if b.eaclTableSet {
body.SetEACL(b.eaclTable.ToV2())
}
body := new(aclgrpc.BearerToken_Body)
body.SetEaclTable(b.eaclTable.ToV2())
if b.targetUserSet {
var targetUser refs.OwnerID
var targetUser refsgrpc.OwnerID
b.targetUser.WriteToV2(&targetUser)
body.SetOwnerID(&targetUser)
body.SetOwnerId(&targetUser)
}
if b.lifetimeSet {
var lifetime acl.TokenLifetime
var lifetime aclgrpc.BearerToken_Body_TokenLifetime
lifetime.SetIat(b.iat)
lifetime.SetNbf(b.nbf)
lifetime.SetExp(b.exp)
@ -118,24 +125,26 @@ func (b Token) fillBody() *acl.BearerTokenBody {
body.SetImpersonate(b.impersonate)
return &body
return body
}
func (b Token) signedData() []byte {
func (b *Token) signedData() []byte {
return b.fillBody().StableMarshal(nil)
}
// WriteToV2 writes Token to the acl.BearerToken message.
// WriteToV2 writes Token to the aclgrpc.BearerToken message.
// The message must not be nil.
//
// See also ReadFromV2.
func (b Token) WriteToV2(m *acl.BearerToken) {
func (b *Token) WriteToV2(m *aclgrpc.BearerToken) {
m.Reset()
m.SetBody(b.fillBody())
var sig *refs.Signature
var sig *refsgrpc.Signature
if b.sigSet {
sig = &b.sig
sig = new(refsgrpc.Signature)
proto.Merge(sig, b.sig)
}
m.SetSignature(sig)
@ -185,7 +194,7 @@ func (b *Token) SetIat(iat uint64) {
// Zero Container is invalid in any epoch.
//
// See also SetExp, SetNbf, SetIat.
func (b Token) InvalidAt(epoch uint64) bool {
func (b *Token) InvalidAt(epoch uint64) bool {
return !b.lifetimeSet || b.nbf > epoch || b.iat > epoch || b.exp < epoch
}
@ -198,20 +207,15 @@ func (b Token) InvalidAt(epoch uint64) bool {
// FrostFS API V2 protocol.
//
// See also EACLTable, AssertContainer.
func (b *Token) SetEACLTable(table eacl.Table) {
func (b *Token) SetEACLTable(table *eacl.Table) {
b.eaclTable = table
b.eaclTableSet = true
}
// EACLTable returns extended ACL table set by SetEACLTable.
//
// Zero Token has zero eacl.Table.
func (b Token) EACLTable() eacl.Table {
if b.eaclTableSet {
func (b *Token) EACLTable() *eacl.Table {
return b.eaclTable
}
return eacl.Table{}
}
// SetImpersonate mark token as impersonate to consider token signer as request owner.
@ -221,7 +225,7 @@ func (b *Token) SetImpersonate(v bool) {
}
// Impersonate returns true if token is impersonated.
func (b Token) Impersonate() bool {
func (b *Token) Impersonate() bool {
return b.impersonate
}
@ -233,8 +237,8 @@ func (b Token) Impersonate() bool {
// Zero Token is valid in any container.
//
// See also SetEACLTable.
func (b Token) AssertContainer(cnr cid.ID) bool {
if !b.eaclTableSet {
func (b *Token) AssertContainer(cnr cid.ID) bool {
if b.eaclTable == nil {
return true
}
@ -258,7 +262,7 @@ func (b *Token) ForUser(id user.ID) {
// Zero Token is available to any user.
//
// See also ForUser.
func (b Token) AssertUser(id user.ID) bool {
func (b *Token) AssertUser(id user.ID) bool {
return !b.targetUserSet || b.targetUser.Equals(id)
}
@ -273,14 +277,17 @@ func (b Token) AssertUser(id user.ID) bool {
//
// See also VerifySignature, Issuer.
func (b *Token) Sign(key ecdsa.PrivateKey) error {
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
err := sig.Calculate(frostfsecdsa.Signer(key), b.signedData())
if err != nil {
return err
}
sig.WriteToV2(&b.sig)
if b.sig == nil {
b.sig = new(refsgrpc.Signature)
}
sig.WriteToV2(b.sig)
b.sigSet = true
return nil
@ -291,12 +298,12 @@ func (b *Token) Sign(key ecdsa.PrivateKey) error {
// Zero Token fails the check.
//
// See also Sign.
func (b Token) VerifySignature() bool {
func (b *Token) VerifySignature() bool {
if !b.sigSet {
return false
}
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
// TODO: (#233) check owner<->key relation
return sig.ReadFromV2(b.sig) == nil && sig.Verify(b.signedData())
@ -306,8 +313,8 @@ func (b Token) VerifySignature() bool {
// (Protocol Buffers V3 with direct field order).
//
// See also Unmarshal.
func (b Token) Marshal() []byte {
var m acl.BearerToken
func (b *Token) Marshal() []byte {
var m aclgrpc.BearerToken
b.WriteToV2(&m)
return m.StableMarshal(nil)
@ -319,25 +326,29 @@ func (b Token) Marshal() []byte {
//
// See also Marshal.
func (b *Token) Unmarshal(data []byte) error {
var m acl.BearerToken
var m aclgrpc.BearerToken
err := m.Unmarshal(data)
err := proto.Unmarshal(data, &m)
if err != nil {
return err
}
return b.readFromV2(m, false)
return b.readFromV2(&m, false)
}
// MarshalJSON encodes Token into a JSON format of the FrostFS API protocol
// (Protocol Buffers V3 JSON).
//
// See also UnmarshalJSON.
func (b Token) MarshalJSON() ([]byte, error) {
var m acl.BearerToken
func (b *Token) MarshalJSON() ([]byte, error) {
var m aclgrpc.BearerToken
b.WriteToV2(&m)
return m.MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
&m,
)
}
// UnmarshalJSON decodes FrostFS API protocol JSON data into the Token
@ -345,14 +356,14 @@ func (b Token) MarshalJSON() ([]byte, error) {
//
// See also MarshalJSON.
func (b *Token) UnmarshalJSON(data []byte) error {
var m acl.BearerToken
var m aclgrpc.BearerToken
err := m.UnmarshalJSON(data)
err := protojson.Unmarshal(data, &m)
if err != nil {
return err
}
return b.readFromV2(m, false)
return b.readFromV2(&m, false)
}
// SigningKeyBytes returns issuer's public key in a binary format of
@ -361,7 +372,7 @@ func (b *Token) UnmarshalJSON(data []byte) error {
// Unsigned Token has empty key.
//
// See also ResolveIssuer.
func (b Token) SigningKeyBytes() []byte {
func (b *Token) SigningKeyBytes() []byte {
if b.sigSet {
return b.sig.GetKey()
}
@ -373,7 +384,7 @@ func (b Token) SigningKeyBytes() []byte {
// Returns zero user.ID if Token is unsigned or key has incorrect format.
//
// See also SigningKeyBytes.
func ResolveIssuer(b Token) (usr user.ID) {
func ResolveIssuer(b *Token) (usr user.ID) {
binKey := b.SigningKeyBytes()
if len(binKey) != 0 {

View file

@ -5,8 +5,8 @@ import (
"math/rand"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
bearertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer/test"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
@ -16,12 +16,13 @@ import (
eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
usertest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user/test"
"github.com/golang/protobuf/proto"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
// compares binary representations of two eacl.Table instances.
func isEqualEACLTables(t1, t2 eacl.Table) bool {
func isEqualEACLTables(t1, t2 *eacl.Table) bool {
d1, err := t1.Marshal()
if err != nil {
panic(err)
@ -37,7 +38,7 @@ func isEqualEACLTables(t1, t2 eacl.Table) bool {
func TestToken_SetEACLTable(t *testing.T) {
var val bearer.Token
var m acl.BearerToken
var m aclgrpc.BearerToken
filled := bearertest.Token()
val.WriteToV2(&m)
@ -58,14 +59,14 @@ func TestToken_SetEACLTable(t *testing.T) {
// set value
eaclTable := *eacltest.Table()
eaclTable := eacltest.Table()
val.SetEACLTable(eaclTable)
require.True(t, isEqualEACLTables(eaclTable, val.EACLTable()))
val.WriteToV2(&m)
eaclTableV2 := eaclTable.ToV2()
require.Equal(t, eaclTableV2, m.GetBody().GetEACL())
require.Equal(t, eaclTableV2, m.GetBody().GetEaclTable())
val2 = filled
@ -83,7 +84,7 @@ func TestToken_SetEACLTable(t *testing.T) {
func TestToken_ForUser(t *testing.T) {
var val bearer.Token
var m acl.BearerToken
var m aclgrpc.BearerToken
filled := bearertest.Token()
val.WriteToV2(&m)
@ -115,14 +116,14 @@ func TestToken_ForUser(t *testing.T) {
val.ForUser(usr)
val.WriteToV2(&m)
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
require.True(t, proto.Equal(&usrV2, m.GetBody().GetOwnerId()))
val2 = filled
require.NoError(t, val2.Unmarshal(val.Marshal()))
val2.WriteToV2(&m)
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
require.True(t, proto.Equal(&usrV2, m.GetBody().GetOwnerId()))
val2 = filled
@ -132,12 +133,12 @@ func TestToken_ForUser(t *testing.T) {
require.NoError(t, val2.UnmarshalJSON(jd))
val2.WriteToV2(&m)
require.Equal(t, usrV2, *m.GetBody().GetOwnerID())
require.True(t, proto.Equal(&usrV2, m.GetBody().GetOwnerId()))
}
func testLifetimeClaim(t *testing.T, setter func(*bearer.Token, uint64), getter func(*acl.BearerToken) uint64) {
func testLifetimeClaim(t *testing.T, setter func(*bearer.Token, uint64), getter func(*aclgrpc.BearerToken) uint64) {
var val bearer.Token
var m acl.BearerToken
var m aclgrpc.BearerToken
filled := bearertest.Token()
val.WriteToV2(&m)
@ -188,19 +189,19 @@ func testLifetimeClaim(t *testing.T, setter func(*bearer.Token, uint64), getter
func TestToken_SetLifetime(t *testing.T) {
t.Run("iat", func(t *testing.T) {
testLifetimeClaim(t, (*bearer.Token).SetIat, func(token *acl.BearerToken) uint64 {
testLifetimeClaim(t, (*bearer.Token).SetIat, func(token *aclgrpc.BearerToken) uint64 {
return token.GetBody().GetLifetime().GetIat()
})
})
t.Run("nbf", func(t *testing.T) {
testLifetimeClaim(t, (*bearer.Token).SetNbf, func(token *acl.BearerToken) uint64 {
testLifetimeClaim(t, (*bearer.Token).SetNbf, func(token *aclgrpc.BearerToken) uint64 {
return token.GetBody().GetLifetime().GetNbf()
})
})
t.Run("exp", func(t *testing.T) {
testLifetimeClaim(t, (*bearer.Token).SetExp, func(token *acl.BearerToken) uint64 {
testLifetimeClaim(t, (*bearer.Token).SetExp, func(token *aclgrpc.BearerToken) uint64 {
return token.GetBody().GetLifetime().GetExp()
})
})
@ -230,7 +231,7 @@ func TestToken_AssertContainer(t *testing.T) {
require.True(t, val.AssertContainer(cnr))
eaclTable := *eacltest.Table()
eaclTable := eacltest.Table()
eaclTable.SetCID(cidtest.ID())
val.SetEACLTable(eaclTable)
@ -269,7 +270,7 @@ func TestToken_Sign(t *testing.T) {
require.True(t, val.VerifySignature())
var m acl.BearerToken
var m aclgrpc.BearerToken
val.WriteToV2(&m)
require.NotZero(t, m.GetSignature().GetKey())
@ -290,24 +291,24 @@ func TestToken_Sign(t *testing.T) {
func TestToken_ReadFromV2(t *testing.T) {
var val bearer.Token
var m acl.BearerToken
var m aclgrpc.BearerToken
require.Error(t, val.ReadFromV2(m))
require.Error(t, val.ReadFromV2(&m))
var body acl.BearerTokenBody
var body aclgrpc.BearerToken_Body
m.SetBody(&body)
require.Error(t, val.ReadFromV2(m))
require.Error(t, val.ReadFromV2(&m))
eaclTable := eacltest.Table().ToV2()
body.SetEACL(eaclTable)
body.SetEaclTable(eaclTable)
require.Error(t, val.ReadFromV2(m))
require.Error(t, val.ReadFromV2(&m))
var lifetime acl.TokenLifetime
var lifetime aclgrpc.BearerToken_Body_TokenLifetime
body.SetLifetime(&lifetime)
require.Error(t, val.ReadFromV2(m))
require.Error(t, val.ReadFromV2(&m))
const iat, nbf, exp = 1, 2, 3
lifetime.SetIat(iat)
@ -316,21 +317,21 @@ func TestToken_ReadFromV2(t *testing.T) {
body.SetLifetime(&lifetime)
require.Error(t, val.ReadFromV2(m))
require.Error(t, val.ReadFromV2(&m))
var sig refs.Signature
m.SetSignature(&sig)
require.NoError(t, val.ReadFromV2(m))
require.NoError(t, val.ReadFromV2(&m))
body.SetEACL(nil)
body.SetEaclTable(nil)
body.SetImpersonate(true)
require.NoError(t, val.ReadFromV2(m))
require.NoError(t, val.ReadFromV2(&m))
var m2 acl.BearerToken
var m2 aclgrpc.BearerToken
val.WriteToV2(&m2)
require.Equal(t, m, m2)
require.True(t, proto.Equal(&m, &m2))
usr, usr2 := *usertest.ID(), *usertest.ID()
@ -340,12 +341,12 @@ func TestToken_ReadFromV2(t *testing.T) {
var usrV2 refs.OwnerID
usr.WriteToV2(&usrV2)
body.SetOwnerID(&usrV2)
body.SetOwnerId(&usrV2)
require.NoError(t, val.ReadFromV2(m))
require.NoError(t, val.ReadFromV2(&m))
val.WriteToV2(&m2)
require.Equal(t, m, m2)
require.True(t, proto.Equal(&m, &m2))
require.True(t, val.AssertUser(usr))
require.False(t, val.AssertUser(usr2))
@ -361,7 +362,7 @@ func TestToken_ReadFromV2(t *testing.T) {
s.WriteToV2(&sig)
require.NoError(t, val.ReadFromV2(m))
require.NoError(t, val.ReadFromV2(&m))
require.True(t, val.VerifySignature())
require.Equal(t, sig.GetKey(), val.SigningKeyBytes())
}
@ -372,9 +373,9 @@ func TestResolveIssuer(t *testing.T) {
var val bearer.Token
require.Zero(t, bearer.ResolveIssuer(val))
require.Zero(t, bearer.ResolveIssuer(&val))
var m acl.BearerToken
var m aclgrpc.BearerToken
var sig refs.Signature
sig.SetKey([]byte("invalid key"))
@ -383,12 +384,12 @@ func TestResolveIssuer(t *testing.T) {
require.NoError(t, val.Unmarshal(m.StableMarshal(nil)))
require.Zero(t, bearer.ResolveIssuer(val))
require.Zero(t, bearer.ResolveIssuer(&val))
require.NoError(t, val.Sign(k.PrivateKey))
var usr user.ID
user.IDFromKey(&usr, k.PrivateKey.PublicKey)
require.Equal(t, usr, bearer.ResolveIssuer(val))
require.Equal(t, usr, bearer.ResolveIssuer(&val))
}

View file

@ -14,7 +14,7 @@ func Token() (t bearer.Token) {
t.SetNbf(2)
t.SetIat(1)
t.ForUser(*usertest.ID())
t.SetEACLTable(*eacltest.Table())
t.SetEACLTable(eacltest.Table())
return t
}

View file

@ -6,21 +6,30 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/tzhash/tz"
"github.com/golang/protobuf/proto"
)
// Checksum represents checksum of some digital data.
//
// Checksum is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Checksum
// Checksum is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refsgrpc.Checksum
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
// Instances must be created by NewChecksum() constructor.
//
// Note that direct typecast is not safe and may result in loss of compatibility:
//
// _ = Checksum(refs.Checksum{}) // not recommended
type Checksum refs.Checksum
// _ = Checksum(refsgrpc.Checksum{}) // not recommended
type Checksum struct {
checksum *refsgrpc.Checksum
}
func NewChecksum() Checksum {
return Checksum{
checksum: &refsgrpc.Checksum{},
}
}
// Type represents the enumeration
// of checksum types.
@ -37,11 +46,11 @@ const (
TZ
)
// ReadFromV2 reads Checksum from the refs.Checksum message. Checks if the
// ReadFromV2 reads Checksum from the refsgrpc.Checksum message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (c *Checksum) ReadFromV2(m refs.Checksum) error {
func (c *Checksum) ReadFromV2(m *refsgrpc.Checksum) error {
if len(m.GetSum()) == 0 {
return errors.New("missing value")
}
@ -49,20 +58,24 @@ func (c *Checksum) ReadFromV2(m refs.Checksum) error {
switch m.GetType() {
default:
return fmt.Errorf("unsupported type %v", m.GetType())
case refs.SHA256, refs.TillichZemor:
case refsgrpc.ChecksumType_SHA256, refsgrpc.ChecksumType_TZ:
}
*c = Checksum(m)
if c.checksum == nil {
c.checksum = new(refsgrpc.Checksum)
}
proto.Merge(c.checksum, m)
return nil
}
// WriteToV2 writes Checksum to the refs.Checksum message.
// WriteToV2 writes Checksum to the refsgrpc.Checksum message.
// The message must not be nil.
//
// See also ReadFromV2.
func (c Checksum) WriteToV2(m *refs.Checksum) {
*m = (refs.Checksum)(c)
func (c *Checksum) WriteToV2(m *refsgrpc.Checksum) {
m.Reset()
proto.Merge(m, c.checksum)
}
// Type returns checksum type.
@ -70,12 +83,11 @@ func (c Checksum) WriteToV2(m *refs.Checksum) {
// Zero Checksum has Unknown checksum type.
//
// See also SetTillichZemor and SetSHA256.
func (c Checksum) Type() Type {
v2 := (refs.Checksum)(c)
switch v2.GetType() {
case refs.SHA256:
func (c *Checksum) Type() Type {
switch c.checksum.GetType() {
case refsgrpc.ChecksumType_SHA256:
return SHA256
case refs.TillichZemor:
case refsgrpc.ChecksumType_TZ:
return TZ
default:
return Unknown
@ -88,19 +100,16 @@ func (c Checksum) Type() Type {
// Zero Checksum has nil sum.
//
// See also SetTillichZemor and SetSHA256.
func (c Checksum) Value() []byte {
v2 := (refs.Checksum)(c)
return v2.GetSum()
func (c *Checksum) Value() []byte {
return c.checksum.GetSum()
}
// SetSHA256 sets checksum to SHA256 hash.
//
// See also Calculate.
func (c *Checksum) SetSHA256(v [sha256.Size]byte) {
v2 := (*refs.Checksum)(c)
v2.SetType(refs.SHA256)
v2.SetSum(v[:])
c.checksum.SetChecksumType(refsgrpc.ChecksumType_SHA256)
c.checksum.SetSum(v[:])
}
// Calculate calculates checksum and sets it
@ -127,19 +136,16 @@ func Calculate(c *Checksum, t Type, v []byte) {
//
// See also Calculate.
func (c *Checksum) SetTillichZemor(v [tz.Size]byte) {
v2 := (*refs.Checksum)(c)
v2.SetType(refs.TillichZemor)
v2.SetSum(v[:])
c.checksum.SetChecksumType(refsgrpc.ChecksumType_TZ)
c.checksum.SetSum(v[:])
}
// String implements fmt.Stringer.
//
// String is designed to be human-readable, and its format MAY differ between
// SDK versions.
func (c Checksum) String() string {
v2 := (refs.Checksum)(c)
return fmt.Sprintf("%s:%s", c.Type(), hex.EncodeToString(v2.GetSum()))
func (c *Checksum) String() string {
return fmt.Sprintf("%s:%s", c.checksum.GetType(), hex.EncodeToString(c.checksum.GetSum()))
}
// String implements fmt.Stringer.
@ -147,15 +153,15 @@ func (c Checksum) String() string {
// String is designed to be human-readable, and its format MAY differ between
// SDK versions.
func (m Type) String() string {
var m2 refs.ChecksumType
var m2 refsgrpc.ChecksumType
switch m {
default:
m2 = refs.UnknownChecksum
m2 = refsgrpc.ChecksumType_CHECKSUM_TYPE_UNSPECIFIED
case TZ:
m2 = refs.TillichZemor
m2 = refsgrpc.ChecksumType_TZ
case SHA256:
m2 = refs.SHA256
m2 = refsgrpc.ChecksumType_SHA256
}
return m2.String()

View file

@ -5,13 +5,13 @@ import (
"crypto/sha256"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/tzhash/tz"
"github.com/stretchr/testify/require"
)
func TestChecksum(t *testing.T) {
var c Checksum
c := NewChecksum()
cSHA256 := [sha256.Size]byte{}
_, _ = rand.Read(cSHA256[:])
@ -21,10 +21,10 @@ func TestChecksum(t *testing.T) {
require.Equal(t, SHA256, c.Type())
require.Equal(t, cSHA256[:], c.Value())
var cV2 refs.Checksum
var cV2 refsgrpc.Checksum
c.WriteToV2(&cV2)
require.Equal(t, refs.SHA256, cV2.GetType())
require.Equal(t, refsgrpc.ChecksumType_SHA256, cV2.GetType())
require.Equal(t, cSHA256[:], cV2.GetSum())
cTZ := [tz.Size]byte{}
@ -37,7 +37,7 @@ func TestChecksum(t *testing.T) {
c.WriteToV2(&cV2)
require.Equal(t, refs.TillichZemor, cV2.GetType())
require.Equal(t, refsgrpc.ChecksumType_TZ, cV2.GetType())
require.Equal(t, cTZ[:], cV2.GetSum())
}
@ -50,16 +50,16 @@ func TestNewChecksum(t *testing.T) {
require.Nil(t, chs.Value())
// convert to v2 message
var chsV2 refs.Checksum
var chsV2 refsgrpc.Checksum
chs.WriteToV2(&chsV2)
require.Equal(t, refs.UnknownChecksum, chsV2.GetType())
require.Equal(t, refsgrpc.ChecksumType_CHECKSUM_TYPE_UNSPECIFIED, chsV2.GetType())
require.Nil(t, chsV2.GetSum())
})
}
func TestCalculation(t *testing.T) {
var c Checksum
c := NewChecksum()
payload := []byte{0, 1, 2, 3, 4, 5}
t.Run("SHA256", func(t *testing.T) {

View file

@ -6,7 +6,7 @@ import (
"fmt"
"math/rand"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
)
func ExampleCalculate() {
@ -20,8 +20,8 @@ func ExampleCalculate() {
func ExampleChecksum_WriteToV2() {
var (
csRaw [sha256.Size]byte
csV2 refs.Checksum
cs Checksum
csV2 refsgrpc.Checksum
cs = NewChecksum()
)
rand.Read(csRaw[:])

View file

@ -13,7 +13,7 @@ func Checksum() checksum.Checksum {
rand.Read(cs[:])
var x checksum.Checksum
x := checksum.NewChecksum()
x.SetSHA256(cs)

View file

@ -3,8 +3,8 @@ package client
import (
"context"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
accgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/accounting"
@ -33,6 +33,12 @@ type ResBalanceGet struct {
amount accounting.Decimal
}
func NewResBalanceGet() ResBalanceGet {
return ResBalanceGet{
amount: accounting.NewDecimal(),
}
}
// Amount returns current amount of funds on the FrostFS account as decimal number.
func (x ResBalanceGet) Amount() accounting.Decimal {
return x.amount
@ -57,14 +63,14 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
}
// form request body
var accountV2 refs.OwnerID
var accountV2 refsgrpc.OwnerID
prm.account.WriteToV2(&accountV2)
var body v2accounting.BalanceRequestBody
body.SetOwnerID(&accountV2)
var body accgrpc.BalanceRequest_Body
body.SetOwnerId(&accountV2)
// form request
var req v2accounting.BalanceRequest
var req accgrpc.BalanceRequest
req.SetBody(&body)
@ -72,7 +78,7 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
var (
cc contextCall
res ResBalanceGet
res = NewResBalanceGet()
)
c.initCallContext(&cc)
@ -83,7 +89,7 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
return rpcapi.Balance(&c.c, &req, client.WithContext(ctx))
}
cc.result = func(r responseV2) {
resp := r.(*v2accounting.BalanceResponse)
resp := r.(*accgrpc.BalanceResponse)
const fieldBalance = "balance"
@ -93,10 +99,7 @@ func (c *Client) BalanceGet(ctx context.Context, prm PrmBalanceGet) (*ResBalance
return
}
cc.err = res.amount.ReadFromV2(*bal)
if cc.err != nil {
cc.err = newErrInvalidResponseField(fieldBalance, cc.err)
}
res.amount.ReadFromV2(bal)
}
// process call

View file

@ -4,14 +4,14 @@ import (
"context"
"fmt"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
)
// interface of FrostFS API server. Exists for test purposes only.
type frostFSAPIServer interface {
netMapSnapshot(context.Context, v2netmap.SnapshotRequest) (*v2netmap.SnapshotResponse, error)
netMapSnapshot(context.Context, *netmapgrpc.NetmapSnapshotRequest) (*netmapgrpc.NetmapSnapshotResponse, error)
}
// wrapper over real client connection which communicates over FrostFS API protocol.
@ -25,8 +25,8 @@ func rpcErr(e error) error {
// executes NetmapService.NetmapSnapshot RPC declared in FrostFS API protocol
// using underlying client.Client.
func (x *coreServer) netMapSnapshot(ctx context.Context, req v2netmap.SnapshotRequest) (*v2netmap.SnapshotResponse, error) {
resp, err := rpcapi.NetMapSnapshot((*client.Client)(x), &req, client.WithContext(ctx))
func (x *coreServer) netMapSnapshot(ctx context.Context, req *netmapgrpc.NetmapSnapshotRequest) (*netmapgrpc.NetmapSnapshotResponse, error) {
resp, err := rpcapi.NetMapSnapshot((*client.Client)(x), req, client.WithContext(ctx))
if err != nil {
return nil, rpcErr(err)
}

View file

@ -7,7 +7,7 @@ import (
"errors"
"time"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting"
v2accounting "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/accounting/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"google.golang.org/grpc"

View file

@ -17,15 +17,17 @@ File contains common functionality used for client package testing.
var key, _ = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
var statusErr apistatus.ServerInternal
var statusErr = apistatus.NewServerInternal()
func init() {
statusErr.SetMessage("test status error")
}
func assertStatusErr(tb testing.TB, res interface{ Status() apistatus.Status }) {
require.IsType(tb, &statusErr, res.Status())
require.Equal(tb, statusErr.Message(), res.Status().(*apistatus.ServerInternal).Message())
require.IsType(tb, statusErr, res.Status())
m := statusErr.Message()
r := res.Status()
require.Equal(tb, m, r.(apistatus.ServerInternal).Message())
}
func newClient(server frostFSAPIServer) *Client {

View file

@ -5,11 +5,13 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
)
@ -53,7 +55,7 @@ func (x *prmCommonMeta) WithXHeaders(hs ...string) {
x.xHeaders = hs
}
func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
func writeXHeadersToMeta(xHeaders []string, h *sessiongrpc.RequestMetaHeader) {
if len(xHeaders) == 0 {
return
}
@ -62,7 +64,7 @@ func writeXHeadersToMeta(xHeaders []string, h *v2session.RequestMetaHeader) {
panic("slice of X-Headers with odd length")
}
hs := make([]v2session.XHeader, len(xHeaders)/2)
hs := slices.MakePreallocPointerSlice[sessiongrpc.XHeader](len(xHeaders) / 2)
for i := 0; i < len(xHeaders); i += 2 {
hs[i].SetKey(xHeaders[i])
hs[i].SetValue(xHeaders[i+1])
@ -139,25 +141,25 @@ type contextCall struct {
}
type request interface {
GetMetaHeader() *v2session.RequestMetaHeader
SetMetaHeader(*v2session.RequestMetaHeader)
SetVerificationHeader(*v2session.RequestVerificationHeader)
GetMetaHeader() *sessiongrpc.RequestMetaHeader
SetMetaHeader(*sessiongrpc.RequestMetaHeader)
SetVerifyHeader(*sessiongrpc.RequestVerificationHeader)
}
// sets needed fields of the request meta header.
func (x contextCall) prepareRequest() {
meta := x.req.GetMetaHeader()
if meta == nil {
meta = new(v2session.RequestMetaHeader)
meta = new(sessiongrpc.RequestMetaHeader)
x.req.SetMetaHeader(meta)
}
if meta.GetTTL() == 0 {
meta.SetTTL(2)
if meta.GetTtl() == 0 {
meta.SetTtl(2)
}
if meta.GetVersion() == nil {
var verV2 refs.Version
var verV2 refsgrpc.Version
version.Current().WriteToV2(&verV2)
meta.SetVersion(&verV2)
}
@ -167,8 +169,8 @@ func (x contextCall) prepareRequest() {
writeXHeadersToMeta(x.meta.xHeaders, meta)
}
func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader) {
ttl := meta.GetTTL()
func (c *Client) prepareRequest(req request, meta *sessiongrpc.RequestMetaHeader) {
ttl := meta.GetTtl()
if ttl == 0 {
ttl = 2
}
@ -179,7 +181,7 @@ func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader)
version.Current().WriteToV2(verV2)
}
meta.SetTTL(ttl)
meta.SetTtl(ttl)
meta.SetVersion(verV2)
meta.SetNetworkMagic(c.prm.netMagic)
@ -191,7 +193,7 @@ func (c *Client) prepareRequest(req request, meta *v2session.RequestMetaHeader)
func (x *contextCall) writeRequest() bool {
x.prepareRequest()
x.req.SetVerificationHeader(nil)
x.req.SetVerifyHeader(nil)
// sign the request
x.err = signature.SignServiceMessage(&x.key, x.req)
@ -220,7 +222,7 @@ func (x *contextCall) processResponse() bool {
// call response callback if set
if x.callbackResp != nil {
x.err = x.callbackResp(ResponseMetaInfo{
key: x.resp.GetVerificationHeader().GetBodySignature().GetKey(),
key: x.resp.GetVerifyHeader().GetBodySignature().GetKey(),
epoch: x.resp.GetMetaHeader().GetEpoch(),
})
if x.err != nil {
@ -259,7 +261,7 @@ func (x *contextCall) processResponse() bool {
func (c *Client) processResponse(resp responseV2) (apistatus.Status, error) {
if c.prm.cbRespInfo != nil {
rmi := ResponseMetaInfo{
key: resp.GetVerificationHeader().GetBodySignature().GetKey(),
key: resp.GetVerifyHeader().GetBodySignature().GetKey(),
epoch: resp.GetMetaHeader().GetEpoch(),
}
if err := c.prm.cbRespInfo(rmi); err != nil {

View file

@ -16,7 +16,7 @@ import (
// Returns any network/parsing config errors.
//
// See also NetworkInfo, container.ApplyNetworkConfig.
func SyncContainerWithNetwork(ctx context.Context, cnr *container.Container, c *Client) error {
func SyncContainerWithNetwork(ctx context.Context, cnr container.Container, c *Client) error {
res, err := c.NetworkInfo(ctx, PrmNetworkInfo{})
if err != nil {
return fmt.Errorf("network info call: %w", err)

View file

@ -4,11 +4,11 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
@ -34,43 +34,43 @@ func (x *PrmContainerDelete) SetContainer(id cid.ID) {
x.idSet = true
}
func (x *PrmContainerDelete) buildRequest(c *Client) (*v2container.DeleteRequest, error) {
func (x *PrmContainerDelete) buildRequest(c *Client) (*containergrpc.DeleteRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
var cidV2 refsgrpc.ContainerID
x.id.WriteToV2(&cidV2)
// Container contract expects signature of container ID value,
// don't get confused with stable marshaled protobuf container.ID structure.
data := cidV2.GetValue()
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), data)
if err != nil {
return nil, fmt.Errorf("calculate signature: %w", err)
}
var sigv2 refs.Signature
var sigv2 refsgrpc.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.DeleteRequestBody)
reqBody.SetContainerID(&cidV2)
reqBody.SetSignature(&sigv2)
reqBody := new(containergrpc.DeleteRequest_Body)
reqBody.SetContainerId(&cidV2)
reqBody.SetSignature(sigv2.ToRFC6979())
var meta v2session.RequestMetaHeader
var meta sessiongrpc.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.tokSet {
var tokv2 v2session.Token
var tokv2 sessiongrpc.SessionToken
x.tok.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.DeleteRequest
var req containergrpc.DeleteRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil

View file

@ -4,11 +4,11 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
@ -30,20 +30,20 @@ func (x *PrmContainerEACL) SetContainer(id cid.ID) {
x.idSet = true
}
func (x *PrmContainerEACL) buildRequest(c *Client) (*v2container.GetExtendedACLRequest, error) {
func (x *PrmContainerEACL) buildRequest(c *Client) (*containergrpc.GetExtendedACLRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
var cidV2 refsgrpc.ContainerID
x.id.WriteToV2(&cidV2)
reqBody := new(v2container.GetExtendedACLRequestBody)
reqBody.SetContainerID(&cidV2)
reqBody := new(containergrpc.GetExtendedACLRequest_Body)
reqBody.SetContainerId(&cidV2)
var req v2container.GetExtendedACLRequest
var req containergrpc.GetExtendedACLRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
c.prepareRequest(&req, new(sessiongrpc.RequestMetaHeader))
return &req, nil
}
@ -95,7 +95,7 @@ func (c *Client) ContainerEACL(ctx context.Context, prm PrmContainerEACL) (*ResC
return &res, err
}
eACL := resp.GetBody().GetEACL()
eACL := resp.GetBody().GetEacl()
if eACL == nil {
return &res, newErrMissingResponseField("eACL")
}

View file

@ -5,11 +5,11 @@ import (
"errors"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
@ -31,20 +31,20 @@ func (x *PrmContainerGet) SetContainer(id cid.ID) {
x.idSet = true
}
func (x *PrmContainerGet) buildRequest(c *Client) (*v2container.GetRequest, error) {
func (x *PrmContainerGet) buildRequest(c *Client) (*containergrpc.GetRequest, error) {
if !x.idSet {
return nil, errorMissingContainer
}
var cidV2 refs.ContainerID
var cidV2 refsgrpc.ContainerID
x.id.WriteToV2(&cidV2)
reqBody := new(v2container.GetRequestBody)
reqBody.SetContainerID(&cidV2)
reqBody := new(containergrpc.GetRequest_Body)
reqBody.SetContainerId(&cidV2)
var req v2container.GetRequest
var req containergrpc.GetRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
c.prepareRequest(&req, new(sessiongrpc.RequestMetaHeader))
return &req, nil
}
@ -52,13 +52,19 @@ func (x *PrmContainerGet) buildRequest(c *Client) (*v2container.GetRequest, erro
type ResContainerGet struct {
statusRes
cnr container.Container
cnr *container.Container
}
func NewResContainerGet() *ResContainerGet {
return &ResContainerGet{
cnr: new(container.Container),
}
}
// Container returns structured information about the requested container.
//
// Client doesn't retain value so modification is safe.
func (x ResContainerGet) Container() container.Container {
func (x *ResContainerGet) Container() *container.Container {
return x.cnr
}
@ -91,18 +97,18 @@ func (c *Client) ContainerGet(ctx context.Context, prm PrmContainerGet) (*ResCon
return nil, err
}
var res ResContainerGet
res := NewResContainerGet()
res.st, err = c.processResponse(resp)
if err != nil || !apistatus.IsSuccessful(res.st) {
return &res, err
return nil, err
}
cnrV2 := resp.GetBody().GetContainer()
if cnrV2 == nil {
return &res, errors.New("missing container in response")
return nil, errors.New("missing container in response")
}
if err := res.cnr.ReadFromV2(*cnrV2); err != nil {
return &res, fmt.Errorf("invalid container in response: %w", err)
if err := res.cnr.ReadFromV2(cnrV2); err != nil {
return nil, fmt.Errorf("invalid container in response: %w", err)
}
return &res, nil
return res, nil
}

View file

@ -4,11 +4,11 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
@ -30,20 +30,20 @@ func (x *PrmContainerList) SetAccount(id user.ID) {
x.ownerSet = true
}
func (x *PrmContainerList) buildRequest(c *Client) (*v2container.ListRequest, error) {
func (x *PrmContainerList) buildRequest(c *Client) (*containergrpc.ListRequest, error) {
if !x.ownerSet {
return nil, errorAccountNotSet
}
var ownerV2 refs.OwnerID
var ownerV2 refsgrpc.OwnerID
x.ownerID.WriteToV2(&ownerV2)
reqBody := new(v2container.ListRequestBody)
reqBody.SetOwnerID(&ownerV2)
reqBody := new(containergrpc.ListRequest_Body)
reqBody.SetOwnerId(&ownerV2)
var req v2container.ListRequest
var req containergrpc.ListRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
c.prepareRequest(&req, new(sessiongrpc.RequestMetaHeader))
return &req, nil
}
@ -95,8 +95,8 @@ func (c *Client) ContainerList(ctx context.Context, prm PrmContainerList) (*ResC
return &res, err
}
res.ids = make([]cid.ID, len(resp.GetBody().GetContainerIDs()))
for i, cidV2 := range resp.GetBody().GetContainerIDs() {
res.ids = make([]cid.ID, len(resp.GetBody().GetContainerIds()))
for i, cidV2 := range resp.GetBody().GetContainerIds() {
if err := res.ids[i].ReadFromV2(cidV2); err != nil {
return &res, fmt.Errorf("invalid ID in the response: %w", err)
}

View file

@ -4,11 +4,11 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
@ -48,40 +48,40 @@ func (x *PrmContainerPut) WithinSession(s session.Container) {
x.sessionSet = true
}
func (x *PrmContainerPut) buildRequest(c *Client) (*v2container.PutRequest, error) {
func (x *PrmContainerPut) buildRequest(c *Client) (*containergrpc.PutRequest, error) {
if !x.cnrSet {
return nil, errorMissingContainer
}
// TODO: check private key is set before forming the request
var cnr v2container.Container
var cnr containergrpc.Container
x.cnr.WriteToV2(&cnr)
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
err := container.CalculateSignature(&sig, x.cnr, c.prm.key)
if err != nil {
return nil, fmt.Errorf("calculate container signature: %w", err)
}
var sigv2 refs.Signature
var sigv2 refsgrpc.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.PutRequestBody)
reqBody := new(containergrpc.PutRequest_Body)
reqBody.SetContainer(&cnr)
reqBody.SetSignature(&sigv2)
reqBody.SetSignature(sigv2.ToRFC6979())
var meta v2session.RequestMetaHeader
var meta sessiongrpc.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.sessionSet {
var tokv2 v2session.Token
var tokv2 sessiongrpc.SessionToken
x.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.PutRequest
var req containergrpc.PutRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
@ -144,11 +144,11 @@ func (c *Client) ContainerPut(ctx context.Context, prm PrmContainerPut) (*ResCon
const fieldCnrID = "container ID"
cidV2 := resp.GetBody().GetContainerID()
cidV2 := resp.GetBody().GetContainerId()
if cidV2 == nil {
return &res, newErrMissingResponseField(fieldCnrID)
}
if err := res.id.ReadFromV2(*cidV2); err != nil {
if err := res.id.ReadFromV2(cidV2); err != nil {
return &res, newErrInvalidResponseField(fieldCnrID, err)
}
return &res, nil

View file

@ -4,15 +4,15 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
eaclsdk "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
)
@ -21,7 +21,7 @@ type PrmContainerSetEACL struct {
prmCommonMeta
tableSet bool
table eacl.Table
table *eaclsdk.Table
sessionSet bool
session session.Container
@ -29,7 +29,7 @@ type PrmContainerSetEACL struct {
// SetTable sets eACL table structure to be set for the container.
// Required parameter.
func (x *PrmContainerSetEACL) SetTable(table eacl.Table) {
func (x *PrmContainerSetEACL) SetTable(table *eaclsdk.Table) {
x.table = table
x.tableSet = true
}
@ -50,14 +50,14 @@ func (x *PrmContainerSetEACL) WithinSession(s session.Container) {
x.sessionSet = true
}
func (x *PrmContainerSetEACL) buildRequest(c *Client) (*v2container.SetExtendedACLRequest, error) {
func (x *PrmContainerSetEACL) buildRequest(c *Client) (*containergrpc.SetExtendedACLRequest, error) {
if !x.tableSet {
return nil, errorEACLTableNotSet
}
eaclV2 := x.table.ToV2()
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
err := sig.Calculate(frostfsecdsa.SignerRFC6979(c.prm.key), eaclV2.StableMarshal(nil))
if err != nil {
@ -67,21 +67,21 @@ func (x *PrmContainerSetEACL) buildRequest(c *Client) (*v2container.SetExtendedA
var sigv2 refs.Signature
sig.WriteToV2(&sigv2)
reqBody := new(v2container.SetExtendedACLRequestBody)
reqBody.SetEACL(eaclV2)
reqBody.SetSignature(&sigv2)
reqBody := new(containergrpc.SetExtendedACLRequest_Body)
reqBody.SetEacl(eaclV2)
reqBody.SetSignature(sigv2.ToRFC6979())
var meta v2session.RequestMetaHeader
var meta sessiongrpc.RequestMetaHeader
writeXHeadersToMeta(x.prmCommonMeta.xHeaders, &meta)
if x.sessionSet {
var tokv2 v2session.Token
var tokv2 sessiongrpc.SessionToken
x.session.WriteToV2(&tokv2)
meta.SetSessionToken(&tokv2)
}
var req v2container.SetExtendedACLRequest
var req containergrpc.SetExtendedACLRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil

View file

@ -4,12 +4,13 @@ import (
"context"
"fmt"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
)
// PrmAnnounceSpace groups parameters of ContainerAnnounceUsedSpace operation.
@ -27,22 +28,22 @@ func (x *PrmAnnounceSpace) SetValues(vs []container.SizeEstimation) {
x.announcements = vs
}
func (x *PrmAnnounceSpace) buildRequest(c *Client) (*v2container.AnnounceUsedSpaceRequest, error) {
func (x *PrmAnnounceSpace) buildRequest(c *Client) (*containergrpc.AnnounceUsedSpaceRequest, error) {
if len(x.announcements) == 0 {
return nil, errorMissingAnnouncements
}
v2announce := make([]v2container.UsedSpaceAnnouncement, len(x.announcements))
v2announce := slices.MakePreallocPointerSlice[containergrpc.AnnounceUsedSpaceRequest_Body_Announcement](len(x.announcements))
for i := range x.announcements {
x.announcements[i].WriteToV2(&v2announce[i])
x.announcements[i].WriteToV2(v2announce[i])
}
reqBody := new(v2container.AnnounceUsedSpaceRequestBody)
reqBody := new(containergrpc.AnnounceUsedSpaceRequest_Body)
reqBody.SetAnnouncements(v2announce)
var req v2container.AnnounceUsedSpaceRequest
var req containergrpc.AnnounceUsedSpaceRequest
req.SetBody(reqBody)
c.prepareRequest(&req, new(v2session.RequestMetaHeader))
c.prepareRequest(&req, new(sessiongrpc.RequestMetaHeader))
return &req, nil
}

View file

@ -4,10 +4,10 @@ import (
"context"
"fmt"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
@ -19,12 +19,12 @@ type PrmEndpointInfo struct {
prmCommonMeta
}
func (x *PrmEndpointInfo) buildRequest(c *Client) (*v2netmap.LocalNodeInfoRequest, error) {
meta := new(v2session.RequestMetaHeader)
func (x *PrmEndpointInfo) buildRequest(c *Client) (*netmapgrpc.LocalNodeInfoRequest, error) {
meta := new(sessiongrpc.RequestMetaHeader)
writeXHeadersToMeta(x.xHeaders, meta)
req := new(v2netmap.LocalNodeInfoRequest)
req.SetBody(new(v2netmap.LocalNodeInfoRequestBody))
req := new(netmapgrpc.LocalNodeInfoRequest)
req.SetBody(new(netmapgrpc.LocalNodeInfoRequest_Body))
c.prepareRequest(req, meta)
return req, nil
}
@ -94,9 +94,7 @@ func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEnd
if verV2 == nil {
return nil, newErrMissingResponseField(fieldVersion)
}
if err := res.version.ReadFromV2(*verV2); err != nil {
return nil, newErrInvalidResponseField(fieldVersion, err)
}
res.version.ReadFromV2(verV2)
const fieldNodeInfo = "node info"
@ -104,7 +102,7 @@ func (c *Client) EndpointInfo(ctx context.Context, prm PrmEndpointInfo) (*ResEnd
if nodeInfoV2 == nil {
return nil, newErrMissingResponseField(fieldNodeInfo)
}
if err := res.ni.ReadFromV2(*nodeInfoV2); err != nil {
if err := res.ni.ReadFromV2(nodeInfoV2); err != nil {
return nil, newErrInvalidResponseField(fieldNodeInfo, err)
}
return &res, nil
@ -115,12 +113,12 @@ type PrmNetworkInfo struct {
prmCommonMeta
}
func (x PrmNetworkInfo) buildRequest(c *Client) (*v2netmap.NetworkInfoRequest, error) {
meta := new(v2session.RequestMetaHeader)
func (x PrmNetworkInfo) buildRequest(c *Client) (*netmapgrpc.NetworkInfoRequest, error) {
meta := new(sessiongrpc.RequestMetaHeader)
writeXHeadersToMeta(x.xHeaders, meta)
var req v2netmap.NetworkInfoRequest
req.SetBody(new(v2netmap.NetworkInfoRequestBody))
var req netmapgrpc.NetworkInfoRequest
req.SetBody(new(netmapgrpc.NetworkInfoRequest_Body))
c.prepareRequest(&req, meta)
return &req, nil
}
@ -179,7 +177,7 @@ func (c *Client) NetworkInfo(ctx context.Context, prm PrmNetworkInfo) (*ResNetwo
if netInfoV2 == nil {
return nil, newErrMissingResponseField(fieldNetInfo)
}
if err := res.info.ReadFromV2(*netInfoV2); err != nil {
if err := res.info.ReadFromV2(netInfoV2); err != nil {
return nil, newErrInvalidResponseField(fieldNetInfo, err)
}
return &res, nil
@ -218,13 +216,13 @@ func (x ResNetMapSnapshot) NetMap() netmap.NetMap {
// - global (see Client docs).
func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResNetMapSnapshot, error) {
// form request body
var body v2netmap.SnapshotRequestBody
var body netmapgrpc.NetmapSnapshotRequest_Body
// form meta header
var meta v2session.RequestMetaHeader
var meta sessiongrpc.RequestMetaHeader
// form request
var req v2netmap.SnapshotRequest
var req netmapgrpc.NetmapSnapshotRequest
req.SetBody(&body)
c.prepareRequest(&req, &meta)
@ -233,7 +231,7 @@ func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResN
return nil, fmt.Errorf("sign request: %w", err)
}
resp, err := c.server.netMapSnapshot(ctx, req)
resp, err := c.server.netMapSnapshot(ctx, &req)
if err != nil {
return nil, err
}
@ -250,12 +248,12 @@ func (c *Client) NetMapSnapshot(ctx context.Context, _ PrmNetMapSnapshot) (*ResN
const fieldNetMap = "network map"
netMapV2 := resp.GetBody().NetMap()
netMapV2 := resp.GetBody().GetNetmap()
if netMapV2 == nil {
return nil, newErrMissingResponseField(fieldNetMap)
}
err = res.netMap.ReadFromV2(*netMapV2)
err = res.netMap.ReadFromV2(netMapV2)
if err != nil {
return nil, newErrInvalidResponseField(fieldNetMap, err)
}

View file

@ -6,8 +6,8 @@ import (
"fmt"
"testing"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
@ -22,11 +22,11 @@ type serverNetMap struct {
statusOK bool
setNetMap bool
netMap v2netmap.NetMap
netMap netmapgrpc.Netmap
}
func (x *serverNetMap) netMapSnapshot(ctx context.Context, req v2netmap.SnapshotRequest) (*v2netmap.SnapshotResponse, error) {
err := signature.VerifyServiceMessage(&req)
func (x *serverNetMap) netMapSnapshot(ctx context.Context, req *netmapgrpc.NetmapSnapshotRequest) (*netmapgrpc.NetmapSnapshotResponse, error) {
err := signature.VerifyServiceMessage(req)
if err != nil {
return nil, err
}
@ -35,19 +35,19 @@ func (x *serverNetMap) netMapSnapshot(ctx context.Context, req v2netmap.Snapshot
return nil, x.errTransport
}
var body v2netmap.SnapshotResponseBody
var body netmapgrpc.NetmapSnapshotResponse_Body
if x.setNetMap {
body.SetNetMap(&x.netMap)
body.SetNetmap(&x.netMap)
}
var meta session.ResponseMetaHeader
var meta sessiongrpc.ResponseMetaHeader
if !x.statusOK {
meta.SetStatus(statusErr.ToStatusV2())
}
var resp v2netmap.SnapshotResponse
var resp netmapgrpc.NetmapSnapshotResponse
resp.SetBody(&body)
resp.SetMetaHeader(&meta)
@ -99,13 +99,13 @@ func TestClient_NetMapSnapshot(t *testing.T) {
// invalid network map
var netMap netmap.NetMap
var node netmap.NodeInfo
node := netmap.NewNodeInfo()
// TODO: #260 use instance corrupter
var nodeV2 v2netmap.NodeInfo
var nodeV2 netmapgrpc.NodeInfo
node.WriteToV2(&nodeV2)
require.Error(t, new(netmap.NodeInfo).ReadFromV2(nodeV2))
require.Error(t, new(netmap.NodeInfo).ReadFromV2(&nodeV2))
netMap.SetNodes([]netmap.NodeInfo{node})
netMap.WriteToV2(&srv.netMap)
@ -119,7 +119,7 @@ func TestClient_NetMapSnapshot(t *testing.T) {
node.SetNetworkEndpoints("1", "2", "3")
node.WriteToV2(&nodeV2)
require.NoError(t, new(netmap.NodeInfo).ReadFromV2(nodeV2))
require.NoError(t, new(netmap.NodeInfo).ReadFromV2(&nodeV2))
netMap.SetNodes([]netmap.NodeInfo{node})
netMap.WriteToV2(&srv.netMap)

View file

@ -5,12 +5,12 @@ import (
"crypto/ecdsa"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -21,16 +21,24 @@ import (
// PrmObjectDelete groups parameters of ObjectDelete operation.
type PrmObjectDelete struct {
meta v2session.RequestMetaHeader
meta *sessiongrpc.RequestMetaHeader
body v2object.DeleteRequestBody
body *objectgrpc.DeleteRequest_Body
addr v2refs.Address
addr *refsgrpc.Address
keySet bool
key ecdsa.PrivateKey
}
func NewPrmObjectDelete() PrmObjectDelete {
return PrmObjectDelete{
meta: &sessiongrpc.RequestMetaHeader{},
body: &objectgrpc.DeleteRequest_Body{},
addr: &refsgrpc.Address{},
}
}
// WithinSession specifies session within which object should be read.
//
// Creator of the session acquires the authorship of the request.
@ -38,9 +46,8 @@ type PrmObjectDelete struct {
//
// Must be signed.
func (x *PrmObjectDelete) WithinSession(t session.Object) {
var tv2 v2session.Token
var tv2 sessiongrpc.SessionToken
t.WriteToV2(&tv2)
x.meta.SetSessionToken(&tv2)
}
@ -50,7 +57,7 @@ func (x *PrmObjectDelete) WithinSession(t session.Object) {
//
// Must be signed.
func (x *PrmObjectDelete) WithBearerToken(t bearer.Token) {
var v2token acl.BearerToken
var v2token aclgrpc.BearerToken
t.WriteToV2(&v2token)
x.meta.SetBearerToken(&v2token)
}
@ -58,19 +65,20 @@ func (x *PrmObjectDelete) WithBearerToken(t bearer.Token) {
// FromContainer specifies FrostFS container of the object.
// Required parameter.
func (x *PrmObjectDelete) FromContainer(id cid.ID) {
var cidV2 v2refs.ContainerID
var cidV2 refsgrpc.ContainerID
id.WriteToV2(&cidV2)
x.addr.SetContainerID(&cidV2)
x.addr.SetContainerId(&cidV2)
}
// ByID specifies identifier of the requested object.
// Required parameter.
func (x *PrmObjectDelete) ByID(id oid.ID) {
var idV2 v2refs.ObjectID
var idV2 refsgrpc.ObjectID
id.WriteToV2(&idV2)
x.addr.SetObjectID(&idV2)
if x.addr == nil {
x.addr = new(refsgrpc.Address)
}
x.addr.SetObjectId(&idV2)
}
// UseKey specifies private key to sign the requests.
@ -85,7 +93,7 @@ func (x *PrmObjectDelete) UseKey(key ecdsa.PrivateKey) {
//
// Slice must not be mutated until the operation completes.
func (x *PrmObjectDelete) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// ResObjectDelete groups resulting values of ObjectDelete operation.
@ -125,19 +133,23 @@ func (x ResObjectDelete) Tombstone() oid.ID {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObjectDelete, error) {
switch {
case prm.addr.GetContainerID() == nil:
case prm.addr.GetContainerId() == nil:
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
case prm.addr.GetObjectId() == nil:
return nil, errorMissingObject
}
if prm.body == nil {
prm.body = new(objectgrpc.DeleteRequest_Body)
}
// form request body
prm.body.SetAddress(&prm.addr)
prm.body.SetAddress(prm.addr)
// form request
var req v2object.DeleteRequest
req.SetBody(&prm.body)
c.prepareRequest(&req, &prm.meta)
var req objectgrpc.DeleteRequest
req.SetBody(prm.body)
c.prepareRequest(&req, prm.meta)
key := c.prm.key
if prm.keySet {
@ -166,12 +178,12 @@ func (c *Client) ObjectDelete(ctx context.Context, prm PrmObjectDelete) (*ResObj
const fieldTombstone = "tombstone"
idTombV2 := resp.GetBody().GetTombstone().GetObjectID()
idTombV2 := resp.GetBody().GetTombstone().GetObjectId()
if idTombV2 == nil {
return nil, newErrMissingResponseField(fieldTombstone)
}
err = res.tomb.ReadFromV2(*idTombV2)
err = res.tomb.ReadFromV2(idTombV2)
if err != nil {
return nil, newErrInvalidResponseField(fieldTombstone, err)
}

View file

@ -7,12 +7,12 @@ import (
"fmt"
"io"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -24,11 +24,18 @@ import (
// shared parameters of GET/HEAD/RANGE.
type prmObjectRead struct {
meta v2session.RequestMetaHeader
meta *sessiongrpc.RequestMetaHeader
raw bool
addr v2refs.Address
addr *refsgrpc.Address
}
func newPrmObjectRead() prmObjectRead {
return prmObjectRead{
meta: &sessiongrpc.RequestMetaHeader{},
addr: &refsgrpc.Address{},
}
}
// WithXHeaders specifies list of extended headers (string key-value pairs)
@ -36,7 +43,7 @@ type prmObjectRead struct {
//
// Slice must not be mutated until the operation completes.
func (x *prmObjectRead) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// MarkRaw marks an intent to read physically stored object.
@ -46,7 +53,7 @@ func (x *prmObjectRead) MarkRaw() {
// MarkLocal tells the server to execute the operation locally.
func (x *prmObjectRead) MarkLocal() {
x.meta.SetTTL(1)
x.meta.SetTtl(1)
}
// WithinSession specifies session within which object should be read.
@ -56,7 +63,7 @@ func (x *prmObjectRead) MarkLocal() {
//
// Must be signed.
func (x *prmObjectRead) WithinSession(t session.Object) {
var tokv2 v2session.Token
var tokv2 sessiongrpc.SessionToken
t.WriteToV2(&tokv2)
x.meta.SetSessionToken(&tokv2)
}
@ -67,7 +74,7 @@ func (x *prmObjectRead) WithinSession(t session.Object) {
//
// Must be signed.
func (x *prmObjectRead) WithBearerToken(t bearer.Token) {
var v2token acl.BearerToken
var v2token aclgrpc.BearerToken
t.WriteToV2(&v2token)
x.meta.SetBearerToken(&v2token)
}
@ -75,17 +82,17 @@ func (x *prmObjectRead) WithBearerToken(t bearer.Token) {
// FromContainer specifies FrostFS container of the object.
// Required parameter.
func (x *prmObjectRead) FromContainer(id cid.ID) {
var cnrV2 v2refs.ContainerID
var cnrV2 refsgrpc.ContainerID
id.WriteToV2(&cnrV2)
x.addr.SetContainerID(&cnrV2)
x.addr.SetContainerId(&cnrV2)
}
// ByID specifies identifier of the requested object.
// Required parameter.
func (x *prmObjectRead) ByID(id oid.ID) {
var objV2 v2refs.ObjectID
var objV2 refsgrpc.ObjectID
id.WriteToV2(&objV2)
x.addr.SetObjectID(&objV2)
x.addr.SetObjectId(&objV2)
}
// PrmObjectGet groups parameters of ObjectGetInit operation.
@ -95,6 +102,12 @@ type PrmObjectGet struct {
key *ecdsa.PrivateKey
}
func NewPrmObjectGet() PrmObjectGet {
return PrmObjectGet{
prmObjectRead: newPrmObjectRead(),
}
}
// ResObjectGet groups the final result values of ObjectGetInit operation.
type ResObjectGet struct {
statusRes
@ -109,7 +122,7 @@ type ObjectReader struct {
client *Client
stream interface {
Read(resp *v2object.GetResponse) error
Read(resp *objectgrpc.GetResponse) error
}
res ResObjectGet
@ -129,7 +142,7 @@ func (x *PrmObjectGet) UseKey(key ecdsa.PrivateKey) {
// ReadHeader reads header of the object. Result means success.
// Failure reason can be received via Close.
func (x *ObjectReader) ReadHeader(dst *object.Object) bool {
var resp v2object.GetResponse
var resp objectgrpc.GetResponse
x.err = x.stream.Read(&resp)
if x.err != nil {
return false
@ -140,28 +153,28 @@ func (x *ObjectReader) ReadHeader(dst *object.Object) bool {
return false
}
var partInit *v2object.GetObjectPartInit
var partInit *objectgrpc.GetResponse_Body_Init_
switch v := resp.GetBody().GetObjectPart().(type) {
default:
x.err = fmt.Errorf("unexpected message instead of heading part: %T", v)
return false
case *v2object.SplitInfo:
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
case *objectgrpc.GetResponse_Body_SplitInfo:
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v.SplitInfo))
return false
case *v2object.GetObjectPartInit:
case *objectgrpc.GetResponse_Body_Init_:
partInit = v
}
var objv2 v2object.Object
var objv2 objectgrpc.Object
objv2.SetObjectID(partInit.GetObjectID())
objv2.SetHeader(partInit.GetHeader())
objv2.SetSignature(partInit.GetSignature())
objv2.SetObjectId(partInit.Init.GetObjectId())
objv2.SetHeader(partInit.Init.GetHeader())
objv2.SetSignature(partInit.Init.GetSignature())
x.remainingPayloadLen = int(objv2.GetHeader().GetPayloadLength())
*dst = *object.NewFromV2(&objv2) // need smth better
*dst = *object.NewFromV2(&objv2)
return true
}
@ -182,7 +195,7 @@ func (x *ObjectReader) readChunk(buf []byte) (int, bool) {
var lastRead int
for {
var resp v2object.GetResponse
var resp objectgrpc.GetResponse
x.err = x.stream.Read(&resp)
if x.err != nil {
return read, false
@ -194,7 +207,7 @@ func (x *ObjectReader) readChunk(buf []byte) (int, bool) {
}
part := resp.GetBody().GetObjectPart()
partChunk, ok := part.(*v2object.GetObjectPartChunk)
partChunk, ok := part.(*objectgrpc.GetResponse_Body_Chunk)
if !ok {
x.err = fmt.Errorf("unexpected message instead of chunk part: %T", part)
return read, false
@ -301,23 +314,23 @@ func (x *ObjectReader) Read(p []byte) (int, error) {
func (c *Client) ObjectGetInit(ctx context.Context, prm PrmObjectGet) (*ObjectReader, error) {
// check parameters
switch {
case prm.addr.GetContainerID() == nil:
case prm.addr.GetContainerId() == nil:
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
case prm.addr.GetObjectId() == nil:
return nil, errorMissingObject
}
// form request body
var body v2object.GetRequestBody
var body objectgrpc.GetRequest_Body
body.SetRaw(prm.raw)
body.SetAddress(&prm.addr)
body.SetAddress(prm.addr)
// form request
var req v2object.GetRequest
var req objectgrpc.GetRequest
req.SetBody(&body)
c.prepareRequest(&req, &prm.meta)
c.prepareRequest(&req, prm.meta)
key := prm.key
if key == nil {
@ -353,6 +366,12 @@ type PrmObjectHead struct {
key ecdsa.PrivateKey
}
func NewPrmObjectHead() PrmObjectHead {
return PrmObjectHead{
prmObjectRead: newPrmObjectRead(),
}
}
// UseKey specifies private key to sign the requests.
// If key is not provided, then Client default key is used.
func (x *PrmObjectHead) UseKey(key ecdsa.PrivateKey) {
@ -367,7 +386,7 @@ type ResObjectHead struct {
// requested object (response doesn't carry the ID)
idObj oid.ID
hdr *v2object.HeaderWithSignature
hdr *objectgrpc.HeaderWithSignature
}
// ReadHeader reads header of the requested object.
@ -377,7 +396,7 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool {
return false
}
var objv2 v2object.Object
var objv2 objectgrpc.Object
objv2.SetHeader(x.hdr.GetHeader())
objv2.SetSignature(x.hdr.GetSignature())
@ -414,19 +433,19 @@ func (x *ResObjectHead) ReadHeader(dst *object.Object) bool {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectHead, error) {
switch {
case prm.addr.GetContainerID() == nil:
case prm.addr.GetContainerId() == nil:
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
case prm.addr.GetObjectId() == nil:
return nil, errorMissingObject
}
var body v2object.HeadRequestBody
var body objectgrpc.HeadRequest_Body
body.SetRaw(prm.raw)
body.SetAddress(&prm.addr)
body.SetAddress(prm.addr)
var req v2object.HeadRequest
var req objectgrpc.HeadRequest
req.SetBody(&body)
c.prepareRequest(&req, &prm.meta)
c.prepareRequest(&req, prm.meta)
key := c.prm.key
if prm.keySet {
@ -454,15 +473,15 @@ func (c *Client) ObjectHead(ctx context.Context, prm PrmObjectHead) (*ResObjectH
return &res, nil
}
_ = res.idObj.ReadFromV2(*prm.addr.GetObjectID())
_ = res.idObj.ReadFromV2(prm.addr.GetObjectId())
switch v := resp.GetBody().GetHeaderPart().(type) {
switch v := resp.GetBody().GetHead().(type) {
default:
return nil, fmt.Errorf("unexpected header type %T", v)
case *v2object.SplitInfo:
return nil, object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
case *v2object.HeaderWithSignature:
res.hdr = v
case *objectgrpc.HeadResponse_Body_SplitInfo:
return nil, object.NewSplitInfoError(object.NewSplitInfoFromV2(v.SplitInfo))
case *objectgrpc.HeadResponse_Body_Header:
res.hdr = v.Header
}
return &res, nil
@ -474,7 +493,14 @@ type PrmObjectRange struct {
key *ecdsa.PrivateKey
rng v2object.Range
rng *objectgrpc.Range
}
func NewPrmObjectRange() PrmObjectRange {
return PrmObjectRange{
prmObjectRead: newPrmObjectRead(),
rng: &objectgrpc.Range{},
}
}
// SetOffset sets offset of the payload range to be read.
@ -514,7 +540,7 @@ type ObjectRangeReader struct {
err error
stream interface {
Read(resp *v2object.GetRangeResponse) error
Read(resp *objectgrpc.GetRangeResponse) error
}
tailPayload []byte
@ -534,12 +560,12 @@ func (x *ObjectRangeReader) readChunk(buf []byte) (int, bool) {
return read, true
}
var partChunk *v2object.GetRangePartChunk
var partChunk *objectgrpc.GetRangeResponse_Body_Chunk
var chunk []byte
var lastRead int
for {
var resp v2object.GetRangeResponse
var resp objectgrpc.GetRangeResponse
x.err = x.stream.Read(&resp)
if x.err != nil {
return read, false
@ -555,10 +581,10 @@ func (x *ObjectRangeReader) readChunk(buf []byte) (int, bool) {
default:
x.err = fmt.Errorf("unexpected message received: %T", v)
return read, false
case *v2object.SplitInfo:
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v))
case *objectgrpc.GetRangeResponse_Body_SplitInfo:
x.err = object.NewSplitInfoError(object.NewSplitInfoFromV2(v.SplitInfo))
return read, false
case *v2object.GetRangePartChunk:
case *objectgrpc.GetRangeResponse_Body_Chunk:
partChunk = v
}
@ -664,26 +690,26 @@ func (x *ObjectRangeReader) Read(p []byte) (int, error) {
func (c *Client) ObjectRangeInit(ctx context.Context, prm PrmObjectRange) (*ObjectRangeReader, error) {
// check parameters
switch {
case prm.addr.GetContainerID() == nil:
case prm.addr.GetContainerId() == nil:
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
case prm.addr.GetObjectId() == nil:
return nil, errorMissingObject
case prm.rng.GetLength() == 0:
return nil, errorZeroRangeLength
}
// form request body
var body v2object.GetRangeRequestBody
var body objectgrpc.GetRangeRequest_Body
body.SetRaw(prm.raw)
body.SetAddress(&prm.addr)
body.SetRange(&prm.rng)
body.SetAddress(prm.addr)
body.SetRange(prm.rng)
// form request
var req v2object.GetRangeRequest
var req objectgrpc.GetRangeRequest
req.SetBody(&body)
c.prepareRequest(&req, &prm.meta)
c.prepareRequest(&req, prm.meta)
key := prm.key
if key == nil {

View file

@ -5,44 +5,53 @@ import (
"crypto/ecdsa"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
)
// PrmObjectHash groups parameters of ObjectHash operation.
type PrmObjectHash struct {
meta v2session.RequestMetaHeader
meta *sessiongrpc.RequestMetaHeader
body v2object.GetRangeHashRequestBody
body *objectgrpc.GetRangeHashRequest_Body
csAlgo v2refs.ChecksumType
csAlgo refsgrpc.ChecksumType
addr v2refs.Address
addr *refsgrpc.Address
keySet bool
key ecdsa.PrivateKey
key *ecdsa.PrivateKey
}
func NewPrmObjectHash() PrmObjectHash {
return PrmObjectHash{
meta: &sessiongrpc.RequestMetaHeader{},
body: &objectgrpc.GetRangeHashRequest_Body{},
addr: &refsgrpc.Address{},
}
}
// UseKey specifies private key to sign the requests.
// If key is not provided, then Client default key is used.
func (x *PrmObjectHash) UseKey(key ecdsa.PrivateKey) {
func (x *PrmObjectHash) UseKey(key *ecdsa.PrivateKey) {
x.keySet = true
x.key = key
}
// MarkLocal tells the server to execute the operation locally.
func (x *PrmObjectHash) MarkLocal() {
x.meta.SetTTL(1)
x.meta.SetTtl(1)
}
// WithinSession specifies session within which object should be read.
@ -52,9 +61,8 @@ func (x *PrmObjectHash) MarkLocal() {
//
// Must be signed.
func (x *PrmObjectHash) WithinSession(t session.Object) {
var tv2 v2session.Token
var tv2 sessiongrpc.SessionToken
t.WriteToV2(&tv2)
x.meta.SetSessionToken(&tv2)
}
@ -64,7 +72,7 @@ func (x *PrmObjectHash) WithinSession(t session.Object) {
//
// Must be signed.
func (x *PrmObjectHash) WithBearerToken(t bearer.Token) {
var v2token acl.BearerToken
var v2token aclgrpc.BearerToken
t.WriteToV2(&v2token)
x.meta.SetBearerToken(&v2token)
}
@ -72,19 +80,17 @@ func (x *PrmObjectHash) WithBearerToken(t bearer.Token) {
// FromContainer specifies FrostFS container of the object.
// Required parameter.
func (x *PrmObjectHash) FromContainer(id cid.ID) {
var cidV2 v2refs.ContainerID
var cidV2 refsgrpc.ContainerID
id.WriteToV2(&cidV2)
x.addr.SetContainerID(&cidV2)
x.addr.SetContainerId(&cidV2)
}
// ByID specifies identifier of the requested object.
// Required parameter.
func (x *PrmObjectHash) ByID(id oid.ID) {
var idV2 v2refs.ObjectID
var idV2 refsgrpc.ObjectID
id.WriteToV2(&idV2)
x.addr.SetObjectID(&idV2)
x.addr.SetObjectId(&idV2)
}
// SetRangeList sets list of ranges in (offset, length) pair format.
@ -97,7 +103,7 @@ func (x *PrmObjectHash) SetRangeList(r ...uint64) {
panic("odd number of range parameters")
}
rs := make([]v2object.Range, ln/2)
rs := slices.MakePreallocPointerSlice[objectgrpc.Range](ln / 2)
for i := 0; i < ln/2; i++ {
rs[i].SetOffset(r[2*i])
@ -112,7 +118,7 @@ func (x *PrmObjectHash) SetRangeList(r ...uint64) {
//
// By default, SHA256 hash function is used.
func (x *PrmObjectHash) TillichZemorAlgo() {
x.csAlgo = v2refs.TillichZemor
x.csAlgo = refsgrpc.ChecksumType_TZ
}
// UseSalt sets the salt to XOR the data range before hashing.
@ -127,7 +133,7 @@ func (x *PrmObjectHash) UseSalt(salt []byte) {
//
// Slice must not be mutated until the operation completes.
func (x *PrmObjectHash) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// ResObjectHash groups resulting values of ObjectHash operation.
@ -166,31 +172,31 @@ func (x ResObjectHash) Checksums() [][]byte {
// - *apistatus.SessionTokenExpired.
func (c *Client) ObjectHash(ctx context.Context, prm PrmObjectHash) (*ResObjectHash, error) {
switch {
case prm.addr.GetContainerID() == nil:
case prm.addr.GetContainerId() == nil:
return nil, errorMissingContainer
case prm.addr.GetObjectID() == nil:
case prm.addr.GetObjectId() == nil:
return nil, errorMissingObject
case len(prm.body.GetRanges()) == 0:
return nil, errorMissingRanges
}
prm.body.SetAddress(&prm.addr)
if prm.csAlgo == v2refs.UnknownChecksum {
prm.body.SetType(v2refs.SHA256)
prm.body.SetAddress(prm.addr)
if prm.csAlgo == refsgrpc.ChecksumType_CHECKSUM_TYPE_UNSPECIFIED {
prm.body.SetType(refsgrpc.ChecksumType_SHA256)
} else {
prm.body.SetType(prm.csAlgo)
}
var req v2object.GetRangeHashRequest
c.prepareRequest(&req, &prm.meta)
req.SetBody(&prm.body)
var req objectgrpc.GetRangeHashRequest
c.prepareRequest(&req, prm.meta)
req.SetBody(prm.body)
key := c.prm.key
key := &c.prm.key
if prm.keySet {
key = prm.key
}
err := signature.SignServiceMessage(&key, &req)
err := signature.SignServiceMessage(key, &req)
if err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}

View file

@ -4,8 +4,8 @@ import (
"context"
"crypto/ecdsa"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@ -21,13 +21,19 @@ const defaultGRPCPayloadChunkLen = 3 << 20
type PrmObjectPutInit struct {
copyNum []uint32
key *ecdsa.PrivateKey
meta v2session.RequestMetaHeader
meta *sessiongrpc.RequestMetaHeader
maxChunkLen int
maxSize uint64
epochSource transformer.EpochSource
withoutHomomorphicHash bool
}
func NewPrmObjectPutInit() PrmObjectPutInit {
return PrmObjectPutInit{
meta: new(sessiongrpc.RequestMetaHeader),
}
}
// SetCopiesNumber sets number of object copies that is enough to consider put successful.
func (x *PrmObjectPutInit) SetCopiesNumber(copiesNumber uint32) {
x.copyNum = []uint32{copiesNumber}
@ -101,7 +107,7 @@ func (x *PrmObjectPutInit) UseKey(key ecdsa.PrivateKey) {
// WithBearerToken attaches bearer token to be used for the operation.
// Should be called once before any writing steps.
func (x *PrmObjectPutInit) WithBearerToken(t bearer.Token) {
var v2token acl.BearerToken
var v2token aclgrpc.BearerToken
t.WriteToV2(&v2token)
x.meta.SetBearerToken(&v2token)
}
@ -109,7 +115,7 @@ func (x *PrmObjectPutInit) WithBearerToken(t bearer.Token) {
// WithinSession specifies session within which object should be stored.
// Should be called once before any writing steps.
func (x *PrmObjectPutInit) WithinSession(t session.Object) {
var tv2 v2session.Token
var tv2 sessiongrpc.SessionToken
t.WriteToV2(&tv2)
x.meta.SetSessionToken(&tv2)
@ -117,7 +123,7 @@ func (x *PrmObjectPutInit) WithinSession(t session.Object) {
// MarkLocal tells the server to execute the operation locally.
func (x *PrmObjectPutInit) MarkLocal() {
x.meta.SetTTL(1)
x.meta.SetTtl(1)
}
// WithXHeaders specifies list of extended headers (string key-value pairs)
@ -125,7 +131,7 @@ func (x *PrmObjectPutInit) MarkLocal() {
//
// Slice must not be mutated until the operation completes.
func (x *PrmObjectPutInit) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// WithObjectMaxSize specifies max object size value and use it during object splitting.

View file

@ -7,7 +7,7 @@ import (
"fmt"
"io"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
@ -16,8 +16,8 @@ import (
)
func (c *Client) objectPutInitRaw(ctx context.Context, prm PrmObjectPutInit) (*objectWriterRaw, error) {
var w objectWriterRaw
stream, err := rpcapi.PutObject(&c.c, &w.respV2, client.WithContext(ctx))
w := newObjectWriterRaw()
stream, err := rpcapi.PutObject(&c.c, w.respV2, client.WithContext(ctx))
if err != nil {
return nil, fmt.Errorf("open stream: %w", err)
}
@ -28,14 +28,16 @@ func (c *Client) objectPutInitRaw(ctx context.Context, prm PrmObjectPutInit) (*o
}
w.client = c
w.stream = stream
w.partInit = new(v2object.PutRequest_Body_Init)
w.partInit.SetCopiesNumber(prm.copyNum)
w.req.SetBody(new(v2object.PutRequestBody))
w.req = new(v2object.PutRequest)
w.req.SetBody(new(v2object.PutRequest_Body))
if prm.maxChunkLen > 0 {
w.maxChunkLen = prm.maxChunkLen
} else {
w.maxChunkLen = defaultGRPCPayloadChunkLen
}
c.prepareRequest(&w.req, &prm.meta)
c.prepareRequest(w.req, prm.meta)
return &w, nil
}
@ -50,37 +52,50 @@ type objectWriterRaw struct {
res ResObjectPut
err error
chunkCalled bool
respV2 v2object.PutResponse
req v2object.PutRequest
partInit v2object.PutObjectPartInit
partChunk v2object.PutObjectPartChunk
respV2 *v2object.PutResponse
req *v2object.PutRequest
partInit *v2object.PutRequest_Body_Init
partChunk *v2object.PutRequest_Body_Chunk
maxChunkLen int
}
func newObjectWriterRaw() objectWriterRaw {
return objectWriterRaw{
respV2: &v2object.PutResponse{},
req: &v2object.PutRequest{},
partInit: &v2object.PutRequest_Body_Init{},
partChunk: &v2object.PutRequest_Body_Chunk{},
}
}
func (x *objectWriterRaw) WriteHeader(_ context.Context, hdr object.Object) bool {
v2Hdr := hdr.ToV2()
x.partInit.SetObjectID(v2Hdr.GetObjectID())
if x.partInit == nil {
x.partInit = new(v2object.PutRequest_Body_Init)
}
x.partInit.SetObjectId(v2Hdr.GetObjectId())
x.partInit.SetHeader(v2Hdr.GetHeader())
x.partInit.SetSignature(v2Hdr.GetSignature())
x.req.GetBody().SetObjectPart(&x.partInit)
x.req.SetVerificationHeader(nil)
x.req.GetBody().SetInit(x.partInit)
x.req.SetVerifyHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
x.err = signature.SignServiceMessage(x.key, x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
x.err = x.stream.Write(x.req)
return x.err == nil
}
func (x *objectWriterRaw) WritePayloadChunk(_ context.Context, chunk []byte) bool {
if !x.chunkCalled {
x.chunkCalled = true
x.req.GetBody().SetObjectPart(&x.partChunk)
x.req.GetBody().SetChunk(x.partChunk)
}
for ln := len(chunk); ln > 0; ln = len(chunk) {
@ -98,15 +113,15 @@ func (x *objectWriterRaw) WritePayloadChunk(_ context.Context, chunk []byte) boo
// It is mentally assumed that allocating and filling the buffer is better than
// synchronous sending, but this needs to be tested.
x.partChunk.SetChunk(chunk[:ln])
x.req.SetVerificationHeader(nil)
x.req.SetVerifyHeader(nil)
x.err = signature.SignServiceMessage(x.key, &x.req)
x.err = signature.SignServiceMessage(x.key, x.req)
if x.err != nil {
x.err = fmt.Errorf("sign message: %w", x.err)
return false
}
x.err = x.stream.Write(&x.req)
x.err = x.stream.Write(x.req)
if x.err != nil {
return false
}
@ -129,7 +144,7 @@ func (x *objectWriterRaw) Close(_ context.Context) (*ResObjectPut, error) {
return nil, x.err
}
x.res.st, x.err = x.client.processResponse(&x.respV2)
x.res.st, x.err = x.client.processResponse(x.respV2)
if x.err != nil {
return nil, x.err
}
@ -140,12 +155,12 @@ func (x *objectWriterRaw) Close(_ context.Context) (*ResObjectPut, error) {
const fieldID = "ID"
idV2 := x.respV2.GetBody().GetObjectID()
idV2 := x.respV2.GetBody().GetObjectId()
if idV2 == nil {
return nil, newErrMissingResponseField(fieldID)
}
x.err = x.res.obj.ReadFromV2(*idV2)
x.err = x.res.obj.ReadFromV2(idV2)
if x.err != nil {
x.err = newErrInvalidResponseField(fieldID, x.err)
}

View file

@ -5,11 +5,11 @@ import (
"crypto/ecdsa"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
@ -18,11 +18,17 @@ import (
// PrmObjectPutSingle groups parameters of PutSingle operation.
type PrmObjectPutSingle struct {
copyNum []uint32
meta v2session.RequestMetaHeader
object *v2object.Object
meta *sessiongrpc.RequestMetaHeader
object *objectgrpc.Object
key *ecdsa.PrivateKey
}
func NewPrmObjectPutSingle() PrmObjectPutSingle {
return PrmObjectPutSingle{
meta: new(sessiongrpc.RequestMetaHeader),
}
}
// SetCopiesNumber sets ordered list of minimal required object copies numbers
// per placement vector. List's length MUST equal container's placement vector number,
// otherwise request will fail.
@ -39,7 +45,7 @@ func (x *PrmObjectPutSingle) UseKey(key *ecdsa.PrivateKey) {
// WithBearerToken attaches bearer token to be used for the operation.
// Should be called once before any writing steps.
func (x *PrmObjectPutSingle) WithBearerToken(t bearer.Token) {
v2token := &acl.BearerToken{}
v2token := &aclgrpc.BearerToken{}
t.WriteToV2(v2token)
x.meta.SetBearerToken(v2token)
}
@ -47,14 +53,14 @@ func (x *PrmObjectPutSingle) WithBearerToken(t bearer.Token) {
// WithinSession specifies session within which object should be stored.
// Should be called once before any writing steps.
func (x *PrmObjectPutSingle) WithinSession(t session.Object) {
tv2 := &v2session.Token{}
tv2 := &sessiongrpc.SessionToken{}
t.WriteToV2(tv2)
x.meta.SetSessionToken(tv2)
}
// ExecuteLocal tells the server to execute the operation locally.
func (x *PrmObjectPutSingle) ExecuteLocal() {
x.meta.SetTTL(1)
x.meta.SetTtl(1)
}
// WithXHeaders specifies list of extended headers (string key-value pairs)
@ -62,11 +68,11 @@ func (x *PrmObjectPutSingle) ExecuteLocal() {
//
// Slice must not be mutated until the operation completes.
func (x *PrmObjectPutSingle) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// SetObject specifies prepared object to put.
func (x *PrmObjectPutSingle) SetObject(o *v2object.Object) {
func (x *PrmObjectPutSingle) SetObject(o *objectgrpc.Object) {
x.object = o
}
@ -82,14 +88,14 @@ type ResObjectPutSingle struct {
// If Client is tuned to resolve FrostFS API statuses, then FrostFS failures
// codes are returned as error.
func (c *Client) ObjectPutSingle(ctx context.Context, prm PrmObjectPutSingle) (*ResObjectPutSingle, error) {
body := &v2object.PutSingleRequestBody{}
body := &objectgrpc.PutSingleRequest_Body{}
body.SetCopiesNumber(prm.copyNum)
body.SetObject(prm.object)
req := &v2object.PutSingleRequest{}
req := &objectgrpc.PutSingleRequest{}
req.SetBody(body)
c.prepareRequest(req, &prm.meta)
c.prepareRequest(req, prm.meta)
key := &c.prm.key
if prm.key != nil {

View file

@ -7,12 +7,12 @@ import (
"fmt"
"io"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
v2refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/bearer"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
@ -24,7 +24,7 @@ import (
// PrmObjectSearch groups parameters of ObjectSearch operation.
type PrmObjectSearch struct {
meta v2session.RequestMetaHeader
meta *sessiongrpc.RequestMetaHeader
key *ecdsa.PrivateKey
@ -34,9 +34,15 @@ type PrmObjectSearch struct {
filters object.SearchFilters
}
func NewPrmObjectSearch() PrmObjectSearch {
return PrmObjectSearch{
meta: &sessiongrpc.RequestMetaHeader{},
}
}
// MarkLocal tells the server to execute the operation locally.
func (x *PrmObjectSearch) MarkLocal() {
x.meta.SetTTL(1)
x.meta.SetTtl(1)
}
// WithinSession specifies session within which the search query must be executed.
@ -46,7 +52,7 @@ func (x *PrmObjectSearch) MarkLocal() {
//
// Must be signed.
func (x *PrmObjectSearch) WithinSession(t session.Object) {
var tokv2 v2session.Token
var tokv2 sessiongrpc.SessionToken
t.WriteToV2(&tokv2)
x.meta.SetSessionToken(&tokv2)
}
@ -57,7 +63,7 @@ func (x *PrmObjectSearch) WithinSession(t session.Object) {
//
// Must be signed.
func (x *PrmObjectSearch) WithBearerToken(t bearer.Token) {
var v2token acl.BearerToken
var v2token aclgrpc.BearerToken
t.WriteToV2(&v2token)
x.meta.SetBearerToken(&v2token)
}
@ -67,7 +73,7 @@ func (x *PrmObjectSearch) WithBearerToken(t bearer.Token) {
//
// Slice must not be mutated until the operation completes.
func (x *PrmObjectSearch) WithXHeaders(hs ...string) {
writeXHeadersToMeta(hs, &x.meta)
writeXHeadersToMeta(hs, x.meta)
}
// UseKey specifies private key to sign the requests.
@ -103,9 +109,9 @@ type ObjectListReader struct {
err error
res ResObjectSearch
stream interface {
Read(resp *v2object.SearchResponse) error
Read(resp *objectgrpc.SearchResponse) error
}
tail []v2refs.ObjectID
tail []*refsgrpc.ObjectID
}
// Read reads another list of the object identifiers. Works similar to
@ -127,7 +133,7 @@ func (x *ObjectListReader) Read(buf []oid.ID) (int, bool) {
}
for {
var resp v2object.SearchResponse
var resp objectgrpc.SearchResponse
x.err = x.stream.Read(&resp)
if x.err != nil {
return read, false
@ -139,7 +145,7 @@ func (x *ObjectListReader) Read(buf []oid.ID) (int, bool) {
}
// read new chunk of objects
ids := resp.GetBody().GetIDList()
ids := resp.GetBody().GetIdList()
if len(ids) == 0 {
// just skip empty lists since they are not prohibited by protocol
continue
@ -157,7 +163,7 @@ func (x *ObjectListReader) Read(buf []oid.ID) (int, bool) {
}
}
func copyIDBuffers(dst []oid.ID, src []v2refs.ObjectID) int {
func copyIDBuffers(dst []oid.ID, src []*refsgrpc.ObjectID) int {
var i int
for ; i < len(dst) && i < len(src); i++ {
_ = dst[i].ReadFromV2(src[i])
@ -226,18 +232,18 @@ func (c *Client) ObjectSearchInit(ctx context.Context, prm PrmObjectSearch) (*Ob
return nil, errorMissingContainer
}
var cidV2 v2refs.ContainerID
var cidV2 refsgrpc.ContainerID
prm.cnrID.WriteToV2(&cidV2)
var body v2object.SearchRequestBody
var body objectgrpc.SearchRequest_Body
body.SetVersion(1)
body.SetContainerID(&cidV2)
body.SetContainerId(&cidV2)
body.SetFilters(prm.filters.ToV2())
// init reader
var req v2object.SearchRequest
var req objectgrpc.SearchRequest
req.SetBody(&body)
c.prepareRequest(&req, &prm.meta)
c.prepareRequest(&req, prm.meta)
key := prm.key
if key == nil {

View file

@ -7,11 +7,12 @@ import (
"io"
"testing"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
signatureV2 "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
@ -143,14 +144,14 @@ func (s *singleStreamResponder) Read(resp *v2object.SearchResponse) error {
panic("unexpected call to `Read`")
}
var body v2object.SearchResponseBody
var body v2object.SearchResponse_Body
if s.idList[s.n] != nil {
ids := make([]refs.ObjectID, len(s.idList[s.n]))
ids := slices.MakePreallocPointerSlice[refsgrpc.ObjectID](len(s.idList[s.n]))
for i := range s.idList[s.n] {
s.idList[s.n][i].WriteToV2(&ids[i])
s.idList[s.n][i].WriteToV2(ids[i])
}
body.SetIDList(ids)
body.SetIdList(ids)
}
resp.SetBody(&body)

View file

@ -1,6 +1,8 @@
package client
import "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
import (
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
)
// ResponseMetaInfo groups meta information about any FrostFS API response.
type ResponseMetaInfo struct {
@ -10,8 +12,8 @@ type ResponseMetaInfo struct {
}
type responseV2 interface {
GetMetaHeader() *session.ResponseMetaHeader
GetVerificationHeader() *session.ResponseVerificationHeader
GetMetaHeader() *sessiongrpc.ResponseMetaHeader
GetVerifyHeader() *sessiongrpc.ResponseVerificationHeader
}
// ResponderKey returns responder's public key in a binary format.

View file

@ -5,11 +5,11 @@ import (
"crypto/ecdsa"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
rpcapi "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/rpc/client"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
v2signature "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/signature"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
)
@ -36,7 +36,7 @@ func (x *PrmSessionCreate) UseKey(key ecdsa.PrivateKey) {
x.key = key
}
func (x *PrmSessionCreate) buildRequest(c *Client) (*v2session.CreateRequest, error) {
func (x *PrmSessionCreate) buildRequest(c *Client) (*sessiongrpc.CreateRequest, error) {
ownerKey := c.prm.key.PublicKey
if x.keySet {
ownerKey = x.key.PublicKey
@ -44,17 +44,17 @@ func (x *PrmSessionCreate) buildRequest(c *Client) (*v2session.CreateRequest, er
var ownerID user.ID
user.IDFromKey(&ownerID, ownerKey)
var ownerIDV2 refs.OwnerID
var ownerIDV2 refsgrpc.OwnerID
ownerID.WriteToV2(&ownerIDV2)
reqBody := new(v2session.CreateRequestBody)
reqBody.SetOwnerID(&ownerIDV2)
reqBody := new(sessiongrpc.CreateRequest_Body)
reqBody.SetOwnerId(&ownerIDV2)
reqBody.SetExpiration(x.exp)
var meta v2session.RequestMetaHeader
var meta sessiongrpc.RequestMetaHeader
writeXHeadersToMeta(x.xHeaders, &meta)
var req v2session.CreateRequest
var req sessiongrpc.CreateRequest
req.SetBody(reqBody)
c.prepareRequest(&req, &meta)
return &req, nil
@ -102,7 +102,7 @@ func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResS
return nil, err
}
if err := signature.SignServiceMessage(&c.prm.key, req); err != nil {
if err := v2signature.SignServiceMessage(&c.prm.key, req); err != nil {
return nil, fmt.Errorf("sign request: %w", err)
}
@ -118,7 +118,7 @@ func (c *Client) SessionCreate(ctx context.Context, prm PrmSessionCreate) (*ResS
}
body := resp.GetBody()
res.id = body.GetID()
res.id = body.GetId()
res.sessionKey = body.GetSessionKey()
return &res, nil
}

View file

@ -3,7 +3,9 @@ package apistatus
import (
"encoding/binary"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
status "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
// ServerInternal describes failure statuses related to internal server errors.
@ -11,19 +13,28 @@ import (
//
// The status is purely informative, the client should not go into details of the error except for debugging needs.
type ServerInternal struct {
v2 status.Status
status *statusgrpc.Status
}
func NewServerInternal() ServerInternal {
return ServerInternal{
status: new(statusgrpc.Status),
}
}
func (x ServerInternal) Error() string {
return errMessageStatusV2(
globalizeCodeV2(status.Internal, status.GlobalizeCommonFail),
x.v2.Message(),
x.status.GetMessage(),
)
}
// implements local interface defined in FromStatusV2 func.
func (x *ServerInternal) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ServerInternal) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -32,23 +43,23 @@ func (x *ServerInternal) fromStatusV2(st *status.Status) {
// - code: INTERNAL;
// - string message: empty;
// - details: empty.
func (x ServerInternal) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(status.Internal, status.GlobalizeCommonFail))
return &x.v2
func (x ServerInternal) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(status.Internal, status.GlobalizeCommonFail)))
return x.status
}
// SetMessage sets message describing internal error.
//
// Message should be used for debug purposes only.
func (x *ServerInternal) SetMessage(msg string) {
x.v2.SetMessage(msg)
x.status.SetMessage(msg)
}
// Message returns message describing internal server error.
//
// Message should be used for debug purposes only. By default, it is empty.
func (x ServerInternal) Message() string {
return x.v2.Message()
return x.status.GetMessage()
}
// WriteInternalServerErr writes err message to ServerInternal instance.
@ -59,19 +70,28 @@ func WriteInternalServerErr(x *ServerInternal, err error) {
// WrongMagicNumber describes failure status related to incorrect network magic.
// Instances provide Status and StatusV2 interfaces.
type WrongMagicNumber struct {
v2 status.Status
status *statusgrpc.Status
}
func NewWrongMagicNumber() WrongMagicNumber {
return WrongMagicNumber{
status: new(statusgrpc.Status),
}
}
func (x WrongMagicNumber) Error() string {
return errMessageStatusV2(
globalizeCodeV2(status.WrongMagicNumber, status.GlobalizeCommonFail),
x.v2.Message(),
x.status.GetMessage(),
)
}
// implements local interface defined in FromStatusV2 func.
func (x *WrongMagicNumber) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x WrongMagicNumber) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -80,9 +100,9 @@ func (x *WrongMagicNumber) fromStatusV2(st *status.Status) {
// - code: WRONG_MAGIC_NUMBER;
// - string message: empty;
// - details: empty.
func (x WrongMagicNumber) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(status.WrongMagicNumber, status.GlobalizeCommonFail))
return &x.v2
func (x WrongMagicNumber) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(status.WrongMagicNumber, status.GlobalizeCommonFail)))
return x.status
}
// WriteCorrectMagic writes correct network magic.
@ -93,13 +113,13 @@ func (x *WrongMagicNumber) WriteCorrectMagic(magic uint64) {
binary.BigEndian.PutUint64(buf, magic)
// create corresponding detail
var d status.Detail
var d statusgrpc.Status_Detail
d.SetID(status.DetailIDCorrectMagic)
d.SetId(statusgrpc.DetailIDCorrectMagic)
d.SetValue(buf)
// attach the detail
x.v2.AppendDetails(d)
x.status.AppendDetails(&d)
}
// CorrectMagic returns network magic returned by the server.
@ -108,9 +128,9 @@ func (x *WrongMagicNumber) WriteCorrectMagic(magic uint64) {
// - 0 if number is not presented
// - +1 otherwise
func (x WrongMagicNumber) CorrectMagic() (magic uint64, ok int8) {
x.v2.IterateDetails(func(d *status.Detail) bool {
if d.ID() == status.DetailIDCorrectMagic {
if val := d.Value(); len(val) == 8 {
x.status.IterateDetails(func(d *statusgrpc.Status_Detail) bool {
if d.GetId() == statusgrpc.DetailIDCorrectMagic {
if val := d.GetValue(); len(val) == 8 {
magic = binary.BigEndian.Uint64(val)
ok = 1
} else {
@ -127,13 +147,19 @@ func (x WrongMagicNumber) CorrectMagic() (magic uint64, ok int8) {
// SignatureVerification describes failure status related to signature verification.
// Instances provide Status and StatusV2 interfaces.
type SignatureVerification struct {
v2 status.Status
status *statusgrpc.Status
}
func NewSignatureVerification() SignatureVerification {
return SignatureVerification{
status: new(statusgrpc.Status),
}
}
const defaultSignatureVerificationMsg = "signature verification failed"
func (x SignatureVerification) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultSignatureVerificationMsg
}
@ -145,8 +171,11 @@ func (x SignatureVerification) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *SignatureVerification) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x SignatureVerification) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -156,14 +185,14 @@ func (x *SignatureVerification) fromStatusV2(st *status.Status) {
// - string message: written message via SetMessage or
// "signature verification failed" as a default message;
// - details: empty.
func (x SignatureVerification) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(status.SignatureVerificationFail, status.GlobalizeCommonFail))
func (x SignatureVerification) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(status.SignatureVerificationFail, status.GlobalizeCommonFail)))
if x.v2.Message() == "" {
x.v2.SetMessage(defaultSignatureVerificationMsg)
if x.status.GetMessage() == "" {
x.status.SetMessage(defaultSignatureVerificationMsg)
}
return &x.v2
return x.status
}
// SetMessage writes signature verification failure message.
@ -171,7 +200,7 @@ func (x SignatureVerification) ToStatusV2() *status.Status {
//
// See also Message.
func (x *SignatureVerification) SetMessage(v string) {
x.v2.SetMessage(v)
x.status.SetMessage(v)
}
// Message returns status message. Zero status returns empty message.
@ -179,13 +208,19 @@ func (x *SignatureVerification) SetMessage(v string) {
//
// See also SetMessage.
func (x SignatureVerification) Message() string {
return x.v2.Message()
return x.status.GetMessage()
}
// NodeUnderMaintenance describes failure status for nodes being under maintenance.
// Instances provide Status and StatusV2 interfaces.
type NodeUnderMaintenance struct {
v2 status.Status
status *statusgrpc.Status
}
func NewNodeUnderMaintenance() NodeUnderMaintenance {
return NodeUnderMaintenance{
status: new(statusgrpc.Status),
}
}
const defaultNodeUnderMaintenanceMsg = "node is under maintenance"
@ -203,8 +238,11 @@ func (x NodeUnderMaintenance) Error() string {
)
}
func (x *NodeUnderMaintenance) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x NodeUnderMaintenance) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -214,13 +252,13 @@ func (x *NodeUnderMaintenance) fromStatusV2(st *status.Status) {
// - string message: written message via SetMessage or
// "node is under maintenance" as a default message;
// - details: empty.
func (x NodeUnderMaintenance) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(status.NodeUnderMaintenance, status.GlobalizeCommonFail))
if x.v2.Message() == "" {
x.v2.SetMessage(defaultNodeUnderMaintenanceMsg)
func (x NodeUnderMaintenance) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(status.NodeUnderMaintenance, status.GlobalizeCommonFail)))
if x.status.GetMessage() == "" {
x.status.SetMessage(defaultNodeUnderMaintenanceMsg)
}
return &x.v2
return x.status
}
// SetMessage writes signature verification failure message.
@ -228,7 +266,7 @@ func (x NodeUnderMaintenance) ToStatusV2() *status.Status {
//
// See also Message.
func (x *NodeUnderMaintenance) SetMessage(v string) {
x.v2.SetMessage(v)
x.status.SetMessage(v)
}
// Message returns status message. Zero status returns empty message.
@ -236,5 +274,5 @@ func (x *NodeUnderMaintenance) SetMessage(v string) {
//
// See also SetMessage.
func (x NodeUnderMaintenance) Message() string {
return x.v2.Message()
return x.status.GetMessage()
}

View file

@ -3,7 +3,7 @@ package apistatus_test
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/stretchr/testify/require"
)
@ -11,17 +11,17 @@ import (
func TestServerInternal_Message(t *testing.T) {
const msg = "some message"
var st apistatus.ServerInternal
st := apistatus.NewServerInternal()
res := st.Message()
resv2 := apistatus.ToStatusV2(st).Message()
resv2 := apistatus.ToStatusV2(st).GetMessage()
require.Empty(t, res)
require.Empty(t, resv2)
st.SetMessage(msg)
res = st.Message()
resv2 = apistatus.ToStatusV2(st).Message()
resv2 = apistatus.ToStatusV2(st).GetMessage()
require.Equal(t, msg, res)
require.Equal(t, msg, resv2)
}
@ -29,7 +29,7 @@ func TestServerInternal_Message(t *testing.T) {
func TestWrongMagicNumber_CorrectMagic(t *testing.T) {
const magic = 1337
var st apistatus.WrongMagicNumber
st := apistatus.NewWrongMagicNumber()
res, ok := st.CorrectMagic()
require.Zero(t, res)
@ -42,7 +42,7 @@ func TestWrongMagicNumber_CorrectMagic(t *testing.T) {
require.EqualValues(t, 1, ok)
// corrupt the value
apistatus.ToStatusV2(st).IterateDetails(func(d *status.Detail) bool {
apistatus.ToStatusV2(st).IterateDetails(func(d *statusgrpc.Status_Detail) bool {
d.SetValue([]byte{1, 2, 3}) // any slice with len != 8
return true
})
@ -53,13 +53,13 @@ func TestWrongMagicNumber_CorrectMagic(t *testing.T) {
func TestSignatureVerification(t *testing.T) {
t.Run("default", func(t *testing.T) {
var st apistatus.SignatureVerification
st := apistatus.NewSignatureVerification()
require.Empty(t, st.Message())
})
t.Run("custom message", func(t *testing.T) {
var st apistatus.SignatureVerification
st := apistatus.NewSignatureVerification()
msg := "some message"
st.SetMessage(msg)
@ -67,38 +67,38 @@ func TestSignatureVerification(t *testing.T) {
stV2 := st.ToStatusV2()
require.Equal(t, msg, st.Message())
require.Equal(t, msg, stV2.Message())
require.Equal(t, msg, stV2.GetMessage())
})
t.Run("empty to V2", func(t *testing.T) {
var st apistatus.SignatureVerification
st := apistatus.NewSignatureVerification()
stV2 := st.ToStatusV2()
require.Equal(t, "signature verification failed", stV2.Message())
require.Equal(t, "signature verification failed", stV2.GetMessage())
})
t.Run("non-empty to V2", func(t *testing.T) {
var st apistatus.SignatureVerification
st := apistatus.NewSignatureVerification()
msg := "some other msg"
st.SetMessage(msg)
stV2 := st.ToStatusV2()
require.Equal(t, msg, stV2.Message())
require.Equal(t, msg, stV2.GetMessage())
})
}
func TestNodeUnderMaintenance(t *testing.T) {
t.Run("default", func(t *testing.T) {
var st apistatus.NodeUnderMaintenance
st := apistatus.NewNodeUnderMaintenance()
require.Empty(t, st.Message())
})
t.Run("custom message", func(t *testing.T) {
var st apistatus.NodeUnderMaintenance
st := apistatus.NewNodeUnderMaintenance()
msg := "some message"
st.SetMessage(msg)
@ -106,25 +106,25 @@ func TestNodeUnderMaintenance(t *testing.T) {
stV2 := st.ToStatusV2()
require.Equal(t, msg, st.Message())
require.Equal(t, msg, stV2.Message())
require.Equal(t, msg, stV2.GetMessage())
})
t.Run("empty to V2", func(t *testing.T) {
var st apistatus.NodeUnderMaintenance
st := apistatus.NewNodeUnderMaintenance()
stV2 := st.ToStatusV2()
require.Empty(t, "", stV2.Message())
require.Empty(t, "", stV2.GetMessage())
})
t.Run("non-empty to V2", func(t *testing.T) {
var st apistatus.NodeUnderMaintenance
st := apistatus.NewNodeUnderMaintenance()
msg := "some other msg"
st.SetMessage(msg)
stV2 := st.ToStatusV2()
require.Equal(t, msg, stV2.Message())
require.Equal(t, msg, stV2.GetMessage())
})
}

View file

@ -2,19 +2,27 @@ package apistatus
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
status "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
// ContainerNotFound describes status of the failure because of the missing container.
// Instances provide Status and StatusV2 interfaces.
type ContainerNotFound struct {
v2 status.Status
status *statusgrpc.Status
}
func NewContainerNotFound() ContainerNotFound {
return ContainerNotFound{
status: new(statusgrpc.Status),
}
}
const defaultContainerNotFoundMsg = "container not found"
func (x ContainerNotFound) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultContainerNotFoundMsg
}
@ -26,8 +34,11 @@ func (x ContainerNotFound) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ContainerNotFound) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ContainerNotFound) fromStatusV2(st *status.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -37,22 +48,28 @@ func (x *ContainerNotFound) fromStatusV2(st *status.Status) {
// - string message: "container not found";
// - details: empty.
func (x ContainerNotFound) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(container.StatusNotFound, container.GlobalizeFail))
x.v2.SetMessage(defaultContainerNotFoundMsg)
return &x.v2
x.status.SetCode(uint32(globalizeCodeV2(container.StatusNotFound, container.GlobalizeFail)))
x.status.SetMessage(defaultContainerNotFoundMsg)
return x.status
}
// EACLNotFound describes status of the failure because of the missing eACL
// table.
// Instances provide Status and StatusV2 interfaces.
type EACLNotFound struct {
v2 status.Status
status *statusgrpc.Status
}
func NewEACLNotFound() EACLNotFound {
return EACLNotFound{
status: new(statusgrpc.Status),
}
}
const defaultEACLNotFoundMsg = "eACL not found"
func (x EACLNotFound) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultEACLNotFoundMsg
}
@ -64,8 +81,11 @@ func (x EACLNotFound) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *EACLNotFound) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x EACLNotFound) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -74,8 +94,8 @@ func (x *EACLNotFound) fromStatusV2(st *status.Status) {
// - code: EACL_NOT_FOUND;
// - string message: "eACL not found";
// - details: empty.
func (x EACLNotFound) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(container.StatusEACLNotFound, container.GlobalizeFail))
x.v2.SetMessage(defaultEACLNotFoundMsg)
return &x.v2
func (x EACLNotFound) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(container.StatusEACLNotFound, container.GlobalizeFail)))
x.status.SetMessage(defaultEACLNotFoundMsg)
return x.status
}

View file

@ -2,19 +2,26 @@ package apistatus
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
// ObjectLocked describes status of the failure because of the locked object.
// Instances provide Status and StatusV2 interfaces.
type ObjectLocked struct {
v2 status.Status
status *statusgrpc.Status
}
func NewObjectLocked() ObjectLocked {
return ObjectLocked{
status: new(statusgrpc.Status),
}
}
const defaultObjectLockedMsg = "object is locked"
func (x ObjectLocked) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultObjectLockedMsg
}
@ -26,8 +33,11 @@ func (x ObjectLocked) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ObjectLocked) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ObjectLocked) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -36,22 +46,28 @@ func (x *ObjectLocked) fromStatusV2(st *status.Status) {
// - code: LOCKED;
// - string message: "object is locked";
// - details: empty.
func (x ObjectLocked) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusLocked, object.GlobalizeFail))
x.v2.SetMessage(defaultObjectLockedMsg)
return &x.v2
func (x ObjectLocked) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusLocked, object.GlobalizeFail)))
x.status.SetMessage(defaultObjectLockedMsg)
return x.status
}
// LockNonRegularObject describes status returned on locking the non-regular object.
// Instances provide Status and StatusV2 interfaces.
type LockNonRegularObject struct {
v2 status.Status
status *statusgrpc.Status
}
func NewLockNonRegularObject() LockNonRegularObject {
return LockNonRegularObject{
status: new(statusgrpc.Status),
}
}
const defaultLockNonRegularObjectMsg = "locking non-regular object is forbidden"
func (x LockNonRegularObject) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultLockNonRegularObjectMsg
}
@ -63,8 +79,11 @@ func (x LockNonRegularObject) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *LockNonRegularObject) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x LockNonRegularObject) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -73,22 +92,28 @@ func (x *LockNonRegularObject) fromStatusV2(st *status.Status) {
// - code: LOCK_NON_REGULAR_OBJECT;
// - string message: "locking non-regular object is forbidden";
// - details: empty.
func (x LockNonRegularObject) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusLockNonRegularObject, object.GlobalizeFail))
x.v2.SetMessage(defaultLockNonRegularObjectMsg)
return &x.v2
func (x LockNonRegularObject) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusLockNonRegularObject, object.GlobalizeFail)))
x.status.SetMessage(defaultLockNonRegularObjectMsg)
return x.status
}
// ObjectAccessDenied describes status of the failure because of the access control violation.
// Instances provide Status and StatusV2 interfaces.
type ObjectAccessDenied struct {
v2 status.Status
status *statusgrpc.Status
}
func NewObjectAccessDenied() ObjectAccessDenied {
return ObjectAccessDenied{
status: new(statusgrpc.Status),
}
}
const defaultObjectAccessDeniedMsg = "access to object operation denied"
func (x ObjectAccessDenied) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultObjectAccessDeniedMsg
}
@ -100,8 +125,11 @@ func (x ObjectAccessDenied) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ObjectAccessDenied) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ObjectAccessDenied) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -110,33 +138,39 @@ func (x *ObjectAccessDenied) fromStatusV2(st *status.Status) {
// - code: ACCESS_DENIED;
// - string message: "access to object operation denied";
// - details: empty.
func (x ObjectAccessDenied) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusAccessDenied, object.GlobalizeFail))
x.v2.SetMessage(defaultObjectAccessDeniedMsg)
return &x.v2
func (x ObjectAccessDenied) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusAccessDenied, object.GlobalizeFail)))
x.status.SetMessage(defaultObjectAccessDeniedMsg)
return x.status
}
// WriteReason writes human-readable access rejection reason.
func (x *ObjectAccessDenied) WriteReason(reason string) {
object.WriteAccessDeniedDesc(&x.v2, reason)
object.WriteAccessDeniedDesc(x.status, reason)
}
// Reason returns human-readable access rejection reason returned by the server.
// Returns empty value is reason is not presented.
func (x ObjectAccessDenied) Reason() string {
return object.ReadAccessDeniedDesc(x.v2)
return object.ReadAccessDeniedDesc(x.status)
}
// ObjectNotFound describes status of the failure because of the missing object.
// Instances provide Status and StatusV2 interfaces.
type ObjectNotFound struct {
v2 status.Status
status *statusgrpc.Status
}
func NewObjectNotFound() ObjectNotFound {
return ObjectNotFound{
status: new(statusgrpc.Status),
}
}
const defaultObjectNotFoundMsg = "object not found"
func (x ObjectNotFound) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultObjectNotFoundMsg
}
@ -148,8 +182,11 @@ func (x ObjectNotFound) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ObjectNotFound) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ObjectNotFound) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -158,22 +195,28 @@ func (x *ObjectNotFound) fromStatusV2(st *status.Status) {
// - code: OBJECT_NOT_FOUND;
// - string message: "object not found";
// - details: empty.
func (x ObjectNotFound) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusNotFound, object.GlobalizeFail))
x.v2.SetMessage(defaultObjectNotFoundMsg)
return &x.v2
func (x ObjectNotFound) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusNotFound, object.GlobalizeFail)))
x.status.SetMessage(defaultObjectNotFoundMsg)
return x.status
}
// ObjectAlreadyRemoved describes status of the failure because object has been
// already removed. Instances provide Status and StatusV2 interfaces.
type ObjectAlreadyRemoved struct {
v2 status.Status
status *statusgrpc.Status
}
func NewObjectAlreadyRemoved() ObjectAlreadyRemoved {
return ObjectAlreadyRemoved{
status: new(statusgrpc.Status),
}
}
const defaultObjectAlreadyRemovedMsg = "object already removed"
func (x ObjectAlreadyRemoved) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultObjectAlreadyRemovedMsg
}
@ -185,8 +228,11 @@ func (x ObjectAlreadyRemoved) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ObjectAlreadyRemoved) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ObjectAlreadyRemoved) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -195,23 +241,29 @@ func (x *ObjectAlreadyRemoved) fromStatusV2(st *status.Status) {
// - code: OBJECT_ALREADY_REMOVED;
// - string message: "object already removed";
// - details: empty.
func (x ObjectAlreadyRemoved) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusAlreadyRemoved, object.GlobalizeFail))
x.v2.SetMessage(defaultObjectAlreadyRemovedMsg)
return &x.v2
func (x ObjectAlreadyRemoved) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusAlreadyRemoved, object.GlobalizeFail)))
x.status.SetMessage(defaultObjectAlreadyRemovedMsg)
return x.status
}
// ObjectOutOfRange describes status of the failure because of the incorrect
// provided object ranges.
// Instances provide Status and StatusV2 interfaces.
type ObjectOutOfRange struct {
v2 status.Status
status *statusgrpc.Status
}
func NewObjectOutOfRange() ObjectOutOfRange {
return ObjectOutOfRange{
status: new(statusgrpc.Status),
}
}
const defaultObjectOutOfRangeMsg = "out of range"
func (x ObjectOutOfRange) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultObjectOutOfRangeMsg
}
@ -223,8 +275,11 @@ func (x ObjectOutOfRange) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *ObjectOutOfRange) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x ObjectOutOfRange) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -233,8 +288,8 @@ func (x *ObjectOutOfRange) fromStatusV2(st *status.Status) {
// - code: OUT_OF_RANGE;
// - string message: "out of range";
// - details: empty.
func (x ObjectOutOfRange) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(object.StatusOutOfRange, object.GlobalizeFail))
x.v2.SetMessage(defaultObjectOutOfRangeMsg)
return &x.v2
func (x ObjectOutOfRange) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(object.StatusOutOfRange, object.GlobalizeFail)))
x.status.SetMessage(defaultObjectOutOfRangeMsg)
return x.status
}

View file

@ -10,7 +10,7 @@ import (
func TestObjectAccessDenied_WriteReason(t *testing.T) {
const reason = "any reason"
var st apistatus.ObjectAccessDenied
st := apistatus.NewObjectAccessDenied()
res := st.Reason()
require.Empty(t, res)

View file

@ -2,19 +2,26 @@ package apistatus
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
// SessionTokenNotFound describes status of the failure because of the missing session token.
// Instances provide Status and StatusV2 interfaces.
type SessionTokenNotFound struct {
v2 status.Status
status *statusgrpc.Status
}
func NewSessionTokenNotFound() SessionTokenNotFound {
return SessionTokenNotFound{
status: new(statusgrpc.Status),
}
}
const defaultSessionTokenNotFoundMsg = "session token not found"
func (x SessionTokenNotFound) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultSessionTokenNotFoundMsg
}
@ -26,8 +33,11 @@ func (x SessionTokenNotFound) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *SessionTokenNotFound) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x SessionTokenNotFound) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -36,22 +46,29 @@ func (x *SessionTokenNotFound) fromStatusV2(st *status.Status) {
// - code: TOKEN_NOT_FOUND;
// - string message: "session token not found";
// - details: empty.
func (x SessionTokenNotFound) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(session.StatusTokenNotFound, session.GlobalizeFail))
x.v2.SetMessage(defaultSessionTokenNotFoundMsg)
return &x.v2
func (x SessionTokenNotFound) ToStatusV2() *statusgrpc.Status {
x = NewSessionTokenNotFound()
x.status.SetCode(uint32(globalizeCodeV2(session.StatusTokenNotFound, session.GlobalizeFail)))
x.status.SetMessage(defaultSessionTokenNotFoundMsg)
return x.status
}
// SessionTokenExpired describes status of the failure because of the expired session token.
// Instances provide Status and StatusV2 interfaces.
type SessionTokenExpired struct {
v2 status.Status
status *statusgrpc.Status
}
func NewSessionTokenExpired() SessionTokenExpired {
return SessionTokenExpired{
status: new(statusgrpc.Status),
}
}
const defaultSessionTokenExpiredMsg = "expired session token"
func (x SessionTokenExpired) Error() string {
msg := x.v2.Message()
msg := x.status.GetMessage()
if msg == "" {
msg = defaultSessionTokenExpiredMsg
}
@ -63,8 +80,11 @@ func (x SessionTokenExpired) Error() string {
}
// implements local interface defined in FromStatusV2 func.
func (x *SessionTokenExpired) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x SessionTokenExpired) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -73,8 +93,8 @@ func (x *SessionTokenExpired) fromStatusV2(st *status.Status) {
// - code: TOKEN_EXPIRED;
// - string message: "expired session token";
// - details: empty.
func (x SessionTokenExpired) ToStatusV2() *status.Status {
x.v2.SetCode(globalizeCodeV2(session.StatusTokenExpired, session.GlobalizeFail))
x.v2.SetMessage(defaultSessionTokenExpiredMsg)
return &x.v2
func (x SessionTokenExpired) ToStatusV2() *statusgrpc.Status {
x.status.SetCode(uint32(globalizeCodeV2(session.StatusTokenExpired, session.GlobalizeFail)))
x.status.SetMessage(defaultSessionTokenExpiredMsg)
return x.status
}

View file

@ -2,19 +2,32 @@ package apistatus
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
// SuccessDefaultV2 represents Status instance of default success. Implements StatusV2.
type SuccessDefaultV2 struct {
isNil bool
v2 *status.Status
status *statusgrpc.Status
}
func NewSuccessDefaultV2() SuccessDefaultV2 {
return SuccessDefaultV2{
status: new(statusgrpc.Status),
}
}
// implements local interface defined in FromStatusV2 func.
func (x *SuccessDefaultV2) fromStatusV2(st *status.Status) {
x.isNil = st == nil
x.v2 = st
func (x SuccessDefaultV2) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
if x.isNil = st == nil; x.isNil {
return
}
proto.Merge(x.status, st)
}
// ToStatusV2 implements StatusV2 interface method.
@ -23,9 +36,9 @@ func (x *SuccessDefaultV2) fromStatusV2(st *status.Status) {
// - code: OK;
// - string message: empty;
// - details: empty.
func (x SuccessDefaultV2) ToStatusV2() *status.Status {
if x.isNil || x.v2 != nil {
return x.v2
func (x SuccessDefaultV2) ToStatusV2() *statusgrpc.Status {
if x.isNil || x.status != nil {
return x.status
}
return newStatusV2WithLocalCode(status.OK, status.GlobalizeSuccess)

View file

@ -1,18 +1,28 @@
package apistatus
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
"github.com/golang/protobuf/proto"
)
type unrecognizedStatusV2 struct {
v2 status.Status
status *statusgrpc.Status
}
func newUnrecognizedStatusV2() unrecognizedStatusV2 {
return unrecognizedStatusV2{
status: new(statusgrpc.Status),
}
}
func (x unrecognizedStatusV2) Error() string {
return errMessageStatusV2("unrecognized", x.v2.Message())
return errMessageStatusV2("unrecognized", x.status.GetMessage())
}
// implements local interface defined in FromStatusV2 func.
func (x *unrecognizedStatusV2) fromStatusV2(st *status.Status) {
x.v2 = *st
func (x unrecognizedStatusV2) fromStatusV2(st *statusgrpc.Status) {
if x.status == nil {
x.status = new(statusgrpc.Status)
}
proto.Merge(x.status, st)
}

View file

@ -6,7 +6,8 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
status "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status"
statusgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status/grpc"
)
// StatusV2 defines a variety of Status instances compatible with FrostFS API V2 protocol.
@ -16,7 +17,7 @@ type StatusV2 interface {
Status
// ToStatusV2 returns the status as git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/status.Status message structure.
ToStatusV2() *status.Status
ToStatusV2() *statusgrpc.Status
}
// FromStatusV2 converts status.Status message structure to Status instance. Inverse to ToStatusV2 operation.
@ -38,64 +39,64 @@ type StatusV2 interface {
// - object.StatusLocked: *ObjectLocked;
// - object.StatusLockNonRegularObject: *LockNonRegularObject.
// - object.StatusAccessDenied: *ObjectAccessDenied.
func FromStatusV2(st *status.Status) Status {
func FromStatusV2(st *statusgrpc.Status) Status {
var decoder interface {
fromStatusV2(*status.Status)
fromStatusV2(*statusgrpc.Status)
}
switch code := st.Code(); {
switch code := status.Code(st.GetCode()); {
case status.IsSuccess(code):
//nolint:exhaustive
switch status.LocalizeSuccess(&code); code {
case status.OK:
decoder = new(SuccessDefaultV2)
decoder = NewSuccessDefaultV2()
}
case status.IsCommonFail(code):
switch status.LocalizeCommonFail(&code); code {
case status.Internal:
decoder = new(ServerInternal)
decoder = NewServerInternal()
case status.WrongMagicNumber:
decoder = new(WrongMagicNumber)
decoder = NewWrongMagicNumber()
case status.SignatureVerificationFail:
decoder = new(SignatureVerification)
decoder = NewSignatureVerification()
case status.NodeUnderMaintenance:
decoder = new(NodeUnderMaintenance)
decoder = NewNodeUnderMaintenance()
}
case object.LocalizeFailStatus(&code):
switch code {
case object.StatusLocked:
decoder = new(ObjectLocked)
decoder = NewObjectLocked()
case object.StatusLockNonRegularObject:
decoder = new(LockNonRegularObject)
decoder = NewLockNonRegularObject()
case object.StatusAccessDenied:
decoder = new(ObjectAccessDenied)
decoder = NewObjectAccessDenied()
case object.StatusNotFound:
decoder = new(ObjectNotFound)
decoder = NewObjectNotFound()
case object.StatusAlreadyRemoved:
decoder = new(ObjectAlreadyRemoved)
decoder = NewObjectAlreadyRemoved()
case object.StatusOutOfRange:
decoder = new(ObjectOutOfRange)
decoder = NewObjectOutOfRange()
}
case container.LocalizeFailStatus(&code):
//nolint:exhaustive
switch code {
case container.StatusNotFound:
decoder = new(ContainerNotFound)
decoder = NewContainerNotFound()
case container.StatusEACLNotFound:
decoder = new(EACLNotFound)
decoder = NewEACLNotFound()
}
case session.LocalizeFailStatus(&code):
//nolint:exhaustive
switch code {
case session.StatusTokenNotFound:
decoder = new(SessionTokenNotFound)
decoder = NewSessionTokenNotFound()
case session.StatusTokenExpired:
decoder = new(SessionTokenExpired)
decoder = NewSessionTokenExpired()
}
}
if decoder == nil {
decoder = new(unrecognizedStatusV2)
decoder = newUnrecognizedStatusV2()
}
decoder.fromStatusV2(st)
@ -108,7 +109,7 @@ func FromStatusV2(st *status.Status) Status {
// If argument is the StatusV2 instance, it is converted directly.
// Otherwise, successes are converted with status.OK code w/o details and message,
// failures - with status.Internal and error text message w/o details.
func ToStatusV2(st Status) *status.Status {
func ToStatusV2(st Status) *statusgrpc.Status {
if v, ok := st.(StatusV2); ok {
return v.ToStatusV2()
}
@ -136,10 +137,10 @@ func errMessageStatusV2(code any, msg string) string {
return fmt.Sprintf(noMsgFmt, code)
}
func newStatusV2WithLocalCode(code status.Code, globalizer func(*status.Code)) *status.Status {
var st status.Status
func newStatusV2WithLocalCode(code status.Code, globalizer func(*status.Code)) *statusgrpc.Status {
var st statusgrpc.Status
st.SetCode(globalizeCodeV2(code, globalizer))
st.SetCode(uint32(globalizeCodeV2(code, globalizer)))
return &st
}

View file

@ -5,6 +5,7 @@ import (
"testing"
apistatus "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/client/status"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/require"
)
@ -13,7 +14,7 @@ func TestToStatusV2(t *testing.T) {
for _, testItem := range [...]struct {
status any // Status or statusConstructor
codeV2 uint64
codeV2 uint32
messageV2 string
}{
{
@ -43,7 +44,7 @@ func TestToStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.ServerInternal
st := apistatus.NewServerInternal()
st.SetMessage("internal error message")
@ -53,7 +54,7 @@ func TestToStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.WrongMagicNumber
st := apistatus.NewWrongMagicNumber()
st.WriteCorrectMagic(322)
@ -63,19 +64,19 @@ func TestToStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectLocked)
return apistatus.NewObjectLocked()
}),
codeV2: 2050,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.LockNonRegularObject)
return apistatus.NewLockNonRegularObject()
}),
codeV2: 2051,
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.ObjectAccessDenied
st := apistatus.NewObjectAccessDenied()
st.WriteReason("any reason")
@ -85,49 +86,49 @@ func TestToStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectNotFound)
return apistatus.NewObjectNotFound()
}),
codeV2: 2049,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectAlreadyRemoved)
return apistatus.NewObjectAlreadyRemoved()
}),
codeV2: 2052,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectOutOfRange)
return apistatus.NewObjectOutOfRange()
}),
codeV2: 2053,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ContainerNotFound)
return apistatus.NewContainerNotFound()
}),
codeV2: 3072,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.EACLNotFound)
return apistatus.NewEACLNotFound()
}),
codeV2: 3073,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.SessionTokenNotFound)
return apistatus.NewSessionTokenNotFound()
}),
codeV2: 4096,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.SessionTokenExpired)
return apistatus.NewSessionTokenExpired()
}),
codeV2: 4097,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.NodeUnderMaintenance)
return apistatus.NewNodeUnderMaintenance()
}),
codeV2: 1027,
},
@ -143,9 +144,9 @@ func TestToStatusV2(t *testing.T) {
stv2 := apistatus.ToStatusV2(st)
// must generate the same status.Status message
require.EqualValues(t, testItem.codeV2, stv2.Code())
require.EqualValues(t, testItem.codeV2, stv2.GetCode())
if len(testItem.messageV2) > 0 {
require.Equal(t, testItem.messageV2, stv2.Message())
require.Equal(t, testItem.messageV2, stv2.GetMessage())
}
_, ok := st.(apistatus.StatusV2)
@ -156,7 +157,7 @@ func TestToStatusV2(t *testing.T) {
res := apistatus.ToStatusV2(restored)
// must generate the same status.Status message
require.Equal(t, stv2, res)
require.True(t, proto.Equal(stv2, res))
}
}
}
@ -196,7 +197,7 @@ func TestFromStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.ServerInternal
st := apistatus.NewServerInternal()
st.SetMessage("internal error message")
@ -206,7 +207,7 @@ func TestFromStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.WrongMagicNumber
st := apistatus.NewWrongMagicNumber()
st.WriteCorrectMagic(322)
@ -216,19 +217,19 @@ func TestFromStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectLocked)
return apistatus.NewObjectLocked()
}),
codeV2: 2050,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.LockNonRegularObject)
return apistatus.NewLockNonRegularObject()
}),
codeV2: 2051,
},
{
status: (statusConstructor)(func() apistatus.Status {
var st apistatus.ObjectAccessDenied
st := apistatus.NewObjectAccessDenied()
st.WriteReason("any reason")
@ -238,49 +239,49 @@ func TestFromStatusV2(t *testing.T) {
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectNotFound)
return apistatus.NewObjectNotFound()
}),
codeV2: 2049,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ObjectAlreadyRemoved)
return apistatus.NewObjectAlreadyRemoved()
}),
codeV2: 2052,
},
{
status: statusConstructor(func() apistatus.Status {
return new(apistatus.ObjectOutOfRange)
return apistatus.NewObjectOutOfRange()
}),
codeV2: 2053,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.ContainerNotFound)
return apistatus.NewContainerNotFound()
}),
codeV2: 3072,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.EACLNotFound)
return apistatus.NewEACLNotFound()
}),
codeV2: 3073,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.SessionTokenNotFound)
return apistatus.NewSessionTokenNotFound()
}),
codeV2: 4096,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.SessionTokenExpired)
return apistatus.NewSessionTokenExpired()
}),
codeV2: 4097,
},
{
status: (statusConstructor)(func() apistatus.Status {
return new(apistatus.NodeUnderMaintenance)
return apistatus.NewNodeUnderMaintenance()
}),
codeV2: 1027,
},
@ -296,9 +297,9 @@ func TestFromStatusV2(t *testing.T) {
stv2 := apistatus.ToStatusV2(st)
// must generate the same status.Status message
require.EqualValues(t, testItem.codeV2, stv2.Code())
require.EqualValues(t, testItem.codeV2, stv2.GetCode())
if len(testItem.messageV2) > 0 {
require.Equal(t, testItem.messageV2, stv2.Message())
require.Equal(t, testItem.messageV2, stv2.GetMessage())
}
_, ok := st.(apistatus.StatusV2)
@ -309,7 +310,7 @@ func TestFromStatusV2(t *testing.T) {
res := apistatus.ToStatusV2(restored)
// must generate the same status.Status message
require.Equal(t, stv2, res)
require.True(t, proto.Equal(stv2, res))
}
}
}

View file

@ -9,9 +9,9 @@ import (
"strings"
"time"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/acl"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
@ -19,10 +19,12 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/golang/protobuf/proto"
"github.com/google/uuid"
"google.golang.org/protobuf/encoding/protojson"
)
// Container represents descriptor of the FrostFS container. Container logically
// Container represents descriptor of the FrostFS containergrpc. Container logically
// stores FrostFS objects. Container is one of the basic and at the same time
// necessary data storage units in the FrostFS. Container includes data about the
// owner, rules for placing objects and other information necessary for the
@ -37,10 +39,16 @@ import (
// Instances for existing containers can be initialized using decoding methods
// (e.g Unmarshal).
//
// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.Container
// Container is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/containergrpc.Container
// message. See ReadFromV2 / WriteToV2 methods.
type Container struct {
v2 container.Container
container *containergrpc.Container
}
func NewContainer() Container {
return Container{
container: &containergrpc.Container{},
}
}
const (
@ -48,16 +56,16 @@ const (
attributeTimestamp = "Timestamp"
)
// reads Container from the container.Container message. If checkFieldPresence is set,
// reads Container from the containergrpc.Container message. If checkFieldPresence is set,
// returns an error on absence of any protocol-required field.
func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) error {
func (x *Container) readFromV2(m *containergrpc.Container, checkFieldPresence bool) error {
var err error
ownerV2 := m.GetOwnerID()
ownerV2 := m.GetOwnerId()
if ownerV2 != nil {
var owner user.ID
err = owner.ReadFromV2(*ownerV2)
err = owner.ReadFromV2(ownerV2)
if err != nil {
return fmt.Errorf("invalid owner: %w", err)
}
@ -88,7 +96,7 @@ func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) e
if policyV2 != nil {
var policy netmap.PlacementPolicy
err = policy.ReadFromV2(*policyV2)
err = policy.ReadFromV2(policyV2)
if err != nil {
return fmt.Errorf("invalid placement policy: %w", err)
}
@ -100,12 +108,15 @@ func (x *Container) readFromV2(m container.Container, checkFieldPresence bool) e
return err
}
x.v2 = m
if x.container == nil {
x.container = new(containergrpc.Container)
}
proto.Merge(x.container, m)
return nil
}
func checkAttributes(m container.Container) error {
func checkAttributes(m *containergrpc.Container) error {
attrs := m.GetAttributes()
mAttr := make(map[string]struct{}, len(attrs))
var key, val string
@ -141,28 +152,29 @@ func checkAttributes(m container.Container) error {
return nil
}
// ReadFromV2 reads Container from the container.Container message. Checks if the
// ReadFromV2 reads Container from the containergrpc.Container message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *Container) ReadFromV2(m container.Container) error {
func (x *Container) ReadFromV2(m *containergrpc.Container) error {
return x.readFromV2(m, true)
}
// WriteToV2 writes Container into the container.Container message.
// WriteToV2 writes Container into the containergrpc.Container message.
// The message MUST NOT be nil.
//
// See also ReadFromV2.
func (x Container) WriteToV2(m *container.Container) {
*m = x.v2
func (x *Container) WriteToV2(m *containergrpc.Container) {
m.Reset()
proto.Merge(m, x.container)
}
// Marshal encodes Container into a binary format of the FrostFS API protocol
// (Protocol Buffers with direct field order).
//
// See also Unmarshal.
func (x Container) Marshal() []byte {
return x.v2.StableMarshal(nil)
func (x *Container) Marshal() []byte {
return x.container.StableMarshal(nil)
}
// Unmarshal decodes FrostFS API protocol binary format into the Container
@ -171,22 +183,26 @@ func (x Container) Marshal() []byte {
//
// See also Marshal.
func (x *Container) Unmarshal(data []byte) error {
var m container.Container
var m containergrpc.Container
err := m.Unmarshal(data)
err := proto.Unmarshal(data, &m)
if err != nil {
return err
}
return x.readFromV2(m, false)
return x.readFromV2(&m, false)
}
// MarshalJSON encodes Container into a JSON format of the FrostFS API protocol
// (Protocol Buffers JSON).
//
// See also UnmarshalJSON.
func (x Container) MarshalJSON() ([]byte, error) {
return x.v2.MarshalJSON()
func (x *Container) MarshalJSON() ([]byte, error) {
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
x.container,
)
}
// UnmarshalJSON decodes FrostFS API protocol JSON format into the Container
@ -194,25 +210,28 @@ func (x Container) MarshalJSON() ([]byte, error) {
//
// See also MarshalJSON.
func (x *Container) UnmarshalJSON(data []byte) error {
return x.v2.UnmarshalJSON(data)
return protojson.Unmarshal(data, x.container)
}
// Init initializes all internal data of the Container required by FrostFS API
// protocol. Init MUST be called when creating a new container. Init SHOULD NOT
// protocol. Init MUST be called when creating a new containergrpc. Init SHOULD NOT
// be called multiple times. Init SHOULD NOT be called if the Container instance
// is used for decoding only.
func (x *Container) Init() {
if x.container == nil {
x.container = new(containergrpc.Container)
}
var ver refs.Version
version.Current().WriteToV2(&ver)
x.v2.SetVersion(&ver)
x.container.SetVersion(&ver)
nonce, err := uuid.New().MarshalBinary()
if err != nil {
panic(fmt.Sprintf("unexpected error from UUID.MarshalBinary: %v", err))
}
x.v2.SetNonce(nonce)
x.container.SetNonce(nonce)
}
// SetOwner specifies the owner of the Container. Each Container has exactly
@ -224,17 +243,17 @@ func (x *Container) SetOwner(owner user.ID) {
var m refs.OwnerID
owner.WriteToV2(&m)
x.v2.SetOwnerID(&m)
x.container.SetOwnerId(&m)
}
// Owner returns owner of the Container set using SetOwner.
//
// Zero Container has no owner which is incorrect according to FrostFS API
// protocol.
func (x Container) Owner() (res user.ID) {
m := x.v2.GetOwnerID()
func (x *Container) Owner() (res user.ID) {
m := x.container.GetOwnerId()
if m != nil {
err := res.ReadFromV2(*m)
err := res.ReadFromV2(m)
if err != nil {
panic(fmt.Sprintf("unexpected error from user.ID.ReadFromV2: %v", err))
}
@ -248,15 +267,15 @@ func (x Container) Owner() (res user.ID) {
//
// See also BasicACL.
func (x *Container) SetBasicACL(basicACL acl.Basic) {
x.v2.SetBasicACL(basicACL.Bits())
x.container.SetBasicAcl(basicACL.Bits())
}
// BasicACL returns basic ACL set using SetBasicACL.
//
// Zero Container has zero basic ACL which structurally correct but doesn't
// make sense since it denies any access to any party.
func (x Container) BasicACL() (res acl.Basic) {
res.FromBits(x.v2.GetBasicACL())
func (x *Container) BasicACL() (res acl.Basic) {
res.FromBits(x.container.GetBasicAcl())
return
}
@ -265,20 +284,19 @@ func (x Container) BasicACL() (res acl.Basic) {
//
// See also PlacementPolicy.
func (x *Container) SetPlacementPolicy(policy netmap.PlacementPolicy) {
var m v2netmap.PlacementPolicy
var m netmapgrpc.PlacementPolicy
policy.WriteToV2(&m)
x.v2.SetPlacementPolicy(&m)
x.container.SetPlacementPolicy(&m)
}
// PlacementPolicy returns placement policy set using SetPlacementPolicy.
//
// Zero Container has no placement policy which is incorrect according to
// FrostFS API protocol.
func (x Container) PlacementPolicy() (res netmap.PlacementPolicy) {
m := x.v2.GetPlacementPolicy()
func (x *Container) PlacementPolicy() (res netmap.PlacementPolicy) {
m := x.container.GetPlacementPolicy()
if m != nil {
err := res.ReadFromV2(*m)
err := res.ReadFromV2(m)
if err != nil {
panic(fmt.Sprintf("unexpected error from PlacementPolicy.ReadFromV2: %v", err))
}
@ -305,7 +323,7 @@ func (x *Container) SetAttribute(key, value string) {
panic("empty attribute value")
}
attrs := x.v2.GetAttributes()
attrs := x.container.GetAttributes()
ln := len(attrs)
for i := 0; i < ln; i++ {
@ -315,11 +333,11 @@ func (x *Container) SetAttribute(key, value string) {
}
}
attrs = append(attrs, container.Attribute{})
attrs = append(attrs, &containergrpc.Container_Attribute{})
attrs[ln].SetKey(key)
attrs[ln].SetValue(value)
x.v2.SetAttributes(attrs)
x.container.SetAttributes(attrs)
}
// Attribute reads value of the Container attribute by key. Empty result means
@ -327,7 +345,7 @@ func (x *Container) SetAttribute(key, value string) {
//
// See also SetAttribute, IterateAttributes, IterateUserAttributes.
func (x Container) Attribute(key string) string {
attrs := x.v2.GetAttributes()
attrs := x.container.GetAttributes()
for i := range attrs {
if attrs[i].GetKey() == key {
return attrs[i].GetValue()
@ -341,8 +359,8 @@ func (x Container) Attribute(key string) string {
// into f. The handler MUST NOT be nil.
//
// See also SetAttribute, Attribute.
func (x Container) IterateAttributes(f func(key, val string)) {
attrs := x.v2.GetAttributes()
func (x *Container) IterateAttributes(f func(key, val string)) {
attrs := x.container.GetAttributes()
for i := range attrs {
f(attrs[i].GetKey(), attrs[i].GetValue())
}
@ -353,11 +371,11 @@ func (x Container) IterateAttributes(f func(key, val string)) {
//
// See also SetAttribute, Attribute.
func (x Container) IterateUserAttributes(f func(key, val string)) {
attrs := x.v2.GetAttributes()
attrs := x.container.GetAttributes()
for _, attr := range attrs {
var key = attr.GetKey()
if !strings.HasPrefix(key, container.SysAttributePrefix) &&
!strings.HasPrefix(key, container.SysAttributePrefixNeoFS) {
if !strings.HasPrefix(key, containergrpc.SysAttributePrefix) &&
!strings.HasPrefix(key, containergrpc.SysAttributePrefixNeoFS) {
f(key, attr.GetValue())
}
}
@ -366,7 +384,7 @@ func (x Container) IterateUserAttributes(f func(key, val string)) {
// SetName sets human-readable name of the Container. Name MUST NOT be empty.
//
// See also Name.
func SetName(cnr *Container, name string) {
func SetName(cnr Container, name string) {
cnr.SetAttribute(attributeName, name)
}
@ -380,7 +398,7 @@ func Name(cnr Container) string {
// SetCreationTime writes container's creation time in Unix Timestamp format.
//
// See also CreatedAt.
func SetCreationTime(cnr *Container, t time.Time) {
func SetCreationTime(cnr Container, t time.Time) {
cnr.SetAttribute(attributeTimestamp, strconv.FormatInt(t.Unix(), 10))
}
@ -409,16 +427,19 @@ const attributeHomoHashEnabled = "true"
// Container data.
//
// See also IsHomomorphicHashingDisabled.
func DisableHomomorphicHashing(cnr *Container) {
cnr.SetAttribute(container.SysAttributeHomomorphicHashing, attributeHomoHashEnabled)
func DisableHomomorphicHashing(cnr Container) {
cnr.SetAttribute(containergrpc.SysAttributeHomomorphicHashing, attributeHomoHashEnabled)
}
// IsHomomorphicHashingDisabled checks if DisableHomomorphicHashing was called.
//
// Zero Container has enabled hashing.
func IsHomomorphicHashingDisabled(cnr Container) bool {
return cnr.Attribute(container.SysAttributeHomomorphicHashing) == attributeHomoHashEnabled ||
cnr.Attribute(container.SysAttributeHomomorphicHashingNeoFS) == attributeHomoHashEnabled
if cnr.container == nil {
return false
}
return cnr.Attribute(containergrpc.SysAttributeHomomorphicHashing) == attributeHomoHashEnabled ||
cnr.Attribute(containergrpc.SysAttributeHomomorphicHashingNeoFS) == attributeHomoHashEnabled
}
// Domain represents information about container domain registered in the NNS
@ -456,20 +477,20 @@ func (x Domain) Zone() string {
}
// WriteDomain writes Domain into the Container. Name MUST NOT be empty.
func WriteDomain(cnr *Container, domain Domain) {
cnr.SetAttribute(container.SysAttributeName, domain.Name())
cnr.SetAttribute(container.SysAttributeZone, domain.Zone())
func WriteDomain(cnr Container, domain Domain) {
cnr.SetAttribute(containergrpc.SysAttributeName, domain.Name())
cnr.SetAttribute(containergrpc.SysAttributeZone, domain.Zone())
}
// ReadDomain reads Domain from the Container. Returns value with empty name
// if domain is not specified.
func ReadDomain(cnr Container) (res Domain) {
if name := cnr.Attribute(container.SysAttributeName); name != "" {
if name := cnr.Attribute(containergrpc.SysAttributeName); name != "" {
res.SetName(name)
res.SetZone(cnr.Attribute(container.SysAttributeZone))
} else if name = cnr.Attribute(container.SysAttributeNameNeoFS); name != "" {
res.SetZone(cnr.Attribute(containergrpc.SysAttributeZone))
} else if name = cnr.Attribute(containergrpc.SysAttributeNameNeoFS); name != "" {
res.SetName(name)
res.SetZone(cnr.Attribute(container.SysAttributeZoneNeoFS))
res.SetZone(cnr.Attribute(containergrpc.SysAttributeZoneNeoFS))
}
return
@ -488,7 +509,7 @@ func CalculateSignature(dst *frostfscrypto.Signature, cnr Container, signer ecds
// VerifySignature verifies Container signature calculated using CalculateSignature.
// Result means signature correctness.
func VerifySignature(sig frostfscrypto.Signature, cnr Container) bool {
func VerifySignature(sig *frostfscrypto.Signature, cnr *Container) bool {
return sig.Verify(cnr.Marshal())
}

View file

@ -6,9 +6,9 @@ import (
"testing"
"time"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
@ -20,26 +20,35 @@ import (
"github.com/google/uuid"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestPlacementPolicyEncoding(t *testing.T) {
v := containertest.Container()
t.Run("binary", func(t *testing.T) {
var v2 container.Container
v2 := container.NewContainer()
require.NoError(t, v2.Unmarshal(v.Marshal()))
require.Equal(t, v, v2)
var c1, c2 containergrpc.Container
v.WriteToV2(&c1)
v2.WriteToV2(&c2)
require.True(t, proto.Equal(&c1, &c2))
})
t.Run("json", func(t *testing.T) {
data, err := v.MarshalJSON()
require.NoError(t, err)
var v2 container.Container
v2 := container.NewContainer()
require.NoError(t, v2.UnmarshalJSON(data))
require.Equal(t, v, v2)
var c1, c2 containergrpc.Container
v.WriteToV2(&c1)
v2.WriteToV2(&c2)
require.True(t, proto.Equal(&c1, &c2))
})
}
@ -48,7 +57,7 @@ func TestContainer_Init(t *testing.T) {
val.Init()
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
binNonce := msg.GetNonce()
@ -60,19 +69,26 @@ func TestContainer_Init(t *testing.T) {
verV2 := msg.GetVersion()
require.NotNil(t, verV2)
var ver version.Version
require.NoError(t, ver.ReadFromV2(*verV2))
ver := version.NewVersion()
ver.ReadFromV2(verV2)
require.Equal(t, version.Current(), ver)
var v1, v2 refs.Version
version.Current().WriteToV2(&v1)
ver.WriteToV2(&v2)
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
require.True(t, proto.Equal(&v1, &v2))
require.Equal(t, val, val2)
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
var c1, c2 containergrpc.Container
val.WriteToV2(&c1)
val2.WriteToV2(&c2)
require.True(t, proto.Equal(&c1, &c2))
}
func TestContainer_Owner(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Zero(t, val.Owner())
@ -82,22 +98,22 @@ func TestContainer_Owner(t *testing.T) {
val.SetOwner(owner)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
var msgOwner refs.OwnerID
owner.WriteToV2(&msgOwner)
require.Equal(t, &msgOwner, msg.GetOwnerID())
require.True(t, proto.Equal(&msgOwner, msg.GetOwnerId()))
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.True(t, val2.Owner().Equals(owner))
}
func TestContainer_BasicACL(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Zero(t, val.BasicACL())
@ -106,19 +122,19 @@ func TestContainer_BasicACL(t *testing.T) {
basicACL := containertest.BasicACL()
val.SetBasicACL(basicACL)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
require.EqualValues(t, basicACL.Bits(), msg.GetBasicACL())
require.EqualValues(t, basicACL.Bits(), msg.GetBasicAcl())
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, basicACL, val2.BasicACL())
}
func TestContainer_PlacementPolicy(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Zero(t, val.PlacementPolicy())
@ -127,30 +143,43 @@ func TestContainer_PlacementPolicy(t *testing.T) {
pp := netmaptest.PlacementPolicy()
val.SetPlacementPolicy(pp)
var msgPolicy v2netmap.PlacementPolicy
var msgPolicy netmapgrpc.PlacementPolicy
pp.WriteToV2(&msgPolicy)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
require.Equal(t, &msgPolicy, msg.GetPlacementPolicy())
require.True(t, proto.Equal(&msgPolicy, msg.GetPlacementPolicy()))
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, pp, val2.PlacementPolicy())
var p1, p2 netmapgrpc.PlacementPolicy
pp.WriteToV2(&p1)
val2.PlacementPolicy().WriteToV2(&p2)
require.True(t, proto.Equal(&p1, &p2))
}
func assertContainsAttribute(t *testing.T, m v2container.Container, key, val string) {
var msgAttr v2container.Attribute
func assertContainsAttribute(t *testing.T, m *containergrpc.Container, key, val string) {
var msgAttr containergrpc.Container_Attribute
msgAttr.SetKey(key)
msgAttr.SetValue(val)
require.Contains(t, m.GetAttributes(), msgAttr)
var found bool
for _, attr := range m.GetAttributes() {
if found = proto.Equal(attr, &msgAttr); found {
break
}
}
require.True(t, found, "Attribute has not been found")
}
func TestContainer_Attribute(t *testing.T) {
const attrKey1, attrKey2 = v2container.SysAttributePrefix + "key1", v2container.SysAttributePrefixNeoFS + "key2"
const attrKey1, attrKey2 = containergrpc.SysAttributePrefix + "key1", containergrpc.SysAttributePrefixNeoFS + "key2"
const attrVal1, attrVal2 = "val1", "val2"
val := containertest.Container()
@ -164,15 +193,15 @@ func TestContainer_Attribute(t *testing.T) {
})
require.Equal(t, 1, i)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
require.GreaterOrEqual(t, len(msg.GetAttributes()), 2)
assertContainsAttribute(t, msg, attrKey1, attrVal1)
assertContainsAttribute(t, msg, attrKey2, attrVal2)
assertContainsAttribute(t, &msg, attrKey1, attrVal1)
assertContainsAttribute(t, &msg, attrKey2, attrVal2)
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, attrVal1, val2.Attribute(attrKey1))
require.Equal(t, attrVal2, val2.Attribute(attrKey2))
@ -192,31 +221,31 @@ func TestContainer_Attribute(t *testing.T) {
}
func TestSetName(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Panics(t, func() {
container.SetName(&val, "")
container.SetName(val, "")
})
val = containertest.Container()
const name = "some name"
container.SetName(&val, name)
container.SetName(val, name)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, "Name", name)
assertContainsAttribute(t, &msg, "Name", name)
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, name, container.Name(val2))
}
func TestSetCreationTime(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Zero(t, container.CreatedAt(val).Unix())
@ -224,15 +253,15 @@ func TestSetCreationTime(t *testing.T) {
creat := time.Now()
container.SetCreationTime(&val, creat)
container.SetCreationTime(val, creat)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, "Timestamp", strconv.FormatInt(creat.Unix(), 10))
assertContainsAttribute(t, &msg, "Timestamp", strconv.FormatInt(creat.Unix(), 10))
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, creat.Unix(), container.CreatedAt(val2).Unix())
}
@ -244,21 +273,21 @@ func TestDisableHomomorphicHashing(t *testing.T) {
val = containertest.Container()
container.DisableHomomorphicHashing(&val)
container.DisableHomomorphicHashing(val)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, v2container.SysAttributePrefix+"DISABLE_HOMOMORPHIC_HASHING", "true")
assertContainsAttribute(t, &msg, containergrpc.SysAttributePrefix+"DISABLE_HOMOMORPHIC_HASHING", "true")
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.True(t, container.IsHomomorphicHashingDisabled(val2))
}
func TestWriteDomain(t *testing.T) {
var val container.Container
val := container.NewContainer()
require.Zero(t, container.ReadDomain(val).Name())
@ -269,26 +298,26 @@ func TestWriteDomain(t *testing.T) {
var d container.Domain
d.SetName(name)
container.WriteDomain(&val, d)
container.WriteDomain(val, d)
var msg v2container.Container
var msg containergrpc.Container
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, v2container.SysAttributeName, name)
assertContainsAttribute(t, msg, v2container.SysAttributeZone, "container")
assertContainsAttribute(t, &msg, containergrpc.SysAttributeName, name)
assertContainsAttribute(t, &msg, containergrpc.SysAttributeZone, "container")
const zone = "domain zone"
d.SetZone(zone)
container.WriteDomain(&val, d)
container.WriteDomain(val, d)
val.WriteToV2(&msg)
assertContainsAttribute(t, msg, v2container.SysAttributeZone, zone)
assertContainsAttribute(t, &msg, containergrpc.SysAttributeZone, zone)
var val2 container.Container
require.NoError(t, val2.ReadFromV2(msg))
val2 := container.NewContainer()
require.NoError(t, val2.ReadFromV2(&msg))
require.Equal(t, d, container.ReadDomain(val2))
}
@ -308,7 +337,7 @@ func TestCalculateID(t *testing.T) {
require.Equal(t, h[:], msg.GetValue())
var id2 cid.ID
require.NoError(t, id2.ReadFromV2(msg))
require.NoError(t, id2.ReadFromV2(&msg))
require.True(t, container.AssertID(id2, val))
}
@ -319,7 +348,7 @@ func TestCalculateSignature(t *testing.T) {
val := containertest.Container()
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
require.NoError(t, container.CalculateSignature(&sig, val, key.PrivateKey))
@ -327,7 +356,7 @@ func TestCalculateSignature(t *testing.T) {
sig.WriteToV2(&msg)
var sig2 frostfscrypto.Signature
require.NoError(t, sig2.ReadFromV2(msg))
require.NoError(t, sig2.ReadFromV2(&msg))
require.True(t, container.VerifySignature(sig2, val))
require.True(t, container.VerifySignature(&sig2, &val))
}

View file

@ -4,7 +4,7 @@ import (
"crypto/sha256"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"github.com/mr-tron/base58"
)
@ -25,7 +25,7 @@ type ID [sha256.Size]byte
// to the FrostFS API V2 protocol.
//
// See also WriteToV2.
func (id *ID) ReadFromV2(m refs.ContainerID) error {
func (id *ID) ReadFromV2(m *refs.ContainerID) error {
return id.Decode(m.GetValue())
}
@ -34,6 +34,7 @@ func (id *ID) ReadFromV2(m refs.ContainerID) error {
//
// See also ReadFromV2.
func (id ID) WriteToV2(m *refs.ContainerID) {
m.Reset()
m.SetValue(id[:])
}

View file

@ -5,7 +5,7 @@ import (
"math/rand"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"github.com/mr-tron/base58"
@ -29,7 +29,7 @@ func TestID_ToV2(t *testing.T) {
id.WriteToV2(&idV2)
var newID cid.ID
require.NoError(t, newID.ReadFromV2(idV2))
require.NoError(t, newID.ReadFromV2(&idV2))
require.Equal(t, id, newID)
require.Equal(t, checksum[:], idV2.GetValue())
@ -82,7 +82,7 @@ func TestNewFromV2(t *testing.T) {
v2 refs.ContainerID
)
require.Error(t, x.ReadFromV2(v2))
require.Error(t, x.ReadFromV2(&v2))
})
}

View file

@ -7,7 +7,7 @@ import (
// ApplyNetworkConfig applies network configuration to the
// container. Changes the container if it does not satisfy
// network configuration.
func ApplyNetworkConfig(cnr *Container, cfg netmap.NetworkInfo) {
func ApplyNetworkConfig(cnr Container, cfg netmap.NetworkInfo) {
if cfg.HomomorphicHashingDisabled() {
DisableHomomorphicHashing(cnr)
}

View file

@ -26,7 +26,7 @@ func TestContainer_NetworkConfig(t *testing.T) {
t.Run("apply", func(t *testing.T) {
require.False(t, container.IsHomomorphicHashingDisabled(c))
container.ApplyNetworkConfig(&c, nc)
container.ApplyNetworkConfig(c, nc)
require.True(t, container.IsHomomorphicHashingDisabled(c))
})

View file

@ -4,9 +4,10 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"google.golang.org/protobuf/proto"
)
// SizeEstimation groups information about estimation of the size of the data
@ -15,27 +16,36 @@ import (
// SizeEstimation is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container.UsedSpaceAnnouncement
// message. See ReadFromV2 / WriteToV2 methods.
type SizeEstimation struct {
m container.UsedSpaceAnnouncement
m *containergrpc.AnnounceUsedSpaceRequest_Body_Announcement
}
func NewSizeEstimation() *SizeEstimation {
return &SizeEstimation{
m: &containergrpc.AnnounceUsedSpaceRequest_Body_Announcement{},
}
}
// ReadFromV2 reads SizeEstimation from the container.UsedSpaceAnnouncement message.
// Checks if the message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *SizeEstimation) ReadFromV2(m container.UsedSpaceAnnouncement) error {
cnrV2 := m.GetContainerID()
func (x *SizeEstimation) ReadFromV2(m *containergrpc.AnnounceUsedSpaceRequest_Body_Announcement) error {
cnrV2 := m.GetContainerId()
if cnrV2 == nil {
return errors.New("missing container")
}
var cnr cid.ID
err := cnr.ReadFromV2(*cnrV2)
err := cnr.ReadFromV2(cnrV2)
if err != nil {
return fmt.Errorf("invalid container: %w", err)
}
x.m = m
if x.m == nil {
x.m = new(containergrpc.AnnounceUsedSpaceRequest_Body_Announcement)
}
proto.Merge(x.m, m)
return nil
}
@ -44,8 +54,9 @@ func (x *SizeEstimation) ReadFromV2(m container.UsedSpaceAnnouncement) error {
// The message MUST NOT be nil.
//
// See also ReadFromV2.
func (x SizeEstimation) WriteToV2(m *container.UsedSpaceAnnouncement) {
*m = x.m
func (x SizeEstimation) WriteToV2(m *containergrpc.AnnounceUsedSpaceRequest_Body_Announcement) {
m.Reset()
proto.Merge(m, x.m)
}
// SetEpoch sets epoch when estimation of the container data size was calculated.
@ -67,10 +78,10 @@ func (x SizeEstimation) Epoch() uint64 {
//
// See also Container.
func (x *SizeEstimation) SetContainer(cnr cid.ID) {
var cidV2 refs.ContainerID
var cidV2 refsgrpc.ContainerID
cnr.WriteToV2(&cidV2)
x.m.SetContainerID(&cidV2)
x.m.SetContainerId(&cidV2)
}
// Container returns container set using SetContainer.
@ -78,9 +89,9 @@ func (x *SizeEstimation) SetContainer(cnr cid.ID) {
// Zero SizeEstimation is not bound to any container (returns zero) which is
// incorrect according to FrostFS API protocol.
func (x SizeEstimation) Container() (res cid.ID) {
m := x.m.GetContainerID()
m := x.m.GetContainerId()
if m != nil {
err := res.ReadFromV2(*m)
err := res.ReadFromV2(m)
if err != nil {
panic(fmt.Errorf("unexpected error from cid.ID.ReadFromV2: %w", err))
}

View file

@ -4,16 +4,17 @@ import (
"crypto/sha256"
"testing"
v2container "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
containergrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/container/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestSizeEstimation_Epoch(t *testing.T) {
var val container.SizeEstimation
val := container.NewSizeEstimation()
require.Zero(t, val.Epoch())
@ -22,14 +23,14 @@ func TestSizeEstimation_Epoch(t *testing.T) {
val.SetEpoch(epoch)
require.EqualValues(t, epoch, val.Epoch())
var msg v2container.UsedSpaceAnnouncement
var msg containergrpc.AnnounceUsedSpaceRequest_Body_Announcement
val.WriteToV2(&msg)
require.EqualValues(t, epoch, msg.GetEpoch())
}
func TestSizeEstimation_Container(t *testing.T) {
var val container.SizeEstimation
val := container.NewSizeEstimation()
require.Zero(t, val.Container())
@ -38,17 +39,17 @@ func TestSizeEstimation_Container(t *testing.T) {
val.SetContainer(cnr)
require.True(t, val.Container().Equals(cnr))
var msg v2container.UsedSpaceAnnouncement
var msg containergrpc.AnnounceUsedSpaceRequest_Body_Announcement
val.WriteToV2(&msg)
var msgCnr refs.ContainerID
var msgCnr refsgrpc.ContainerID
cnr.WriteToV2(&msgCnr)
require.Equal(t, &msgCnr, msg.GetContainerID())
require.True(t, proto.Equal(&msgCnr, msg.GetContainerId()))
}
func TestSizeEstimation_Value(t *testing.T) {
var val container.SizeEstimation
val := container.NewSizeEstimation()
require.Zero(t, val.Value())
@ -57,7 +58,7 @@ func TestSizeEstimation_Value(t *testing.T) {
val.SetValue(value)
require.EqualValues(t, value, val.Value())
var msg v2container.UsedSpaceAnnouncement
var msg containergrpc.AnnounceUsedSpaceRequest_Body_Announcement
val.WriteToV2(&msg)
require.EqualValues(t, value, msg.GetUsedSpace())
@ -66,22 +67,22 @@ func TestSizeEstimation_Value(t *testing.T) {
func TestSizeEstimation_ReadFromV2(t *testing.T) {
const epoch = 654
const value = 903
var cnrMsg refs.ContainerID
var cnrMsg refsgrpc.ContainerID
var msg v2container.UsedSpaceAnnouncement
msg := new(containergrpc.AnnounceUsedSpaceRequest_Body_Announcement)
var val container.SizeEstimation
val := container.NewSizeEstimation()
require.Error(t, val.ReadFromV2(msg))
msg.SetContainerID(&cnrMsg)
msg.SetContainerId(&cnrMsg)
require.Error(t, val.ReadFromV2(msg))
cnrMsg.SetValue(make([]byte, sha256.Size))
var cnr cid.ID
require.NoError(t, cnr.ReadFromV2(cnrMsg))
require.NoError(t, cnr.ReadFromV2(&cnrMsg))
msg.SetEpoch(epoch)
msg.SetUsedSpace(value)

View file

@ -14,6 +14,7 @@ import (
func Container() (x container.Container) {
owner := usertest.ID()
x = container.NewContainer()
x.Init()
x.SetAttribute("some attribute", "value")
x.SetOwner(*owner)

View file

@ -4,7 +4,7 @@ import (
"math/rand"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
@ -19,7 +19,7 @@ func TestSignature(t *testing.T) {
require.NoError(t, err)
var s frostfscrypto.Signature
var m refs.Signature
var m = new(refs.Signature)
for _, f := range []func() frostfscrypto.Signer{
func() frostfscrypto.Signer {
@ -37,7 +37,7 @@ func TestSignature(t *testing.T) {
err := s.Calculate(signer, data)
require.NoError(t, err)
s.WriteToV2(&m)
s.WriteToV2(m)
require.NoError(t, s.ReadFromV2(m))

View file

@ -40,7 +40,7 @@ On server side:
// recv msg
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
sig.ReadFromV2(msg)
// process sig

View file

@ -4,7 +4,8 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"github.com/golang/protobuf/proto"
)
// Signature represents a confirmation of data integrity received by the
@ -16,13 +17,21 @@ import (
// Note that direct typecast is not safe and may result in loss of compatibility:
//
// _ = Signature(refs.Signature{}) // not recommended
type Signature refs.Signature
type Signature struct {
signature *refsgrpc.Signature
}
func NewSignature() Signature {
return Signature{
signature: &refsgrpc.Signature{},
}
}
// ReadFromV2 reads Signature from the refs.Signature message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *Signature) ReadFromV2(m refs.Signature) error {
func (x *Signature) ReadFromV2(m *refsgrpc.Signature) error {
if len(m.GetKey()) == 0 {
return errors.New("missing public key")
} else if len(m.GetSign()) == 0 {
@ -33,12 +42,15 @@ func (x *Signature) ReadFromV2(m refs.Signature) error {
default:
return fmt.Errorf("unsupported scheme %v", m.GetSign())
case
refs.ECDSA_SHA512,
refs.ECDSA_RFC6979_SHA256,
refs.ECDSA_RFC6979_SHA256_WALLET_CONNECT:
refsgrpc.SignatureScheme_ECDSA_SHA512,
refsgrpc.SignatureScheme_ECDSA_RFC6979_SHA256,
refsgrpc.SignatureScheme_ECDSA_RFC6979_SHA256_WALLET_CONNECT:
}
*x = Signature(m)
if x.signature == nil {
x.signature = new(refsgrpc.Signature)
}
proto.Merge(x.signature, m)
return nil
}
@ -47,8 +59,9 @@ func (x *Signature) ReadFromV2(m refs.Signature) error {
// The message must not be nil.
//
// See also ReadFromV2.
func (x Signature) WriteToV2(m *refs.Signature) {
*m = (refs.Signature)(x)
func (x *Signature) WriteToV2(m *refsgrpc.Signature) {
m.Reset()
proto.Merge(m, x.signature)
}
// Calculate signs data using Signer and encodes public key for subsequent
@ -68,13 +81,12 @@ func (x *Signature) Calculate(signer Signer, data []byte) error {
key := make([]byte, pub.MaxEncodedSize())
key = key[:pub.Encode(key)]
m := (*refs.Signature)(x)
m.SetScheme(refs.SignatureScheme(signer.Scheme()))
m := new(refsgrpc.Signature)
m.SetScheme(refsgrpc.SignatureScheme(signer.Scheme()))
m.SetSign(signature)
m.SetKey(key)
return nil
return x.ReadFromV2(m)
}
// Verify verifies data signature using encoded public key. True means valid
@ -83,20 +95,18 @@ func (x *Signature) Calculate(signer Signer, data []byte) error {
// Verify fails if signature scheme is not supported (see RegisterScheme).
//
// See also Calculate.
func (x Signature) Verify(data []byte) bool {
m := (*refs.Signature)(&x)
f, ok := publicKeys[Scheme(m.GetScheme())]
func (x *Signature) Verify(data []byte) bool {
f, ok := publicKeys[Scheme(x.signature.GetScheme())]
if !ok {
return false
}
key := f()
err := key.Decode(m.GetKey())
err := key.Decode(x.signature.GetKey())
if err != nil {
return false
}
return key.Verify(data, m.GetSign())
return key.Verify(data, x.signature.GetSign())
}

View file

@ -3,7 +3,7 @@ package frostfscrypto
import (
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
)
// Scheme represents digital signature algorithm with fixed cryptographic hash function.

View file

@ -1,7 +1,7 @@
package eacl
import (
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
)
// Action taken if ContainerEACL record matched request.
@ -102,23 +102,23 @@ const (
)
// ToV2 converts Action to v2 Action enum value.
func (a Action) ToV2() v2acl.Action {
func (a Action) ToV2() aclgrpc.Action {
switch a {
case ActionAllow:
return v2acl.ActionAllow
return aclgrpc.Action_ALLOW
case ActionDeny:
return v2acl.ActionDeny
return aclgrpc.Action_DENY
default:
return v2acl.ActionUnknown
return aclgrpc.Action_ACTION_UNSPECIFIED
}
}
// ActionFromV2 converts v2 Action enum value to Action.
func ActionFromV2(action v2acl.Action) (a Action) {
func ActionFromV2(action aclgrpc.Action) (a Action) {
switch action {
case v2acl.ActionAllow:
case aclgrpc.Action_ALLOW:
a = ActionAllow
case v2acl.ActionDeny:
case aclgrpc.Action_DENY:
a = ActionDeny
default:
a = ActionUnknown
@ -142,7 +142,7 @@ func (a Action) String() string {
//
// Returns true if s was parsed successfully.
func (a *Action) FromString(s string) bool {
var g v2acl.Action
var g aclgrpc.Action
ok := g.FromString(s)
@ -154,43 +154,43 @@ func (a *Action) FromString(s string) bool {
}
// ToV2 converts Operation to v2 Operation enum value.
func (o Operation) ToV2() v2acl.Operation {
func (o Operation) ToV2() aclgrpc.Operation {
switch o {
case OperationGet:
return v2acl.OperationGet
return aclgrpc.Operation_GET
case OperationHead:
return v2acl.OperationHead
return aclgrpc.Operation_HEAD
case OperationPut:
return v2acl.OperationPut
return aclgrpc.Operation_PUT
case OperationDelete:
return v2acl.OperationDelete
return aclgrpc.Operation_DELETE
case OperationSearch:
return v2acl.OperationSearch
return aclgrpc.Operation_SEARCH
case OperationRange:
return v2acl.OperationRange
return aclgrpc.Operation_GETRANGE
case OperationRangeHash:
return v2acl.OperationRangeHash
return aclgrpc.Operation_GETRANGEHASH
default:
return v2acl.OperationUnknown
return aclgrpc.Operation_OPERATION_UNSPECIFIED
}
}
// OperationFromV2 converts v2 Operation enum value to Operation.
func OperationFromV2(operation v2acl.Operation) (o Operation) {
func OperationFromV2(operation aclgrpc.Operation) (o Operation) {
switch operation {
case v2acl.OperationGet:
case aclgrpc.Operation_GET:
o = OperationGet
case v2acl.OperationHead:
case aclgrpc.Operation_HEAD:
o = OperationHead
case v2acl.OperationPut:
case aclgrpc.Operation_PUT:
o = OperationPut
case v2acl.OperationDelete:
case aclgrpc.Operation_DELETE:
o = OperationDelete
case v2acl.OperationSearch:
case aclgrpc.Operation_SEARCH:
o = OperationSearch
case v2acl.OperationRange:
case aclgrpc.Operation_GETRANGE:
o = OperationRange
case v2acl.OperationRangeHash:
case aclgrpc.Operation_GETRANGEHASH:
o = OperationRangeHash
default:
o = OperationUnknown
@ -219,7 +219,7 @@ func (o Operation) String() string {
//
// Returns true if s was parsed successfully.
func (o *Operation) FromString(s string) bool {
var g v2acl.Operation
var g aclgrpc.Operation
ok := g.FromString(s)
@ -231,27 +231,27 @@ func (o *Operation) FromString(s string) bool {
}
// ToV2 converts Role to v2 Role enum value.
func (r Role) ToV2() v2acl.Role {
func (r Role) ToV2() aclgrpc.Role {
switch r {
case RoleUser:
return v2acl.RoleUser
return aclgrpc.Role_USER
case RoleSystem:
return v2acl.RoleSystem
return aclgrpc.Role_SYSTEM
case RoleOthers:
return v2acl.RoleOthers
return aclgrpc.Role_OTHERS
default:
return v2acl.RoleUnknown
return aclgrpc.Role_ROLE_UNSPECIFIED
}
}
// RoleFromV2 converts v2 Role enum value to Role.
func RoleFromV2(role v2acl.Role) (r Role) {
func RoleFromV2(role aclgrpc.Role) (r Role) {
switch role {
case v2acl.RoleUser:
case aclgrpc.Role_USER:
r = RoleUser
case v2acl.RoleSystem:
case aclgrpc.Role_SYSTEM:
r = RoleSystem
case v2acl.RoleOthers:
case aclgrpc.Role_OTHERS:
r = RoleOthers
default:
r = RoleUnknown
@ -276,7 +276,7 @@ func (r Role) String() string {
//
// Returns true if s was parsed successfully.
func (r *Role) FromString(s string) bool {
var g v2acl.Role
var g aclgrpc.Role
ok := g.FromString(s)
@ -288,23 +288,23 @@ func (r *Role) FromString(s string) bool {
}
// ToV2 converts Match to v2 MatchType enum value.
func (m Match) ToV2() v2acl.MatchType {
func (m Match) ToV2() aclgrpc.MatchType {
switch m {
case MatchStringEqual:
return v2acl.MatchTypeStringEqual
return aclgrpc.MatchType_STRING_EQUAL
case MatchStringNotEqual:
return v2acl.MatchTypeStringNotEqual
return aclgrpc.MatchType_STRING_NOT_EQUAL
default:
return v2acl.MatchTypeUnknown
return aclgrpc.MatchType_MATCH_TYPE_UNSPECIFIED
}
}
// MatchFromV2 converts v2 MatchType enum value to Match.
func MatchFromV2(match v2acl.MatchType) (m Match) {
func MatchFromV2(match aclgrpc.MatchType) (m Match) {
switch match {
case v2acl.MatchTypeStringEqual:
case aclgrpc.MatchType_STRING_EQUAL:
m = MatchStringEqual
case v2acl.MatchTypeStringNotEqual:
case aclgrpc.MatchType_STRING_NOT_EQUAL:
m = MatchStringNotEqual
default:
m = MatchUnknown
@ -328,7 +328,7 @@ func (m Match) String() string {
//
// Returns true if s was parsed successfully.
func (m *Match) FromString(s string) bool {
var g v2acl.MatchType
var g aclgrpc.MatchType
ok := g.FromString(s)
@ -340,27 +340,27 @@ func (m *Match) FromString(s string) bool {
}
// ToV2 converts FilterHeaderType to v2 HeaderType enum value.
func (h FilterHeaderType) ToV2() v2acl.HeaderType {
func (h FilterHeaderType) ToV2() aclgrpc.HeaderType {
switch h {
case HeaderFromRequest:
return v2acl.HeaderTypeRequest
return aclgrpc.HeaderType_REQUEST
case HeaderFromObject:
return v2acl.HeaderTypeObject
return aclgrpc.HeaderType_OBJECT
case HeaderFromService:
return v2acl.HeaderTypeService
return aclgrpc.HeaderType_SERVICE
default:
return v2acl.HeaderTypeUnknown
return aclgrpc.HeaderType_HEADER_UNSPECIFIED
}
}
// FilterHeaderTypeFromV2 converts v2 HeaderType enum value to FilterHeaderType.
func FilterHeaderTypeFromV2(header v2acl.HeaderType) (h FilterHeaderType) {
func FilterHeaderTypeFromV2(header aclgrpc.HeaderType) (h FilterHeaderType) {
switch header {
case v2acl.HeaderTypeRequest:
case aclgrpc.HeaderType_REQUEST:
h = HeaderFromRequest
case v2acl.HeaderTypeObject:
case aclgrpc.HeaderType_OBJECT:
h = HeaderFromObject
case v2acl.HeaderTypeService:
case aclgrpc.HeaderType_SERVICE:
h = HeaderFromService
default:
h = HeaderTypeUnknown
@ -384,7 +384,7 @@ func (h FilterHeaderType) String() string {
//
// Returns true if s was parsed successfully.
func (h *FilterHeaderType) FromString(s string) bool {
var g v2acl.HeaderType
var g aclgrpc.HeaderType
ok := g.FromString(s)

View file

@ -3,47 +3,47 @@ package eacl_test
import (
"testing"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
"github.com/stretchr/testify/require"
)
var (
eqV2Actions = map[eacl.Action]v2acl.Action{
eacl.ActionUnknown: v2acl.ActionUnknown,
eacl.ActionAllow: v2acl.ActionAllow,
eacl.ActionDeny: v2acl.ActionDeny,
eqV2Actions = map[eacl.Action]aclgrpc.Action{
eacl.ActionUnknown: aclgrpc.Action_ACTION_UNSPECIFIED,
eacl.ActionAllow: aclgrpc.Action_ALLOW,
eacl.ActionDeny: aclgrpc.Action_DENY,
}
eqV2Operations = map[eacl.Operation]v2acl.Operation{
eacl.OperationUnknown: v2acl.OperationUnknown,
eacl.OperationGet: v2acl.OperationGet,
eacl.OperationHead: v2acl.OperationHead,
eacl.OperationPut: v2acl.OperationPut,
eacl.OperationDelete: v2acl.OperationDelete,
eacl.OperationSearch: v2acl.OperationSearch,
eacl.OperationRange: v2acl.OperationRange,
eacl.OperationRangeHash: v2acl.OperationRangeHash,
eqV2Operations = map[eacl.Operation]aclgrpc.Operation{
eacl.OperationUnknown: aclgrpc.Operation_OPERATION_UNSPECIFIED,
eacl.OperationGet: aclgrpc.Operation_GET,
eacl.OperationHead: aclgrpc.Operation_HEAD,
eacl.OperationPut: aclgrpc.Operation_PUT,
eacl.OperationDelete: aclgrpc.Operation_DELETE,
eacl.OperationSearch: aclgrpc.Operation_SEARCH,
eacl.OperationRange: aclgrpc.Operation_GETRANGE,
eacl.OperationRangeHash: aclgrpc.Operation_GETRANGEHASH,
}
eqV2Roles = map[eacl.Role]v2acl.Role{
eacl.RoleUnknown: v2acl.RoleUnknown,
eacl.RoleUser: v2acl.RoleUser,
eacl.RoleSystem: v2acl.RoleSystem,
eacl.RoleOthers: v2acl.RoleOthers,
eqV2Roles = map[eacl.Role]aclgrpc.Role{
eacl.RoleUnknown: aclgrpc.Role_ROLE_UNSPECIFIED,
eacl.RoleUser: aclgrpc.Role_USER,
eacl.RoleSystem: aclgrpc.Role_SYSTEM,
eacl.RoleOthers: aclgrpc.Role_OTHERS,
}
eqV2Matches = map[eacl.Match]v2acl.MatchType{
eacl.MatchUnknown: v2acl.MatchTypeUnknown,
eacl.MatchStringEqual: v2acl.MatchTypeStringEqual,
eacl.MatchStringNotEqual: v2acl.MatchTypeStringNotEqual,
eqV2Matches = map[eacl.Match]aclgrpc.MatchType{
eacl.MatchUnknown: aclgrpc.MatchType_MATCH_TYPE_UNSPECIFIED,
eacl.MatchStringEqual: aclgrpc.MatchType_STRING_EQUAL,
eacl.MatchStringNotEqual: aclgrpc.MatchType_STRING_NOT_EQUAL,
}
eqV2HeaderTypes = map[eacl.FilterHeaderType]v2acl.HeaderType{
eacl.HeaderTypeUnknown: v2acl.HeaderTypeUnknown,
eacl.HeaderFromRequest: v2acl.HeaderTypeRequest,
eacl.HeaderFromObject: v2acl.HeaderTypeObject,
eacl.HeaderFromService: v2acl.HeaderTypeService,
eqV2HeaderTypes = map[eacl.FilterHeaderType]aclgrpc.HeaderType{
eacl.HeaderTypeUnknown: aclgrpc.HeaderType_HEADER_UNSPECIFIED,
eacl.HeaderFromRequest: aclgrpc.HeaderType_REQUEST,
eacl.HeaderFromObject: aclgrpc.HeaderType_OBJECT,
eacl.HeaderFromService: aclgrpc.HeaderType_SERVICE,
}
)
@ -56,8 +56,8 @@ func TestAction(t *testing.T) {
})
t.Run("unknown actions", func(t *testing.T) {
require.Equal(t, (eacl.ActionDeny + 1).ToV2(), v2acl.ActionUnknown)
require.Equal(t, eacl.ActionFromV2(v2acl.ActionDeny+1), eacl.ActionUnknown)
require.Equal(t, (eacl.ActionDeny + 1).ToV2(), aclgrpc.Action_ACTION_UNSPECIFIED)
require.Equal(t, eacl.ActionFromV2(aclgrpc.Action_DENY+1), eacl.ActionUnknown)
})
}
@ -70,8 +70,8 @@ func TestOperation(t *testing.T) {
})
t.Run("unknown operations", func(t *testing.T) {
require.Equal(t, (eacl.OperationRangeHash + 1).ToV2(), v2acl.OperationUnknown)
require.Equal(t, eacl.OperationFromV2(v2acl.OperationRangeHash+1), eacl.OperationUnknown)
require.Equal(t, (eacl.OperationRangeHash + 1).ToV2(), aclgrpc.Operation_OPERATION_UNSPECIFIED)
require.Equal(t, eacl.OperationFromV2(aclgrpc.Operation_GETRANGEHASH+1), eacl.OperationUnknown)
})
}
@ -84,8 +84,8 @@ func TestRole(t *testing.T) {
})
t.Run("unknown roles", func(t *testing.T) {
require.Equal(t, (eacl.RoleOthers + 1).ToV2(), v2acl.RoleUnknown)
require.Equal(t, eacl.RoleFromV2(v2acl.RoleOthers+1), eacl.RoleUnknown)
require.Equal(t, (eacl.RoleOthers + 1).ToV2(), aclgrpc.Role_ROLE_UNSPECIFIED)
require.Equal(t, eacl.RoleFromV2(aclgrpc.Role_OTHERS+1), eacl.RoleUnknown)
})
}
@ -98,8 +98,8 @@ func TestMatch(t *testing.T) {
})
t.Run("unknown matches", func(t *testing.T) {
require.Equal(t, (eacl.MatchStringNotEqual + 1).ToV2(), v2acl.MatchTypeUnknown)
require.Equal(t, eacl.MatchFromV2(v2acl.MatchTypeStringNotEqual+1), eacl.MatchUnknown)
require.Equal(t, (eacl.MatchStringNotEqual + 1).ToV2(), aclgrpc.MatchType_MATCH_TYPE_UNSPECIFIED)
require.Equal(t, eacl.MatchFromV2(aclgrpc.MatchType_STRING_NOT_EQUAL+1), eacl.MatchUnknown)
})
}
@ -112,8 +112,8 @@ func TestFilterHeaderType(t *testing.T) {
})
t.Run("unknown header types", func(t *testing.T) {
require.Equal(t, (eacl.HeaderFromService + 1).ToV2(), v2acl.HeaderTypeUnknown)
require.Equal(t, eacl.FilterHeaderTypeFromV2(v2acl.HeaderTypeService+1), eacl.HeaderTypeUnknown)
require.Equal(t, (eacl.HeaderFromService + 1).ToV2(), aclgrpc.HeaderType_HEADER_UNSPECIFIED)
require.Equal(t, eacl.FilterHeaderTypeFromV2(aclgrpc.HeaderType_SERVICE+1), eacl.HeaderTypeUnknown)
})
}

View file

@ -3,7 +3,10 @@ package eacl
import (
"strconv"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Filter defines check conditions if request header is matched or not. Matched
@ -75,16 +78,16 @@ func (f Filter) From() FilterHeaderType {
// ToV2 converts Filter to v2 acl.EACLRecord.Filter message.
//
// Nil Filter converts to nil.
func (f *Filter) ToV2() *v2acl.HeaderFilter {
func (f *Filter) ToV2() *aclgrpc.EACLRecord_Filter {
if f == nil {
return nil
}
filter := new(v2acl.HeaderFilter)
filter := new(aclgrpc.EACLRecord_Filter)
filter.SetValue(f.value.EncodeToString())
filter.SetKey(f.key.String())
filter.SetMatchType(f.matcher.ToV2())
filter.SetHeaderType(f.from.ToV2())
filter.SetHeader(f.from.ToV2())
return filter
}
@ -94,23 +97,23 @@ func (k filterKey) String() string {
default:
return k.str
case fKeyObjVersion:
return v2acl.FilterObjectVersion
return acl.FilterObjectVersion
case fKeyObjID:
return v2acl.FilterObjectID
return acl.FilterObjectID
case fKeyObjContainerID:
return v2acl.FilterObjectContainerID
return acl.FilterObjectContainerID
case fKeyObjOwnerID:
return v2acl.FilterObjectOwnerID
return acl.FilterObjectOwnerID
case fKeyObjCreationEpoch:
return v2acl.FilterObjectCreationEpoch
return acl.FilterObjectCreationEpoch
case fKeyObjPayloadLength:
return v2acl.FilterObjectPayloadLength
return acl.FilterObjectPayloadLength
case fKeyObjPayloadHash:
return v2acl.FilterObjectPayloadHash
return acl.FilterObjectPayloadHash
case fKeyObjType:
return v2acl.FilterObjectType
return acl.FilterObjectType
case fKeyObjHomomorphicHash:
return v2acl.FilterObjectHomomorphicHash
return acl.FilterObjectHomomorphicHash
}
}
@ -118,23 +121,23 @@ func (k *filterKey) fromString(s string) {
switch s {
default:
k.typ, k.str = 0, s
case v2acl.FilterObjectVersion:
case acl.FilterObjectVersion:
k.typ, k.str = fKeyObjVersion, ""
case v2acl.FilterObjectID:
case acl.FilterObjectID:
k.typ, k.str = fKeyObjID, ""
case v2acl.FilterObjectContainerID:
case acl.FilterObjectContainerID:
k.typ, k.str = fKeyObjContainerID, ""
case v2acl.FilterObjectOwnerID:
case acl.FilterObjectOwnerID:
k.typ, k.str = fKeyObjOwnerID, ""
case v2acl.FilterObjectCreationEpoch:
case acl.FilterObjectCreationEpoch:
k.typ, k.str = fKeyObjCreationEpoch, ""
case v2acl.FilterObjectPayloadLength:
case acl.FilterObjectPayloadLength:
k.typ, k.str = fKeyObjPayloadLength, ""
case v2acl.FilterObjectPayloadHash:
case acl.FilterObjectPayloadHash:
k.typ, k.str = fKeyObjPayloadHash, ""
case v2acl.FilterObjectType:
case acl.FilterObjectType:
k.typ, k.str = fKeyObjType, ""
case v2acl.FilterObjectHomomorphicHash:
case acl.FilterObjectHomomorphicHash:
k.typ, k.str = fKeyObjHomomorphicHash, ""
}
}
@ -147,11 +150,11 @@ func (k *filterKey) fromString(s string) {
// - key: "";
// - value: "".
func NewFilter() *Filter {
return NewFilterFromV2(new(v2acl.HeaderFilter))
return NewFilterFromV2(new(aclgrpc.EACLRecord_Filter))
}
// NewFilterFromV2 converts v2 acl.EACLRecord.Filter message to Filter.
func NewFilterFromV2(filter *v2acl.HeaderFilter) *Filter {
func NewFilterFromV2(filter *aclgrpc.EACLRecord_Filter) *Filter {
f := new(Filter)
if filter == nil {
@ -173,8 +176,8 @@ func (f *Filter) Marshal() ([]byte, error) {
// Unmarshal unmarshals protobuf binary representation of Filter.
func (f *Filter) Unmarshal(data []byte) error {
fV2 := new(v2acl.HeaderFilter)
if err := fV2.Unmarshal(data); err != nil {
fV2 := new(aclgrpc.EACLRecord_Filter)
if err := proto.Unmarshal(data, fV2); err != nil {
return err
}
@ -185,13 +188,17 @@ func (f *Filter) Unmarshal(data []byte) error {
// MarshalJSON encodes Filter to protobuf JSON format.
func (f *Filter) MarshalJSON() ([]byte, error) {
return f.ToV2().MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
f.ToV2(),
)
}
// UnmarshalJSON decodes Filter from protobuf JSON format.
func (f *Filter) UnmarshalJSON(data []byte) error {
fV2 := new(v2acl.HeaderFilter)
if err := fV2.UnmarshalJSON(data); err != nil {
fV2 := new(aclgrpc.EACLRecord_Filter)
if err := protojson.Unmarshal(data, fV2); err != nil {
return err
}

View file

@ -4,7 +4,7 @@ import (
"strconv"
"testing"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"github.com/stretchr/testify/require"
)
@ -24,8 +24,8 @@ func TestFilter(t *testing.T) {
v2 := filter.ToV2()
require.NotNil(t, v2)
require.Equal(t, v2acl.HeaderTypeObject, v2.GetHeaderType())
require.EqualValues(t, v2acl.MatchTypeStringEqual, v2.GetMatchType())
require.Equal(t, aclgrpc.HeaderType_OBJECT, v2.GetHeaderType())
require.EqualValues(t, aclgrpc.MatchType_STRING_EQUAL, v2.GetMatchType())
require.Equal(t, filter.Key(), v2.GetKey())
require.Equal(t, filter.Value(), v2.GetValue())
@ -82,8 +82,8 @@ func TestFilter_ToV2(t *testing.T) {
require.Empty(t, filterV2.GetKey())
require.Empty(t, filterV2.GetValue())
require.Equal(t, v2acl.HeaderTypeUnknown, filterV2.GetHeaderType())
require.Equal(t, v2acl.MatchTypeUnknown, filterV2.GetMatchType())
require.Equal(t, aclgrpc.HeaderType_HEADER_UNSPECIFIED, filterV2.GetHeaderType())
require.Equal(t, aclgrpc.MatchType_MATCH_TYPE_UNSPECIFIED, filterV2.GetMatchType())
})
t.Run("reserved types", func(t *testing.T) {

View file

@ -3,13 +3,16 @@ package eacl
import (
"crypto/ecdsa"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Record of the ContainerEACL rule, that defines ContainerEACL action, targets for this action,
@ -110,8 +113,8 @@ func (r *Record) AddObjectAttributeFilter(m Match, key, value string) {
}
// AddObjectVersionFilter adds filter by object version.
func (r *Record) AddObjectVersionFilter(m Match, v *version.Version) {
r.addObjectReservedFilter(m, fKeyObjVersion, staticStringer(version.EncodeToString(*v)))
func (r *Record) AddObjectVersionFilter(m Match, v version.Version) {
r.addObjectReservedFilter(m, fKeyObjVersion, staticStringer(version.EncodeToString(v)))
}
// AddObjectIDFilter adds filter by object ID.
@ -157,26 +160,26 @@ func (r *Record) AddObjectHomomorphicHashFilter(m Match, h checksum.Checksum) {
// ToV2 converts Record to v2 acl.EACLRecord message.
//
// Nil Record converts to nil.
func (r *Record) ToV2() *v2acl.Record {
func (r *Record) ToV2() *aclgrpc.EACLRecord {
if r == nil {
return nil
}
v2 := new(v2acl.Record)
v2 := new(aclgrpc.EACLRecord)
if r.targets != nil {
targets := make([]v2acl.Target, len(r.targets))
targets := slices.MakePreallocPointerSlice[aclgrpc.EACLRecord_Target](len(r.targets))
for i := range r.targets {
targets[i] = *r.targets[i].ToV2()
targets[i] = r.targets[i].ToV2()
}
v2.SetTargets(targets)
}
if r.filters != nil {
filters := make([]v2acl.HeaderFilter, len(r.filters))
filters := slices.MakePreallocPointerSlice[aclgrpc.EACLRecord_Filter](len(r.filters))
for i := range r.filters {
filters[i] = *r.filters[i].ToV2()
filters[i] = r.filters[i].ToV2()
}
v2.SetFilters(filters)
@ -211,7 +214,7 @@ func CreateRecord(action Action, operation Operation) *Record {
}
// NewRecordFromV2 converts v2 acl.EACLRecord message to Record.
func NewRecordFromV2(record *v2acl.Record) *Record {
func NewRecordFromV2(record *aclgrpc.EACLRecord) *Record {
r := NewRecord()
if record == nil {
@ -226,12 +229,12 @@ func NewRecordFromV2(record *v2acl.Record) *Record {
r.targets = make([]Target, len(v2targets))
for i := range v2targets {
r.targets[i] = *NewTargetFromV2(&v2targets[i])
r.targets[i] = *NewTargetFromV2(v2targets[i])
}
r.filters = make([]Filter, len(v2filters))
for i := range v2filters {
r.filters[i] = *NewFilterFromV2(&v2filters[i])
r.filters[i] = *NewFilterFromV2(v2filters[i])
}
return r
@ -244,8 +247,8 @@ func (r *Record) Marshal() ([]byte, error) {
// Unmarshal unmarshals protobuf binary representation of Record.
func (r *Record) Unmarshal(data []byte) error {
fV2 := new(v2acl.Record)
if err := fV2.Unmarshal(data); err != nil {
fV2 := new(aclgrpc.EACLRecord)
if err := proto.Unmarshal(data, fV2); err != nil {
return err
}
@ -256,13 +259,17 @@ func (r *Record) Unmarshal(data []byte) error {
// MarshalJSON encodes Record to protobuf JSON format.
func (r *Record) MarshalJSON() ([]byte, error) {
return r.ToV2().MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
r.ToV2(),
)
}
// UnmarshalJSON decodes Record from protobuf JSON format.
func (r *Record) UnmarshalJSON(data []byte) error {
tV2 := new(v2acl.Record)
if err := tV2.UnmarshalJSON(data); err != nil {
tV2 := new(aclgrpc.EACLRecord)
if err := protojson.Unmarshal(data, tV2); err != nil {
return err
}

View file

@ -5,7 +5,8 @@ import (
"fmt"
"testing"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
checksumtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum/test"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
@ -29,8 +30,8 @@ func TestRecord(t *testing.T) {
v2 := record.ToV2()
require.NotNil(t, v2)
require.Equal(t, v2acl.OperationRange, v2.GetOperation())
require.Equal(t, v2acl.ActionAllow, v2.GetAction())
require.Equal(t, aclgrpc.Operation_GETRANGE, v2.GetOperation())
require.Equal(t, aclgrpc.Action_ALLOW, v2.GetAction())
require.Len(t, v2.GetFilters(), len(record.Filters()))
require.Len(t, v2.GetTargets(), len(record.Targets()))
@ -123,7 +124,7 @@ func TestRecordEncoding(t *testing.T) {
})
}
func TestRecord_ToV2(t *testing.T) {
func TestRecord_ToProtobuf(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *Record
@ -142,8 +143,8 @@ func TestRecord_ToV2(t *testing.T) {
// convert to v2 message
recordV2 := record.ToV2()
require.Equal(t, v2acl.OperationUnknown, recordV2.GetOperation())
require.Equal(t, v2acl.ActionUnknown, recordV2.GetAction())
require.Equal(t, aclgrpc.Operation_OPERATION_UNSPECIFIED, recordV2.GetOperation())
require.Equal(t, aclgrpc.Action_ACTION_UNSPECIFIED, recordV2.GetAction())
require.Nil(t, recordV2.GetTargets())
require.Nil(t, recordV2.GetFilters())
})
@ -170,43 +171,43 @@ func TestReservedRecords(t *testing.T) {
value: "bar",
},
{
f: func(r *Record) { r.AddObjectVersionFilter(MatchStringEqual, &v) },
key: v2acl.FilterObjectVersion,
f: func(r *Record) { r.AddObjectVersionFilter(MatchStringEqual, v) },
key: acl.FilterObjectVersion,
value: v.String(),
},
{
f: func(r *Record) { r.AddObjectIDFilter(MatchStringEqual, oid) },
key: v2acl.FilterObjectID,
key: acl.FilterObjectID,
value: oid.EncodeToString(),
},
{
f: func(r *Record) { r.AddObjectContainerIDFilter(MatchStringEqual, cid) },
key: v2acl.FilterObjectContainerID,
key: acl.FilterObjectContainerID,
value: cid.EncodeToString(),
},
{
f: func(r *Record) { r.AddObjectOwnerIDFilter(MatchStringEqual, ownerid) },
key: v2acl.FilterObjectOwnerID,
key: acl.FilterObjectOwnerID,
value: ownerid.EncodeToString(),
},
{
f: func(r *Record) { r.AddObjectCreationEpoch(MatchStringEqual, 100) },
key: v2acl.FilterObjectCreationEpoch,
key: acl.FilterObjectCreationEpoch,
value: "100",
},
{
f: func(r *Record) { r.AddObjectPayloadLengthFilter(MatchStringEqual, 5000) },
key: v2acl.FilterObjectPayloadLength,
key: acl.FilterObjectPayloadLength,
value: "5000",
},
{
f: func(r *Record) { r.AddObjectPayloadHashFilter(MatchStringEqual, h) },
key: v2acl.FilterObjectPayloadHash,
key: acl.FilterObjectPayloadHash,
value: h.String(),
},
{
f: func(r *Record) { r.AddObjectHomomorphicHashFilter(MatchStringEqual, h) },
key: v2acl.FilterObjectHomomorphicHash,
key: acl.FilterObjectHomomorphicHash,
value: h.String(),
},
{
@ -214,7 +215,7 @@ func TestReservedRecords(t *testing.T) {
require.True(t, typ.FromString("REGULAR"))
r.AddObjectTypeFilter(MatchStringEqual, *typ)
},
key: v2acl.FilterObjectType,
key: acl.FilterObjectType,
value: "REGULAR",
},
{
@ -222,7 +223,7 @@ func TestReservedRecords(t *testing.T) {
require.True(t, typ.FromString("TOMBSTONE"))
r.AddObjectTypeFilter(MatchStringEqual, *typ)
},
key: v2acl.FilterObjectType,
key: acl.FilterObjectType,
value: "TOMBSTONE",
},
{
@ -230,7 +231,7 @@ func TestReservedRecords(t *testing.T) {
require.True(t, typ.FromString("STORAGE_GROUP"))
r.AddObjectTypeFilter(MatchStringEqual, *typ)
},
key: v2acl.FilterObjectType,
key: acl.FilterObjectType,
value: "STORAGE_GROUP",
},
}

View file

@ -4,10 +4,13 @@ import (
"crypto/sha256"
"fmt"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Table is a group of ContainerEACL records for single container.
@ -20,7 +23,7 @@ type Table struct {
}
// CID returns identifier of the container that should use given access control rules.
func (t Table) CID() (cID cid.ID, isSet bool) {
func (t *Table) CID() (cID cid.ID, isSet bool) {
if t.cid != nil {
cID = *t.cid
isSet = true
@ -35,7 +38,7 @@ func (t *Table) SetCID(cid cid.ID) {
}
// Version returns version of eACL format.
func (t Table) Version() version.Version {
func (t *Table) Version() version.Version {
return t.version
}
@ -59,31 +62,31 @@ func (t *Table) AddRecord(r *Record) {
// ToV2 converts Table to v2 acl.EACLTable message.
//
// Nil Table converts to nil.
func (t *Table) ToV2() *v2acl.Table {
func (t *Table) ToV2() *aclgrpc.EACLTable {
if t == nil {
return nil
}
v2 := new(v2acl.Table)
var cidV2 refs.ContainerID
v2 := new(aclgrpc.EACLTable)
var cidV2 refsgrpc.ContainerID
if t.cid != nil {
t.cid.WriteToV2(&cidV2)
v2.SetContainerID(&cidV2)
v2.SetContainerId(&cidV2)
}
if t.records != nil {
records := make([]v2acl.Record, len(t.records))
records := slices.MakePreallocPointerSlice[aclgrpc.EACLRecord](len(t.records))
for i := range t.records {
records[i] = *t.records[i].ToV2()
records[i] = t.records[i].ToV2()
}
v2.SetRecords(records)
}
var verV2 refs.Version
t.version.WriteToV2(&verV2)
v2.SetVersion(&verV2)
verV2 := new(refsgrpc.Version)
t.version.WriteToV2(verV2)
v2.SetVersion(verV2)
return v2
}
@ -112,7 +115,7 @@ func CreateTable(cid cid.ID) *Table {
}
// NewTableFromV2 converts v2 acl.EACLTable message to Table.
func NewTableFromV2(table *v2acl.Table) *Table {
func NewTableFromV2(table *aclgrpc.EACLTable) *Table {
t := new(Table)
if table == nil {
@ -121,7 +124,7 @@ func NewTableFromV2(table *v2acl.Table) *Table {
// set version
if v := table.GetVersion(); v != nil {
ver := version.Version{}
ver := version.NewVersion()
ver.SetMajor(v.GetMajor())
ver.SetMinor(v.GetMinor())
@ -129,7 +132,7 @@ func NewTableFromV2(table *v2acl.Table) *Table {
}
// set container id
if id := table.GetContainerID(); id != nil {
if id := table.GetContainerId(); id != nil {
if t.cid == nil {
t.cid = new(cid.ID)
}
@ -145,7 +148,7 @@ func NewTableFromV2(table *v2acl.Table) *Table {
t.records = make([]Record, len(v2records))
for i := range v2records {
t.records[i] = *NewRecordFromV2(&v2records[i])
t.records[i] = *NewRecordFromV2(v2records[i])
}
return t
@ -158,8 +161,8 @@ func (t *Table) Marshal() ([]byte, error) {
// Unmarshal unmarshals protobuf binary representation of Table.
func (t *Table) Unmarshal(data []byte) error {
fV2 := new(v2acl.Table)
if err := fV2.Unmarshal(data); err != nil {
fV2 := new(aclgrpc.EACLTable)
if err := proto.Unmarshal(data, fV2); err != nil {
return err
}
@ -176,13 +179,17 @@ func (t *Table) Unmarshal(data []byte) error {
// MarshalJSON encodes Table to protobuf JSON format.
func (t *Table) MarshalJSON() ([]byte, error) {
return t.ToV2().MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
t.ToV2(),
)
}
// UnmarshalJSON decodes Table from protobuf JSON format.
func (t *Table) UnmarshalJSON(data []byte) error {
tV2 := new(v2acl.Table)
if err := tV2.UnmarshalJSON(data); err != nil {
tV2 := new(aclgrpc.EACLTable)
if err := protojson.Unmarshal(data, tV2); err != nil {
return err
}
@ -221,15 +228,15 @@ func EqualTables(t1, t2 Table) bool {
return true
}
func checkFormat(v2 *v2acl.Table) error {
func checkFormat(v2 *aclgrpc.EACLTable) error {
var cID cid.ID
cidV2 := v2.GetContainerID()
cidV2 := v2.GetContainerId()
if cidV2 == nil {
return nil
}
err := cID.ReadFromV2(*cidV2)
err := cID.ReadFromV2(cidV2)
if err != nil {
return fmt.Errorf("could not convert V2 container ID: %w", err)
}

View file

@ -4,16 +4,17 @@ import (
"crypto/sha256"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl"
eacltest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/eacl/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/require"
)
func TestTable(t *testing.T) {
var v version.Version
v := version.NewVersion()
sha := sha256.Sum256([]byte("container id"))
id := cidtest.IDWithChecksum(sha)
@ -30,11 +31,11 @@ func TestTable(t *testing.T) {
require.NotNil(t, v2)
require.Equal(t, uint32(3), v2.GetVersion().GetMajor())
require.Equal(t, uint32(2), v2.GetVersion().GetMinor())
require.Equal(t, sha[:], v2.GetContainerID().GetValue())
require.Equal(t, sha[:], v2.GetContainerId().GetValue())
require.Len(t, v2.GetRecords(), 1)
newTable := eacl.NewTableFromV2(v2)
require.Equal(t, table, newTable)
require.True(t, proto.Equal(table.ToV2(), newTable.ToV2()))
t.Run("new from nil v2 table", func(t *testing.T) {
require.Equal(t, new(eacl.Table), eacl.NewTableFromV2(nil))
@ -110,10 +111,10 @@ func TestTable_ToV2(t *testing.T) {
// convert to v2 message
tableV2 := table.ToV2()
var verV2 refs.Version
var verV2 refsgrpc.Version
version.Current().WriteToV2(&verV2)
require.Equal(t, verV2, *tableV2.GetVersion())
require.True(t, proto.Equal(&verV2, tableV2.GetVersion()))
require.Nil(t, tableV2.GetRecords())
require.Nil(t, tableV2.GetContainerID())
require.Nil(t, tableV2.GetContainerId())
})
}

View file

@ -4,8 +4,10 @@ import (
"bytes"
"crypto/ecdsa"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"github.com/golang/protobuf/proto"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"google.golang.org/protobuf/encoding/protojson"
)
// Target is a group of request senders to match ContainerEACL. Defined by role enum
@ -90,12 +92,12 @@ func (t Target) Role() Role {
// ToV2 converts Target to v2 acl.EACLRecord.Target message.
//
// Nil Target converts to nil.
func (t *Target) ToV2() *v2acl.Target {
func (t *Target) ToV2() *aclgrpc.EACLRecord_Target {
if t == nil {
return nil
}
target := new(v2acl.Target)
target := new(aclgrpc.EACLRecord_Target)
target.SetRole(t.role.ToV2())
target.SetKeys(t.keys)
@ -108,11 +110,11 @@ func (t *Target) ToV2() *v2acl.Target {
// - role: RoleUnknown;
// - keys: nil.
func NewTarget() *Target {
return NewTargetFromV2(new(v2acl.Target))
return NewTargetFromV2(new(aclgrpc.EACLRecord_Target))
}
// NewTargetFromV2 converts v2 acl.EACLRecord.Target message to Target.
func NewTargetFromV2(target *v2acl.Target) *Target {
func NewTargetFromV2(target *aclgrpc.EACLRecord_Target) *Target {
if target == nil {
return new(Target)
}
@ -130,8 +132,8 @@ func (t *Target) Marshal() ([]byte, error) {
// Unmarshal unmarshals protobuf binary representation of Target.
func (t *Target) Unmarshal(data []byte) error {
fV2 := new(v2acl.Target)
if err := fV2.Unmarshal(data); err != nil {
fV2 := new(aclgrpc.EACLRecord_Target)
if err := proto.Unmarshal(data, fV2); err != nil {
return err
}
@ -142,13 +144,17 @@ func (t *Target) Unmarshal(data []byte) error {
// MarshalJSON encodes Target to protobuf JSON format.
func (t *Target) MarshalJSON() ([]byte, error) {
return t.ToV2().MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
t.ToV2(),
)
}
// UnmarshalJSON decodes Target from protobuf JSON format.
func (t *Target) UnmarshalJSON(data []byte) error {
tV2 := new(v2acl.Target)
if err := tV2.UnmarshalJSON(data); err != nil {
tV2 := new(aclgrpc.EACLRecord_Target)
if err := protojson.Unmarshal(data, tV2); err != nil {
return err
}

View file

@ -4,7 +4,7 @@ import (
"crypto/ecdsa"
"testing"
v2acl "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl"
aclgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/acl/grpc"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/stretchr/testify/require"
)
@ -21,7 +21,7 @@ func TestTarget(t *testing.T) {
v2 := target.ToV2()
require.NotNil(t, v2)
require.Equal(t, v2acl.RoleSystem, v2.GetRole())
require.Equal(t, aclgrpc.Role_SYSTEM, v2.GetRole())
require.Len(t, v2.GetKeys(), len(pubs))
for i, key := range v2.GetKeys() {
require.Equal(t, key, (*keys.PublicKey)(pubs[i]).Bytes())
@ -78,7 +78,7 @@ func TestTarget_ToV2(t *testing.T) {
// convert to v2 message
targetV2 := target.ToV2()
require.Equal(t, v2acl.RoleUnknown, targetV2.GetRole())
require.Equal(t, aclgrpc.Role_ROLE_UNSPECIFIED, targetV2.GetRole())
require.Nil(t, targetV2.GetKeys())
})
}

View file

@ -6,8 +6,8 @@ import (
// Header is an interface of string key-value header.
type Header interface {
Key() string
Value() string
GetKey() string
GetValue() string
}
// TypedHeaderSource is the interface that wraps

View file

@ -71,7 +71,7 @@ func matchFilters(hdrSrc TypedHeaderSource, filters []Filter) int {
}
// check header name
if header.Key() != filter.Key() {
if header.GetKey() != filter.Key() {
continue
}
@ -122,10 +122,10 @@ func targetMatches(unit *ValidationUnit, record *Record) bool {
// Maps match type to corresponding function.
var mMatchFns = map[Match]func(Header, *Filter) bool{
MatchStringEqual: func(header Header, filter *Filter) bool {
return header.Value() == filter.Value()
return header.GetValue() == filter.Value()
},
MatchStringNotEqual: func(header Header, filter *Filter) bool {
return header.Value() != filter.Value()
return header.GetValue() != filter.Value()
},
}

View file

@ -214,8 +214,8 @@ type (
}
)
func (h hdr) Key() string { return h.key }
func (h hdr) Value() string { return h.value }
func (h hdr) GetKey() string { return h.key }
func (h hdr) GetValue() string { return h.value }
func makeHeaders(kv ...string) []Header {
hs := make([]Header, len(kv)/2)

4
go.mod
View file

@ -2,6 +2,8 @@ module git.frostfs.info/TrueCloudLab/frostfs-sdk-go
go 1.19
replace git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230704092742-285516a94ebe => git.frostfs.info/aarifullin/frostfs-api-go/v2 v2.15.1-0.20230710090848-bc16a32c24c3
require (
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230704092742-285516a94ebe
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb
@ -9,6 +11,7 @@ require (
git.frostfs.info/TrueCloudLab/hrw v1.2.1
git.frostfs.info/TrueCloudLab/tzhash v1.8.0
github.com/antlr4-go/antlr/v4 v4.13.0
github.com/golang/protobuf v1.5.3
github.com/google/uuid v1.3.0
github.com/hashicorp/golang-lru/v2 v2.0.2
github.com/mr-tron/base58 v1.2.0
@ -24,7 +27,6 @@ require (
github.com/benbjohnson/clock v1.1.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/golang-lru v0.6.0 // indirect
github.com/nspcc-dev/go-ordered-json v0.0.0-20220111165707-25110be27d22 // indirect

4
go.sum
View file

@ -31,8 +31,6 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230704092742-285516a94ebe h1:SB102RiEg+4h9qcwyG97zHBtwduMRbedbtkwRDVSps8=
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.15.1-0.20230704092742-285516a94ebe/go.mod h1:pKJJRLOChW4zDQsAt1e8k/snWKljJtpkiPfxV53ngjI=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb h1:S/TrbOOu9qEXZRZ9/Ddw7crnxbBUQLo68PSzQWYrc9M=
git.frostfs.info/TrueCloudLab/frostfs-contract v0.0.0-20230307110621-19a8ef2d02fb/go.mod h1:nkR5gaGeez3Zv2SE7aceP0YwxG2FzIB5cGKpQO2vV2o=
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
@ -43,6 +41,8 @@ git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0 h1:M2KR3iBj7WpY3hP10IevfIB9MURr4O9m
git.frostfs.info/TrueCloudLab/rfc6979 v0.4.0/go.mod h1:okpbKfVYf/BpejtfFTfhZqFP+sZ8rsHrP8Rr/jYPNRc=
git.frostfs.info/TrueCloudLab/tzhash v1.8.0 h1:UFMnUIk0Zh17m8rjGHJMqku2hCgaXDqjqZzS4gsb4UA=
git.frostfs.info/TrueCloudLab/tzhash v1.8.0/go.mod h1:dhY+oy274hV8wGvGL4MwwMpdL3GYvaX1a8GQZQHvlF8=
git.frostfs.info/aarifullin/frostfs-api-go/v2 v2.15.1-0.20230710090848-bc16a32c24c3 h1:QuPPpzIaS6GGKgwDnhMLKjgS9iHO6e/3sQtFIUX0LMc=
git.frostfs.info/aarifullin/frostfs-api-go/v2 v2.15.1-0.20230710090848-bc16a32c24c3/go.mod h1:pKJJRLOChW4zDQsAt1e8k/snWKljJtpkiPfxV53ngjI=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CityOfZion/neo-go v0.62.1-pre.0.20191114145240-e740fbe708f8/go.mod h1:MJCkWUBhi9pn/CrYO1Q3P687y2KeahrOPS9BD9LDGb0=

View file

@ -40,7 +40,7 @@ type (
}
// weightFunc calculates n's weight.
weightFunc = func(NodeInfo) float64
weightFunc = func(*NodeInfo) float64
)
var (
@ -55,7 +55,7 @@ var (
// newWeightFunc returns weightFunc which multiplies normalized
// capacity and price.
func newWeightFunc(capNorm, priceNorm normalizer) weightFunc {
return func(n NodeInfo) float64 {
return func(n *NodeInfo) float64 {
return capNorm.Normalize(float64(n.capacity())) * priceNorm.Normalize(float64(n.Price()))
}
}

View file

@ -3,7 +3,7 @@ package netmap
import (
"errors"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/hrw"
)
@ -13,10 +13,10 @@ type context struct {
netMap NetMap
// cache of processed filters
processedFilters map[string]*netmap.Filter
processedFilters map[string]*netmapgrpc.Filter
// cache of processed selectors
processedSelectors map[string]*netmap.Selector
processedSelectors map[string]*netmapgrpc.Selector
// stores results of selector processing
selections map[string][]nodes
@ -57,8 +57,8 @@ var (
func newContext(nm NetMap) *context {
return &context{
netMap: nm,
processedFilters: make(map[string]*netmap.Filter),
processedSelectors: make(map[string]*netmap.Selector),
processedFilters: make(map[string]*netmapgrpc.Filter),
processedSelectors: make(map[string]*netmapgrpc.Selector),
selections: make(map[string][]nodes),
numCache: make(map[string]uint64),

View file

@ -4,7 +4,7 @@ import (
"fmt"
"strconv"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
)
// mainFilterName is a name of the filter
@ -22,7 +22,7 @@ func (c *context) processFilters(p PlacementPolicy) error {
return nil
}
func (c *context) processFilter(f netmap.Filter, top bool) error {
func (c *context) processFilter(f *netmapgrpc.Filter, top bool) error {
fName := f.GetName()
if fName == mainFilterName {
return fmt.Errorf("%w: '%s' is reserved", errInvalidFilterName, mainFilterName)
@ -39,7 +39,7 @@ func (c *context) processFilter(f netmap.Filter, top bool) error {
inner := f.GetFilters()
switch op := f.GetOp(); op {
case netmap.AND, netmap.OR, netmap.NOT:
case netmapgrpc.Operation_AND, netmapgrpc.Operation_OR, netmapgrpc.Operation_NOT:
for i := range inner {
if err := c.processFilter(inner[i], false); err != nil {
return fmt.Errorf("process inner filter #%d: %w", i, err)
@ -53,8 +53,8 @@ func (c *context) processFilter(f netmap.Filter, top bool) error {
}
switch op {
case netmap.EQ, netmap.NE:
case netmap.GT, netmap.GE, netmap.LT, netmap.LE:
case netmapgrpc.Operation_EQ, netmapgrpc.Operation_NE:
case netmapgrpc.Operation_GT, netmapgrpc.Operation_GE, netmapgrpc.Operation_LT, netmapgrpc.Operation_LE:
val := f.GetValue()
n, err := strconv.ParseUint(val, 10, 64)
if err != nil {
@ -68,7 +68,7 @@ func (c *context) processFilter(f netmap.Filter, top bool) error {
}
if top {
c.processedFilters[fName] = &f
c.processedFilters[fName] = f
}
return nil
@ -77,40 +77,40 @@ func (c *context) processFilter(f netmap.Filter, top bool) error {
// match matches f against b. It returns no errors because
// filter should have been parsed during context creation
// and missing node properties are considered as a regular fail.
func (c *context) match(f *netmap.Filter, b NodeInfo) bool {
func (c *context) match(f *netmapgrpc.Filter, b *NodeInfo) bool {
switch f.GetOp() {
case netmap.NOT:
case netmapgrpc.Operation_NOT:
inner := f.GetFilters()
fSub := &inner[0]
fSub := inner[0]
if name := inner[0].GetName(); name != "" {
fSub = c.processedFilters[name]
}
return !c.match(fSub, b)
case netmap.AND, netmap.OR:
case netmapgrpc.Operation_AND, netmapgrpc.Operation_OR:
inner := f.GetFilters()
for i := range inner {
fSub := &inner[i]
fSub := inner[i]
if name := inner[i].GetName(); name != "" {
fSub = c.processedFilters[name]
}
ok := c.match(fSub, b)
if ok == (f.GetOp() == netmap.OR) {
if ok == (f.GetOp() == netmapgrpc.Operation_OR) {
return ok
}
}
return f.GetOp() == netmap.AND
return f.GetOp() == netmapgrpc.Operation_AND
default:
return c.matchKeyValue(f, b)
}
}
func (c *context) matchKeyValue(f *netmap.Filter, b NodeInfo) bool {
func (c *context) matchKeyValue(f *netmapgrpc.Filter, b *NodeInfo) bool {
switch op := f.GetOp(); op {
case netmap.EQ:
case netmapgrpc.Operation_EQ:
return b.Attribute(f.GetKey()) == f.GetValue()
case netmap.NE:
case netmapgrpc.Operation_NE:
return b.Attribute(f.GetKey()) != f.GetValue()
default:
var attr uint64
@ -132,13 +132,13 @@ func (c *context) matchKeyValue(f *netmap.Filter, b NodeInfo) bool {
}
switch op {
case netmap.GT:
case netmapgrpc.Operation_GT:
return attr > c.numCache[f.GetValue()]
case netmap.GE:
case netmapgrpc.Operation_GE:
return attr >= c.numCache[f.GetValue()]
case netmap.LT:
case netmapgrpc.Operation_LT:
return attr < c.numCache[f.GetValue()]
case netmap.LE:
case netmapgrpc.Operation_LE:
return attr <= c.numCache[f.GetValue()]
default:
// do nothing and return false

View file

@ -4,17 +4,18 @@ import (
"errors"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"github.com/golang/protobuf/proto"
"github.com/stretchr/testify/require"
)
func TestContext_ProcessFilters(t *testing.T) {
fs := []Filter{
newFilter("StorageSSD", "Storage", "SSD", netmap.EQ),
newFilter("GoodRating", "Rating", "4", netmap.GE),
newFilter("Main", "", "", netmap.AND,
newFilter("StorageSSD", "Storage", "SSD", netmapgrpc.Operation_EQ),
newFilter("GoodRating", "Rating", "4", netmapgrpc.Operation_GE),
newFilter("Main", "", "", netmapgrpc.Operation_AND,
newFilter("StorageSSD", "", "", 0),
newFilter("", "IntField", "123", netmap.LT),
newFilter("", "IntField", "123", netmapgrpc.Operation_LT),
newFilter("GoodRating", "", "", 0)),
}
@ -23,7 +24,7 @@ func TestContext_ProcessFilters(t *testing.T) {
require.NoError(t, c.processFilters(p))
require.Equal(t, 3, len(c.processedFilters))
for _, f := range fs {
require.Equal(t, f.m, *c.processedFilters[f.m.GetName()])
require.True(t, proto.Equal(f.m, c.processedFilters[f.m.GetName()]))
}
require.Equal(t, uint64(4), c.numCache[fs[1].m.GetValue()])
@ -38,24 +39,24 @@ func TestContext_ProcessFiltersInvalid(t *testing.T) {
}{
{
"UnnamedTop",
newFilter("", "Storage", "SSD", netmap.EQ),
newFilter("", "Storage", "SSD", netmapgrpc.Operation_EQ),
errUnnamedTopFilter,
},
{
"InvalidReference",
newFilter("Main", "", "", netmap.AND,
newFilter("Main", "", "", netmapgrpc.Operation_AND,
newFilter("StorageSSD", "", "", 0)),
errFilterNotFound,
},
{
"NonEmptyKeyed",
newFilter("Main", "Storage", "SSD", netmap.EQ,
newFilter("Main", "Storage", "SSD", netmapgrpc.Operation_EQ,
newFilter("StorageSSD", "", "", 0)),
errNonEmptyFilters,
},
{
"InvalidNumber",
newFilter("Main", "Rating", "three", netmap.GE),
newFilter("Main", "Rating", "three", netmapgrpc.Operation_GE),
errInvalidNumber,
},
{
@ -65,7 +66,7 @@ func TestContext_ProcessFiltersInvalid(t *testing.T) {
},
{
"InvalidName",
newFilter("*", "Rating", "3", netmap.GE),
newFilter("*", "Rating", "3", netmapgrpc.Operation_GE),
errInvalidFilterName,
},
}
@ -80,16 +81,16 @@ func TestContext_ProcessFiltersInvalid(t *testing.T) {
}
func TestFilter_MatchSimple_InvalidOp(t *testing.T) {
var b NodeInfo
b := NewNodeInfo()
b.SetAttribute("Rating", "4")
b.SetAttribute("Country", "Germany")
f := newFilter("Main", "Rating", "5", netmap.EQ)
f := newFilter("Main", "Rating", "5", netmapgrpc.Operation_EQ)
c := newContext(NetMap{})
p := newPlacementPolicy(1, nil, nil, []Filter{f})
require.NoError(t, c.processFilters(p))
// just for the coverage
f.m.SetOp(0)
require.False(t, c.match(&f.m, b))
require.False(t, c.match(f.m, &b))
}

View file

@ -1,23 +1,28 @@
package netmap
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"github.com/golang/protobuf/proto"
)
func newFilter(name string, k, v string, op netmap.Operation, fs ...Filter) (f Filter) {
func newFilter(name string, k, v string, op netmapgrpc.Operation, fs ...Filter) (f Filter) {
f = NewFilter()
f.SetName(name)
f.m.SetKey(k)
f.m.SetOp(op)
f.m.SetValue(v)
inner := make([]netmap.Filter, len(fs))
inner := slices.MakePreallocPointerSlice[netmapgrpc.Filter](len(fs))
for i := range fs {
inner[i] = fs[i].m
inner[i] = new(netmapgrpc.Filter)
proto.Merge(inner[i], fs[i].m)
}
f.m.SetFilters(inner)
return f
}
func newSelector(name string, attr string, count uint32, filter string, clause func(*Selector)) (s Selector) {
s = NewSelector()
s.SetName(name)
s.SelectByBucketAttribute(attr)
s.SetNumberOfNodes(count)
@ -35,12 +40,14 @@ func newPlacementPolicy(bf uint32, rs []ReplicaDescriptor, ss []Selector, fs []F
}
func newReplica(c uint32, s string) (r ReplicaDescriptor) {
r = NewReplicaDescriptor()
r.SetNumberOfObjects(c)
r.SetSelectorName(s)
return r
}
func nodeInfoFromAttributes(props ...string) (n NodeInfo) {
n = NewNodeInfo()
for i := 0; i < len(props); i += 2 {
n.SetAttribute(props[i], props[i+1])
}

View file

@ -3,14 +3,15 @@ package netmap
import (
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"git.frostfs.info/TrueCloudLab/hrw"
)
// NetMap represents FrostFS network map. It includes information about all
// storage nodes registered in FrostFS the network.
//
// NetMap is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.NetMap
// NetMap is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmapgrpc.Netmap
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
@ -20,13 +21,13 @@ type NetMap struct {
nodes []NodeInfo
}
// ReadFromV2 reads NetMap from the netmap.NetMap message. Checks if the
// ReadFromV2 reads NetMap from the netmapgrpc.Netmap message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (m *NetMap) ReadFromV2(msg netmap.NetMap) error {
func (m *NetMap) ReadFromV2(msg *netmapgrpc.Netmap) error {
var err error
nodes := msg.Nodes()
nodes := msg.GetNodes()
if nodes == nil {
m.nodes = nil
@ -41,23 +42,23 @@ func (m *NetMap) ReadFromV2(msg netmap.NetMap) error {
}
}
m.epoch = msg.Epoch()
m.epoch = msg.GetEpoch()
return nil
}
// WriteToV2 writes NetMap to the netmap.NetMap message. The message
// WriteToV2 writes NetMap to the netmapgrpc.Netmap message. The message
// MUST NOT be nil.
//
// See also ReadFromV2.
func (m NetMap) WriteToV2(msg *netmap.NetMap) {
var nodes []netmap.NodeInfo
func (m NetMap) WriteToV2(msg *netmapgrpc.Netmap) {
msg.Reset()
var nodes []*netmapgrpc.NodeInfo
if m.nodes != nil {
nodes = make([]netmap.NodeInfo, len(m.nodes))
nodes = slices.MakePreallocPointerSlice[netmapgrpc.NodeInfo](len(m.nodes))
for i := range m.nodes {
m.nodes[i].WriteToV2(&nodes[i])
m.nodes[i].WriteToV2(nodes[i])
}
msg.SetNodes(nodes)
@ -117,7 +118,7 @@ func (n nodes) Hash() uint64 {
func (n nodes) weights(wf weightFunc) []float64 {
w := make([]float64, 0, len(n))
for i := range n {
w = append(w, wf(n[i]))
w = append(w, wf(&n[i]))
}
return w
@ -189,11 +190,11 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, pivot []byte) ([][]NodeInfo, e
sName := p.replicas[i].GetSelector()
if sName == "" {
if len(p.selectors) == 0 {
var s netmap.Selector
var s netmapgrpc.Selector
s.SetCount(p.replicas[i].GetCount())
s.SetFilter(mainFilterName)
nodes, err := c.getSelection(s)
nodes, err := c.getSelection(&s)
if err != nil {
return nil, err
}
@ -221,7 +222,7 @@ func (m NetMap) ContainerNodes(p PlacementPolicy, pivot []byte) ([][]NodeInfo, e
}
if p.unique {
nodes, err := c.getSelection(*c.processedSelectors[sName])
nodes, err := c.getSelection(c.processedSelectors[sName])
if err != nil {
return nil, err
}

View file

@ -3,9 +3,10 @@ package netmap_test
import (
"testing"
v2netmap "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"github.com/stretchr/testify/require"
)
@ -19,15 +20,16 @@ func TestNetMapNodes(t *testing.T) {
nm.SetNodes(nodes)
require.ElementsMatch(t, nodes, nm.Nodes())
nodesV2 := make([]v2netmap.NodeInfo, len(nodes))
nodesV2 := slices.MakePreallocPointerSlice[netmapgrpc.NodeInfo](len(nodes))
for i := range nodes {
nodes[i].WriteToV2(&nodesV2[i])
nodes[i].WriteToV2(nodesV2[i])
}
var m v2netmap.NetMap
var m netmapgrpc.Netmap
nm.WriteToV2(&m)
require.ElementsMatch(t, nodesV2, m.Nodes())
require.ElementsMatch(t, nodesV2, m.GetNodes())
}
func TestNetMap_SetEpoch(t *testing.T) {
@ -40,8 +42,8 @@ func TestNetMap_SetEpoch(t *testing.T) {
nm.SetEpoch(e)
require.EqualValues(t, e, nm.Epoch())
var m v2netmap.NetMap
var m netmapgrpc.Netmap
nm.WriteToV2(&m)
require.EqualValues(t, e, m.Epoch())
require.EqualValues(t, e, m.GetEpoch())
}

View file

@ -6,25 +6,32 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"github.com/golang/protobuf/proto"
"github.com/nspcc-dev/neo-go/pkg/vm/stackitem"
)
// NetworkInfo groups information about the FrostFS network state. Mainly used to
// describe the current state of the network.
//
// NetworkInfo is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.NetworkInfo
// NetworkInfo is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmapgrpc.NetworkInfo
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
// Instances must be created by NewNetworkInfo() constructor.
type NetworkInfo struct {
m netmap.NetworkInfo
m *netmapgrpc.NetworkInfo
}
// reads NetworkInfo from netmap.NetworkInfo message. If checkFieldPresence is set,
func NewNetworkInfo() NetworkInfo {
return NetworkInfo{
m: &netmapgrpc.NetworkInfo{},
}
}
// reads NetworkInfo from netmapgrpc.NetworkInfo message. If checkFieldPresence is set,
// returns an error on absence of any protocol-required field. Verifies format of any
// presented field according to FrostFS API V2 protocol.
func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool) error {
func (x *NetworkInfo) readFromV2(m *netmapgrpc.NetworkInfo, checkFieldPresence bool) error {
c := m.GetNetworkConfig()
if checkFieldPresence && c == nil {
return errors.New("missing network config")
@ -37,7 +44,7 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool)
var err error
mNames := make(map[string]struct{}, c.NumberOfParameters())
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
c.IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) bool {
name := string(prm.GetKey())
_, was := mNames[name]
@ -80,25 +87,29 @@ func (x *NetworkInfo) readFromV2(m netmap.NetworkInfo, checkFieldPresence bool)
return err
}
x.m = m
if x.m == nil {
x.m = new(netmapgrpc.NetworkInfo)
}
proto.Merge(x.m, m)
return nil
}
// ReadFromV2 reads NetworkInfo from the netmap.NetworkInfo message. Checks if the
// ReadFromV2 reads NetworkInfo from the netmapgrpc.NetworkInfo message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *NetworkInfo) ReadFromV2(m netmap.NetworkInfo) error {
func (x *NetworkInfo) ReadFromV2(m *netmapgrpc.NetworkInfo) error {
return x.readFromV2(m, true)
}
// WriteToV2 writes NetworkInfo to the netmap.NetworkInfo message. The message
// WriteToV2 writes NetworkInfo to the netmapgrpc.NetworkInfo message. The message
// MUST NOT be nil.
//
// See also ReadFromV2.
func (x NetworkInfo) WriteToV2(m *netmap.NetworkInfo) {
*m = x.m
func (x *NetworkInfo) WriteToV2(m *netmapgrpc.NetworkInfo) {
m.Reset()
proto.Merge(m, x.m)
}
// CurrentEpoch returns epoch set using SetCurrentEpoch.
@ -116,7 +127,7 @@ func (x *NetworkInfo) SetCurrentEpoch(epoch uint64) {
// MagicNumber returns magic number set using SetMagicNumber.
//
// Zero NetworkInfo has zero magic.
func (x NetworkInfo) MagicNumber() uint64 {
func (x *NetworkInfo) MagicNumber() uint64 {
return x.m.GetMagicNumber()
}
@ -128,7 +139,7 @@ func (x *NetworkInfo) SetMagicNumber(epoch uint64) {
}
// MsPerBlock returns network parameter set using SetMsPerBlock.
func (x NetworkInfo) MsPerBlock() int64 {
func (x *NetworkInfo) MsPerBlock() int64 {
return x.m.GetMsPerBlock()
}
@ -142,13 +153,13 @@ func (x *NetworkInfo) SetMsPerBlock(v int64) {
func (x *NetworkInfo) setConfig(name string, val []byte) {
c := x.m.GetNetworkConfig()
if c == nil {
c = new(netmap.NetworkConfig)
c = new(netmapgrpc.NetworkConfig)
var prm netmap.NetworkParameter
var prm netmapgrpc.NetworkConfig_Parameter
prm.SetKey([]byte(name))
prm.SetValue(val)
c.SetParameters(prm)
c.SetParameters([]*netmapgrpc.NetworkConfig_Parameter{&prm})
x.m.SetNetworkConfig(c)
@ -156,30 +167,30 @@ func (x *NetworkInfo) setConfig(name string, val []byte) {
}
found := false
prms := make([]netmap.NetworkParameter, 0, c.NumberOfParameters())
prms := make([]*netmapgrpc.NetworkConfig_Parameter, 0, c.NumberOfParameters())
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
c.IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) bool {
found = bytes.Equal(prm.GetKey(), []byte(name))
if found {
prm.SetValue(val)
} else {
prms = append(prms, *prm)
prms = append(prms, prm)
}
return found
})
if !found {
prms = append(prms, netmap.NetworkParameter{})
prms = append(prms, &netmapgrpc.NetworkConfig_Parameter{})
prms[len(prms)-1].SetKey([]byte(name))
prms[len(prms)-1].SetValue(val)
c.SetParameters(prms...)
c.SetParameters(prms)
}
}
func (x NetworkInfo) configValue(name string) (res []byte) {
x.m.GetNetworkConfig().IterateParameters(func(prm *netmap.NetworkParameter) bool {
func (x *NetworkInfo) configValue(name string) (res []byte) {
x.m.GetNetworkConfig().IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) bool {
if string(prm.GetKey()) == name {
res = prm.GetValue()
@ -221,7 +232,7 @@ func (x *NetworkInfo) RawNetworkParameter(name string) []byte {
func (x *NetworkInfo) IterateRawNetworkParameters(f func(name string, value []byte)) {
c := x.m.GetNetworkConfig()
c.IterateParameters(func(prm *netmap.NetworkParameter) bool {
c.IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) bool {
name := string(prm.GetKey())
switch name {
default:
@ -282,7 +293,7 @@ func decodeConfigValueBool(val []byte) (bool, error) {
return res, nil
}
func (x NetworkInfo) configUint64(name string) uint64 {
func (x *NetworkInfo) configUint64(name string) uint64 {
val := x.configValue(name)
if val == nil {
return 0
@ -298,7 +309,7 @@ func (x NetworkInfo) configUint64(name string) uint64 {
return res
}
func (x NetworkInfo) configBool(name string) bool {
func (x *NetworkInfo) configBool(name string) bool {
val := x.configValue(name)
if val == nil {
return false
@ -326,7 +337,7 @@ func (x *NetworkInfo) SetAuditFee(fee uint64) {
// AuditFee returns audit fee set using SetAuditFee.
//
// Zero NetworkInfo has zero audit fee.
func (x NetworkInfo) AuditFee() uint64 {
func (x *NetworkInfo) AuditFee() uint64 {
return x.configUint64(configAuditFee)
}
@ -343,7 +354,7 @@ func (x *NetworkInfo) SetStoragePrice(price uint64) {
// StoragePrice returns storage price set using SetStoragePrice.
//
// Zero NetworkInfo has zero storage price.
func (x NetworkInfo) StoragePrice() uint64 {
func (x *NetworkInfo) StoragePrice() uint64 {
return x.configUint64(configStoragePrice)
}
@ -360,7 +371,7 @@ func (x *NetworkInfo) SetContainerFee(fee uint64) {
// ContainerFee returns container fee set using SetContainerFee.
//
// Zero NetworkInfo has zero container fee.
func (x NetworkInfo) ContainerFee() uint64 {
func (x *NetworkInfo) ContainerFee() uint64 {
return x.configUint64(configContainerFee)
}
@ -377,7 +388,7 @@ func (x *NetworkInfo) SetNamedContainerFee(fee uint64) {
// NamedContainerFee returns container fee set using SetNamedContainerFee.
//
// Zero NetworkInfo has zero container fee.
func (x NetworkInfo) NamedContainerFee() uint64 {
func (x *NetworkInfo) NamedContainerFee() uint64 {
return x.configUint64(configNamedContainerFee)
}
@ -394,7 +405,7 @@ func (x *NetworkInfo) SetEpochDuration(blocks uint64) {
// EpochDuration returns epoch duration set using SetEpochDuration.
//
// Zero NetworkInfo has zero iteration number.
func (x NetworkInfo) EpochDuration() uint64 {
func (x *NetworkInfo) EpochDuration() uint64 {
return x.configUint64(configEpochDuration)
}
@ -410,7 +421,7 @@ func (x *NetworkInfo) SetIRCandidateFee(fee uint64) {
// IRCandidateFee returns IR entrance fee set using SetIRCandidateFee.
//
// Zero NetworkInfo has zero fee.
func (x NetworkInfo) IRCandidateFee() uint64 {
func (x *NetworkInfo) IRCandidateFee() uint64 {
return x.configUint64(configIRCandidateFee)
}
@ -480,6 +491,6 @@ func (x *NetworkInfo) AllowMaintenanceMode() {
// maintenance mode for storage nodes.
//
// Zero NetworkInfo has disallows maintenance mode.
func (x NetworkInfo) MaintenanceModeAllowed() bool {
func (x *NetworkInfo) MaintenanceModeAllowed() bool {
return x.configBool(configMaintenanceModeAllowed)
}

View file

@ -4,13 +4,13 @@ import (
"encoding/binary"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
. "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
"github.com/stretchr/testify/require"
)
func TestNetworkInfo_CurrentEpoch(t *testing.T) {
var x NetworkInfo
x := NewNetworkInfo()
require.Zero(t, x.CurrentEpoch())
@ -20,14 +20,14 @@ func TestNetworkInfo_CurrentEpoch(t *testing.T) {
require.EqualValues(t, e, x.CurrentEpoch())
var m netmap.NetworkInfo
var m netmapgrpc.NetworkInfo
x.WriteToV2(&m)
require.EqualValues(t, e, m.GetCurrentEpoch())
}
func TestNetworkInfo_MagicNumber(t *testing.T) {
var x NetworkInfo
x := NewNetworkInfo()
require.Zero(t, x.MagicNumber())
@ -37,14 +37,14 @@ func TestNetworkInfo_MagicNumber(t *testing.T) {
require.EqualValues(t, magic, x.MagicNumber())
var m netmap.NetworkInfo
var m netmapgrpc.NetworkInfo
x.WriteToV2(&m)
require.EqualValues(t, magic, m.GetMagicNumber())
}
func TestNetworkInfo_MsPerBlock(t *testing.T) {
var x NetworkInfo
x := NewNetworkInfo()
require.Zero(t, x.MsPerBlock())
@ -54,7 +54,7 @@ func TestNetworkInfo_MsPerBlock(t *testing.T) {
require.EqualValues(t, ms, x.MsPerBlock())
var m netmap.NetworkInfo
var m netmapgrpc.NetworkInfo
x.WriteToV2(&m)
require.EqualValues(t, ms, m.GetMsPerBlock())
@ -66,19 +66,19 @@ func testConfigValue(t *testing.T,
val1, val2 any,
v2Key string, v2Val func(val any) []byte,
) {
var x NetworkInfo
x := NewNetworkInfo()
require.Zero(t, getter(x))
checkVal := func(exp any) {
require.EqualValues(t, exp, getter(x))
var m netmap.NetworkInfo
var m netmapgrpc.NetworkInfo
x.WriteToV2(&m)
require.EqualValues(t, 1, m.GetNetworkConfig().NumberOfParameters())
found := false
m.GetNetworkConfig().IterateParameters(func(prm *netmap.NetworkParameter) bool {
m.GetNetworkConfig().IterateParameters(func(prm *netmapgrpc.NetworkConfig_Parameter) bool {
require.False(t, found)
require.Equal(t, []byte(v2Key), prm.GetKey())
require.Equal(t, v2Val(exp), prm.GetValue())

View file

@ -7,9 +7,11 @@ import (
"strconv"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
"git.frostfs.info/TrueCloudLab/hrw"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// NodeInfo groups information about FrostFS storage node which is reflected
@ -18,26 +20,31 @@ import (
// about the nodes is available to all network participants to work with the network
// map (mainly to comply with container storage policies).
//
// NodeInfo is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.NodeInfo
// message. See ReadFromV2 / WriteToV2 methods.
// NodeInfo is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmapgrpc.NodeInfo
// message. See ReadFromV2V2 / WriteToV2V2 methods.
//
// Instances can be created using built-in var declaration.
// Instances must be created by NewNodeInfo() constructor.
type NodeInfo struct {
m netmap.NodeInfo
m *netmapgrpc.NodeInfo
hash uint64
}
// reads NodeInfo from netmap.NodeInfo message. If checkFieldPresence is set,
func NewNodeInfo() NodeInfo {
return NodeInfo{
m: &netmapgrpc.NodeInfo{},
}
}
// reads NodeInfo from netmapgrpc.NodeInfo message. If checkFieldPresence is set,
// returns an error on absence of any protocol-required field. Verifies format of any
// presented field according to FrostFS API V2 protocol.
func (x *NodeInfo) readFromV2(m netmap.NodeInfo, checkFieldPresence bool) error {
func (x *NodeInfo) readFromV2(m *netmapgrpc.NodeInfo, checkFieldPresence bool) error {
var err error
binPublicKey := m.GetPublicKey()
if checkFieldPresence && len(binPublicKey) == 0 {
return errors.New("missing public key")
}
if checkFieldPresence && m.NumberOfAddresses() <= 0 {
return errors.New("missing network endpoints")
}
@ -71,34 +78,38 @@ func (x *NodeInfo) readFromV2(m netmap.NodeInfo, checkFieldPresence bool) error
}
}
x.m = m
if x.m == nil {
x.m = new(netmapgrpc.NodeInfo)
}
proto.Merge(x.m, m)
x.hash = hrw.Hash(binPublicKey)
return nil
}
// ReadFromV2 reads NodeInfo from the netmap.NodeInfo message. Checks if the
// ReadFromV2V2 reads NodeInfo from the netmapgrpc.NodeInfo message. Checks if the
// message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *NodeInfo) ReadFromV2(m netmap.NodeInfo) error {
// See also WriteToV2V2.
func (x *NodeInfo) ReadFromV2(m *netmapgrpc.NodeInfo) error {
return x.readFromV2(m, true)
}
// WriteToV2 writes NodeInfo to the netmap.NodeInfo message. The message MUST NOT
// WriteToV2V2 writes NodeInfo to the netmapgrpc.NodeInfo message. The message MUST NOT
// be nil.
//
// See also ReadFromV2.
func (x NodeInfo) WriteToV2(m *netmap.NodeInfo) {
*m = x.m
// See also ReadFromV2V2.
func (x *NodeInfo) WriteToV2(m *netmapgrpc.NodeInfo) {
m.Reset()
proto.Merge(m, x.m)
}
// Marshal encodes NodeInfo into a binary format of the FrostFS API protocol
// (Protocol Buffers with direct field order).
//
// See also Unmarshal.
func (x NodeInfo) Marshal() []byte {
var m netmap.NodeInfo
func (x *NodeInfo) Marshal() []byte {
var m netmapgrpc.NodeInfo
x.WriteToV2(&m)
return m.StableMarshal(nil)
@ -110,25 +121,25 @@ func (x NodeInfo) Marshal() []byte {
//
// See also Marshal.
func (x *NodeInfo) Unmarshal(data []byte) error {
var m netmap.NodeInfo
var m netmapgrpc.NodeInfo
err := m.Unmarshal(data)
err := proto.Unmarshal(data, &m)
if err != nil {
return err
}
return x.readFromV2(m, false)
return x.readFromV2(&m, false)
}
// MarshalJSON encodes NodeInfo into a JSON format of the FrostFS API protocol
// (Protocol Buffers JSON).
//
// See also UnmarshalJSON.
func (x NodeInfo) MarshalJSON() ([]byte, error) {
var m netmap.NodeInfo
func (x *NodeInfo) MarshalJSON() ([]byte, error) {
var m netmapgrpc.NodeInfo
x.WriteToV2(&m)
return m.MarshalJSON()
return protojson.Marshal(&m)
}
// UnmarshalJSON decodes FrostFS API protocol JSON format into the NodeInfo
@ -136,14 +147,14 @@ func (x NodeInfo) MarshalJSON() ([]byte, error) {
//
// See also MarshalJSON.
func (x *NodeInfo) UnmarshalJSON(data []byte) error {
var m netmap.NodeInfo
var m netmapgrpc.NodeInfo
err := m.UnmarshalJSON(data)
err := protojson.Unmarshal(data, &m)
if err != nil {
return err
}
return x.readFromV2(m, false)
return x.readFromV2(&m, false)
}
// SetPublicKey sets binary-encoded public key bound to the node. The key
@ -182,7 +193,7 @@ func StringifyPublicKey(node NodeInfo) string {
//
// See also IterateNetworkEndpoints.
func (x *NodeInfo) SetNetworkEndpoints(v ...string) {
x.m.SetAddresses(v...)
x.m.SetAddresses(v)
}
// NumberOfNetworkEndpoints returns number of network endpoints announced by the node.
@ -206,7 +217,7 @@ func (x NodeInfo) IterateNetworkEndpoints(f func(string) bool) {
// IterateNetworkEndpoints is an extra-sugared function over IterateNetworkEndpoints
// method which allows to unconditionally iterate over all node's network endpoints.
func IterateNetworkEndpoints(node NodeInfo, f func(string)) {
func IterateNetworkEndpoints(node *NodeInfo, f func(string)) {
node.IterateNetworkEndpoints(func(addr string) bool {
f(addr)
return false
@ -231,7 +242,7 @@ func (x NodeInfo) Hash() uint64 {
// x1 is less than x2 if it has less Hash().
//
// Method is needed for internal placement needs.
func less(x1, x2 NodeInfo) bool {
func less(x1, x2 *NodeInfo) bool {
return x1.Hash() < x2.Hash()
}
@ -248,7 +259,7 @@ func (x *NodeInfo) SetPrice(price uint64) {
// Price returns price set using SetPrice.
//
// Zero NodeInfo has zero price.
func (x NodeInfo) Price() uint64 {
func (x *NodeInfo) Price() uint64 {
val := x.Attribute(attrPrice)
if val == "" {
return 0
@ -271,7 +282,7 @@ func (x *NodeInfo) SetCapacity(capacity uint64) {
// capacity returns capacity set using SetCapacity.
//
// Zero NodeInfo has zero capacity.
func (x NodeInfo) capacity() uint64 {
func (x *NodeInfo) capacity() uint64 {
val := x.Attribute(attrCapacity)
if val == "" {
return 0
@ -302,7 +313,7 @@ func (x *NodeInfo) SetLOCODE(locode string) {
//
// Zero NodeInfo has empty location code which is invalid according to
// FrostFS API system requirement.
func (x NodeInfo) LOCODE() string {
func (x *NodeInfo) LOCODE() string {
return x.Attribute(attrUNLOCODE)
}
@ -397,13 +408,13 @@ func (x NodeInfo) ExternalAddresses() []string {
// NumberOfAttributes returns number of attributes announced by the node.
//
// See also SetAttribute.
func (x NodeInfo) NumberOfAttributes() int {
func (x *NodeInfo) NumberOfAttributes() int {
return len(x.m.GetAttributes())
}
// IterateAttributes iterates over all node attributes and passes the into f.
// Handler MUST NOT be nil.
func (x NodeInfo) IterateAttributes(f func(key, value string)) {
func (x *NodeInfo) IterateAttributes(f func(key, value string)) {
a := x.m.GetAttributes()
for i := range a {
f(a[i].GetKey(), a[i].GetValue())
@ -427,16 +438,19 @@ func (x *NodeInfo) SetAttribute(key, value string) {
}
}
a = append(a, netmap.Attribute{})
a = append(a, &netmapgrpc.NodeInfo_Attribute{})
a[len(a)-1].SetKey(key)
a[len(a)-1].SetValue(value)
if x.m == nil {
x.m = new(netmapgrpc.NodeInfo)
}
x.m.SetAttributes(a)
}
// Attribute returns value of the node attribute set using SetAttribute by the
// given key. Returns empty string if attribute is missing.
func (x NodeInfo) Attribute(key string) string {
func (x *NodeInfo) Attribute(key string) string {
a := x.m.GetAttributes()
for i := range a {
if a[i].GetKey() == key {
@ -473,7 +487,7 @@ func (x *NodeInfo) SortAttributes() {
// information about itself in the network map, this action is interpreted as
// an intention to leave the network.
func (x *NodeInfo) SetOffline() {
x.m.SetState(netmap.Offline)
x.m.SetState(netmapgrpc.NodeInfo_OFFLINE)
}
// IsOffline checks if the node is in the "offline" state.
@ -482,8 +496,8 @@ func (x *NodeInfo) SetOffline() {
// mean online).
//
// See also SetOffline.
func (x NodeInfo) IsOffline() bool {
return x.m.GetState() == netmap.Offline
func (x *NodeInfo) IsOffline() bool {
return x.m.GetState() == netmapgrpc.NodeInfo_OFFLINE
}
// SetOnline sets the state of the node to "online". When a node updates
@ -492,7 +506,7 @@ func (x NodeInfo) IsOffline() bool {
//
// See also IsOnline.
func (x *NodeInfo) SetOnline() {
x.m.SetState(netmap.Online)
x.m.SetState(netmapgrpc.NodeInfo_ONLINE)
}
// IsOnline checks if the node is in the "online" state.
@ -501,8 +515,8 @@ func (x *NodeInfo) SetOnline() {
// mean offline).
//
// See also SetOnline.
func (x NodeInfo) IsOnline() bool {
return x.m.GetState() == netmap.Online
func (x *NodeInfo) IsOnline() bool {
return x.m.GetState() == netmapgrpc.NodeInfo_ONLINE
}
// SetMaintenance sets the state of the node to "maintenance". When a node updates
@ -511,7 +525,7 @@ func (x NodeInfo) IsOnline() bool {
//
// See also IsMaintenance.
func (x *NodeInfo) SetMaintenance() {
x.m.SetState(netmap.Maintenance)
x.m.SetState(netmapgrpc.NodeInfo_MAINTENANCE)
}
// IsMaintenance checks if the node is in the "maintenance" state.
@ -519,6 +533,6 @@ func (x *NodeInfo) SetMaintenance() {
// Zero NodeInfo has undefined state.
//
// See also SetMaintenance.
func (x NodeInfo) IsMaintenance() bool {
return x.m.GetState() == netmap.Maintenance
func (x *NodeInfo) IsMaintenance() bool {
return x.m.GetState() == netmapgrpc.NodeInfo_MAINTENANCE
}

View file

@ -7,7 +7,7 @@ import (
)
func TestNodeInfo_SetAttribute(t *testing.T) {
var n NodeInfo
n := NewNodeInfo()
const key = "some key"
val := "some value"
@ -24,7 +24,7 @@ func TestNodeInfo_SetAttribute(t *testing.T) {
}
func TestNodeInfo_Status(t *testing.T) {
var n NodeInfo
n := NewNodeInfo()
require.False(t, n.IsOnline())
require.False(t, n.IsOffline())
@ -47,7 +47,7 @@ func TestNodeInfo_Status(t *testing.T) {
}
func TestNodeInfo_ExternalAddr(t *testing.T) {
var n NodeInfo
n := NewNodeInfo()
require.Empty(t, n.ExternalAddresses())
require.Panics(t, func() { n.SetExternalAddresses() })

View file

@ -7,32 +7,34 @@ import (
"strconv"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/parser"
"github.com/antlr4-go/antlr/v4"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// PlacementPolicy declares policy to store objects in the FrostFS container.
// Within itself, PlacementPolicy represents a set of rules to select a subset
// of nodes from FrostFS network map - node-candidates for object storage.
//
// PlacementPolicy is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap.PlacementPolicy
// PlacementPolicy is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmapgrpc.PlacementPolicy
// message. See ReadFromV2 / WriteToV2 methods.
//
// Instances can be created using built-in var declaration.
type PlacementPolicy struct {
backupFactor uint32
filters []netmap.Filter
filters []*netmapgrpc.Filter
selectors []netmap.Selector
selectors []*netmapgrpc.Selector
replicas []netmap.Replica
replicas []*netmapgrpc.Replica
unique bool
}
func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresence bool) error {
func (p *PlacementPolicy) readFromV2(m *netmapgrpc.PlacementPolicy, checkFieldPresence bool) error {
p.replicas = m.GetReplicas()
if checkFieldPresence && len(p.replicas) == 0 {
return errors.New("missing replicas")
@ -51,7 +53,7 @@ func (p *PlacementPolicy) readFromV2(m netmap.PlacementPolicy, checkFieldPresenc
//
// See also Unmarshal.
func (p PlacementPolicy) Marshal() []byte {
var m netmap.PlacementPolicy
var m netmapgrpc.PlacementPolicy
p.WriteToV2(&m)
return m.StableMarshal(nil)
@ -63,14 +65,14 @@ func (p PlacementPolicy) Marshal() []byte {
//
// See also Marshal.
func (p *PlacementPolicy) Unmarshal(data []byte) error {
var m netmap.PlacementPolicy
var m netmapgrpc.PlacementPolicy
err := m.Unmarshal(data)
err := proto.Unmarshal(data, &m)
if err != nil {
return err
}
return p.readFromV2(m, false)
return p.readFromV2(&m, false)
}
// MarshalJSON encodes PlacementPolicy into a JSON format of the FrostFS API
@ -78,10 +80,14 @@ func (p *PlacementPolicy) Unmarshal(data []byte) error {
//
// See also UnmarshalJSON.
func (p PlacementPolicy) MarshalJSON() ([]byte, error) {
var m netmap.PlacementPolicy
var m netmapgrpc.PlacementPolicy
p.WriteToV2(&m)
return m.MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
&m,
)
}
// UnmarshalJSON decodes FrostFS API protocol JSON format into the PlacementPolicy
@ -89,21 +95,21 @@ func (p PlacementPolicy) MarshalJSON() ([]byte, error) {
//
// See also MarshalJSON.
func (p *PlacementPolicy) UnmarshalJSON(data []byte) error {
var m netmap.PlacementPolicy
var m netmapgrpc.PlacementPolicy
err := m.UnmarshalJSON(data)
err := protojson.Unmarshal(data, &m)
if err != nil {
return err
}
return p.readFromV2(m, false)
return p.readFromV2(&m, false)
}
// ReadFromV2 reads PlacementPolicy from the netmap.PlacementPolicy message.
// ReadFromV2 reads PlacementPolicy from the netmapgrpc.PlacementPolicy message.
// Checks if the message conforms to FrostFS API V2 protocol.
//
// See also WriteToV2.
func (p *PlacementPolicy) ReadFromV2(m netmap.PlacementPolicy) error {
func (p *PlacementPolicy) ReadFromV2(m *netmapgrpc.PlacementPolicy) error {
return p.readFromV2(m, true)
}
@ -111,7 +117,8 @@ func (p *PlacementPolicy) ReadFromV2(m netmap.PlacementPolicy) error {
// The message must not be nil.
//
// See also ReadFromV2.
func (p PlacementPolicy) WriteToV2(m *netmap.PlacementPolicy) {
func (p PlacementPolicy) WriteToV2(m *netmapgrpc.PlacementPolicy) {
m.Reset()
m.SetContainerBackupFactor(p.backupFactor)
m.SetFilters(p.filters)
m.SetSelectors(p.selectors)
@ -122,7 +129,13 @@ func (p PlacementPolicy) WriteToV2(m *netmap.PlacementPolicy) {
// ReplicaDescriptor replica descriptor characterizes replicas of objects from
// the subset selected by a particular Selector.
type ReplicaDescriptor struct {
m netmap.Replica
m *netmapgrpc.Replica
}
func NewReplicaDescriptor() ReplicaDescriptor {
return ReplicaDescriptor{
m: new(netmapgrpc.Replica),
}
}
// SetNumberOfObjects sets number of object replicas.
@ -133,7 +146,7 @@ func (r *ReplicaDescriptor) SetNumberOfObjects(c uint32) {
// NumberOfObjects returns number set using SetNumberOfObjects.
//
// Zero ReplicaDescriptor has zero number of objects.
func (r ReplicaDescriptor) NumberOfObjects() uint32 {
func (r *ReplicaDescriptor) NumberOfObjects() uint32 {
return r.m.GetCount()
}
@ -151,10 +164,11 @@ func (r *ReplicaDescriptor) SetSelectorName(s string) {
func (p *PlacementPolicy) AddReplicas(rs ...ReplicaDescriptor) {
off := len(p.replicas)
p.replicas = append(p.replicas, make([]netmap.Replica, len(rs))...)
p.replicas = append(p.replicas, make([]*netmapgrpc.Replica, len(rs))...)
for i := range rs {
p.replicas[off+i] = rs[i].m
p.replicas[off+i] = new(netmapgrpc.Replica)
proto.Merge(p.replicas[off+i], rs[i].m)
}
}
@ -193,7 +207,13 @@ func (p *PlacementPolicy) SetUnique(b bool) {
// Selector describes the bucket selection operator: choose a number of nodes
// from the bucket taking the nearest nodes to the related container by hash distance.
type Selector struct {
m netmap.Selector
m *netmapgrpc.Selector
}
func NewSelector() Selector {
return Selector{
m: new(netmapgrpc.Selector),
}
}
// SetName sets name with which the Selector can be referenced.
@ -224,7 +244,7 @@ func (s *Selector) SelectByBucketAttribute(bucket string) {
//
// See also SelectByBucketAttribute.
func (s *Selector) SelectSame() {
s.m.SetClause(netmap.Same)
s.m.SetClause(netmapgrpc.Clause_SAME)
}
// SelectDistinct makes selection algorithm to select only nodes having the different values
@ -234,7 +254,7 @@ func (s *Selector) SelectSame() {
//
// See also SelectByBucketAttribute.
func (s *Selector) SelectDistinct() {
s.m.SetClause(netmap.Distinct)
s.m.SetClause(netmapgrpc.Clause_DISTINCT)
}
// SetFilterName sets reference to pre-filtering nodes for selection.
@ -253,16 +273,23 @@ func (s *Selector) SetFilterName(f string) {
func (p *PlacementPolicy) AddSelectors(ss ...Selector) {
off := len(p.selectors)
p.selectors = append(p.selectors, make([]netmap.Selector, len(ss))...)
p.selectors = append(p.selectors, make([]*netmapgrpc.Selector, len(ss))...)
for i := range ss {
p.selectors[off+i] = ss[i].m
p.selectors[off+i] = new(netmapgrpc.Selector)
proto.Merge(p.selectors[off+i], ss[i].m)
}
}
// Filter contains rules for filtering the node sets.
type Filter struct {
m netmap.Filter
m *netmapgrpc.Filter
}
func NewFilter() Filter {
return Filter{
m: new(netmapgrpc.Filter),
}
}
// SetName sets name with which the Filter can be referenced or, for inner filters,
@ -274,7 +301,7 @@ func (x *Filter) SetName(name string) {
x.m.SetName(name)
}
func (x *Filter) setAttribute(key string, op netmap.Operation, val string) {
func (x *Filter) setAttribute(key string, op netmapgrpc.Operation, val string) {
x.m.SetKey(key)
x.m.SetOp(op)
x.m.SetValue(val)
@ -284,14 +311,14 @@ func (x *Filter) setAttribute(key string, op netmap.Operation, val string) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) Equal(key, value string) {
x.setAttribute(key, netmap.EQ, value)
x.setAttribute(key, netmapgrpc.Operation_EQ, value)
}
// NotEqual applies the rule to accept only nodes with the distinct attribute value.
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) NotEqual(key, value string) {
x.setAttribute(key, netmap.NE, value)
x.setAttribute(key, netmapgrpc.Operation_NE, value)
}
// NumericGT applies the rule to accept only nodes with the numeric attribute
@ -299,7 +326,7 @@ func (x *Filter) NotEqual(key, value string) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) NumericGT(key string, num int64) {
x.setAttribute(key, netmap.GT, strconv.FormatInt(num, 10))
x.setAttribute(key, netmapgrpc.Operation_GT, strconv.FormatInt(num, 10))
}
// NumericGE applies the rule to accept only nodes with the numeric attribute
@ -307,7 +334,7 @@ func (x *Filter) NumericGT(key string, num int64) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) NumericGE(key string, num int64) {
x.setAttribute(key, netmap.GE, strconv.FormatInt(num, 10))
x.setAttribute(key, netmapgrpc.Operation_GE, strconv.FormatInt(num, 10))
}
// NumericLT applies the rule to accept only nodes with the numeric attribute
@ -315,7 +342,7 @@ func (x *Filter) NumericGE(key string, num int64) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) NumericLT(key string, num int64) {
x.setAttribute(key, netmap.LT, strconv.FormatInt(num, 10))
x.setAttribute(key, netmapgrpc.Operation_LT, strconv.FormatInt(num, 10))
}
// NumericLE applies the rule to accept only nodes with the numeric attribute
@ -323,19 +350,20 @@ func (x *Filter) NumericLT(key string, num int64) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) NumericLE(key string, num int64) {
x.setAttribute(key, netmap.LE, strconv.FormatInt(num, 10))
x.setAttribute(key, netmapgrpc.Operation_LE, strconv.FormatInt(num, 10))
}
func (x *Filter) setInnerFilters(op netmap.Operation, filters []Filter) {
func (x *Filter) setInnerFilters(op netmapgrpc.Operation, filters []Filter) {
x.setAttribute("", op, "")
inner := x.m.GetFilters()
if rem := len(filters) - len(inner); rem > 0 {
inner = append(inner, make([]netmap.Filter, rem)...)
inner = append(inner, make([]*netmapgrpc.Filter, rem)...)
}
for i := range filters {
inner[i] = filters[i].m
inner[i] = new(netmapgrpc.Filter)
proto.Merge(inner[i], filters[i].m)
}
x.m.SetFilters(inner)
@ -346,7 +374,7 @@ func (x *Filter) setInnerFilters(op netmap.Operation, filters []Filter) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) LogicalOR(filters ...Filter) {
x.setInnerFilters(netmap.OR, filters)
x.setInnerFilters(netmapgrpc.Operation_OR, filters)
}
// LogicalAND applies the rule to accept only nodes which satisfy all the given
@ -354,7 +382,7 @@ func (x *Filter) LogicalOR(filters ...Filter) {
//
// Method SHOULD NOT be called along with other similar methods.
func (x *Filter) LogicalAND(filters ...Filter) {
x.setInnerFilters(netmap.AND, filters)
x.setInnerFilters(netmapgrpc.Operation_AND, filters)
}
// AddFilters adds a Filter bunch that will be applied when selecting nodes.
@ -363,10 +391,11 @@ func (x *Filter) LogicalAND(filters ...Filter) {
func (p *PlacementPolicy) AddFilters(fs ...Filter) {
off := len(p.filters)
p.filters = append(p.filters, make([]netmap.Filter, len(fs))...)
p.filters = append(p.filters, make([]*netmapgrpc.Filter, len(fs))...)
for i := range fs {
p.filters[off+i] = fs[i].m
p.filters[off+i] = new(netmapgrpc.Filter)
proto.Merge(p.filters[off+i], fs[i].m)
}
}
@ -393,7 +422,6 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
} else {
_, err = w.WriteString(fmt.Sprintf("%sREP %d", delim, c))
}
if err != nil {
return err
}
@ -402,8 +430,7 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
}
if p.backupFactor > 0 {
_, err = w.WriteString(fmt.Sprintf("\nCBF %d", p.backupFactor))
if err != nil {
if _, err = w.WriteString(fmt.Sprintf("\nCBF %d", p.backupFactor)); err != nil {
return err
}
}
@ -411,8 +438,7 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
var s string
for i := range p.selectors {
_, err = w.WriteString(fmt.Sprintf("\nSELECT %d", p.selectors[i].GetCount()))
if err != nil {
if _, err = w.WriteString(fmt.Sprintf("\nSELECT %d", p.selectors[i].GetCount())); err != nil {
return err
}
@ -420,43 +446,38 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
var clause string
switch p.selectors[i].GetClause() {
case netmap.Same:
case netmapgrpc.Clause_SAME:
clause = "SAME "
case netmap.Distinct:
case netmapgrpc.Clause_DISTINCT:
clause = "DISTINCT "
default:
clause = ""
}
_, err = w.WriteString(fmt.Sprintf(" IN %s%s", clause, s))
if err != nil {
if _, err = w.WriteString(fmt.Sprintf(" IN %s%s", clause, s)); err != nil {
return err
}
}
if s = p.selectors[i].GetFilter(); s != "" {
_, err = w.WriteString(" FROM " + s)
if err != nil {
if _, err = w.WriteString(" FROM " + s); err != nil {
return err
}
}
if s = p.selectors[i].GetName(); s != "" {
_, err = w.WriteString(" AS " + s)
if err != nil {
if _, err = w.WriteString(" AS " + s); err != nil {
return err
}
}
}
for i := range p.filters {
_, err = w.WriteString("\nFILTER ")
if err != nil {
if _, err = w.WriteString("\nFILTER "); err != nil {
return err
}
err = writeFilterStringTo(w, p.filters[i])
if err != nil {
if err = writeFilterStringTo(w, p.filters[i]); err != nil {
return err
}
}
@ -464,7 +485,7 @@ func (p PlacementPolicy) WriteStringTo(w io.StringWriter) (err error) {
return nil
}
func writeFilterStringTo(w io.StringWriter, f netmap.Filter) error {
func writeFilterStringTo(w io.StringWriter, f *netmapgrpc.Filter) error {
var err error
var s string
op := f.GetOp()
@ -484,7 +505,7 @@ func writeFilterStringTo(w io.StringWriter, f netmap.Filter) error {
inner := f.GetFilters()
if op == netmap.NOT {
if op == netmapgrpc.Operation_NOT {
_, err = w.WriteString(op.String() + " (")
if err != nil {
return err
@ -595,15 +616,16 @@ func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any {
pl.unique = ctx.UNIQUE() != nil
repStmts := ctx.AllRepStmt()
pl.replicas = make([]netmap.Replica, 0, len(repStmts))
pl.replicas = make([]*netmapgrpc.Replica, 0, len(repStmts))
for _, r := range repStmts {
res, ok := r.Accept(p).(*netmap.Replica)
res, ok := r.Accept(p).(*netmapgrpc.Replica)
if !ok {
return nil
}
pl.replicas = append(pl.replicas, *res)
cloned := new(netmapgrpc.Replica)
proto.Merge(cloned, res)
pl.replicas = append(pl.replicas, cloned)
}
if cbfStmt := ctx.CbfStmt(); cbfStmt != nil {
@ -615,22 +637,29 @@ func (p *policyVisitor) VisitPolicy(ctx *parser.PolicyContext) any {
}
selStmts := ctx.AllSelectStmt()
pl.selectors = make([]netmap.Selector, 0, len(selStmts))
pl.selectors = make([]*netmapgrpc.Selector, 0, len(selStmts))
for _, s := range selStmts {
res, ok := s.Accept(p).(*netmap.Selector)
res, ok := s.Accept(p).(*netmapgrpc.Selector)
if !ok {
return nil
}
pl.selectors = append(pl.selectors, *res)
cloned := new(netmapgrpc.Selector)
proto.Merge(cloned, res)
pl.selectors = append(pl.selectors, cloned)
}
filtStmts := ctx.AllFilterStmt()
pl.filters = make([]netmap.Filter, 0, len(filtStmts))
pl.filters = make([]*netmapgrpc.Filter, 0, len(filtStmts))
for _, f := range filtStmts {
pl.filters = append(pl.filters, *f.Accept(p).(*netmap.Filter))
res, ok := f.Accept(p).(*netmapgrpc.Filter)
if !ok {
return nil
}
cloned := new(netmapgrpc.Filter)
proto.Merge(cloned, res)
pl.filters = append(pl.filters, cloned)
}
return pl
@ -652,7 +681,7 @@ func (p *policyVisitor) VisitRepStmt(ctx *parser.RepStmtContext) any {
return p.reportError(errInvalidNumber)
}
rs := new(netmap.Replica)
rs := new(netmapgrpc.Replica)
rs.SetCount(uint32(num))
if sel := ctx.GetSelector(); sel != nil {
@ -669,7 +698,7 @@ func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) any {
return p.reportError(errInvalidNumber)
}
s := new(netmap.Selector)
s := new(netmapgrpc.Selector)
s.SetCount(uint32(res))
if clStmt := ctx.Clause(); clStmt != nil {
@ -690,7 +719,7 @@ func (p *policyVisitor) VisitSelectStmt(ctx *parser.SelectStmtContext) any {
// VisitFilterStmt implements parser.QueryVisitor interface.
func (p *policyVisitor) VisitFilterStmt(ctx *parser.FilterStmtContext) any {
f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*netmap.Filter)
f := p.VisitFilterExpr(ctx.GetExpr().(*parser.FilterExprContext)).(*netmapgrpc.Filter)
f.SetName(ctx.GetName().GetText())
return f
}
@ -704,18 +733,18 @@ func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) any {
return inner.Accept(p)
}
f := new(netmap.Filter)
f := new(netmapgrpc.Filter)
op := operationFromString(ctx.GetOp().GetText())
f.SetOp(op)
if op == netmap.NOT {
f1 := *ctx.GetF1().Accept(p).(*netmap.Filter)
f.SetFilters([]netmap.Filter{f1})
if op == netmapgrpc.Operation_NOT {
f1 := ctx.GetF1().Accept(p).(*netmapgrpc.Filter)
f.SetFilters([]*netmapgrpc.Filter{f1})
return f
}
f1 := *ctx.GetF1().Accept(p).(*netmap.Filter)
f2 := *ctx.GetF2().Accept(p).(*netmap.Filter)
f1 := ctx.GetF1().Accept(p).(*netmapgrpc.Filter)
f2 := ctx.GetF2().Accept(p).(*netmapgrpc.Filter)
// Consider f1=(.. AND ..) AND f2. This can be merged because our AND operation
// is of arbitrary arity. ANTLR generates left-associative parse-tree by default.
@ -724,7 +753,7 @@ func (p *policyVisitor) VisitFilterExpr(ctx *parser.FilterExprContext) any {
return f
}
f.SetFilters([]netmap.Filter{f1, f2})
f.SetFilters([]*netmapgrpc.Filter{f1, f2})
return f
}
@ -754,7 +783,7 @@ func (p *policyVisitor) VisitFilterValue(ctx *parser.FilterValueContext) any {
// VisitExpr implements parser.QueryVisitor interface.
func (p *policyVisitor) VisitExpr(ctx *parser.ExprContext) any {
f := new(netmap.Filter)
f := new(netmapgrpc.Filter)
if flt := ctx.GetFilter(); flt != nil {
f.SetName(flt.GetText())
return f
@ -799,7 +828,7 @@ func validatePolicy(p PlacementPolicy) error {
return nil
}
func clauseFromString(s string) (c netmap.Clause) {
func clauseFromString(s string) (c netmapgrpc.Clause) {
if !c.FromString(strings.ToUpper(s)) {
// Such errors should be handled by ANTLR code thus this panic.
panic(fmt.Errorf("BUG: invalid clause: %s", c))
@ -808,7 +837,7 @@ func clauseFromString(s string) (c netmap.Clause) {
return
}
func operationFromString(s string) (op netmap.Operation) {
func operationFromString(s string) (op netmapgrpc.Operation) {
if !op.FromString(strings.ToUpper(s)) {
// Such errors should be handled by ANTLR code thus this panic.
panic(fmt.Errorf("BUG: invalid operation: %s", op))

View file

@ -4,9 +4,11 @@ import (
"strings"
"testing"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
. "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap"
netmaptest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/netmap/test"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestEncode(t *testing.T) {
@ -65,7 +67,11 @@ func TestPlacementPolicyEncoding(t *testing.T) {
var v2 PlacementPolicy
require.NoError(t, v2.Unmarshal(v.Marshal()))
require.Equal(t, v, v2)
var p1, p2 netmapgrpc.PlacementPolicy
v.WriteToV2(&p1)
v2.WriteToV2(&p2)
require.True(t, proto.Equal(&p1, &p2))
})
t.Run("json", func(t *testing.T) {
@ -75,6 +81,10 @@ func TestPlacementPolicyEncoding(t *testing.T) {
var v2 PlacementPolicy
require.NoError(t, v2.UnmarshalJSON(data))
require.Equal(t, v, v2)
var p1, p2 netmapgrpc.PlacementPolicy
v.WriteToV2(&p1)
v2.WriteToV2(&p2)
require.True(t, proto.Equal(&p1, &p2))
})
}

View file

@ -4,7 +4,7 @@ import (
"fmt"
"sort"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/hrw"
)
@ -21,7 +21,7 @@ func (c *context) processSelectors(p PlacementPolicy) error {
sName := p.selectors[i].GetName()
c.processedSelectors[sName] = &p.selectors[i]
c.processedSelectors[sName] = p.selectors[i]
result, err := c.getSelection(p.selectors[i])
if err != nil {
@ -36,9 +36,9 @@ func (c *context) processSelectors(p PlacementPolicy) error {
// calcNodesCount returns number of buckets and minimum number of nodes in every bucket
// for the given selector.
func calcNodesCount(s netmap.Selector) (int, int) {
func calcNodesCount(s *netmapgrpc.Selector) (int, int) {
switch s.GetClause() {
case netmap.Same:
case netmapgrpc.Clause_SAME:
return 1, int(s.GetCount())
default:
return int(s.GetCount()), 1
@ -48,7 +48,7 @@ func calcNodesCount(s netmap.Selector) (int, int) {
// calcBucketWeight computes weight for a node bucket.
func calcBucketWeight(ns nodes, a aggregator, wf weightFunc) float64 {
for i := range ns {
a.Add(wf(ns[i]))
a.Add(wf(&ns[i]))
}
return a.Compute()
@ -56,7 +56,7 @@ func calcBucketWeight(ns nodes, a aggregator, wf weightFunc) float64 {
// getSelection returns nodes grouped by s.attribute.
// Last argument specifies if more buckets can be used to fulfill CBF.
func (c *context) getSelection(s netmap.Selector) ([]nodes, error) {
func (c *context) getSelection(s *netmapgrpc.Selector) ([]nodes, error) {
bucketCount, nodesInBucket := calcNodesCount(s)
buckets := c.getSelectionBase(s)
@ -71,7 +71,7 @@ func (c *context) getSelection(s netmap.Selector) ([]nodes, error) {
if len(c.hrwSeed) == 0 {
if s.GetAttribute() == "" {
sort.Slice(buckets, func(i, j int) bool {
return less(buckets[i].nodes[0], buckets[j].nodes[0])
return less(&buckets[i].nodes[0], &buckets[j].nodes[0])
})
} else {
sort.Slice(buckets, func(i, j int) bool {
@ -131,7 +131,7 @@ type nodeAttrPair struct {
// getSelectionBase returns nodes grouped by selector attribute.
// It it guaranteed that each pair will contain at least one node.
func (c *context) getSelectionBase(s netmap.Selector) []nodeAttrPair {
func (c *context) getSelectionBase(s *netmapgrpc.Selector) []nodeAttrPair {
fName := s.GetFilter()
f := c.processedFilters[fName]
isMain := fName == mainFilterName
@ -143,7 +143,7 @@ func (c *context) getSelectionBase(s netmap.Selector) []nodeAttrPair {
if c.usedNodes[c.netMap.nodes[i].hash] {
continue
}
if isMain || c.match(f, c.netMap.nodes[i]) {
if isMain || c.match(f, &c.netMap.nodes[i]) {
if attr == "" {
// Default attribute is transparent identifier which is different for every node.
result = append(result, nodeAttrPair{attr: "", nodes: nodes{c.netMap.nodes[i]}})

View file

@ -8,7 +8,7 @@ import (
"strconv"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap"
netmapgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/netmap/grpc"
"git.frostfs.info/TrueCloudLab/hrw"
"github.com/stretchr/testify/require"
)
@ -22,7 +22,7 @@ func BenchmarkHRWSort(b *testing.B) {
key := make([]byte, 33)
rand.Read(key)
var node NodeInfo
node := NewNodeInfo()
node.SetPrice(1)
node.SetCapacity(100)
node.SetPublicKey(key)
@ -85,7 +85,7 @@ func BenchmarkHRWSort(b *testing.B) {
b.StartTimer()
sort.Slice(vectors, func(i, j int) bool {
return less(vectors[i][0], vectors[j][0])
return less(&vectors[i][0], &vectors[j][0])
})
hrw.SortSliceByWeightIndex(realNodes, weights, pivot)
}
@ -103,8 +103,8 @@ func BenchmarkPolicyHRWType(b *testing.B) {
newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame),
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)},
[]Filter{
newFilter("loc1", "Location", "Shanghai", netmap.EQ),
newFilter("loc2", "Location", "Shanghai", netmap.NE),
newFilter("loc1", "Location", "Shanghai", netmapgrpc.Operation_EQ),
newFilter("loc2", "Location", "Shanghai", netmapgrpc.Operation_NE),
})
nodes := make([]NodeInfo, netmapSize)
@ -148,8 +148,8 @@ func TestPlacementPolicy_DeterministicOrder(t *testing.T) {
newSelector("loc1", "Location", 1, "loc1", (*Selector).SelectSame),
newSelector("loc2", "Location", 1, "loc2", (*Selector).SelectSame)},
[]Filter{
newFilter("loc1", "Location", "Shanghai", netmap.EQ),
newFilter("loc2", "Location", "Shanghai", netmap.NE),
newFilter("loc1", "Location", "Shanghai", netmapgrpc.Operation_EQ),
newFilter("loc2", "Location", "Shanghai", netmapgrpc.Operation_NE),
})
nodeList := make([]NodeInfo, netmapSize)
@ -204,8 +204,8 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
newSelector("Main", "Country", 3, "*", (*Selector).SelectDistinct),
},
[]Filter{
newFilter("FromRU", "Country", "Russia", netmap.EQ),
newFilter("Good", "Rating", "4", netmap.GE),
newFilter("FromRU", "Country", "Russia", netmapgrpc.Operation_EQ),
newFilter("Good", "Rating", "4", netmapgrpc.Operation_GE),
})
nodes := []NodeInfo{
nodeInfoFromAttributes("Country", "Russia", "Rating", "1", "City", "SPB"),
@ -231,7 +231,7 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
for _, s := range p.selectors {
sel := c.selections[s.GetName()]
s := c.processedSelectors[s.GetName()]
bucketCount, nodesInBucket := calcNodesCount(*s)
bucketCount, nodesInBucket := calcNodesCount(s)
nodesInBucket *= int(c.cbf)
targ := fmt.Sprintf("selector '%s'", s.GetName())
require.Equal(t, bucketCount, len(sel), targ)
@ -239,7 +239,7 @@ func TestPlacementPolicy_ProcessSelectors(t *testing.T) {
for _, res := range sel {
require.Equal(t, nodesInBucket, len(res), targ)
for j := range res {
require.True(t, fName == mainFilterName || c.match(c.processedFilters[fName], res[j]), targ)
require.True(t, fName == mainFilterName || c.match(c.processedFilters[fName], &res[j]), targ)
}
}
}
@ -288,10 +288,10 @@ func TestPlacementPolicy_ProcessSelectorsExceptForNodes(t *testing.T) {
newSelector("ExceptRU", "City", 2, "ExceptRU", (*Selector).SelectSame),
},
[]Filter{
newFilter("ExceptRU", "", "", netmap.NOT,
newFilter("", "", "", netmap.AND,
newFilter("", "City", "Lyon", netmap.EQ),
newFilter("", "Rating", "10", netmap.LE),
newFilter("ExceptRU", "", "", netmapgrpc.Operation_NOT,
newFilter("", "", "", netmapgrpc.Operation_AND,
newFilter("", "City", "Lyon", netmapgrpc.Operation_EQ),
newFilter("", "Rating", "10", netmapgrpc.Operation_LE),
),
),
})
@ -319,7 +319,7 @@ func TestPlacementPolicy_ProcessSelectorsExceptForNodes(t *testing.T) {
for _, s := range p.selectors {
sel := c.selections[s.GetName()]
s := c.processedSelectors[s.GetName()]
bucketCount, nodesInBucket := calcNodesCount(*s)
bucketCount, nodesInBucket := calcNodesCount(s)
nodesInBucket *= int(c.cbf)
targ := fmt.Sprintf("selector '%s'", s.GetName())
require.Equal(t, bucketCount, len(sel), targ)
@ -327,7 +327,7 @@ func TestPlacementPolicy_ProcessSelectorsExceptForNodes(t *testing.T) {
for _, res := range sel {
require.Equal(t, nodesInBucket, len(res), targ)
for j := range res {
require.True(t, fName == mainFilterName || c.match(c.processedFilters[fName], res[j]), targ)
require.True(t, fName == mainFilterName || c.match(c.processedFilters[fName], &res[j]), targ)
}
}
}
@ -335,7 +335,7 @@ func TestPlacementPolicy_ProcessSelectorsExceptForNodes(t *testing.T) {
func TestSelector_SetName(t *testing.T) {
const name = "some name"
var s Selector
s := NewSelector()
require.Zero(t, s.m.GetName())
@ -345,7 +345,7 @@ func TestSelector_SetName(t *testing.T) {
func TestSelector_SetNumberOfNodes(t *testing.T) {
const num = 3
var s Selector
s := NewSelector()
require.Zero(t, s.m.GetCount())
@ -355,20 +355,20 @@ func TestSelector_SetNumberOfNodes(t *testing.T) {
}
func TestSelectorClauses(t *testing.T) {
var s Selector
s := NewSelector()
require.Equal(t, netmap.UnspecifiedClause, s.m.GetClause())
require.Equal(t, netmapgrpc.Clause_CLAUSE_UNSPECIFIED, s.m.GetClause())
s.SelectDistinct()
require.Equal(t, netmap.Distinct, s.m.GetClause())
require.Equal(t, netmapgrpc.Clause_DISTINCT, s.m.GetClause())
s.SelectSame()
require.Equal(t, netmap.Same, s.m.GetClause())
require.Equal(t, netmapgrpc.Clause_SAME, s.m.GetClause())
}
func TestSelector_SelectByBucketAttribute(t *testing.T) {
const attr = "some attribute"
var s Selector
s := NewSelector()
require.Zero(t, s.m.GetAttribute())
@ -378,7 +378,7 @@ func TestSelector_SelectByBucketAttribute(t *testing.T) {
func TestSelector_SetFilterName(t *testing.T) {
const fName = "some filter"
var s Selector
s := NewSelector()
require.Zero(t, s.m.GetFilter())

View file

@ -7,6 +7,7 @@ import (
)
func filter(withInner bool) (x netmap.Filter) {
x = netmap.NewFilter()
x.SetName("name")
if withInner {
x.LogicalOR(filter(false), filter(false))
@ -24,6 +25,7 @@ func Filter() netmap.Filter {
// Replica returns random netmap.ReplicaDescriptor.
func Replica() (x netmap.ReplicaDescriptor) {
x = netmap.NewReplicaDescriptor()
x.SetNumberOfObjects(666)
x.SetSelectorName("selector")
@ -32,6 +34,7 @@ func Replica() (x netmap.ReplicaDescriptor) {
// Selector returns random netmap.Selector.
func Selector() (x netmap.Selector) {
x = netmap.NewSelector()
x.SetNumberOfNodes(11)
x.SetName("name")
x.SetFilterName("filter")
@ -53,6 +56,7 @@ func PlacementPolicy() (p netmap.PlacementPolicy) {
// NetworkInfo returns random netmap.NetworkInfo.
func NetworkInfo() (x netmap.NetworkInfo) {
x = netmap.NewNetworkInfo()
x.SetCurrentEpoch(21)
x.SetMagicNumber(32)
x.SetMsPerBlock(43)
@ -69,6 +73,7 @@ func NetworkInfo() (x netmap.NetworkInfo) {
// NodeInfo returns random netmap.NodeInfo.
func NodeInfo() (x netmap.NodeInfo) {
x = netmap.NewNodeInfo()
key := make([]byte, 33)
rand.Read(key)

View file

@ -1,17 +1,28 @@
package object
import (
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Attribute represents v2-compatible object attribute.
type Attribute object.Attribute
type Attribute struct {
attribute *objectgrpc.Header_Attribute
}
// NewAttributeFromV2 wraps v2 Attribute message to Attribute.
//
// Nil object.Attribute converts to nil.
func NewAttributeFromV2(aV2 *object.Attribute) *Attribute {
return (*Attribute)(aV2)
// Nil objectgrpc.Header_Attribute converts to nil.
func NewAttributeFromV2(a *objectgrpc.Header_Attribute) *Attribute {
if a == nil {
return nil
}
attr := Attribute{
attribute: &objectgrpc.Header_Attribute{},
}
proto.Merge(attr.attribute, a)
return &attr
}
// NewAttribute creates and initializes blank Attribute.
@ -22,52 +33,59 @@ func NewAttributeFromV2(aV2 *object.Attribute) *Attribute {
// - key: "";
// - value: "".
func NewAttribute() *Attribute {
return NewAttributeFromV2(new(object.Attribute))
return NewAttributeFromV2(new(objectgrpc.Header_Attribute))
}
// Key returns key to the object attribute.
func (a *Attribute) Key() string {
return (*object.Attribute)(a).GetKey()
func (a *Attribute) GetKey() string {
return a.attribute.GetKey()
}
// SetKey sets key to the object attribute.
func (a *Attribute) SetKey(v string) {
(*object.Attribute)(a).SetKey(v)
a.attribute.SetKey(v)
}
// Value return value of the object attribute.
func (a *Attribute) Value() string {
return (*object.Attribute)(a).GetValue()
func (a *Attribute) GetValue() string {
return a.attribute.GetValue()
}
// SetValue sets value of the object attribute.
func (a *Attribute) SetValue(v string) {
(*object.Attribute)(a).SetValue(v)
a.attribute.SetValue(v)
}
// ToV2 converts Attribute to v2 Attribute message.
//
// Nil Attribute converts to nil.
func (a *Attribute) ToV2() *object.Attribute {
return (*object.Attribute)(a)
func (a *Attribute) ToV2() *objectgrpc.Header_Attribute {
if a == nil {
return nil
}
return a.attribute
}
// Marshal marshals Attribute into a protobuf binary form.
func (a *Attribute) Marshal() ([]byte, error) {
return (*object.Attribute)(a).StableMarshal(nil), nil
return a.attribute.StableMarshal(nil), nil
}
// Unmarshal unmarshals protobuf binary representation of Attribute.
func (a *Attribute) Unmarshal(data []byte) error {
return (*object.Attribute)(a).Unmarshal(data)
return proto.Unmarshal(data, a.attribute)
}
// MarshalJSON encodes Attribute to protobuf JSON format.
func (a *Attribute) MarshalJSON() ([]byte, error) {
return (*object.Attribute)(a).MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
a.attribute,
)
}
// UnmarshalJSON decodes Attribute from protobuf JSON format.
func (a *Attribute) UnmarshalJSON(data []byte) error {
return (*object.Attribute)(a).UnmarshalJSON(data)
return protojson.Unmarshal(data, a.attribute)
}

View file

@ -1,21 +1,22 @@
package object
package object_test
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
object "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
"github.com/stretchr/testify/require"
)
func TestAttribute(t *testing.T) {
key, val := "some key", "some value"
a := NewAttribute()
a := object.NewAttribute()
a.SetKey(key)
a.SetValue(val)
require.Equal(t, key, a.Key())
require.Equal(t, val, a.Value())
require.Equal(t, key, a.GetKey())
require.Equal(t, val, a.GetValue())
aV2 := a.ToV2()
@ -24,7 +25,7 @@ func TestAttribute(t *testing.T) {
}
func TestAttributeEncoding(t *testing.T) {
a := NewAttribute()
a := object.NewAttribute()
a.SetKey("key")
a.SetValue("value")
@ -32,7 +33,7 @@ func TestAttributeEncoding(t *testing.T) {
data, err := a.Marshal()
require.NoError(t, err)
a2 := NewAttribute()
a2 := object.NewAttribute()
require.NoError(t, a2.Unmarshal(data))
require.Equal(t, a, a2)
@ -42,7 +43,7 @@ func TestAttributeEncoding(t *testing.T) {
data, err := a.MarshalJSON()
require.NoError(t, err)
a2 := NewAttribute()
a2 := object.NewAttribute()
require.NoError(t, a2.UnmarshalJSON(data))
require.Equal(t, a, a2)
@ -51,15 +52,15 @@ func TestAttributeEncoding(t *testing.T) {
func TestNewAttributeFromV2(t *testing.T) {
t.Run("from nil", func(t *testing.T) {
var x *object.Attribute
var x *objectgrpc.Header_Attribute
require.Nil(t, NewAttributeFromV2(x))
require.Nil(t, object.NewAttributeFromV2(x))
})
}
func TestAttribute_ToV2(t *testing.T) {
t.Run("nil", func(t *testing.T) {
var x *Attribute
var x *object.Attribute
require.Nil(t, x.ToV2())
})
@ -67,11 +68,11 @@ func TestAttribute_ToV2(t *testing.T) {
func TestNewAttribute(t *testing.T) {
t.Run("default values", func(t *testing.T) {
a := NewAttribute()
a := object.NewAttribute()
// check initial values
require.Empty(t, a.Key())
require.Empty(t, a.Value())
require.Empty(t, a.GetKey())
require.Empty(t, a.GetValue())
// convert to v2 message
aV2 := a.ToV2()

View file

@ -7,7 +7,6 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
@ -22,7 +21,7 @@ var (
// CalculatePayloadChecksum calculates and returns checksum of
// object payload bytes.
func CalculatePayloadChecksum(payload []byte) checksum.Checksum {
var res checksum.Checksum
res := checksum.NewChecksum()
checksum.Calculate(&res, checksum.SHA256, payload)
return res
@ -114,21 +113,21 @@ func CalculateAndSetSignature(key ecdsa.PrivateKey, obj *Object) error {
// VerifyIDSignature verifies object ID signature.
func (o *Object) VerifyIDSignature() bool {
m := (*object.Object)(o)
m := o.object
sigV2 := m.GetSignature()
if sigV2 == nil {
return false
}
idV2 := m.GetObjectID()
idV2 := m.GetObjectId()
if idV2 == nil {
return false
}
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
return sig.ReadFromV2(*sigV2) == nil && sig.Verify(idV2.StableMarshal(nil))
return sig.ReadFromV2(sigV2) == nil && sig.Verify(idV2.StableMarshal(nil))
}
// SetIDWithSignature sets object identifier and signature.

View file

@ -29,10 +29,10 @@ func TestVerificationFields(t *testing.T) {
}{
{
corrupt: func() {
payload[0]++
obj.object.Payload[0]++
},
restore: func() {
payload[0]--
obj.object.Payload[0]--
},
},
{
@ -45,10 +45,10 @@ func TestVerificationFields(t *testing.T) {
},
{
corrupt: func() {
obj.ToV2().GetObjectID().GetValue()[0]++
obj.ToV2().GetObjectId().GetValue()[0]++
},
restore: func() {
obj.ToV2().GetObjectID().GetValue()[0]--
obj.ToV2().GetObjectId().GetValue()[0]--
},
},
}

View file

@ -5,44 +5,45 @@ import (
"fmt"
"strings"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cidSDK "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
"google.golang.org/protobuf/encoding/protojson"
)
// Address represents global object identifier in FrostFS network. Each object
// belongs to exactly one container and is uniquely addressed within the container.
//
// Address is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs.Address
// message. See ReadFromV2 / WriteToV2 methods.
// Address is mutually compatible with git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refsgrpc.Address
// message. See ReadFrom / WriteTo methods.
//
// Instances can be created using built-in var declaration.
type Address struct {
cnr cid.ID
cnr cidSDK.ID
obj ID
}
// ReadFromV2 reads Address from the refs.Address message. Returns an error if
// ReadFrom reads Address from the refsgrpc.Address message. Returns an error if
// the message is malformed according to the FrostFS API V2 protocol.
//
// See also WriteToV2.
func (x *Address) ReadFromV2(m refs.Address) error {
cnr := m.GetContainerID()
// See also WriteTo.
func (x *Address) ReadFromV2(m *refsgrpc.Address) error {
cnr := m.GetContainerId()
if cnr == nil {
return errors.New("missing container ID")
}
obj := m.GetObjectID()
obj := m.GetObjectId()
if obj == nil {
return errors.New("missing object ID")
}
err := x.cnr.ReadFromV2(*cnr)
err := x.cnr.ReadFromV2(cnr)
if err != nil {
return fmt.Errorf("invalid container ID: %w", err)
}
err = x.obj.ReadFromV2(*obj)
err = x.obj.ReadFromV2(obj)
if err != nil {
return fmt.Errorf("invalid object ID: %w", err)
}
@ -50,19 +51,20 @@ func (x *Address) ReadFromV2(m refs.Address) error {
return nil
}
// WriteToV2 writes Address to the refs.Address message.
// WriteTo writes Address to the refsgrpc.Address message.
// The message must not be nil.
//
// See also ReadFromV2.
func (x Address) WriteToV2(m *refs.Address) {
var obj refs.ObjectID
// See also ReadFrom.
func (x Address) WriteToV2(m *refsgrpc.Address) {
m.Reset()
var obj refsgrpc.ObjectID
x.obj.WriteToV2(&obj)
var cnr refs.ContainerID
var cnr refsgrpc.ContainerID
x.cnr.WriteToV2(&cnr)
m.SetObjectID(&obj)
m.SetContainerID(&cnr)
m.SetObjectId(&obj)
m.SetContainerId(&cnr)
}
// MarshalJSON encodes Address into a JSON format of the FrostFS API protocol
@ -70,10 +72,10 @@ func (x Address) WriteToV2(m *refs.Address) {
//
// See also UnmarshalJSON.
func (x Address) MarshalJSON() ([]byte, error) {
var m refs.Address
var m refsgrpc.Address
x.WriteToV2(&m)
return m.MarshalJSON()
return protojson.Marshal(&m)
}
// UnmarshalJSON decodes FrostFS API protocol JSON format into the Address
@ -81,14 +83,14 @@ func (x Address) MarshalJSON() ([]byte, error) {
//
// See also MarshalJSON.
func (x *Address) UnmarshalJSON(data []byte) error {
var m refs.Address
var m refsgrpc.Address
err := m.UnmarshalJSON(data)
err := protojson.Unmarshal(data, &m)
if err != nil {
return err
}
return x.ReadFromV2(m)
return x.ReadFromV2(&m)
}
// Container returns unique identifier of the FrostFS object container.
@ -97,14 +99,14 @@ func (x *Address) UnmarshalJSON(data []byte) error {
// API protocol.
//
// See also SetContainer.
func (x Address) Container() cid.ID {
func (x Address) Container() cidSDK.ID {
return x.cnr
}
// SetContainer sets unique identifier of the FrostFS object container.
//
// See also Container.
func (x *Address) SetContainer(id cid.ID) {
func (x *Address) SetContainer(id cidSDK.ID) {
x.cnr = id
}

View file

@ -3,11 +3,12 @@ package oid_test
import (
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
cidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id/test"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
oidtest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id/test"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestAddress_SetContainer(t *testing.T) {
@ -32,38 +33,38 @@ func TestAddress_SetObject(t *testing.T) {
require.Equal(t, obj, x.Object())
}
func TestAddress_ReadFromV2(t *testing.T) {
func TestAddress_ReadFrom(t *testing.T) {
var x oid.Address
var xV2 refs.Address
require.Error(t, x.ReadFromV2(xV2))
require.Error(t, x.ReadFromV2(&xV2))
var cnrV2 refs.ContainerID
xV2.SetContainerID(&cnrV2)
xV2.SetContainerId(&cnrV2)
require.Error(t, x.ReadFromV2(xV2))
require.Error(t, x.ReadFromV2(&xV2))
cnr := cidtest.ID()
cnr.WriteToV2(&cnrV2)
require.Error(t, x.ReadFromV2(xV2))
require.Error(t, x.ReadFromV2(&xV2))
var objV2 refs.ObjectID
xV2.SetObjectID(&objV2)
xV2.SetObjectId(&objV2)
require.Error(t, x.ReadFromV2(xV2))
require.Error(t, x.ReadFromV2(&xV2))
obj := oidtest.ID()
obj.WriteToV2(&objV2)
require.NoError(t, x.ReadFromV2(xV2))
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)
require.True(t, proto.Equal(&xV2, &xV2To))
}
func TestAddress_DecodeString(t *testing.T) {

View file

@ -5,10 +5,12 @@ import (
"crypto/sha256"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
frostfsecdsa "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto/ecdsa"
"github.com/golang/protobuf/proto"
"github.com/mr-tron/base58"
"google.golang.org/protobuf/encoding/protojson"
)
// ID represents FrostFS object identifier in a container.
@ -27,7 +29,7 @@ type ID [sha256.Size]byte
// the message is malformed according to the FrostFS API V2 protocol.
//
// See also WriteToV2.
func (id *ID) ReadFromV2(m refs.ObjectID) error {
func (id *ID) ReadFromV2(m *refs.ObjectID) error {
return id.Decode(m.GetValue())
}
@ -36,6 +38,7 @@ func (id *ID) ReadFromV2(m refs.ObjectID) error {
//
// See also ReadFromV2.
func (id ID) WriteToV2(m *refs.ObjectID) {
m.Reset()
m.SetValue(id[:])
}
@ -123,7 +126,7 @@ func (id ID) CalculateIDSignature(key ecdsa.PrivateKey) (frostfscrypto.Signature
return frostfscrypto.Signature{}, fmt.Errorf("marshal ID: %w", err)
}
var sig frostfscrypto.Signature
sig := frostfscrypto.NewSignature()
return sig, sig.Calculate(frostfsecdsa.Signer(key), data)
}
@ -139,7 +142,7 @@ func (id ID) Marshal() ([]byte, error) {
// Unmarshal unmarshals protobuf binary representation of ID.
func (id *ID) Unmarshal(data []byte) error {
var v2 refs.ObjectID
if err := v2.Unmarshal(data); err != nil {
if err := proto.Unmarshal(data, &v2); err != nil {
return err
}
@ -153,13 +156,13 @@ func (id ID) MarshalJSON() ([]byte, error) {
var v2 refs.ObjectID
v2.SetValue(id[:])
return v2.MarshalJSON()
return protojson.Marshal(&v2)
}
// UnmarshalJSON decodes ID from protobuf JSON format.
func (id *ID) UnmarshalJSON(data []byte) error {
var v2 refs.ObjectID
if err := v2.UnmarshalJSON(data); err != nil {
if err := protojson.Unmarshal(data, &v2); err != nil {
return err
}

View file

@ -6,7 +6,7 @@ import (
"strconv"
"testing"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
refs "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
"github.com/mr-tron/base58"
"github.com/stretchr/testify/require"
)
@ -142,7 +142,7 @@ func TestNewIDFromV2(t *testing.T) {
v2 refs.ObjectID
)
require.Error(t, x.ReadFromV2(v2))
require.Error(t, x.ReadFromV2(&v2))
})
}

View file

@ -1,16 +1,25 @@
package object
import (
v2object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
v2lock "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/lock/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
)
// Lock represents record with locked objects. It is compatible with
// FrostFS API V2 protocol.
//
// Lock instance can be written to the Object, see WriteLock/ReadLock.
type Lock v2object.Lock
type Lock struct {
lock *v2lock.Lock
}
func NewLock() *Lock {
return &Lock{
lock: &v2lock.Lock{},
}
}
// WriteLock writes Lock to the Object, and sets its type to TypeLock.
// The object must not be nil.
@ -26,13 +35,13 @@ func WriteLock(obj *Object, l Lock) {
// if object has TypeLock type.
//
// See also WriteLock.
func ReadLock(l *Lock, obj Object) error {
func ReadLock(l *Lock, obj *Object) error {
return l.Unmarshal(obj.Payload())
}
// NumberOfMembers returns number of members in lock list.
func (x Lock) NumberOfMembers() int {
return (*v2object.Lock)(&x).NumberOfMembers()
return x.lock.NumberOfMembers()
}
// ReadMembers reads list of locked members.
@ -41,7 +50,7 @@ func (x Lock) NumberOfMembers() int {
func (x Lock) ReadMembers(buf []oid.ID) {
var i int
(*v2object.Lock)(&x).IterateMembers(func(idV2 refs.ObjectID) {
x.lock.IterateMembers(func(idV2 *refsgrpc.ObjectID) {
_ = buf[i].ReadFromV2(idV2)
i++
})
@ -49,25 +58,34 @@ func (x Lock) ReadMembers(buf []oid.ID) {
// WriteMembers writes list of locked members.
func (x *Lock) WriteMembers(ids []oid.ID) {
var members []refs.ObjectID
var members []*refsgrpc.ObjectID
if ids != nil {
members = make([]refs.ObjectID, len(ids))
members = slices.MakePreallocPointerSlice[refsgrpc.ObjectID](len(ids))
for i := range ids {
ids[i].WriteToV2(&members[i])
ids[i].WriteToV2(members[i])
}
}
(*v2object.Lock)(x).SetMembers(members)
if x.lock == nil {
x.lock = new(v2lock.Lock)
}
x.lock.SetMembers(members)
}
func (x *Lock) ToV2() *v2lock.Lock {
return x.lock
}
// Marshal encodes the Lock into a FrostFS protocol binary format.
func (x Lock) Marshal() []byte {
return (*v2object.Lock)(&x).StableMarshal(nil)
return x.lock.StableMarshal(nil)
}
// Unmarshal decodes the Lock from its FrostFS protocol binary representation.
func (x *Lock) Unmarshal(data []byte) error {
return (*v2object.Lock)(x).Unmarshal(data)
if x.lock == nil {
x.lock = new(v2lock.Lock)
}
return x.lock.Unmarshal(data)
}

View file

@ -6,6 +6,7 @@ import (
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object"
objecttest "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/test"
"github.com/stretchr/testify/require"
"google.golang.org/protobuf/proto"
)
func TestLockEncoding(t *testing.T) {
@ -14,26 +15,26 @@ func TestLockEncoding(t *testing.T) {
t.Run("binary", func(t *testing.T) {
data := l.Marshal()
var l2 object.Lock
l2 := object.NewLock()
require.NoError(t, l2.Unmarshal(data))
require.Equal(t, l, l2)
require.True(t, proto.Equal(l.ToV2(), l2.ToV2()))
})
}
func TestWriteLock(t *testing.T) {
l := *objecttest.Lock()
var o object.Object
o := object.New()
object.WriteLock(&o, l)
object.WriteLock(o, l)
var l2 object.Lock
l2 := object.NewLock()
require.NoError(t, object.ReadLock(&l2, o))
require.Equal(t, l, l2)
require.NoError(t, object.ReadLock(l2, o))
require.True(t, proto.Equal(l.ToV2(), l2.ToV2()))
// corrupt payload
o.Payload()[0]++
require.Error(t, object.ReadLock(&l2, o))
require.Error(t, object.ReadLock(l2, o))
}

View file

@ -4,31 +4,37 @@ import (
"errors"
"fmt"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
v2session "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session"
object "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object"
objectgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/object/grpc"
refsgrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs/grpc"
sessiongrpc "git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/session/grpc"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/checksum"
cid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container/id"
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
oid "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/object/id"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/session"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/user"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/util/slices"
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/version"
"github.com/golang/protobuf/proto"
"google.golang.org/protobuf/encoding/protojson"
)
// Object represents in-memory structure of the FrostFS object.
// Object represents in-memory structure of the FrostFS objectgrpc.
// Type is compatible with FrostFS API V2 protocol.
//
// Instance can be created depending on scenario:
// - InitCreation (an object to be placed in container);
// - New (blank instance, usually needed for decoding);
// - NewFromV2 (when working under FrostFS API V2 protocol).
type Object object.Object
type Object struct {
object *objectgrpc.Object
}
// RequiredFields contains the minimum set of object data that must be set
// by the FrostFS user at the stage of creation.
type RequiredFields struct {
// Identifier of the FrostFS container associated with the object.
// Identifier of the FrostFS container associated with the objectgrpc.
Container cid.ID
// Object owner's user ID in the FrostFS system.
@ -43,45 +49,52 @@ func InitCreation(dst *Object, rf RequiredFields) {
}
// NewFromV2 wraps v2 Object message to Object.
func NewFromV2(oV2 *object.Object) *Object {
return (*Object)(oV2)
func NewFromV2(obj *objectgrpc.Object) *Object {
objSDK := &Object{
object: new(objectgrpc.Object),
}
proto.Merge(objSDK.object, obj)
return objSDK
}
// New creates and initializes blank Object.
//
// Works similar as NewFromV2(new(Object)).
func New() *Object {
return NewFromV2(new(object.Object))
return NewFromV2(new(objectgrpc.Object))
}
// ToV2 converts Object to v2 Object message.
func (o *Object) ToV2() *object.Object {
return (*object.Object)(o)
func (o *Object) ToV2() *objectgrpc.Object {
return o.object
}
// MarshalHeaderJSON marshals object's header
// into JSON format.
func (o *Object) MarshalHeaderJSON() ([]byte, error) {
return (*object.Object)(o).GetHeader().MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
o.object.GetHeader(),
)
}
func (o *Object) setHeaderField(setter func(*object.Header)) {
obj := (*object.Object)(o)
h := obj.GetHeader()
func (o *Object) setHeaderField(setter func(*objectgrpc.Header)) {
h := o.object.GetHeader()
if h == nil {
h = new(object.Header)
obj.SetHeader(h)
h = new(objectgrpc.Header)
o.object.SetHeader(h)
}
setter(h)
}
func (o *Object) setSplitFields(setter func(*object.SplitHeader)) {
o.setHeaderField(func(h *object.Header) {
func (o *Object) setSplitFields(setter func(*objectgrpc.Header_Split)) {
o.setHeaderField(func(h *objectgrpc.Header) {
split := h.GetSplit()
if split == nil {
split = new(object.SplitHeader)
split = new(objectgrpc.Header_Split)
h.SetSplit(split)
}
@ -91,9 +104,9 @@ func (o *Object) setSplitFields(setter func(*object.SplitHeader)) {
// ID returns object identifier.
func (o *Object) ID() (v oid.ID, isSet bool) {
v2 := (*object.Object)(o)
if id := v2.GetObjectID(); id != nil {
_ = v.ReadFromV2(*v2.GetObjectID())
v2 := o.object
if id := v2.GetObjectId(); id != nil {
_ = v.ReadFromV2(v2.GetObjectId())
isSet = true
}
@ -102,89 +115,88 @@ func (o *Object) ID() (v oid.ID, isSet bool) {
// SetID sets object identifier.
func (o *Object) SetID(v oid.ID) {
var v2 refs.ObjectID
var v2 refsgrpc.ObjectID
v.WriteToV2(&v2)
(*object.Object)(o).
SetObjectID(&v2)
o.object.SetObjectId(&v2)
}
// Signature returns signature of the object identifier.
func (o *Object) Signature() *frostfscrypto.Signature {
sigv2 := (*object.Object)(o).GetSignature()
sigv2 := o.object.GetSignature()
if sigv2 == nil {
return nil
}
var sig frostfscrypto.Signature
_ = sig.ReadFromV2(*sigv2) // FIXME(@cthulhu-rider): #226 handle error
sig := frostfscrypto.NewSignature()
_ = sig.ReadFromV2(sigv2) // FIXME(@cthulhu-rider): #226 handle error
return &sig
}
// SetSignature sets signature of the object identifier.
func (o *Object) SetSignature(v *frostfscrypto.Signature) {
var sigv2 *refs.Signature
var sigv2 *refsgrpc.Signature
if v != nil {
sigv2 = new(refs.Signature)
sigv2 = new(refsgrpc.Signature)
v.WriteToV2(sigv2)
}
(*object.Object)(o).SetSignature(sigv2)
o.object.SetSignature(sigv2)
}
// Payload returns payload bytes.
func (o *Object) Payload() []byte {
return (*object.Object)(o).GetPayload()
return o.object.GetPayload()
}
// SetPayload sets payload bytes.
func (o *Object) SetPayload(v []byte) {
(*object.Object)(o).SetPayload(v)
o.object.SetPayload(v)
}
// Version returns version of the object.
// Version returns version of the objectgrpc.
func (o *Object) Version() *version.Version {
var ver version.Version
if verV2 := (*object.Object)(o).GetHeader().GetVersion(); verV2 != nil {
_ = ver.ReadFromV2(*verV2) // FIXME(@cthulhu-rider): #226 handle error
ver := version.NewVersion()
if verV2 := o.object.GetHeader().GetVersion(); verV2 != nil {
ver.ReadFromV2(verV2)
}
return &ver
}
// SetVersion sets version of the object.
func (o *Object) SetVersion(v *version.Version) {
var verV2 refs.Version
// SetVersion sets version of the objectgrpc.
func (o *Object) SetVersion(v version.Version) {
var verV2 refsgrpc.Version
v.WriteToV2(&verV2)
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetVersion(&verV2)
})
}
// PayloadSize returns payload length of the object.
// PayloadSize returns payload length of the objectgrpc.
func (o *Object) PayloadSize() uint64 {
return (*object.Object)(o).
return o.object.
GetHeader().
GetPayloadLength()
}
// SetPayloadSize sets payload length of the object.
// SetPayloadSize sets payload length of the objectgrpc.
func (o *Object) SetPayloadSize(v uint64) {
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetPayloadLength(v)
})
}
// ContainerID returns identifier of the related container.
func (o *Object) ContainerID() (v cid.ID, isSet bool) {
v2 := (*object.Object)(o)
v2 := o.object
cidV2 := v2.GetHeader().GetContainerID()
cidV2 := v2.GetHeader().GetContainerId()
if cidV2 != nil {
_ = v.ReadFromV2(*cidV2)
_ = v.ReadFromV2(cidV2)
isSet = true
}
@ -193,21 +205,25 @@ func (o *Object) ContainerID() (v cid.ID, isSet bool) {
// SetContainerID sets identifier of the related container.
func (o *Object) SetContainerID(v cid.ID) {
var cidV2 refs.ContainerID
var cidV2 refsgrpc.ContainerID
v.WriteToV2(&cidV2)
o.setHeaderField(func(h *object.Header) {
h.SetContainerID(&cidV2)
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetContainerId(&cidV2)
})
}
func (o *Object) Equal(o1 *Object) bool {
return proto.Equal(o.object, o1.object)
}
// OwnerID returns identifier of the object owner.
func (o *Object) OwnerID() *user.ID {
var id user.ID
m := (*object.Object)(o).GetHeader().GetOwnerID()
m := o.object.GetHeader().GetOwnerId()
if m != nil {
_ = id.ReadFromV2(*m)
_ = id.ReadFromV2(m)
}
return &id
@ -215,40 +231,40 @@ func (o *Object) OwnerID() *user.ID {
// SetOwnerID sets identifier of the object owner.
func (o *Object) SetOwnerID(v *user.ID) {
o.setHeaderField(func(h *object.Header) {
var m refs.OwnerID
o.setHeaderField(func(h *objectgrpc.Header) {
var m refsgrpc.OwnerID
v.WriteToV2(&m)
h.SetOwnerID(&m)
h.SetOwnerId(&m)
})
}
// CreationEpoch returns epoch number in which object was created.
func (o *Object) CreationEpoch() uint64 {
return (*object.Object)(o).
return o.object.
GetHeader().
GetCreationEpoch()
}
// SetCreationEpoch sets epoch number in which object was created.
func (o *Object) SetCreationEpoch(v uint64) {
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetCreationEpoch(v)
})
}
// PayloadChecksum returns checksum of the object payload and
// bool that indicates checksum presence in the object.
// bool that indicates checksum presence in the objectgrpc.
//
// Zero Object does not have payload checksum.
//
// See also SetPayloadChecksum.
func (o *Object) PayloadChecksum() (checksum.Checksum, bool) {
var v checksum.Checksum
v2 := (*object.Object)(o)
v := checksum.NewChecksum()
v2 := o.object
if hash := v2.GetHeader().GetPayloadHash(); hash != nil {
_ = v.ReadFromV2(*hash) // FIXME(@cthulhu-rider): #226 handle error
_ = v.ReadFromV2(hash) // FIXME(@cthulhu-rider): #226 handle error
return v, true
}
@ -259,26 +275,26 @@ func (o *Object) PayloadChecksum() (checksum.Checksum, bool) {
//
// See also PayloadChecksum.
func (o *Object) SetPayloadChecksum(v checksum.Checksum) {
var v2 refs.Checksum
var v2 refsgrpc.Checksum
v.WriteToV2(&v2)
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetPayloadHash(&v2)
})
}
// PayloadHomomorphicHash returns homomorphic hash of the object
// payload and bool that indicates checksum presence in the object.
// payload and bool that indicates checksum presence in the objectgrpc.
//
// Zero Object does not have payload homomorphic checksum.
//
// See also SetPayloadHomomorphicHash.
func (o *Object) PayloadHomomorphicHash() (checksum.Checksum, bool) {
var v checksum.Checksum
v2 := (*object.Object)(o)
v := checksum.NewChecksum()
v2 := o.object
if hash := v2.GetHeader().GetHomomorphicHash(); hash != nil {
_ = v.ReadFromV2(*hash) // FIXME(@cthulhu-rider): #226 handle error
_ = v.ReadFromV2(hash) // FIXME(@cthulhu-rider): #226 handle error
return v, true
}
@ -289,24 +305,24 @@ func (o *Object) PayloadHomomorphicHash() (checksum.Checksum, bool) {
//
// See also PayloadHomomorphicHash.
func (o *Object) SetPayloadHomomorphicHash(v checksum.Checksum) {
var v2 refs.Checksum
var v2 refsgrpc.Checksum
v.WriteToV2(&v2)
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetHomomorphicHash(&v2)
})
}
// Attributes returns object attributes.
func (o *Object) Attributes() []Attribute {
attrs := (*object.Object)(o).
attrs := o.object.
GetHeader().
GetAttributes()
res := make([]Attribute, len(attrs))
for i := range attrs {
res[i] = *NewAttributeFromV2(&attrs[i])
res[i] = *NewAttributeFromV2(attrs[i])
}
return res
@ -314,43 +330,42 @@ func (o *Object) Attributes() []Attribute {
// SetAttributes sets object attributes.
func (o *Object) SetAttributes(v ...Attribute) {
attrs := make([]object.Attribute, len(v))
attrs := slices.MakePreallocPointerSlice[objectgrpc.Header_Attribute](len(v))
for i := range v {
attrs[i] = *v[i].ToV2()
attrs[i] = v[i].ToV2()
}
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetAttributes(attrs)
})
}
// PreviousID returns identifier of the previous sibling object.
// PreviousID returns identifier of the previous sibling objectgrpc.
func (o *Object) PreviousID() (v oid.ID, isSet bool) {
v2 := (*object.Object)(o)
v2 := o.object
v2Prev := v2.GetHeader().GetSplit().GetPrevious()
if v2Prev != nil {
_ = v.ReadFromV2(*v2Prev)
_ = v.ReadFromV2(v2Prev)
isSet = true
}
return
}
// SetPreviousID sets identifier of the previous sibling object.
// SetPreviousID sets identifier of the previous sibling objectgrpc.
func (o *Object) SetPreviousID(v oid.ID) {
var v2 refs.ObjectID
var v2 refsgrpc.ObjectID
v.WriteToV2(&v2)
o.setSplitFields(func(split *object.SplitHeader) {
o.setSplitFields(func(split *objectgrpc.Header_Split) {
split.SetPrevious(&v2)
})
}
// Children return list of the identifiers of the child objects.
func (o *Object) Children() []oid.ID {
v2 := (*object.Object)(o)
v2 := o.object
ids := v2.GetHeader().GetSplit().GetChildren()
var (
@ -368,23 +383,21 @@ func (o *Object) Children() []oid.ID {
// SetChildren sets list of the identifiers of the child objects.
func (o *Object) SetChildren(v ...oid.ID) {
var (
v2 refs.ObjectID
ids = make([]refs.ObjectID, len(v))
)
ids := make([]*refsgrpc.ObjectID, len(v))
for i := range v {
var v2 refsgrpc.ObjectID
v[i].WriteToV2(&v2)
ids[i] = v2
ids[i] = &v2
}
o.setSplitFields(func(split *object.SplitHeader) {
o.setSplitFields(func(split *objectgrpc.Header_Split) {
split.SetChildren(ids)
})
}
// NotificationInfo groups information about object notification
// that can be written to object.
// that can be written to objectgrpc.
//
// Topic is an optional field.
type NotificationInfo struct {
@ -420,7 +433,7 @@ func (n *NotificationInfo) SetTopic(topic string) {
// Returns any error that appeared during notification
// information parsing.
func (o *Object) NotificationInfo() (*NotificationInfo, error) {
ni, err := object.GetNotificationInfo((*object.Object)(o))
ni, err := object.GetNotificationInfo(o.object)
if err != nil {
return nil, err
}
@ -432,53 +445,53 @@ func (o *Object) NotificationInfo() (*NotificationInfo, error) {
// SetNotification writes NotificationInfo to the object structure.
func (o *Object) SetNotification(ni NotificationInfo) {
object.WriteNotificationInfo((*object.Object)(o), ni.ni)
object.WriteNotificationInfo(o.object, ni.ni)
}
// SplitID return split identity of split object. If object is not split
// SplitID return split identity of split objectgrpc. If object is not split
// returns nil.
func (o *Object) SplitID() *SplitID {
return NewSplitIDFromV2(
(*object.Object)(o).
o.object.
GetHeader().
GetSplit().
GetSplitID(),
GetSplitId(),
)
}
// SetSplitID sets split identifier for the split object.
// SetSplitID sets split identifier for the split objectgrpc.
func (o *Object) SetSplitID(id *SplitID) {
o.setSplitFields(func(split *object.SplitHeader) {
split.SetSplitID(id.ToV2())
o.setSplitFields(func(split *objectgrpc.Header_Split) {
split.SetSplitId(id.ToV2())
})
}
// ParentID returns identifier of the parent object.
// ParentID returns identifier of the parent objectgrpc.
func (o *Object) ParentID() (v oid.ID, isSet bool) {
v2 := (*object.Object)(o)
v2 := o.object
v2Par := v2.GetHeader().GetSplit().GetParent()
if v2Par != nil {
_ = v.ReadFromV2(*v2Par)
_ = v.ReadFromV2(v2Par)
isSet = true
}
return
}
// SetParentID sets identifier of the parent object.
// SetParentID sets identifier of the parent objectgrpc.
func (o *Object) SetParentID(v oid.ID) {
var v2 refs.ObjectID
var v2 refsgrpc.ObjectID
v.WriteToV2(&v2)
o.setSplitFields(func(split *object.SplitHeader) {
o.setSplitFields(func(split *objectgrpc.Header_Split) {
split.SetParent(&v2)
})
}
// Parent returns parent object w/o payload.
func (o *Object) Parent() *Object {
h := (*object.Object)(o).
h := o.object.
GetHeader().
GetSplit()
@ -489,8 +502,8 @@ func (o *Object) Parent() *Object {
return nil
}
oV2 := new(object.Object)
oV2.SetObjectID(h.GetParent())
oV2 := new(objectgrpc.Object)
oV2.SetObjectId(h.GetParent())
oV2.SetSignature(parSig)
oV2.SetHeader(parHdr)
@ -499,21 +512,21 @@ func (o *Object) Parent() *Object {
// SetParent sets parent object w/o payload.
func (o *Object) SetParent(v *Object) {
o.setSplitFields(func(split *object.SplitHeader) {
split.SetParent((*object.Object)(v).GetObjectID())
split.SetParentSignature((*object.Object)(v).GetSignature())
split.SetParentHeader((*object.Object)(v).GetHeader())
o.setSplitFields(func(split *objectgrpc.Header_Split) {
split.SetParent(v.object.GetObjectId())
split.SetParentSignature(v.object.GetSignature())
split.SetParentHeader(v.object.GetHeader())
})
}
func (o *Object) initRelations() {
o.setHeaderField(func(h *object.Header) {
h.SetSplit(new(object.SplitHeader))
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetSplit(new(objectgrpc.Header_Split))
})
}
func (o *Object) resetRelations() {
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetSplit(nil)
})
}
@ -521,26 +534,26 @@ func (o *Object) resetRelations() {
// SessionToken returns token of the session
// within which object was created.
func (o *Object) SessionToken() *session.Object {
tokv2 := (*object.Object)(o).GetHeader().GetSessionToken()
tokv2 := o.object.GetHeader().GetSessionToken()
if tokv2 == nil {
return nil
}
var res session.Object
res := session.NewObject()
_ = res.ReadFromV2(*tokv2)
_ = res.ReadFromV2(tokv2)
return &res
return res
}
// SetSessionToken sets token of the session
// within which object was created.
func (o *Object) SetSessionToken(v *session.Object) {
o.setHeaderField(func(h *object.Header) {
var tokv2 *v2session.Token
o.setHeaderField(func(h *objectgrpc.Header) {
var tokv2 *sessiongrpc.SessionToken
if v != nil {
tokv2 = new(v2session.Token)
tokv2 = new(sessiongrpc.SessionToken)
v.WriteToV2(tokv2)
}
@ -551,32 +564,29 @@ func (o *Object) SetSessionToken(v *session.Object) {
// Type returns type of the object.
func (o *Object) Type() Type {
return TypeFromV2(
(*object.Object)(o).
o.object.
GetHeader().
GetObjectType(),
)
}
// SetType sets type of the object.
// SetType sets type of the objectgrpc.
func (o *Object) SetType(v Type) {
o.setHeaderField(func(h *object.Header) {
o.setHeaderField(func(h *objectgrpc.Header) {
h.SetObjectType(v.ToV2())
})
}
// CutPayload returns Object w/ empty payload.
//
// Changes of non-payload fields affect source object.
// CutPayload returns Object with empty payload.
func (o *Object) CutPayload() *Object {
ov2 := new(object.Object)
*ov2 = *(*object.Object)(o)
ov2.SetPayload(nil)
return (*Object)(ov2)
ov2 := New()
proto.Merge(ov2.object, o.object)
ov2.object.SetPayload(nil)
return ov2
}
func (o *Object) HasParent() bool {
return (*object.Object)(o).
return o.object.
GetHeader().
GetSplit() != nil
}
@ -593,72 +603,79 @@ func (o *Object) InitRelations() {
// Marshal marshals object into a protobuf binary form.
func (o *Object) Marshal() ([]byte, error) {
return (*object.Object)(o).StableMarshal(nil), nil
return o.object.StableMarshal(nil), nil
}
// Unmarshal unmarshals protobuf binary representation of object.
func (o *Object) Unmarshal(data []byte) error {
err := (*object.Object)(o).Unmarshal(data)
if o.object == nil {
o.object = new(objectgrpc.Object)
}
err := proto.Unmarshal(data, o.object)
if err != nil {
return err
}
return formatCheck((*object.Object)(o))
return formatCheck(o.object)
}
// MarshalJSON encodes object to protobuf JSON format.
func (o *Object) MarshalJSON() ([]byte, error) {
return (*object.Object)(o).MarshalJSON()
return protojson.MarshalOptions{
EmitUnpopulated: true,
}.Marshal(
o.object,
)
}
// UnmarshalJSON decodes object from protobuf JSON format.
func (o *Object) UnmarshalJSON(data []byte) error {
err := (*object.Object)(o).UnmarshalJSON(data)
err := protojson.Unmarshal(data, o.object)
if err != nil {
return err
}
return formatCheck((*object.Object)(o))
return formatCheck(o.object)
}
var errOIDNotSet = errors.New("object ID is not set")
var errCIDNotSet = errors.New("container ID is not set")
func formatCheck(v2 *object.Object) error {
func formatCheck(v2 *objectgrpc.Object) error {
var (
oID oid.ID
cID cid.ID
)
oidV2 := v2.GetObjectID()
oidV2 := v2.GetObjectId()
if oidV2 == nil {
return errOIDNotSet
}
err := oID.ReadFromV2(*oidV2)
err := oID.ReadFromV2(oidV2)
if err != nil {
return fmt.Errorf("could not convert V2 object ID: %w", err)
}
cidV2 := v2.GetHeader().GetContainerID()
cidV2 := v2.GetHeader().GetContainerId()
if cidV2 == nil {
return errCIDNotSet
}
err = cID.ReadFromV2(*cidV2)
err = cID.ReadFromV2(cidV2)
if err != nil {
return fmt.Errorf("could not convert V2 container ID: %w", err)
}
if prev := v2.GetHeader().GetSplit().GetPrevious(); prev != nil {
err = oID.ReadFromV2(*prev)
err = oID.ReadFromV2(prev)
if err != nil {
return fmt.Errorf("could not convert previous object ID: %w", err)
}
}
if parent := v2.GetHeader().GetSplit().GetParent(); parent != nil {
err = oID.ReadFromV2(*parent)
err = oID.ReadFromV2(parent)
if err != nil {
return fmt.Errorf("could not convert parent object ID: %w", err)
}

Some files were not shown because too many files have changed in this diff Show more